{
  "version": 3,
  "sources": ["../../../../src/workers/observability/collector.worker.ts", "../../../../src/workers/observability/tail-to-store.ts", "../../../../src/workers/observability/trace-store.ts"],
  "sourcesContent": ["/**\n * The local observability collector. Miniflare attaches it to the user's\n * worker(s) as a tail consumer, so workerd delivers each invocation's tail events\n * here. `TailToStoreHandler` converts them into spans and logs, which are stored\n * in the `TraceStore` Durable Object hosted by this same worker. The endpoint for\n * querying that store is also defined here.\n */\nimport { WorkerEntrypoint } from \"cloudflare:workers\";\nimport { TailToStoreHandler } from \"./tail-to-store\";\nimport { TraceStore } from \"./trace-store\";\n\n// Re-export so the embedded worker registers the DO class under its namespace.\nexport { TraceStore };\n\ninterface Env {\n\tTRACE_STORE: DurableObjectNamespace<TraceStore>;\n}\n\nexport default class LocalObservabilityCollector extends WorkerEntrypoint<Env> {\n\ttailStream(onset: TailStream.TailEvent<TailStream.Onset>) {\n\t\t// Fold this invocation's tail straight into the singleton TraceStore.\n\t\tconst store = this.env.TRACE_STORE.get(\n\t\t\tthis.env.TRACE_STORE.idFromName(\"singleton\")\n\t\t);\n\t\t// Miniflare core passes the source worker's name in binding props (workerd\n\t\t// doesn't surface it on the tail onset locally), so captured spans can be\n\t\t// attributed to the right worker.\n\t\tconst worker = (this.ctx.props as { worker?: string } | undefined)?.worker;\n\t\treturn new TailToStoreHandler(store, onset, worker);\n\t}\n\n\t/**\n\t * Reads from the trace store. A single `POST /query` runs read-only SQL against\n\t * the `spans` and `logs` tables. The Local Explorer's Observability API\n\t * forwards requests here, so the UI's built-in views and any coding agent all\n\t * go through this one endpoint. The query validation lives in\n\t * `TraceStore.query`.\n\t */\n\tasync fetch(request: Request): Promise<Response> {\n\t\tconst url = new URL(request.url);\n\t\tconst store = this.env.TRACE_STORE.get(\n\t\t\tthis.env.TRACE_STORE.idFromName(\"singleton\")\n\t\t);\n\t\tif (url.pathname === \"/query\" && request.method === \"POST\") {\n\t\t\tconst { sql, params } = (await request.json()) as {\n\t\t\t\tsql?: string;\n\t\t\t\tparams?: SqlStorageValue[];\n\t\t\t};\n\t\t\tif (typeof sql !== \"string\") {\n\t\t\t\treturn Response.json({ error: \"missing 'sql'\" }, { status: 400 });\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn Response.json(await store.query(sql, params ?? []));\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treturn Response.json({ error: message }, { status: 400 });\n\t\t\t}\n\t\t}\n\t\t// Delete all captured spans and logs. Separate from the read-only `/query`\n\t\t// path on purpose \u2014 this is the one mutation the store exposes.\n\t\tif (url.pathname === \"/clear\" && request.method === \"POST\") {\n\t\t\tawait store.clear();\n\t\t\treturn Response.json({ success: true });\n\t\t}\n\t\treturn new Response(\"not found\", { status: 404 });\n\t}\n}\n", "/**\n * Converts one invocation's workerd tail events into the spans and logs the\n * store keeps. Spans are written as they happen: a span is created when it starts\n * (with no duration yet), its attributes are added as they arrive, and it is\n * finished when it closes. This way long-running work (agents, waits, streamed\n * responses) shows up while it is still running, not only once the invocation\n * ends.\n *\n * There is no OpenTelemetry layer in between. Following the OTLP format would only\n * matter for sending traces to a real backend, but here the same process both\n * produces and reads them. So we keep just the attribute names the Workers\n * Observability UI expects (`faas.trigger`, `http.request.method`,\n * `cloudflare.outcome`, `cpu_time_ms`, \u2026) and skip the SDK and wire format. The\n * URLs and headers belong to the developer, so nothing is redacted.\n */\nimport type { LogInput, SpanClose, SpanInput } from \"./trace-store\";\n\n/** The write-through subset of the TraceStore the handler drives (the DO stub\n * satisfies this; RPC methods resolve to promises). */\ninterface WriteThroughStore {\n\topenSpan(s: SpanInput): void | Promise<void>;\n\tmergeAttributes(\n\t\ttraceId: string,\n\t\tspanId: string,\n\t\tattributes: Record<string, unknown>\n\t): void | Promise<void>;\n\tcloseSpan(\n\t\ttraceId: string,\n\t\tspanId: string,\n\t\tclose: SpanClose\n\t): void | Promise<void>;\n\tappendLog(log: LogInput): void | Promise<void>;\n}\n\n/** A tail event's `timestamp` is a `Date` (or ms number); normalise to epoch ms. */\nfunction toMs(timestamp: Date | number): number {\n\treturn typeof timestamp === \"number\" ? timestamp : timestamp.getTime();\n}\n\n/**\n * The span context for an event. For `onset` / `spanOpen` the new span's id is on\n * the event; `spanContext.spanId` is then its parent. For every other event the\n * `spanContext` already points at the span the event acts on.\n */\nfunction ids(event: TailStream.TailEvent<TailStream.EventType>): {\n\ttraceId: string;\n\tspanId?: string;\n\tparentId?: string;\n} {\n\tif (event.event.type === \"onset\" || event.event.type === \"spanOpen\") {\n\t\treturn {\n\t\t\ttraceId: event.spanContext.traceId,\n\t\t\tspanId: event.event.spanId,\n\t\t\tparentId: event.spanContext.spanId,\n\t\t};\n\t}\n\treturn {\n\t\ttraceId: event.spanContext.traceId,\n\t\tspanId: event.spanContext.spanId,\n\t};\n}\n\n/** Friendly `kind` for the UI: root span from its trigger, children from name. */\nfunction friendlyKind(faasTrigger: string | undefined, name: string): string {\n\tif (faasTrigger) {\n\t\tswitch (faasTrigger) {\n\t\t\tcase \"http\":\n\t\t\t\treturn \"http\";\n\t\t\tcase \"timer\":\n\t\t\t\treturn \"scheduled\";\n\t\t\tcase \"pubsub\":\n\t\t\t\treturn \"queue\";\n\t\t\tcase \"email\":\n\t\t\t\treturn \"email\";\n\t\t\tcase \"jsrpc\":\n\t\t\t\treturn \"jsrpc\";\n\t\t\tcase \"websocket\":\n\t\t\t\treturn \"websocket\";\n\t\t\tcase \"trace\":\n\t\t\t\treturn \"trace\";\n\t\t\tdefault:\n\t\t\t\treturn \"worker\";\n\t\t}\n\t}\n\tconst n = name.toLowerCase();\n\tif (n.includes(\"kv\")) {\n\t\treturn \"kv\";\n\t}\n\tif (n.includes(\"d1\")) {\n\t\treturn \"d1\";\n\t}\n\tif (n.includes(\"r2\")) {\n\t\treturn \"r2\";\n\t}\n\tif (n.includes(\"queue\")) {\n\t\treturn \"queue\";\n\t}\n\tif (n.includes(\"durable\") || n.includes(\"do_\")) {\n\t\treturn \"do\";\n\t}\n\tif (n.includes(\"cache\")) {\n\t\treturn \"cache\";\n\t}\n\tif (n.includes(\"fetch\")) {\n\t\treturn \"fetch\";\n\t}\n\treturn \"span\";\n}\n\n/** Root-span name + attributes derived from the onset trigger info. */\nfunction describeTrigger(info: TailStream.Onset[\"info\"]): {\n\tname: string;\n\tattributes: Record<string, unknown>;\n} {\n\tswitch (info.type) {\n\t\tcase \"fetch\":\n\t\t\treturn {\n\t\t\t\tname: info.method,\n\t\t\t\tattributes: {\n\t\t\t\t\t\"faas.trigger\": \"http\",\n\t\t\t\t\t\"http.request.method\": info.method,\n\t\t\t\t\t\"url.full\": info.url,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"jsrpc\":\n\t\t\treturn { name: \"jsrpc\", attributes: { \"faas.trigger\": \"jsrpc\" } };\n\t\tcase \"scheduled\":\n\t\t\treturn {\n\t\t\t\tname: \"scheduled\",\n\t\t\t\tattributes: { \"faas.trigger\": \"timer\", \"faas.cron\": info.cron },\n\t\t\t};\n\t\tcase \"alarm\":\n\t\t\treturn { name: \"alarm\", attributes: { \"faas.trigger\": \"timer\" } };\n\t\tcase \"queue\":\n\t\t\treturn {\n\t\t\t\tname: \"queue\",\n\t\t\t\tattributes: {\n\t\t\t\t\t\"faas.trigger\": \"pubsub\",\n\t\t\t\t\t\"cloudflare.queue.name\": info.queueName,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"email\":\n\t\t\treturn {\n\t\t\t\tname: \"email\",\n\t\t\t\tattributes: {\n\t\t\t\t\t\"faas.trigger\": \"email\",\n\t\t\t\t\t\"cloudflare.email.to\": info.rcptTo,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"trace\":\n\t\t\treturn { name: \"trace\", attributes: { \"faas.trigger\": \"trace\" } };\n\t\tcase \"hibernatableWebSocket\":\n\t\t\treturn {\n\t\t\t\tname: \"hibernatableWebSocket\",\n\t\t\t\tattributes: { \"faas.trigger\": \"websocket\" },\n\t\t\t};\n\t\tdefault:\n\t\t\treturn { name: info.type, attributes: { \"faas.trigger\": \"other\" } };\n\t}\n}\n\n/**\n * Every `EventOutcome` other than \"ok\" is a failure (canceled, exception,\n * exceededCpu, exceededWallTime, internalError, \u2026). Matching on \"not ok\" keeps\n * capture in step with the read side (`SPAN_IS_ERROR` uses `outcome != 'ok'`) and\n * covers any future outcomes without another allowlist to maintain.\n */\nfunction isErrorOutcome(outcome: TailStream.EventOutcome): boolean {\n\treturn outcome !== \"ok\";\n}\n\n/**\n * Per-span bookkeeping kept between events so we can compute a duration and fold\n * in error info when the span closes. Attributes are written straight through to\n * the store (not buffered here), so this holds only what `closeSpan` needs.\n */\ninterface PendingSpan {\n\ttraceId: string;\n\tstartMs: number;\n\tname: string | null;\n\toutcome: string | null;\n\terror: string | null;\n\terrored: boolean;\n\tclosed: boolean;\n}\n\n/**\n * Handles the tail events for a single invocation. Each store write is sent as\n * soon as its event arrives (the Durable Object receives them in call order) and\n * awaited when the invocation ends, so no write is dropped.\n */\nexport class TailToStoreHandler implements TailStream.TailEventHandlerObject {\n\t#spans = new Map<string, PendingSpan>();\n\t#rootSpanId: string | null = null;\n\t#traceId: string | null = null;\n\t#startMs: number | null = null;\n\t#invocationBody: string | null = null;\n\t#writes: Promise<unknown>[] = [];\n\n\tconstructor(\n\t\tprivate readonly store: WriteThroughStore,\n\t\tonset: TailStream.TailEvent<TailStream.Onset>,\n\t\t/** Owning worker name (from miniflare core), for multi-worker attribution. */\n\t\tprivate readonly worker?: string\n\t) {\n\t\tconst { traceId, spanId, parentId } = ids(onset);\n\t\tif (!spanId) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#rootSpanId = spanId;\n\t\tthis.#traceId = traceId;\n\t\tthis.#startMs = toMs(onset.timestamp);\n\n\t\tconst { name, attributes: triggerAttributes } = describeTrigger(\n\t\t\tonset.event.info\n\t\t);\n\t\t// Start from any attributes carried directly on the onset (not guaranteed\n\t\t// to arrive later via the `attributes` callback), then let the canonical\n\t\t// trigger-derived keys (`faas.trigger`, `http.request.method`, \u2026) win since\n\t\t// the UI keys off those.\n\t\tconst attributes: Record<string, unknown> = {};\n\t\t// `attributes` is typed as required but isn't always populated on the onset\n\t\t// in local dev (events come through a cf-to-otel shim), so guard the loop.\n\t\tfor (const attr of onset.event.attributes ?? []) {\n\t\t\tattributes[attr.name] = normalizeAttr(attr.value);\n\t\t}\n\t\tObject.assign(attributes, triggerAttributes);\n\t\tif (onset.invocationId) {\n\t\t\tattributes[\"faas.invocation_id\"] = onset.invocationId;\n\t\t}\n\t\t// Invocation-log body: for fetch, method + URL (mirrors the prod Logs view);\n\t\t// otherwise the trigger name.\n\t\tthis.#invocationBody =\n\t\t\tonset.event.info.type === \"fetch\"\n\t\t\t\t? `${onset.event.info.method} ${onset.event.info.url}`\n\t\t\t\t: name;\n\t\tthis.#spans.set(spanId, {\n\t\t\ttraceId,\n\t\t\tstartMs: this.#startMs,\n\t\t\tname,\n\t\t\toutcome: null,\n\t\t\terror: null,\n\t\t\terrored: false,\n\t\t\tclosed: false,\n\t\t});\n\t\tthis.#open({\n\t\t\ttraceId,\n\t\t\tspanId,\n\t\t\t// A sub-invocation (e.g. downstream of a service binding) carries the\n\t\t\t// caller's span as its parent, so it nests into one distributed trace;\n\t\t\t// a true top-level invocation has no inherited parent (\u2192 null root).\n\t\t\tparentId: parentId ?? null,\n\t\t\tservice: this.worker ?? null,\n\t\t\tname,\n\t\t\tkind: friendlyKind(attributes[\"faas.trigger\"] as string, name),\n\t\t\tstartMs: this.#startMs,\n\t\t\tdurationMs: null,\n\t\t\toutcome: null,\n\t\t\terror: null,\n\t\t\tattributes,\n\t\t});\n\t}\n\n\tspanOpen(event: TailStream.TailEvent<TailStream.SpanOpen>) {\n\t\tconst { traceId, spanId, parentId } = ids(event);\n\t\tif (!spanId) {\n\t\t\treturn;\n\t\t}\n\t\tconst startMs = toMs(event.timestamp);\n\t\tthis.#spans.set(spanId, {\n\t\t\ttraceId,\n\t\t\tstartMs,\n\t\t\tname: event.event.name,\n\t\t\toutcome: null,\n\t\t\terror: null,\n\t\t\terrored: false,\n\t\t\tclosed: false,\n\t\t});\n\t\tthis.#open({\n\t\t\ttraceId,\n\t\t\tspanId,\n\t\t\tparentId: parentId ?? null,\n\t\t\tservice: this.worker ?? null,\n\t\t\tname: event.event.name,\n\t\t\tkind: friendlyKind(undefined, event.event.name),\n\t\t\tstartMs,\n\t\t\tdurationMs: null,\n\t\t\toutcome: null,\n\t\t\terror: null,\n\t\t\tattributes: null,\n\t\t});\n\t}\n\n\tspanClose(event: TailStream.TailEvent<TailStream.SpanClose>) {\n\t\tconst { traceId, spanId } = ids(event);\n\t\tconst pending = spanId ? this.#spans.get(spanId) : undefined;\n\t\tif (spanId && pending) {\n\t\t\t// A span can close with a failure outcome (exception, exceededCpu, \u2026).\n\t\t\t// Fold it in so the span isn't recorded as \"ok\". A preceding exception\n\t\t\t// event already set a richer outcome/error, so don't overwrite that.\n\t\t\tif (isErrorOutcome(event.event.outcome)) {\n\t\t\t\tpending.errored = true;\n\t\t\t\tpending.outcome ??= event.event.outcome;\n\t\t\t}\n\t\t\tthis.#close(traceId, spanId, pending, toMs(event.timestamp), null);\n\t\t}\n\t}\n\n\tattributes(event: TailStream.TailEvent<TailStream.Attributes>) {\n\t\tconst { traceId, spanId } = ids(event);\n\t\tif (!spanId || !this.#spans.has(spanId)) {\n\t\t\treturn;\n\t\t}\n\t\tconst attrs: Record<string, unknown> = {};\n\t\tfor (const attr of event.event.info) {\n\t\t\tattrs[attr.name] = normalizeAttr(attr.value);\n\t\t}\n\t\tif (Object.keys(attrs).length > 0) {\n\t\t\tthis.#track(this.store.mergeAttributes(traceId, spanId, attrs));\n\t\t}\n\t}\n\n\treturn(event: TailStream.TailEvent<TailStream.Return>) {\n\t\tconst { traceId, spanId } = ids(event);\n\t\tconst pending = spanId ? this.#spans.get(spanId) : undefined;\n\t\tif (spanId && pending && event.event.info?.type === \"fetch\") {\n\t\t\tthis.#track(\n\t\t\t\tthis.store.mergeAttributes(traceId, spanId, {\n\t\t\t\t\t\"http.response.status_code\": event.event.info.statusCode,\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\t}\n\n\tlog(event: TailStream.TailEvent<TailStream.Log>) {\n\t\tconst { traceId, spanId } = ids(event);\n\t\t// `console.log` surfaces as level \"log\"; fold into \"info\" so the stored set\n\t\t// stays {debug, info, warn, error}.\n\t\tconst level = event.event.level === \"log\" ? \"info\" : event.event.level;\n\t\tthis.#track(\n\t\t\tthis.store.appendLog({\n\t\t\t\ttraceId,\n\t\t\t\tspanId: spanId ?? null,\n\t\t\t\ttsMs: toMs(event.timestamp),\n\t\t\t\tlevel,\n\t\t\t\tmessage: serialize(event.event.message),\n\t\t\t\toperation: null,\n\t\t\t})\n\t\t);\n\t}\n\n\texception(event: TailStream.TailEvent<TailStream.Exception>) {\n\t\tconst { traceId, spanId } = ids(event);\n\t\tconst pending = spanId ? this.#spans.get(spanId) : undefined;\n\t\tconst type = event.event.name || \"Error\";\n\t\tconst message = event.event.message ?? \"\";\n\t\tconst head = `${type}: ${message}`;\n\t\tconst text = event.event.stack ? `${head}\\n${event.event.stack}` : head;\n\t\tif (pending) {\n\t\t\t// Recorded on the span so it lands as `error`/outcome when it closes.\n\t\t\tpending.errored = true;\n\t\t\tpending.outcome = \"error\";\n\t\t\tpending.error = head;\n\t\t}\n\t\t// Surface exceptions as error-level logs too, so failures show in the Logs\n\t\t// view even when the worker never called console.error.\n\t\tthis.#track(\n\t\t\tthis.store.appendLog({\n\t\t\t\ttraceId,\n\t\t\t\tspanId: spanId ?? null,\n\t\t\t\ttsMs: toMs(event.timestamp),\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage: serialize(text),\n\t\t\t\toperation: pending?.name ?? null,\n\t\t\t})\n\t\t);\n\t}\n\n\tasync outcome(event: TailStream.TailEvent<TailStream.Outcome>) {\n\t\tconst endMs = toMs(event.timestamp);\n\t\tconst traceId = this.#traceId ?? event.spanContext.traceId;\n\t\tconst root = this.#rootSpanId\n\t\t\t? this.#spans.get(this.#rootSpanId)\n\t\t\t: undefined;\n\t\tif (root && this.#rootSpanId) {\n\t\t\tif (isErrorOutcome(event.event.outcome)) {\n\t\t\t\troot.errored = true;\n\t\t\t}\n\t\t\troot.outcome = event.event.outcome;\n\t\t\t// The root closes with the invocation: fold in the final outcome and\n\t\t\t// resource attributes at the same time.\n\t\t\tthis.#close(traceId, this.#rootSpanId, root, endMs, {\n\t\t\t\t\"cloudflare.outcome\": event.event.outcome,\n\t\t\t\tcpu_time_ms: event.event.cpuTime,\n\t\t\t\twall_time_ms: event.event.wallTime,\n\t\t\t});\n\t\t}\n\n\t\t// Close any span left open (error/bug) so it still shows in the waterfall.\n\t\tfor (const [spanId, pending] of this.#spans) {\n\t\t\tif (!pending.closed) {\n\t\t\t\tthis.#close(pending.traceId, spanId, pending, endMs, null);\n\t\t\t}\n\t\t}\n\n\t\t// One synthetic invocation log so silent workers still appear.\n\t\tif (this.#rootSpanId && this.#invocationBody !== null) {\n\t\t\tthis.#track(\n\t\t\t\tthis.store.appendLog({\n\t\t\t\t\ttraceId,\n\t\t\t\t\tspanId: this.#rootSpanId,\n\t\t\t\t\ttsMs: this.#startMs ?? endMs,\n\t\t\t\t\tlevel: root?.errored ? \"error\" : \"info\",\n\t\t\t\t\tmessage: serialize(this.#invocationBody),\n\t\t\t\t\toperation: null,\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\n\t\tawait Promise.all(this.#writes);\n\t}\n\n\t#open(input: SpanInput) {\n\t\tthis.#track(this.store.openSpan(input));\n\t}\n\n\t/** Finish a span, setting its duration and outcome and adding any final\n\t * attributes. Runs at most once per span (guarded by `closed`). */\n\t#close(\n\t\ttraceId: string,\n\t\tspanId: string,\n\t\tpending: PendingSpan,\n\t\tendMs: number,\n\t\tattributes: Record<string, unknown> | null\n\t) {\n\t\tif (pending.closed) {\n\t\t\treturn;\n\t\t}\n\t\tpending.closed = true;\n\t\tthis.#track(\n\t\t\tthis.store.closeSpan(traceId, spanId, {\n\t\t\t\tdurationMs: Math.max(0, endMs - pending.startMs),\n\t\t\t\toutcome: pending.outcome ?? (pending.errored ? \"error\" : \"ok\"),\n\t\t\t\terror: pending.error,\n\t\t\t\tattributes,\n\t\t\t})\n\t\t);\n\t}\n\n\t/** Track an in-flight store write so `outcome` can await completion. */\n\t#track(result: void | Promise<unknown>) {\n\t\tthis.#writes.push(Promise.resolve(result));\n\t}\n}\n\n/**\n * Tail attribute values can be bigint (or bigint arrays); `JSON.stringify` throws\n * on those. Downcast to number where safe, else string, so the value survives\n * serialization into the store's `attributes` blob.\n */\nfunction normalizeAttr(value: TailStream.Attribute[\"value\"]): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map((v) => (typeof v === \"bigint\" ? bigintToJson(v) : v));\n\t}\n\treturn typeof value === \"bigint\" ? bigintToJson(value) : value;\n}\n\nfunction bigintToJson(value: bigint): number | string {\n\treturn value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER\n\t\t? Number(value)\n\t\t: value.toString();\n}\n\nfunction serialize(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value ?? \"\");\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n", "/**\n * The local observability trace store: a SQLite-backed Durable Object that holds\n * the captured traces. The collector writes to it and the Local Explorer's\n * Observability API reads from it, both over RPC. The tables are created on first\n * use. This data is local only: it is never exposed to the user's app or sent\n * anywhere.\n *\n * A \"trace\" is the root span (the one with no parent) plus everything below it.\n * When a request calls other workers, those sub-invocations share its trace_id\n * and attach to the calling span through parent_id. Request-level data (HTTP\n * status, CPU/wall time, trigger, worker name) is stored on the root span's\n * `attributes`. Times are absolute (epoch ms); the read API shifts them so each\n * trace starts at zero.\n */\nimport { DurableObject } from \"cloudflare:workers\";\n\n/** A span as written by the collector (attributes still a plain object). */\nexport interface SpanInput {\n\ttraceId: string;\n\tspanId: string;\n\tparentId: string | null;\n\t/** Owning worker (service) name, for multi-worker attribution/filtering. */\n\tservice: string | null;\n\tname: string | null;\n\tkind: string | null;\n\tstartMs: number;\n\t/** Null while the span is still open (see `openSpan`/`closeSpan`). */\n\tdurationMs: number | null;\n\toutcome: string | null;\n\terror: string | null;\n\tattributes: Record<string, unknown> | null;\n}\n\n/** Fields set when a span closes (`closeSpan`). */\nexport interface SpanClose {\n\tdurationMs: number;\n\toutcome: string | null;\n\terror: string | null;\n\t/** Final attributes merged in at close (e.g. status code, cpu/wall time). */\n\tattributes: Record<string, unknown> | null;\n}\n\n/** A log record as written by the collector. `message` is already serialized to\n * a JSON string by the collector (so it survives the RPC hop unchanged). The\n * store assigns `seq` at insert time \u2014 see `persist`. */\nexport interface LogInput {\n\ttraceId: string;\n\tspanId: string | null;\n\ttsMs: number;\n\tlevel: string;\n\tmessage: string;\n\toperation: string | null;\n}\n\nconst SCHEMA = [\n\t`CREATE TABLE IF NOT EXISTS spans (\n\t\ttrace_id     TEXT NOT NULL,\n\t\tspan_id      TEXT NOT NULL,\n\t\tparent_id    TEXT,\n\t\tservice      TEXT,\n\t\tname         TEXT,\n\t\tkind         TEXT,\n\t\tstart_ms     INTEGER,\n\t\tduration_ms  INTEGER,          -- whole ms; NULL while the span is still running\n\t\toutcome      TEXT,\n\t\terror        TEXT,\n\t\tattributes   BLOB,\n\t\tcreated_at   TEXT DEFAULT (datetime('now')),\n\t\tPRIMARY KEY (trace_id, span_id)\n\t)`,\n\t`CREATE INDEX IF NOT EXISTS spans_roots ON spans (start_ms) WHERE parent_id IS NULL`,\n\t`CREATE TABLE IF NOT EXISTS logs (\n\t\ttrace_id   TEXT NOT NULL,\n\t\tspan_id    TEXT,\n\t\tseq        INTEGER NOT NULL,\n\t\tts_ms      INTEGER,\n\t\tlevel      TEXT,\n\t\tmessage    TEXT,\n\t\toperation  TEXT,\n\t\tcreated_at TEXT DEFAULT (datetime('now')),\n\t\tPRIMARY KEY (trace_id, seq)\n\t)`,\n\t`CREATE INDEX IF NOT EXISTS logs_by_level ON logs (level)`,\n];\n\n/**\n * Upper bound on rows returned by a single `/query`. Local dev volume is small;\n * this just stops an unbounded `SELECT` from pulling the entire store back in\n * one response (there's no query-level timeout in the DO SQLite API to lean on).\n */\nconst MAX_QUERY_ROWS = 10_000;\n\nexport class TraceStore extends DurableObject {\n\tprivate sql = this.ctx.storage.sql;\n\n\tconstructor(ctx: DurableObjectState, env: unknown) {\n\t\tsuper(ctx, env as never);\n\t\tthis.ctx.blockConcurrencyWhile(async () => {\n\t\t\tfor (const stmt of SCHEMA) this.sql.exec(stmt);\n\t\t});\n\t}\n\n\t/** Persist one invocation's spans + logs. Called by the collector. */\n\tpersist(spans: SpanInput[], logs: LogInput[]): void {\n\t\tfor (const s of spans) {\n\t\t\tthis.sql.exec(\n\t\t\t\t`INSERT OR REPLACE INTO spans\n\t\t\t\t\t(trace_id, span_id, parent_id, service, name, kind, start_ms, duration_ms, outcome, error, attributes)\n\t\t\t\t\tVALUES (?,?,?,?,?,?,?,?,?,?, jsonb(?))`,\n\t\t\t\ts.traceId,\n\t\t\t\ts.spanId,\n\t\t\t\ts.parentId,\n\t\t\t\ts.service,\n\t\t\t\ts.name,\n\t\t\t\ts.kind,\n\t\t\t\ts.startMs,\n\t\t\t\ts.durationMs == null ? null : Math.round(s.durationMs),\n\t\t\t\ts.outcome,\n\t\t\t\ts.error,\n\t\t\t\ts.attributes ? JSON.stringify(s.attributes) : null\n\t\t\t);\n\t\t}\n\t\t// Assign `seq` here rather than trusting the caller: the collector creates a\n\t\t// fresh handler (and would restart any counter) per invocation, but\n\t\t// sub-invocations of one distributed trace share a trace_id, so a\n\t\t// caller-side counter would collide on (trace_id, seq). The DO is\n\t\t// single-threaded, so reading MAX(seq) then inserting is race-free.\n\t\tconst nextSeq = new Map<string, number>();\n\t\tfor (const l of logs) {\n\t\t\tlet seq = nextSeq.get(l.traceId);\n\t\t\tif (seq === undefined) {\n\t\t\t\tconst row = this.sql\n\t\t\t\t\t.exec<{ next: number }>(\n\t\t\t\t\t\t`SELECT COALESCE(MAX(seq), -1) + 1 AS next FROM logs WHERE trace_id = ?`,\n\t\t\t\t\t\tl.traceId\n\t\t\t\t\t)\n\t\t\t\t\t.one();\n\t\t\t\tseq = Number(row.next);\n\t\t\t}\n\t\t\tthis.sql.exec(\n\t\t\t\t`INSERT INTO logs\n\t\t\t\t\t(trace_id, span_id, seq, ts_ms, level, message, operation)\n\t\t\t\t\tVALUES (?,?,?,?,?,?,?)`,\n\t\t\t\tl.traceId,\n\t\t\t\tl.spanId,\n\t\t\t\tseq,\n\t\t\t\tl.tsMs,\n\t\t\t\tl.level,\n\t\t\t\tl.message,\n\t\t\t\tl.operation\n\t\t\t);\n\t\t\tnextSeq.set(l.traceId, seq + 1);\n\t\t}\n\t}\n\n\t/**\n\t * Write-through capture (for long-running spans). A span is written across\n\t * its lifetime instead of all at once on `outcome`, so the UI can show it\n\t * in-flight: `openSpan` on start, `mergeAttributes` as they stream in, and\n\t * `closeSpan` when it ends. `duration_ms IS NULL` marks a still-open span.\n\t */\n\n\t/** Insert a span at open time (duration/outcome stay NULL until it closes). */\n\topenSpan(s: SpanInput): void {\n\t\tthis.sql.exec(\n\t\t\t`INSERT INTO spans\n\t\t\t\t(trace_id, span_id, parent_id, service, name, kind, start_ms, duration_ms, outcome, error, attributes)\n\t\t\t\tVALUES (?,?,?,?,?,?,?,?,?,?, jsonb(?))\n\t\t\t\tON CONFLICT (trace_id, span_id) DO NOTHING`,\n\t\t\ts.traceId,\n\t\t\ts.spanId,\n\t\t\ts.parentId,\n\t\t\ts.service,\n\t\t\ts.name,\n\t\t\ts.kind,\n\t\t\ts.startMs,\n\t\t\ts.durationMs == null ? null : Math.round(s.durationMs),\n\t\t\ts.outcome,\n\t\t\ts.error,\n\t\t\ts.attributes ? JSON.stringify(s.attributes) : null\n\t\t);\n\t}\n\n\t/** Merge attributes onto an open span as the tail stream emits them. */\n\tmergeAttributes(\n\t\ttraceId: string,\n\t\tspanId: string,\n\t\tattributes: Record<string, unknown>\n\t): void {\n\t\tthis.sql.exec(\n\t\t\t`UPDATE spans\n\t\t\t\tSET attributes = jsonb_patch(COALESCE(attributes, jsonb('{}')), jsonb(?))\n\t\t\t\tWHERE trace_id = ? AND span_id = ?`,\n\t\t\tJSON.stringify(attributes),\n\t\t\ttraceId,\n\t\t\tspanId\n\t\t);\n\t}\n\n\t/** Finalise a span: set duration/outcome/error and merge any final attributes. */\n\tcloseSpan(traceId: string, spanId: string, close: SpanClose): void {\n\t\tthis.sql.exec(\n\t\t\t`UPDATE spans\n\t\t\t\tSET duration_ms = ?, outcome = ?, error = ?,\n\t\t\t\t\tattributes = jsonb_patch(COALESCE(attributes, jsonb('{}')), jsonb(?))\n\t\t\t\tWHERE trace_id = ? AND span_id = ?`,\n\t\t\tMath.round(close.durationMs),\n\t\t\tclose.outcome,\n\t\t\tclose.error,\n\t\t\tclose.attributes ? JSON.stringify(close.attributes) : \"{}\",\n\t\t\ttraceId,\n\t\t\tspanId\n\t\t);\n\t}\n\n\t/** Append a single log, assigning the next per-trace `seq` (store-owned). */\n\tappendLog(log: LogInput): void {\n\t\tconst { next } = this.sql\n\t\t\t.exec<{ next: number }>(\n\t\t\t\t`SELECT COALESCE(MAX(seq), -1) + 1 AS next FROM logs WHERE trace_id = ?`,\n\t\t\t\tlog.traceId\n\t\t\t)\n\t\t\t.one();\n\t\tthis.sql.exec(\n\t\t\t`INSERT INTO logs\n\t\t\t\t(trace_id, span_id, seq, ts_ms, level, message, operation)\n\t\t\t\tVALUES (?,?,?,?,?,?,?)`,\n\t\t\tlog.traceId,\n\t\t\tlog.spanId,\n\t\t\tNumber(next),\n\t\t\tlog.tsMs,\n\t\t\tlog.level,\n\t\t\tlog.message,\n\t\t\tlog.operation\n\t\t);\n\t}\n\n\t/**\n\t * The only way to read the store: a single read-only SQL query. The\n\t * Observability tab and coding agents both go through here (the UI has a set of\n\t * built-in queries; agents write their own), so the `spans` and `logs` schema\n\t * acts as the contract and is documented in the `/query` endpoint's OpenAPI\n\t * description.\n\t *\n\t * Because this runs SQL we did not write, and workerd's DO SQLite has no\n\t * read-only execution mode to rely on (`PRAGMA query_only` is rejected with\n\t * SQLITE_AUTH), we guard it two ways. First a syntactic check: checking only\n\t * the first keyword is not enough (`WITH \u2026 DELETE` is a single statement that\n\t * still starts with `WITH`), so we remove comments and anything inside quotes \u2014\n\t * so a value like `'\u2026delete\u2026'` or a `;` inside a string cannot trip the checks \u2014\n\t * then require a single statement (no `;`) that starts with `SELECT`/`WITH` and\n\t * contains no data- or schema-changing keyword. Second, and not relying on that\n\t * regex, the statement runs inside a transaction that is always rolled back, so\n\t * any write or DDL that slipped past the checks is discarded rather than\n\t * persisted. Values are always passed as bound `params`, and at most\n\t * `MAX_QUERY_ROWS` rows are returned.\n\t *\n\t * `attributes` is stored as JSONB; wrap it with `json(attributes)` to read it\n\t * back as JSON (the built-in queries already do).\n\t */\n\tquery(\n\t\tsql: string,\n\t\tparams: SqlStorageValue[] = []\n\t): { columns: string[]; rows: unknown[][] } {\n\t\t// Drop a single trailing `;` so the common \"SELECT \u2026;\" form is allowed.\n\t\tconst statement = sql.trim().replace(/;\\s*$/, \"\");\n\t\t// Remove comments and anything inside quotes so the keyword and `;` checks\n\t\t// can't be fooled by (or wrongly triggered by) text inside strings.\n\t\t// `REPLACE` is only matched as `REPLACE INTO`, because `replace()` is a\n\t\t// common function in read queries.\n\t\tconst stripped = statement\n\t\t\t.replace(/--[^\\n]*/g, \" \")\n\t\t\t.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \")\n\t\t\t.replace(/'(?:[^']|'')*'/g, \"''\")\n\t\t\t.replace(/\"(?:[^\"]|\"\")*\"/g, '\"\"')\n\t\t\t.trim();\n\t\tif (!/^(SELECT|WITH)\\b/i.test(stripped)) {\n\t\t\tthrow new Error(\"Only read-only SELECT/WITH queries are allowed\");\n\t\t}\n\t\tif (stripped.includes(\";\")) {\n\t\t\tthrow new Error(\"Only a single statement is allowed\");\n\t\t}\n\t\tif (\n\t\t\t/\\b(INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|TRUNCATE|PRAGMA|ATTACH|DETACH|VACUUM|REINDEX|ANALYZE|BEGIN|COMMIT|ROLLBACK|SAVEPOINT|RELEASE|LOAD_EXTENSION)\\b|\\bREPLACE\\s+INTO\\b/i.test(\n\t\t\t\tstripped\n\t\t\t)\n\t\t) {\n\t\t\tthrow new Error(\"Only read-only SELECT/WITH queries are allowed\");\n\t\t}\n\t\t// Run inside a transaction that always rolls back. The rows are collected\n\t\t// first, then a sentinel is thrown to abort the transaction: a read-only\n\t\t// SELECT/WITH is unaffected, but any write or DDL that got past the checks\n\t\t// above is undone instead of committed. This is the real read-only barrier\n\t\t// (the regex is just the first line); a statement that can't run in a\n\t\t// transaction would throw here rather than take effect, so it fails safe.\n\t\tconst columns: string[] = [];\n\t\tconst rows: unknown[][] = [];\n\t\tconst rollback = Symbol(\"rollback\");\n\t\ttry {\n\t\t\tthis.ctx.storage.transactionSync(() => {\n\t\t\t\tconst cursor = this.sql.exec(statement, ...params);\n\t\t\t\tcolumns.push(...cursor.columnNames);\n\t\t\t\tfor (const row of cursor.raw()) {\n\t\t\t\t\tif (rows.length >= MAX_QUERY_ROWS) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\trows.push([...row]);\n\t\t\t\t}\n\t\t\t\tthrow rollback;\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tif (e !== rollback) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t}\n\t\treturn { columns, rows };\n\t}\n\n\t/** Delete all captured data. An RPC method; nothing calls it yet. */\n\tclear(): void {\n\t\tthis.sql.exec(\"DELETE FROM logs\");\n\t\tthis.sql.exec(\"DELETE FROM spans\");\n\t}\n}\n"],
  "mappings": "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",
  "names": []
}
