Development #24

Merged
kyle merged 35 commits from development into main 2026-08-28 10:40:10 -05:00
17 changed files with 5 additions and 58 deletions
Showing only changes of commit 895737febc - Show all commits
+1 -2
View File
@@ -9,8 +9,7 @@ export const Route = createFileRoute("/api/health")({
ensureTelemetryScheduler();
const snapshot = await getHealthSnapshot();
// Always 200: a PB/SuperTokens outage must not fail the k8s probes;
// restarting the app pod cannot fix a dependency.
// Always 200: a dependency outage must not fail the k8s probes.
return new Response(
JSON.stringify({
status: snapshot.status,
-2
View File
@@ -45,8 +45,6 @@ const writeEvents = async (
const { pbAdmin } = await import("@/lib/pocketbase/client");
await pbAdmin.authPromise;
// Sequential on purpose: SQLite is single-writer; a burst of parallel
// creates just queues behind the lock.
for (const event of events) {
try {
if (event.kind === "error") {
-2
View File
@@ -5,8 +5,6 @@ const csrfMiddleware = createCsrfMiddleware({
filter: (ctx) => ctx.handlerType === "serverFn",
});
// Global function middleware: every server fn (current and future) is audited
// without opting in at the definition site.
export const startInstance = createStart(() => ({
requestMiddleware: [csrfMiddleware],
functionMiddleware: [serverFnLoggingMiddleware],
@@ -10,7 +10,6 @@ interface QuietBoundaryState {
hasError: boolean;
}
// One failing telemetry card must not blank the whole dashboard.
export class QuietBoundary extends Component<QuietBoundaryProps, QuietBoundaryState> {
state: QuietBoundaryState = { hasError: false };
-4
View File
@@ -99,8 +99,6 @@ export const getClientErrorGroups = createServerFn()
const sample = latest.items[0];
if (!sample) continue;
// A group counts as resolved when its most recent occurrence is
// resolved; a recurrence arrives resolved=false and surfaces again.
const resolved = !!sample.resolved;
if (resolved && !includeResolved) continue;
@@ -161,8 +159,6 @@ export const getTelemetryRuntimeStatus = createServerFn()
.middleware([superTokensAdminFunctionMiddleware])
.handler(async () =>
toServerResult<TelemetryRuntimeStatus>(async () => {
// Dev has no k8s probes hitting /api/health, so opening the dashboard
// is the scheduler's fallback starter.
ensureTelemetryScheduler();
const health = await getHealthSnapshot();
return {
+1 -6
View File
@@ -199,8 +199,7 @@ export function createTelemetryService(pb: PocketBase) {
};
},
// Idempotent by the (date, metric, dim) unique index; dim must be "" (never
// null/undefined) or the index stops deduplicating.
// dim must be "" (never null/undefined) or the unique index stops deduplicating.
async upsertRollup(input: RollupInput): Promise<RollupRecord> {
const data = { ...input, dim: input.dim ?? "" };
const filter = pbFilter(pb, "date = {:date} && metric = {:metric} && dim = {:dim}", {
@@ -277,8 +276,6 @@ export function createTelemetryService(pb: PocketBase) {
};
},
// Bounded flip of a group's rows; new occurrences arrive resolved=false by
// design, so a partial flip on a huge group is acceptable.
async resolveErrorsByGroup(groupHash: string, resolved = true): Promise<number> {
const MAX_PAGES = 25;
let updated = 0;
@@ -300,8 +297,6 @@ export function createTelemetryService(pb: PocketBase) {
return updated;
},
// Paged scan over a base collection (never SQL views). Stable created sort;
// tight `fields` keeps payloads small for rollup passes.
async pageCollection<T>(
collection: string,
opts: { filter?: string; fields?: string },
-3
View File
@@ -2,9 +2,6 @@ import { createMiddleware } from "@tanstack/react-start";
import { recordActivity } from "@/utils/activities";
import { getRequestActor } from "./request-context.server";
// Request-type counterpart of serverFnLoggingMiddleware for createFileRoute
// API handlers, which the global function middleware never sees. Not for the
// SSE route (a long-lived stream is not a request-shaped unit) or /api/health.
export const apiLoggingMiddleware = createMiddleware({
type: "request",
}).server(async ({ next, request }) => {
-4
View File
@@ -9,8 +9,6 @@ interface AuthEventInput {
error?: string;
}
// Fire-and-forget: auth flows must never fail or slow down because telemetry
// did. The phone number is used only to resolve the player, never stored.
export const recordAuthEvent = (name: string, input: AuthEventInput) => {
void (async () => {
try {
@@ -52,8 +50,6 @@ export const recordAuthEvent = (name: string, input: AuthEventInput) => {
type PasswordlessOverride = (originalImplementation: any) => any;
// Composes with a recipe's existing override.functions so telemetry wraps the
// final implementation (Twilio verify included).
export const withPasswordlessTelemetry =
(existing?: PasswordlessOverride): PasswordlessOverride =>
(originalImplementation: any) => {
+1 -7
View File
@@ -1,10 +1,5 @@
import type { AnyRouter } from "@tanstack/react-router";
// Provider-free by design: renders nothing and mounts no React context, so it
// cannot disturb the LinguiProvider -> AuthProvider order. Browser-only; every
// entry point is a no-op during SSR. Runs in dev too - events go to the same
// PB the app is pointed at, which in dev is the local instance.
type QueuedEvent = Record<string, unknown> & { kind: "event" | "error" | "vital" };
const FLUSH_INTERVAL_MS = 10_000;
@@ -148,8 +143,7 @@ export const initTelemetry = (router: AnyRouter) => {
captureError("unhandledrejection", event.reason);
});
// Vitals mostly report at hidden-visibility; their callbacks are registered
// before the flush listeners so those reports make the final beacon.
// Vitals report at hidden-visibility; register before the flush listeners below.
void import("web-vitals")
.then(({ onLCP, onCLS, onINP, onFCP, onTTFB }) => {
const report = (metric: { name: string; value: number; rating: string }) => {
-5
View File
@@ -1,6 +1,3 @@
// Deterministic client-error grouping across deploys: volatile fragments
// (ids, URLs, asset content hashes) are normalized away before hashing.
const normalizeMessage = (message: string): string =>
message
.toLowerCase()
@@ -13,8 +10,6 @@ const normalizeMessage = (message: string): string =>
const FRAME_NOISE = /^(at\s+)?(async\s+)?(module code|<anonymous>|eval)/i;
// Vite emits content-hashed asset names (index-Bq2z1a3f.js); strip the hash so
// the same frame groups across deploys.
const normalizeFrame = (frame: string): string =>
frame
.trim()
-2
View File
@@ -41,8 +41,6 @@ const runChecks = async (): Promise<HealthSnapshot> => {
return cached;
};
// Stale-while-revalidate: k8s probes get the cached snapshot instantly while a
// refresh runs in the background; only the very first request awaits a check.
export const getHealthSnapshot = async (): Promise<HealthSnapshot> => {
if (cached && Date.now() - Date.parse(cached.checkedAt) < CHECK_TTL_MS) {
return cached;
@@ -1,6 +1,3 @@
// Per-request side-channel between the session layer and the global logging
// middleware, which runs outside session middleware and cannot see its context.
const actorByRequest = new WeakMap<Request, { playerId?: string }>();
const deniedRecorded = new WeakSet<Request>();
-1
View File
@@ -20,7 +20,6 @@ export interface ClientErrorRow {
group_hash: string;
}
// Nearest-rank percentile; values need not be pre-sorted.
export const percentile = (values: number[], p: number): number => {
if (values.length === 0) return 0;
const sorted = [...values].sort((a, b) => a - b);
-4
View File
@@ -23,8 +23,6 @@ const addDays = (dateStr: string, days: number): string => {
return utcDay(d);
};
// PB stores autodates as "YYYY-MM-DD HH:MM:SS.sssZ" UTC; boundaries in the
// same shape compare correctly in filters.
const bound = (dateStr: string): string => `${dateStr} 00:00:00.000Z`;
const dayFilter = (dateStr: string): string =>
@@ -91,8 +89,6 @@ export const runRollups = async (dateStr: string): Promise<number> => {
return rollups.length;
};
// The first run after UTC midnight recomputes yesterday once more so its
// partial rows become final. Idempotent via the (date, metric, dim) key.
export const runScheduledRollups = async (lastRunDay?: string): Promise<string> => {
const today = utcDay(new Date());
if (lastRunDay && lastRunDay !== today) {
+1 -3
View File
@@ -52,9 +52,7 @@ const tickAlerts = async () => {
}
};
// Single-replica deployment makes in-process intervals a valid scheduler
// (same precedent as the badge migration job). Started lazily from request
// handlers (health probes guarantee a call within seconds of boot).
// In-process intervals are valid only while the deployment runs a single replica.
export const ensureTelemetryScheduler = () => {
if (initialized || typeof window !== "undefined") return;
initialized = true;
+1 -6
View File
@@ -41,8 +41,6 @@ const serverFnName = (request: Request, meta?: ServerFnMeta): string => {
return pathParts[pathParts.length - 1] || "unknown";
};
// Successful reads are skipped (client page views cover usage); read failures
// are always recorded. Naming is uniform across every feature server.ts.
export const READ_FN_NAME = /^(get|list|search|fetch|preview|is[A-Z])/;
const readSampleRate = (): number => {
@@ -56,8 +54,6 @@ const shouldRecordSuccess = (name: string): boolean => {
return sample > 0 && Math.random() < sample;
};
// Thrown Responses/redirects are control flow (session refresh 401s, route
// redirects), not failures.
const isControlFlowError = (error: unknown): boolean =>
error instanceof Response || isRedirect(error);
@@ -86,8 +82,7 @@ export const serverFnLoggingMiddleware = createMiddleware({
const userAgent = request.headers.get("user-agent") || undefined;
const safeArgs = redactArguments(data);
// Registered globally, so session middleware runs inside this one; the actor
// is stashed on the Request by getSessionContextCore and read after next().
// Runs outside session middleware; the actor is stashed on the Request and read after next().
const resolveActor = (): string | undefined =>
getRequestActor(request)?.playerId ??
((context as any)?.metadata?.player_id as string | undefined);
-3
View File
@@ -26,9 +26,6 @@ export const superTokensRequestMiddleware = createMiddleware({
return next({ context });
});
// Session context when available, anonymous otherwise — never throws or
// redirects. For endpoints that must accept logged-out traffic (telemetry
// beacon: login-page errors are exactly the signal we want).
export const superTokensOptionalRequestMiddleware = createMiddleware({
type: "request",
}).server(async ({ next, request }) => {