@bitfab/sdk 0.36.2 → 0.36.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/codeChange.ts","../src/errors.ts","../src/readEnv.ts","../src/compress.ts","../src/version.generated.ts","../src/constants.ts","../src/asyncStorage.ts","../src/replayContext.ts","../src/payloadBudget.ts","../src/warnOnce.ts","../src/serializePayload.ts","../src/otel.ts","../src/unrefTimer.ts","../src/transport.ts","../src/http.ts","../src/mockOverride.ts","../src/randomUuid.ts","../src/serialize.ts","../src/replay.ts"],"sourcesContent":["import type { CodeChangeFile } from \"./http\"\n\n/**\n * Auto-capture the code change to attach to a replay, when the caller passed\n * none explicitly.\n *\n * This lives in the SDK (not a wrapper) on purpose: `replay()` is the only point\n * guaranteed to run on every replay, so capturing here works no matter how the\n * replay was launched (plugin wrapper, a hand-run script, CI). Precedence:\n *\n * 1. `BITFAB_CODE_CHANGE_PATH` file — an override a caller/tool can inject.\n * 2. `git diff` vs trunk — the default fallback.\n *\n * Both are best-effort and browser-safe: any failure (no git, no fs, not a repo,\n * bad JSON) yields `null` and the replay proceeds with no code change. The diff\n * is cumulative (whole branch vs trunk), not per-experiment; an explicit\n * `codeChangeFiles` on `replay()` always wins over this and is what carries a\n * precise per-experiment before/after.\n */\n\nexport interface ResolvedCodeChange {\n description?: string\n files?: CodeChangeFile[]\n}\n\n// Bounds so a large delta never bloats the experiment payload.\nconst MAX_FILES = 60\nconst MAX_FILE_BYTES = 500_000\nconst MAX_TOTAL_BYTES = 2_000_000\n\n// Candidate trunk refs, tried in order, when no explicit base is supplied.\nconst TRUNK_CANDIDATES = [\n \"origin/HEAD\",\n \"origin/main\",\n \"origin/master\",\n \"main\",\n \"master\",\n]\n\nconst NUL = String.fromCharCode(0)\n\n/**\n * Resolve an auto code change: the `BITFAB_CODE_CHANGE_PATH` override first,\n * then the git-vs-trunk diff. Returns null when neither yields anything.\n */\nexport async function resolveAutoCodeChange(\n label?: string,\n): Promise<ResolvedCodeChange | null> {\n if (typeof process === \"undefined\") {\n return null\n }\n if (process.env?.BITFAB_DISABLE_CODE_CHANGE_CAPTURE) {\n return null\n }\n const fromEnv = await readCodeChangeFile()\n if (fromEnv) {\n return fromEnv\n }\n return captureCodeChangeFromGit(process.cwd?.() ?? \".\", label)\n}\n\nasync function readCodeChangeFile(): Promise<ResolvedCodeChange | null> {\n const path = process.env?.BITFAB_CODE_CHANGE_PATH\n if (!path) {\n return null\n }\n try {\n const { readFile } = await import(\"node:fs/promises\")\n const parsed = JSON.parse(await readFile(path, \"utf8\"))\n // A malformed payload (non-array, or entries that aren't objects) must yield\n // no code change, never forward a bad shape to the start-replay request.\n const files =\n Array.isArray(parsed?.files) &&\n parsed.files.every(\n (f: unknown) =>\n typeof f === \"object\" && f !== null && !Array.isArray(f),\n )\n ? parsed.files\n : undefined\n const description =\n typeof parsed?.description === \"string\" ? parsed.description : undefined\n if (!files && description === undefined) {\n return null\n }\n return { description, files }\n } catch {\n return null\n }\n}\n\nasync function captureCodeChangeFromGit(\n cwd: string,\n label?: string,\n): Promise<ResolvedCodeChange | null> {\n let execFile: typeof import(\"node:child_process\").execFile\n let readFile: typeof import(\"node:fs/promises\").readFile\n try {\n ;({ execFile } = await import(\"node:child_process\"))\n ;({ readFile } = await import(\"node:fs/promises\"))\n } catch {\n // No child_process / fs (e.g. a browser bundle): capture is a no-op.\n return null\n }\n\n const git = (dir: string, args: string[]): Promise<string | null> =>\n new Promise((resolve) => {\n execFile(\n \"git\",\n args,\n // 30s timeout so a hung git (e.g. a network-touching ref op) can't\n // block the whole replay indefinitely.\n { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 30_000 },\n (err, stdout) => resolve(err ? null : stdout),\n )\n })\n\n try {\n const root = (await git(cwd, [\"rev-parse\", \"--show-toplevel\"]))?.trim()\n if (!root) {\n return null\n }\n\n const resolved = await resolveBase(git, root)\n if (!resolved) {\n return null\n }\n const { base, fromTrunk } = resolved\n\n // Size of a path on either side WITHOUT reading its contents: the git blob\n // size for `before`, a stat for the working `after`. Lets us skip an\n // oversized file before loading it into memory.\n const blobBytes = async (ref: string, path: string): Promise<number> => {\n const out = await git(root, [\"cat-file\", \"-s\", `${ref}:${path}`])\n const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN\n return Number.isFinite(n) ? n : 0\n }\n const workingBytes = async (path: string): Promise<number> => {\n try {\n const { stat } = await import(\"node:fs/promises\")\n const { join } = await import(\"node:path\")\n return (await stat(join(root, path))).size\n } catch {\n return 0\n }\n }\n\n // Tracked changes vs base. `:!.bitfab` keeps replay artifacts out.\n const tracked = await git(root, [\n \"diff\",\n \"--name-status\",\n \"--no-renames\",\n \"-z\",\n base,\n \"--\",\n \":!.bitfab\",\n ])\n // Untracked-but-not-ignored files (the diff above omits these).\n const untracked = await git(root, [\n \"ls-files\",\n \"--others\",\n \"--exclude-standard\",\n \"-z\",\n \"--\",\n \":!.bitfab\",\n ])\n\n const entries: Array<{ status: string; path: string }> = [\n ...parseNameStatusZ(tracked ?? \"\"),\n ...(untracked ?? \"\")\n .split(NUL)\n .filter((p) => p.length > 0)\n .map((path) => ({ status: \"A\", path })),\n ]\n if (entries.length === 0) {\n return null\n }\n\n const files: CodeChangeFile[] = []\n let totalBytes = 0\n for (const { status, path } of entries) {\n if (files.length >= MAX_FILES) {\n break\n }\n // Skip oversized files by size BEFORE reading their full contents, so a\n // huge changed file can't OOM/stall the replay just to be discarded.\n const beforeBytes = status === \"A\" ? 0 : await blobBytes(base, path)\n const afterBytes = status === \"D\" ? 0 : await workingBytes(path)\n if (beforeBytes > MAX_FILE_BYTES || afterBytes > MAX_FILE_BYTES) {\n continue\n }\n // Normalize CRLF -> LF on both sides: git's blob is already LF-normalized\n // (autocrlf clean), so a raw CRLF working file would otherwise skew every\n // line as changed. Comparing/storing LF keeps the diff meaningful.\n const before = (\n status === \"A\"\n ? \"\"\n : ((await git(root, [\"show\", `${base}:${path}`])) ?? \"\")\n ).replace(/\\r\\n/g, \"\\n\")\n const after = (\n status === \"D\" ? \"\" : await readWorkingFile(readFile, root, path)\n ).replace(/\\r\\n/g, \"\\n\")\n if (before === after) {\n continue\n }\n // Bytes, not chars: a multi-byte source file must count against the byte\n // cap the same way Ruby's `bytesize` does.\n const size =\n Buffer.byteLength(before, \"utf8\") + Buffer.byteLength(after, \"utf8\")\n if (\n totalBytes + size > MAX_TOTAL_BYTES ||\n looksBinary(before) ||\n looksBinary(after)\n ) {\n continue\n }\n totalBytes += size\n files.push({ path, before, after })\n }\n\n if (files.length === 0) {\n return null\n }\n\n const subject = (\n await git(root, [\"log\", \"-1\", \"--format=%s\", \"HEAD\"])\n )?.trim()\n const fileWord = files.length === 1 ? \"file\" : \"files\"\n const head = label?.trim() || subject || \"Working-tree change\"\n // \"vs trunk\" only when we actually diffed against a trunk merge-base; the\n // HEAD fallback captures uncommitted work only, so label it honestly.\n const against = fromTrunk ? \"vs trunk\" : \"uncommitted (vs HEAD)\"\n return {\n description: `${head} (${files.length} ${fileWord} changed ${against})`,\n files,\n }\n } catch {\n return null\n }\n}\n\nasync function resolveBase(\n git: (dir: string, args: string[]) => Promise<string | null>,\n root: string,\n): Promise<{ base: string; fromTrunk: boolean } | null> {\n const forced = process.env?.BITFAB_CODE_CHANGE_BASE\n if (forced && (await refExists(git, root, forced))) {\n const base =\n (await git(root, [\"merge-base\", \"HEAD\", forced]))?.trim() ||\n (await git(root, [\"rev-parse\", \"--verify\", forced]))?.trim() ||\n null\n return base ? { base, fromTrunk: true } : null\n }\n for (const candidate of TRUNK_CANDIDATES) {\n if (!(await refExists(git, root, candidate))) {\n continue\n }\n const mb = (await git(root, [\"merge-base\", \"HEAD\", candidate]))?.trim()\n if (mb) {\n return { base: mb, fromTrunk: true }\n }\n }\n return (await refExists(git, root, \"HEAD\"))\n ? { base: \"HEAD\", fromTrunk: false }\n : null\n}\n\nasync function refExists(\n git: (dir: string, args: string[]) => Promise<string | null>,\n root: string,\n ref: string,\n): Promise<boolean> {\n return (\n (await git(root, [\"rev-parse\", \"--verify\", `${ref}^{object}`])) !== null\n )\n}\n\nasync function readWorkingFile(\n readFile: typeof import(\"node:fs/promises\").readFile,\n root: string,\n path: string,\n): Promise<string> {\n try {\n const { join } = await import(\"node:path\")\n return await readFile(join(root, path), \"utf8\")\n } catch {\n return \"\"\n }\n}\n\nfunction parseNameStatusZ(\n raw: string,\n): Array<{ status: string; path: string }> {\n const parts = raw.split(NUL).filter((p) => p.length > 0)\n const out: Array<{ status: string; path: string }> = []\n for (let i = 0; i + 1 < parts.length; i += 2) {\n out.push({ status: parts[i].charAt(0), path: parts[i + 1] })\n }\n return out\n}\n\nfunction looksBinary(s: string): boolean {\n return s.slice(0, 8000).includes(NUL)\n}\n","/**\n * Shared error type for Bitfab SDK runtime errors. Lives in its own\n * module to avoid import cycles between `http.ts` and modules that need\n * to throw structured errors (e.g. `dbSnapshot.ts` validation).\n */\n\nexport class BitfabError extends Error {\n constructor(\n message: string,\n public readonly url?: string,\n /**\n * HTTP status the request failed with, when it failed with one. The\n * transport's retry policy needs the code itself (retry 408/425/429/5xx,\n * never a 4xx the server will reject again), which a formatted message\n * cannot supply. Absent for network failures and non-HTTP errors.\n */\n public readonly status?: number,\n ) {\n super(message)\n this.name = \"BitfabError\"\n }\n}\n","/**\n * Read an environment variable without throwing in non-Node runtimes\n * (browsers, edge workers) where `process` is absent. The SDK ships to\n * browsers, so this must never assume `process` exists.\n */\nexport function readEnv(name: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[name]\n }\n return undefined\n}\n","import { readEnv } from \"./readEnv.js\"\n\nconst DISABLE_COMPRESSION_ENV = \"BITFAB_DISABLE_COMPRESSION\"\n\n/**\n * Below this, compressing costs more than the saved bytes are worth, so small\n * requests (function lookups, replay status polls, single-span batches) ride\n * uncompressed.\n */\nconst MIN_COMPRESSED_BYTES = 8_192\n\nexport interface EncodedRequestBody {\n body: string | ArrayBuffer\n contentEncoding?: \"gzip\"\n}\n\n/**\n * Node's gzip, loaded dynamically so browser bundlers never have to resolve\n * `node:zlib`. Deliberately the async form: it runs on libuv's threadpool\n * rather than the event loop. Measured on 8 concurrent 1 MB bodies, the\n * synchronous form stalled the loop for 326ms and the async form for 1ms,\n * while also finishing 3.8x sooner because the threadpool compresses in\n * parallel. A tracing SDK must not block its host's event loop.\n */\nlet gzipNode: ((data: Uint8Array) => Promise<Uint8Array>) | undefined\n\ntype NodeZlib = {\n gzip: (\n data: Uint8Array,\n callback: (error: Error | null, result: Uint8Array) => void,\n ) => void\n}\n\nexport const _nodeGzipReady: Promise<void> = (\n typeof process !== \"undefined\" && process.versions?.node\n ? // The join trick hides \"node:zlib\" from static analysis so bundlers that\n // ban Node.js built-ins don't fail at build time. webpackIgnore tells\n // webpack/turbopack to emit a native import() so Node.js can resolve the\n // module at runtime. Same pattern as `asyncStorage.ts`.\n import(\n /* webpackIgnore: true */\n [\"node\", \"zlib\"].join(\":\")\n )\n .then(({ gzip }: NodeZlib) => {\n gzipNode = (data) =>\n new Promise((resolve, reject) => {\n gzip(data, (error, result) => {\n if (error) {\n reject(error)\n } else {\n resolve(result)\n }\n })\n })\n })\n .catch(() => {})\n : Promise.resolve()\n).then(() => {})\n\n/** Test seam for exercising the browser path on Node. */\nexport function _setNodeGzip(\n impl: ((data: Uint8Array) => Promise<Uint8Array>) | undefined,\n): void {\n gzipNode = impl\n}\n\nfunction toArrayBuffer(view: Uint8Array): ArrayBuffer {\n return view.buffer.slice(\n view.byteOffset,\n view.byteOffset + view.byteLength,\n ) as ArrayBuffer\n}\n\nasync function gzipViaStream(bytes: Uint8Array): Promise<ArrayBuffer> {\n const stream = new Blob([bytes as BlobPart])\n .stream()\n .pipeThrough(new CompressionStream(\"gzip\"))\n return await new Response(stream).arrayBuffer()\n}\n\n/**\n * Compression is best-effort: any failure sends the original body rather than\n * dropping the span. `CompressionStream` is absent on older browsers, so its\n * presence is checked rather than assumed.\n *\n * Returns a plain value (not a promise) whenever it can, so a request still\n * reaches `fetch` in the caller's tick rather than one microtask later. Callers\n * await the union.\n */\nexport function encodeRequestBody(\n body: string,\n): EncodedRequestBody | Promise<EncodedRequestBody> {\n if (readEnv(DISABLE_COMPRESSION_ENV)) {\n return { body }\n }\n const bytes = new TextEncoder().encode(body)\n if (bytes.byteLength < MIN_COMPRESSED_BYTES) {\n return { body }\n }\n if (gzipNode) {\n return gzipNode(bytes).then(\n (compressed) => ({\n body: toArrayBuffer(compressed),\n contentEncoding: \"gzip\" as const,\n }),\n () => ({ body }),\n )\n }\n if (typeof CompressionStream === \"undefined\") {\n return { body }\n }\n return gzipViaStream(bytes).then(\n (compressed) => ({ body: compressed, contentEncoding: \"gzip\" as const }),\n () => ({ body }),\n )\n}\n","/**\n * Auto-generated version file.\n * This file is generated by scripts/generate-version.ts during build.\n * DO NOT EDIT MANUALLY.\n */\n\n/**\n * SDK version from package.json (injected at build time)\n */\nexport const __version__ = \"0.36.2\"\n","/**\n * Constants for the Bitfab SDK.\n */\n\n/**\n * Default service URL for Bitfab API.\n */\nexport const DEFAULT_SERVICE_URL = \"https://bitfab.ai\"\n\n/**\n * SDK version from package.json (injected at build time)\n *\n * The version is generated at build time by scripts/generate-version.ts\n * to ensure compatibility with both Node.js and browser environments.\n */\nexport { __version__ } from \"./version.generated.js\"\n","/**\n * Shared AsyncLocalStorage loader.\n *\n * Provides two ways to initialize AsyncLocalStorage:\n *\n * 1. **Synchronous registration** (preferred for Node.js):\n * `asyncStorageNode.ts` calls `registerAsyncLocalStorageClass()` at module\n * evaluation time, so the class is available immediately - no async gap.\n * The `node.ts` entry point imports it before anything else.\n *\n * 2. **Async dynamic import** (fallback for the default entry point):\n * Loads `node:async_hooks` via a bundler-safe dynamic import. This is used\n * by the default `index.ts` entry point so the SDK works in browsers\n * (where the import silently fails) and in Node.js when imported via the\n * default entry point.\n *\n * ## Why the dynamic import looks like this\n *\n * We need to handle three environments:\n *\n * 1. **Pure Node.js** - `import(\"node:async_hooks\")` works natively.\n * 2. **Webpack/Turbopack (Next.js server)** - The bundler processes\n * `import()` calls at build time. The `webpackIgnore` magic comment tells\n * webpack (and turbopack) to emit a native `import()` call instead of\n * trying to resolve it, so Node.js handles it at runtime.\n * 3. **Browsers / Edge** - The `process.versions?.node` guard prevents\n * execution entirely. If it somehow runs, `.catch(() => {})` swallows\n * the failure.\n */\n\nexport interface AsyncLocalStorageLike<T> {\n getStore(): T | undefined\n run<R>(store: T, fn: () => R): R\n}\n\nlet AsyncLocalStorageClass: (new () => AsyncLocalStorageLike<unknown>) | null =\n null\nlet initDone = false\n\n/**\n * Register the AsyncLocalStorage class synchronously.\n *\n * Called by `asyncStorageNode.ts` at module evaluation time so the class\n * is available before any span is created - no async gap, no race condition.\n *\n * Safe to call multiple times; subsequent calls are no-ops.\n */\nexport function registerAsyncLocalStorageClass(\n cls: new () => AsyncLocalStorageLike<unknown>,\n): void {\n if (!AsyncLocalStorageClass) {\n AsyncLocalStorageClass = cls\n }\n initDone = true\n}\n\n/**\n * Assert that AsyncLocalStorage was registered successfully.\n *\n * Called by `node.ts` after importing `asyncStorageNode.ts` to catch\n * import-order bugs at startup rather than silently degrading to the\n * browser fallback (flat spans with no nesting).\n *\n * This should ONLY be called from the Node.js entry point where we\n * know `node:async_hooks` must be available.\n */\nexport function assertAsyncStorageRegistered(): void {\n if (!AsyncLocalStorageClass) {\n console.warn(\n \"Bitfab: AsyncLocalStorage not available - nested span context will not propagate.\",\n )\n }\n}\n\nexport const asyncStorageReady: Promise<void> = (\n typeof process !== \"undefined\" && process.versions?.node\n ? // The join trick hides \"node:async_hooks\" from static analysis so\n // bundlers that ban Node.js built-ins don't fail at build time.\n // webpackIgnore tells webpack/turbopack to emit a native import()\n // so Node.js can resolve the module at runtime.\n import(\n /* webpackIgnore: true */\n [\"node\", \"async_hooks\"].join(\":\")\n )\n .then(\n (mod: {\n AsyncLocalStorage: new () => AsyncLocalStorageLike<unknown>\n }) => {\n registerAsyncLocalStorageClass(mod.AsyncLocalStorage)\n },\n )\n .catch(() => {})\n : Promise.resolve()\n).then(() => {\n initDone = true\n})\n\nexport function isAsyncStorageInitDone(): boolean {\n return initDone\n}\n\nexport function createAsyncLocalStorage<T>(): AsyncLocalStorageLike<T> | null {\n return AsyncLocalStorageClass\n ? (new AsyncLocalStorageClass() as AsyncLocalStorageLike<T>)\n : null\n}\n","/**\n * Replay context propagation via AsyncLocalStorage.\n *\n * When set, the withSpan wrapper injects testRunId into the span payload\n * so that new spans created during replay are linked to the test run.\n * Optionally carries a mock tree so child spans can return historical\n * outputs instead of executing.\n */\n\nimport {\n type AsyncLocalStorageLike,\n asyncStorageReady,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\nimport type { MockOverride } from \"./mockOverride.js\"\n\n/**\n * A single span entry in the mock tree.\n *\n * Under the eager path (`mock: \"all\"`) `output`/`outputMeta` are populated\n * inline. Under the lazy path (`marked` / overrides) they are absent and the\n * recorded output is fetched on demand via `externalSpanId` - see\n * {@link ReplayContext.fetchSpanOutput}.\n */\nexport interface MockSpan {\n sourceSpanId: string\n /** Row id accepted by `getExternalSpan`, for the lazy per-span output fetch. */\n externalSpanId?: string\n output?: unknown\n outputMeta?: unknown\n}\n\n/**\n * Per-item DB branch resolved by the Bitfab service from the source\n * trace's `dbSnapshotRef`. Carried on the replay context so that\n * customer code reads `databaseUrl` through `getCurrentReplayBranch()`, and so\n * the process-isolated replay runner can materialize it into a `.env`\n * overlay file before customer code initializes its DB client.\n *\n * `neonBranchId` is the literal Neon branch id; passing it to\n * `releaseDbBranchLease` deletes that branch.\n */\nexport interface DbBranchLease {\n neonBranchId: string\n /** Env var name the customer's app reads, e.g. \"DATABASE_URL\". */\n envKey: string\n databaseUrl: string\n expiresAt: string\n /**\n * The instant the branch was pinned to (the source trace's wall clock).\n * Echoed back in `db_snapshot_usage` on the replayed trace's completion.\n */\n snapshotTimestamp?: string\n providerConsoleUrl?: string\n readOnly?: boolean\n /**\n * The branch's region, e.g. `aws-us-east-1`. A compute runs in its project's\n * region, so a runner elsewhere pays that round trip on every query.\n */\n region?: string\n}\n\n/**\n * Wire shape of the caller's `ReplayOptions.dbBranch`, sent to\n * `/api/sdk/replay/start` and applied per lease.\n */\nexport interface DbBranchSettings {\n minCu?: number\n maxCu?: number\n warmupSql?: string\n}\n\n/**\n * Pre-built lookup table of historical span outputs.\n * Keys are `${traceFunctionKey}:${spanName}:${callIndex}` so that repeated\n * calls with the same (key, name) are matched by call order, but spans\n * sharing only the traceFunctionKey (different name) do not collide.\n */\nexport interface MockTree {\n spans: Map<string, MockSpan>\n}\n\nexport interface ReplayContext {\n testRunId: string\n traceId?: string\n inputSourceSpanId?: string\n /**\n * External trace ID from `external_traces.id`. Used for span-chain\n * lookup against the source platform's trace tree (Braintrust, etc.).\n * NOT the same as the Bitfab `traceId` - see `sourceBitfabTraceId`.\n */\n inputSourceTraceId?: string\n /**\n * The Bitfab `traces.id` of the historical trace that produced this\n * replay item's input. This is what customer-facing surfaces (e.g.\n * `ReplayBranch.traceId`) should expose, since it's the ID the\n * customer sees in the Bitfab dashboard.\n */\n sourceBitfabTraceId?: string\n mockTree?: MockTree\n callCounters?: Map<string, number>\n mockStrategy?: \"none\" | \"all\" | \"marked\"\n /**\n * Resolved override chain for this replay, per-call overrides first then\n * registered ones (first matcher wins). Empty/absent when no overrides apply.\n */\n mockOverrides?: MockOverride[]\n /**\n * Memoized lazy fetch of a span's recorded output (deserialized), keyed by\n * `externalSpanId`. Present ONLY on the lazy path (`marked` / overrides);\n * absent under `mock: \"all\"`, where outputs are inline on the mock tree. Its\n * presence is the signal that outputs must be fetched rather than read inline.\n */\n fetchSpanOutput?: (externalSpanId: string) => Promise<unknown>\n dbBranchLease?: DbBranchLease\n /**\n * Set to true by `ReplayBranch` the first time customer code actually\n * obtains `databaseUrl` for this item. Reported on the trace completion inside\n * `db_snapshot_usage` so the server can distinguish \"branch was\n * provisioned and exposed\" from \"branch URL was actually consumed\".\n * Only an explicit `databaseUrl` read may set it. A path that hands the URL\n * over by other means (e.g. a process-isolated runner writing an env\n * overlay) must leave it alone: setting it there would make every such\n * replay report `accessed` for free, and the flag would stop separating\n * \"branch was used\" from \"branch was offered\".\n */\n dbSnapshotAccessed?: boolean\n}\n\nlet replayContextStorage: AsyncLocalStorageLike<ReplayContext | null> | null =\n null\nconst REPLAY_CONTEXT_STORAGE_SYMBOL = Symbol.for(\"bitfab.replayContextStorage\")\n\nexport const replayContextReady: Promise<void> = asyncStorageReady.then(() => {\n const shared = globalThis as typeof globalThis & Record<symbol, unknown>\n const existing = shared[REPLAY_CONTEXT_STORAGE_SYMBOL] as\n | AsyncLocalStorageLike<ReplayContext | null>\n | undefined\n if (existing) {\n replayContextStorage = existing\n return\n }\n const created = createAsyncLocalStorage<ReplayContext | null>()\n if (created) {\n shared[REPLAY_CONTEXT_STORAGE_SYMBOL] = created\n replayContextStorage = created\n }\n})\n\n/** Get the current replay context, if any. */\nexport function getReplayContext(): ReplayContext | null {\n return replayContextStorage?.getStore() ?? null\n}\n\n/** Run a function within a replay context. */\nexport function runWithReplayContext<T>(ctx: ReplayContext, fn: () => T): T {\n if (replayContextStorage) {\n return replayContextStorage.run(ctx, fn)\n }\n return fn()\n}\n","/**\n * The ceiling on a span's encoded carrier, and the trimming that enforces it.\n *\n * A span's whole payload (input, output, contexts, prompt, metadata) ships as\n * a single `bitfab.payload` string attribute, and the exporter drops any\n * carrier that exceeds the per-request byte ceiling outright rather than\n * trimming it. Capping each value on its own cannot prevent that: two values\n * that each fit can still add up to an undeliverable span. So the budget is\n * enforced on the whole span, and an oversized one ships with its largest\n * fields stubbed instead of vanishing.\n *\n * The budget is measured on the *carrier* (the payload re-escaped into the\n * OTLP attribute), not on the payload body, because the carrier is what the\n * exporter weighs. Bounding the body instead leaves escape-heavy content to\n * blow the request ceiling anyway: a body of escaped JSON, Windows paths, or\n * regexes is nearly all backslashes, and every one of them doubles. Measured\n * on a body sized exactly to a 2.4 MB cap, prose produced a 2.4 MB carrier but\n * backslash-dense content produced 4.8 MB, which the exporter dropped.\n *\n * 2.8 MB leaves room beneath the 3 MB request ceiling for the span and request\n * envelopes wrapped around the attribute.\n */\nexport const MAX_SPAN_CARRIER_BYTES = 2_800_000\n\nconst textEncoder =\n typeof TextEncoder !== \"undefined\" ? new TextEncoder() : null\n\nexport function byteLength(value: string): number {\n return textEncoder ? textEncoder.encode(value).length : value.length\n}\n\n/**\n * The byte length `body` occupies once re-escaped as a JSON string value.\n *\n * `body` is itself JSON text, so the first encode already replaced every\n * control character with a `\\uXXXX` sequence, leaving only `\"` and `\\` to\n * escape at one extra byte each.\n *\n * Counts UTF-8 width and escapes in the same pass and allocates nothing.\n * `TextEncoder.encode().length` would be the obvious way to get the byte count,\n * but it copies the entire body into a fresh array just to read its length,\n * which on a multi-megabyte span costs more than producing the body did.\n */\nexport function carrierByteLength(body: string): number {\n return carrierBytesOf(textEncoder ? textEncoder.encode(body) : null, body)\n}\n\n/**\n * Counts escapes over the UTF-8 bytes rather than the UTF-16 string. Bytes\n * `0x22` and `0x5c` are unambiguous there (a multi-byte sequence never uses a\n * byte below `0x80`), so a flat byte scan is exact, and it reuses the array the\n * byte count already had to produce instead of walking the string a second\n * time. Measured ~2x faster than the equivalent `charCodeAt` loop.\n */\nfunction carrierBytesOf(encoded: Uint8Array | null, body: string): number {\n if (!encoded) {\n // No TextEncoder (a browser old enough to lack it). Fall back to the string,\n // where `length` is the best available byte estimate.\n return body.length + 2\n }\n let extra = 2 // the quotes wrapping the attribute value\n for (let i = 0; i < encoded.length; i++) {\n const byte = encoded[i]\n if (byte === 34 || byte === 92) {\n extra += 1 // `\"` and `\\` take a leading backslash\n } else if (byte < 0x20) {\n extra +=\n byte === 8 || byte === 9 || byte === 10 || byte === 12 || byte === 13\n ? 1 // \\b \\f \\n \\r \\t\n : 5 // \\uXXXX\n }\n }\n return encoded.length + extra\n}\n\n/**\n * The most carrier bytes one UTF-16 code unit of a *JSON body* can become.\n *\n * A unit is at most 3 UTF-8 bytes, and the only characters that grow under\n * escaping are `\"` and `\\`, which are one byte and become two. A unit cannot be\n * both, so 3 is the ceiling. This holds because every caller passes the output\n * of a JSON encoder, which by specification never emits a raw control character\n * (the case that would otherwise expand to a 6-byte `\\uXXXX`); the invariant is\n * pinned by a test so a future caller that broke it would fail loudly rather\n * than silently ship an oversized carrier.\n */\nconst MAX_BYTES_PER_UNIT = 3\n\n/**\n * Whether `body` fits the carrier budget, escalating only as far as it must.\n *\n * `body.length` is O(1) and brackets the answer for both ordinary spans (far\n * under the budget) and hopeless ones (already past it on raw length alone),\n * which is every span in normal traffic: neither case touches the string. Only\n * a body near the budget is measured exactly, and that costs one encode plus\n * one byte scan.\n */\nexport function fitsCarrierBudget(body: string): boolean {\n const units = body.length\n if (units * MAX_BYTES_PER_UNIT + 2 <= MAX_SPAN_CARRIER_BYTES) {\n return true\n }\n if (units + 2 > MAX_SPAN_CARRIER_BYTES) {\n return false\n }\n return carrierByteLength(body) <= MAX_SPAN_CARRIER_BYTES\n}\n\n/**\n * Span fields that identify the span rather than carry user data. Trimming one\n * would leave a span that no longer says what it is, so they stay whatever the\n * payload costs.\n */\nconst STRUCTURAL_SPAN_KEYS = new Set([\n \"name\",\n \"type\",\n \"function_name\",\n \"error_source\",\n])\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\ninterface Candidate {\n container: Record<string, unknown>\n key: string\n size: number\n}\n\n/**\n * The records holding user data, cloned so trimming never mutates the caller's\n * objects. Returns the payload copy to encode plus the containers to trim.\n */\nfunction cloneTrimmable(payload: Record<string, unknown>): {\n copy: Record<string, unknown>\n containers: Record<string, unknown>[]\n} {\n const copy = { ...payload }\n const containers: Record<string, unknown>[] = []\n\n const spanData = asRecord(copy.span_data)\n if (spanData) {\n const clone = { ...spanData }\n copy.span_data = clone\n containers.push(clone)\n }\n\n const rawSpan = asRecord(copy.rawSpan)\n const rawSpanData = rawSpan && asRecord(rawSpan.span_data)\n if (rawSpan && rawSpanData) {\n const clone = { ...rawSpanData }\n copy.rawSpan = { ...rawSpan, span_data: clone }\n containers.push(clone)\n }\n\n // No span_data anywhere: a trace-level or otherwise unfamiliar payload. Trim\n // its own fields rather than give up, so an oversized body still ships.\n if (containers.length === 0) {\n containers.push(copy)\n }\n\n return { copy, containers }\n}\n\nfunction collectCandidates(containers: Record<string, unknown>[]): Candidate[] {\n const candidates: Candidate[] = []\n for (const container of containers) {\n for (const [key, value] of Object.entries(container)) {\n if (STRUCTURAL_SPAN_KEYS.has(key) || value == null) {\n continue\n }\n let size: number\n try {\n size = byteLength(JSON.stringify(value) ?? \"\")\n } catch {\n continue\n }\n candidates.push({ container, key, size })\n }\n }\n return candidates.sort((a, b) => b.size - a.size)\n}\n\n/**\n * Stub the largest payload fields until the encoded body fits the budget.\n *\n * Returns the trimmed payload and the names of the fields that were stubbed, or\n * `undefined` when nothing could be trimmed (the caller then ships the\n * oversized body and lets the exporter report the drop, which is still better\n * than silently emptying a span).\n */\nexport function trimPayloadToBudget(\n payload: Record<string, unknown>,\n encode: (value: Record<string, unknown>) => string,\n): { value: Record<string, unknown>; trimmed: string[] } | undefined {\n const { copy, containers } = cloneTrimmable(payload)\n const candidates = collectCandidates(containers)\n if (candidates.length === 0) {\n return undefined\n }\n\n const trimmed: string[] = []\n for (const candidate of candidates) {\n candidate.container[candidate.key] =\n `<unserializable: too_large_${candidate.size}_bytes>`\n trimmed.push(candidate.key)\n let body: string\n try {\n body = encode(copy)\n } catch {\n return undefined\n }\n if (fitsCarrierBudget(body)) {\n return { value: copy, trimmed }\n }\n }\n return undefined\n}\n\n/**\n * Record a trim in the payload's own `errors`, which is what the server reads\n * to flag a trace as incomplete.\n */\nexport function markPayloadTrimmed(\n value: Record<string, unknown>,\n trimmed: string[],\n): void {\n const existing = Array.isArray(value.errors) ? value.errors : []\n value.errors = [\n ...existing,\n {\n source: \"sdk\",\n step: \"payload_budget\",\n error: `trimmed oversized field(s) to fit the ${MAX_SPAN_CARRIER_BYTES}-byte span carrier budget: ${[\n ...new Set(trimmed),\n ].join(\", \")}`,\n },\n ]\n}\n","/**\n * Emit a `console.warn` at most once per distinct `key` for the life of the\n * process.\n *\n * The SDK must NEVER crash a host app, so every failure on the user's path\n * degrades silently (a span is dropped, a call runs untraced, a payload is\n * stubbed). Silent is safe but undebuggable: a user who suddenly has no traces,\n * or sees `<unserializable>` in a span, has no signal as to why. A one-time\n * warning per distinct issue restores that signal without spamming the console\n * from a hot path.\n *\n * Keys should identify the specific degradation (e.g. include the traced\n * function key) so each distinct issue warns once, not just the first one seen.\n */\nconst warned = new Set<string>()\n\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key)) {\n return\n }\n warned.add(key)\n try {\n console.warn(`[bitfab] ${message}`)\n } catch {\n // Logging must never crash the host app (e.g. a closed/replaced console).\n }\n}\n\n/** Test-only: clear the dedup set so a warning can fire again. */\nexport function _resetWarnOnce(): void {\n warned.clear()\n}\n","/**\n * Defensive payload encoding, shared by the HTTP path and the OTel carrier\n * path. Lives in its own module because `otel.ts` needs it and importing it\n * from `http.ts` would close an http -> transport -> otel -> http cycle.\n */\n\nimport {\n fitsCarrierBudget,\n MAX_SPAN_CARRIER_BYTES,\n markPayloadTrimmed,\n trimPayloadToBudget,\n} from \"./payloadBudget.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\n/**\n * JSON-encode a request body without ever throwing on a stray value, and\n * within the per-span byte budget.\n *\n * Upstream serialization (`serializeValue` / the LangGraph handler's\n * `safeSerialize`) should already have flattened user data. This is the\n * boundary backstop: if anything non-serializable still slips through\n * (BigInt, function, symbol, circular ref), it is stubbed in place instead of\n * letting `JSON.stringify` throw and drop the whole span/trace silently.\n *\n * The fast path is a plain `JSON.stringify`; the sanitizing replacer only runs\n * when that throws, so happy-path payloads (and shared non-circular refs) are\n * untouched. Returns `dropped` (the stubbed type names) so the caller can warn\n * loudly rather than ship a degraded payload in silence.\n */\nexport function serializePayloadBody(payload: Record<string, unknown>): {\n body: string\n dropped: string[]\n} {\n const encoded = encodePayloadBody(payload)\n if (fitsCarrierBudget(encoded.body)) {\n return { body: encoded.body, dropped: encoded.dropped }\n }\n return applyPayloadBudget(encoded)\n}\n\n/**\n * Trim an over-budget payload, preferring its largest fields, so the span\n * ships degraded rather than being dropped whole by the exporter.\n *\n * Trims the value that was actually encoded, not the caller's original: a\n * cyclic or otherwise non-encodable field cannot be sized (`JSON.stringify`\n * throws on it), so on the original graph the biggest field is skipped as a\n * trim candidate and the oversized body ships anyway. The sanitized copy has\n * those values already replaced with stubs, so every field is sizeable.\n */\nfunction applyPayloadBudget(encoded: EncodedPayload): {\n body: string\n dropped: string[]\n} {\n const result = encoded.value\n ? trimPayloadToBudget(\n encoded.value,\n (value) => encodePayloadBody(value).body,\n )\n : undefined\n if (!result) {\n return { body: encoded.body, dropped: encoded.dropped }\n }\n warnOnce(\n \"payload:over-budget\",\n `a span payload exceeded the ${MAX_SPAN_CARRIER_BYTES}-byte carrier budget; its largest field(s) (${[\n ...new Set(result.trimmed),\n ].join(\n \", \",\n )}) were replaced with placeholders so the span still ships. The span is incomplete and may not be replayable.`,\n )\n markPayloadTrimmed(result.value, result.trimmed)\n // `dropped` names values that could not be encoded, which drives the\n // \"non-serializable value(s)\" warning. A budget trim is a size decision, not\n // an encoding failure, and already has its own warning and `payload_budget`\n // error entry, so it must not be reported as one.\n return {\n body: encodePayloadBody(result.value).body,\n dropped: encoded.dropped,\n }\n}\n\ninterface EncodedPayload {\n body: string\n dropped: string[]\n /**\n * The value the body was encoded from: the payload itself, or its sanitized\n * copy. Undefined when the encoded value isn't an object, which leaves\n * nothing with named fields to trim.\n */\n value: Record<string, unknown> | undefined\n}\n\nfunction encodePayloadBody(payload: Record<string, unknown>): EncodedPayload {\n try {\n return { body: JSON.stringify(payload), dropped: [], value: payload }\n } catch {\n const dropped: string[] = []\n // An explicit backtracking walk, not a JSON.stringify replacer: a replacer\n // gets no subtree-exit signal, so a single WeakSet would mis-tag a shared\n // (DAG) reference under sibling keys as a cycle. Tracking only the\n // current-path ancestors stubs real cycles while serializing DAGs in full.\n const sanitize = (value: unknown, seen: WeakSet<object>): unknown => {\n const t = typeof value\n if (\n value === null ||\n t === \"string\" ||\n t === \"number\" ||\n t === \"boolean\"\n ) {\n return value\n }\n if (t === \"bigint\") {\n dropped.push(\"BigInt\")\n return \"<unserializable: BigInt>\"\n }\n if (t === \"function\") {\n const name = (value as { name?: string }).name || \"Function\"\n dropped.push(name)\n return `<unserializable: ${name}>`\n }\n if (t === \"symbol\") {\n dropped.push(\"Symbol\")\n return \"<unserializable: Symbol>\"\n }\n if (t !== \"object\") {\n return undefined // e.g. undefined; JSON omits/normalizes it\n }\n const obj = value as object\n const className =\n (obj as { constructor?: { name?: string } }).constructor?.name ||\n \"object\"\n if (seen.has(obj)) {\n dropped.push(className)\n return `<cycle: ${className}>`\n }\n seen.add(obj)\n let result: unknown\n if (Array.isArray(obj)) {\n result = obj.map((item) => sanitize(item, seen))\n } else if (typeof (obj as { toJSON?: unknown }).toJSON === \"function\") {\n try {\n result = sanitize((obj as { toJSON(): unknown }).toJSON(), seen)\n } catch {\n dropped.push(className)\n result = `<unserializable: ${className}>`\n }\n } else {\n try {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(obj)) {\n out[k] = sanitize(v, seen)\n }\n result = out\n } catch {\n // A throwing getter or Proxy on `obj` can make `Object.entries`\n // throw. Stub just this object instead of failing the whole payload\n // (which would drop every span field). Mirrors the toJSON branch.\n warnOnce(\n \"payload:field-getter-threw\",\n \"a value with a throwing getter/proxy could not be serialized into a span payload; it was replaced with a placeholder. The span still ships with its other fields intact.\",\n )\n dropped.push(className)\n result = `<unserializable: ${className}>`\n }\n }\n seen.delete(obj) // backtrack: only ancestors stay tracked\n return result\n }\n let sanitized: unknown\n try {\n sanitized = sanitize(payload, new WeakSet())\n } catch (error) {\n // Truly pathological. Still never drop silently: send a marker body.\n const message = error instanceof Error ? error.message : String(error)\n const marker = { error: `payload_serialize_failed: ${message}` }\n return { body: JSON.stringify(marker), dropped, value: marker }\n }\n // Keep the server-side signal that the SDK had to stub values, so the\n // trace can be flagged as possibly incomplete / not replayable, while the\n // span content (everything that did serialize) is preserved.\n const isRecord =\n typeof sanitized === \"object\" &&\n sanitized !== null &&\n !Array.isArray(sanitized)\n if (dropped.length > 0 && isRecord) {\n const obj = sanitized as Record<string, unknown>\n const existing = Array.isArray(obj.errors) ? obj.errors : []\n obj.errors = [\n ...existing,\n {\n source: \"sdk\",\n step: \"json_serialize\",\n error: `stubbed non-serializable value(s): ${[\n ...new Set(dropped),\n ].join(\", \")}`,\n },\n ]\n }\n return {\n body: JSON.stringify(sanitized),\n dropped,\n value: isRecord ? (sanitized as Record<string, unknown>) : undefined,\n }\n }\n}\n","/**\n * OpenTelemetry transport for Bitfab spans and trace completions.\n *\n * OTel is used here as a queueing, batching, and delivery engine only. Bitfab\n * keeps ownership of logical trace identity: every payload travels inside an\n * internal *carrier* span whose `bitfab.payload` attribute holds the encoded\n * Bitfab body, and the server reconstructs the stored tree from that payload\n * rather than from the carrier's OTel topology. The provider and processor are\n * private to each client, so an application's own OTel traces are never mixed\n * into Bitfab traces and the global provider is never replaced.\n */\n\nimport { type Span, SpanStatusCode, type Tracer } from \"@opentelemetry/api\"\nimport {\n type ExportResult,\n ExportResultCode,\n type InstrumentationScope,\n} from \"@opentelemetry/core\"\nimport { resourceFromAttributes } from \"@opentelemetry/resources\"\nimport {\n AlwaysOnSampler,\n BasicTracerProvider,\n BatchSpanProcessor,\n type ReadableSpan,\n type SpanExporter,\n} from \"@opentelemetry/sdk-trace-base\"\nimport { __version__ } from \"./constants.js\"\nimport { BitfabError } from \"./errors.js\"\nimport { byteLength } from \"./payloadBudget.js\"\nimport { readEnv } from \"./readEnv.js\"\nimport { serializePayloadBody } from \"./serializePayload.js\"\nimport type {\n DirectBatchSender,\n TraceOperation,\n TraceTransport,\n} from \"./transportTypes.js\"\nimport { unrefTimer } from \"./unrefTimer.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\nconst OPERATION_ATTRIBUTE = \"bitfab.operation\"\nconst PAYLOAD_ATTRIBUTE = \"bitfab.payload\"\nconst OTLP_TRACES_ENDPOINT = \"/api/sdk/otel/v1/traces\"\nconst MAX_EXPORT_REQUEST_BYTES = 3_000_000\nconst MAX_REQUEST_BYTES_ENV = \"BITFAB_OTEL_MAX_REQUEST_BYTES\"\nconst EXPORT_CONCURRENCY_ENV = \"BITFAB_OTEL_EXPORT_CONCURRENCY\"\nconst MAX_QUEUE_SIZE = 8_192\nconst DIRECT_MAX_EXPORT_BATCH_SIZE = 512\nconst DIRECT_MAX_REQUEST_BATCH_SIZE = 8\nconst DEFAULT_EXPORT_CONCURRENCY = 32\nconst MAX_EXPORT_CONCURRENCY = 64\nconst SCHEDULE_DELAY_MILLIS = 5_000\nconst EXPORT_TIMEOUT_MILLIS = 30_000\nconst RETRY_DELAY_MILLIS = 100\nconst MAX_SEND_ATTEMPTS = 3\nconst DEFAULT_LIFECYCLE_TIMEOUT_MS = 30_000\n\nconst RETRYABLE_STATUSES = new Set([408, 425, 429])\n\nconst liveTransports = new Set<OtelBatchTransport>()\nconst traceSubmissionSpanIds = new Map<string, Set<string>>()\nconst replayTraceSubmissions = new Set<string>()\nlet submissionCounter = 0\n\nfunction readBoundedIntEnv(\n name: string,\n max: number,\n fallback: number,\n warnKey: string,\n): number {\n const raw = readEnv(name)\n if (raw === undefined) {\n return fallback\n }\n const value = Number(raw)\n if (Number.isInteger(value) && value > 0 && value <= max) {\n return value\n }\n warnOnce(\n warnKey,\n `${name} must be a positive integer no greater than ${max}; using ${fallback}`,\n )\n return fallback\n}\n\nfunction logError(message: string, error?: unknown): void {\n try {\n if (error === undefined) {\n console.error(`[bitfab] ${message}`)\n } else {\n console.error(`[bitfab] ${message}`, error)\n }\n } catch {\n // Logging must never crash the host app.\n }\n}\n\n/**\n * Record what a payload contributes to its replay trace's expected persisted\n * span count. Counts unique source span IDs rather than delivery attempts, so\n * a duplicate submission cannot make replay wait for a duplicate database row\n * that the server's idempotent span key will never create.\n */\nfunction recordTraceSubmission(\n operation: TraceOperation,\n payload: Record<string, unknown>,\n): void {\n const sourceTraceId = resolveSourceTraceId(payload)\n if (sourceTraceId === undefined) {\n return\n }\n\n if (operation === \"external_span\") {\n const rawSpan = asRecord(payload.rawSpan)\n if (typeof rawSpan?.id !== \"string\") {\n submissionCounter += 1\n }\n const sourceSpanId =\n typeof rawSpan?.id === \"string\"\n ? rawSpan.id\n : `submission-${submissionCounter}`\n const existing = traceSubmissionSpanIds.get(sourceTraceId)\n if (existing) {\n existing.add(sourceSpanId)\n } else {\n traceSubmissionSpanIds.set(sourceTraceId, new Set([sourceSpanId]))\n }\n return\n }\n\n if (payload.completed !== true) {\n return\n }\n if (typeof payload.testRunId === \"string\") {\n replayTraceSubmissions.add(sourceTraceId)\n if (!traceSubmissionSpanIds.has(sourceTraceId)) {\n traceSubmissionSpanIds.set(sourceTraceId, new Set())\n }\n } else {\n traceSubmissionSpanIds.delete(sourceTraceId)\n }\n}\n\n/**\n * Consume the per-trace expected span counts for a finished replay run. Only\n * traces that actually submitted a replay completion are returned, so a caller\n * never waits on a trace the transport never saw.\n */\nexport function takeReplaySpanCounts(\n traceIds: string[],\n): Record<string, number> {\n const counts: Record<string, number> = {}\n for (const traceId of traceIds) {\n if (!replayTraceSubmissions.has(traceId)) {\n continue\n }\n counts[traceId] = traceSubmissionSpanIds.get(traceId)?.size ?? 0\n traceSubmissionSpanIds.delete(traceId)\n replayTraceSubmissions.delete(traceId)\n }\n return counts\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\nfunction resolveSourceTraceId(\n payload: Record<string, unknown>,\n): string | undefined {\n if (typeof payload.sourceTraceId === \"string\") {\n return payload.sourceTraceId\n }\n const rawTrace = asRecord(payload.externalTrace) ?? asRecord(payload.rawTrace)\n return typeof rawTrace?.id === \"string\" ? rawTrace.id : undefined\n}\n\nfunction otlpValue(value: unknown): Record<string, unknown> {\n if (typeof value === \"boolean\") {\n return { boolValue: value }\n }\n if (typeof value === \"number\") {\n return Number.isInteger(value)\n ? { intValue: String(value) }\n : { doubleValue: value }\n }\n if (typeof value === \"string\") {\n return { stringValue: value }\n }\n if (Array.isArray(value)) {\n return { arrayValue: { values: value.map(otlpValue) } }\n }\n return { stringValue: String(value) }\n}\n\nfunction otlpAttributes(\n attributes: Record<string, unknown> | undefined,\n): Record<string, unknown>[] {\n if (!attributes) {\n return []\n }\n return Object.entries(attributes)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => ({ key, value: otlpValue(value) }))\n}\n\n/**\n * Nanoseconds since the epoch as a decimal string. Built by concatenation\n * rather than arithmetic because the value exceeds `Number.MAX_SAFE_INTEGER`,\n * so multiplying seconds out would silently lose the low digits.\n */\nfunction hrTimeToNanoString(time: [number, number] | undefined): string {\n if (!time) {\n return \"0\"\n }\n return `${time[0]}${String(time[1]).padStart(9, \"0\")}`\n}\n\nfunction spanToOtlp(span: ReadableSpan): Record<string, unknown> {\n const spanContext = span.spanContext()\n const result: Record<string, unknown> = {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n name: span.name,\n kind: span.kind + 1,\n startTimeUnixNano: hrTimeToNanoString(span.startTime),\n endTimeUnixNano: hrTimeToNanoString(span.endTime),\n attributes: otlpAttributes(span.attributes as Record<string, unknown>),\n droppedAttributesCount: span.droppedAttributesCount,\n droppedEventsCount: span.droppedEventsCount,\n droppedLinksCount: span.droppedLinksCount,\n status: {\n code: span.status.code,\n ...(span.status.message ? { message: span.status.message } : {}),\n },\n flags: spanContext.traceFlags,\n }\n const parentSpanId = span.parentSpanContext?.spanId\n if (parentSpanId) {\n result.parentSpanId = parentSpanId\n }\n if (spanContext.traceState) {\n result.traceState = spanContext.traceState.serialize()\n }\n return result\n}\n\n/**\n * A span encoded exactly as it will appear on the wire, carrying its own byte\n * count. Encoding once and remembering the size is what keeps request packing\n * linear: sizing a candidate batch by re-encoding the whole request re-escapes\n * every carrier's `bitfab.payload` string on every span considered.\n */\ninterface EncodedSpan {\n json: string\n size: number\n}\n\ninterface RequestBatch {\n spans: EncodedSpan[]\n size: number\n}\n\n/**\n * The invariant head and tail of an OTLP request for one export window. Key\n * order matches what `JSON.stringify` emits for the equivalent object, so a\n * body assembled by concatenation is byte-identical to encoding that object.\n */\ninterface RequestEnvelope {\n head: string\n tail: string\n size: number\n}\n\n/** The comma `join` puts between adjacent spans in the request's span list. */\nconst SPAN_SEPARATOR_BYTES = 1\n\nfunction encodeSpan(span: ReadableSpan): EncodedSpan {\n const json = JSON.stringify(spanToOtlp(span))\n return { json, size: byteLength(json) }\n}\n\nfunction requestEnvelope(first: ReadableSpan): RequestEnvelope {\n const scope = first.instrumentationScope as InstrumentationScope\n const resource = JSON.stringify({\n attributes: otlpAttributes(\n first.resource.attributes as Record<string, unknown>,\n ),\n })\n const scopeJson = JSON.stringify({\n name: scope.name,\n version: scope.version ?? \"\",\n })\n const head = `{\"resourceSpans\":[{\"resource\":${resource},\"scopeSpans\":[{\"scope\":${scopeJson},\"spans\":[`\n const tail = \"]}]}]}\"\n return { head, tail, size: byteLength(head) + byteLength(tail) }\n}\n\nfunction encodeRequest(\n envelope: RequestEnvelope,\n spans: EncodedSpan[],\n): string {\n return (\n envelope.head + spans.map((span) => span.json).join(\",\") + envelope.tail\n )\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms)\n unrefTimer(timer)\n })\n}\n\n/**\n * Race `work` against `timeoutMs`. Resolves `false` when the deadline wins, so\n * a wedged export can never hold a flush or shutdown open past its budget.\n */\nasync function withDeadline(\n work: Promise<boolean>,\n timeoutMs: number,\n): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n work,\n new Promise<boolean>((resolve) => {\n timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs))\n unrefTimer(timer)\n }),\n ])\n } finally {\n if (timer) {\n clearTimeout(timer)\n }\n }\n}\n\n/** Run `task` over `items` with at most `limit` in flight at any moment. */\nasync function mapWithConcurrency<T, R>(\n items: T[],\n limit: number,\n task: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n const workers = Array.from(\n { length: Math.min(Math.max(limit, 1), items.length) },\n async () => {\n while (next < items.length) {\n const index = next\n next += 1\n results[index] = await task(items[index])\n }\n },\n )\n await Promise.all(workers)\n return results\n}\n\nclass OtlpPayloadTooLargeError extends Error {}\nclass OtlpPartialSuccessError extends Error {}\n\nfunction responseStatus(error: unknown): number | undefined {\n return error instanceof BitfabError ? error.status : undefined\n}\n\nfunction isRetryable(error: unknown): boolean {\n const status = responseStatus(error)\n if (status === undefined) {\n return true\n }\n return RETRYABLE_STATUSES.has(status) || status >= 500\n}\n\n/**\n * Direct delivery to Bitfab's OTLP/JSON ingress.\n *\n * OTel hands this exporter one batch as a candidate window. The window is\n * repacked into requests bounded by both a carrier count and the exact encoded\n * request size, and those complete requests are sent concurrently. That keeps\n * OTel's queue, scheduling, force-flush and shutdown while restoring the small\n * independent requests Bitfab's serverless ingress is built to scale.\n */\nexport class BitfabSpanExporter implements SpanExporter {\n constructor(\n private readonly directSender: DirectBatchSender,\n private readonly maxRequestBytes: number,\n private readonly maxRequestBatchSize: number,\n private readonly exportConcurrency: number,\n ) {}\n\n export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n void this.exportAsync(spans).then(\n (succeeded) => {\n resultCallback({\n code: succeeded ? ExportResultCode.SUCCESS : ExportResultCode.FAILED,\n })\n },\n (error) => {\n resultCallback({ code: ExportResultCode.FAILED, error })\n },\n )\n }\n\n private async exportAsync(spans: ReadableSpan[]): Promise<boolean> {\n if (spans.length === 0) {\n return true\n }\n let encoded: EncodedSpan[]\n let envelope: RequestEnvelope\n try {\n encoded = spans.map(encodeSpan)\n envelope = requestEnvelope(spans[0])\n } catch (error) {\n logError(\"failed to encode an OpenTelemetry span batch\", error)\n return false\n }\n\n const batches = this.buildRequestBatches(envelope, encoded)\n const results = await mapWithConcurrency(\n batches,\n this.exportConcurrency,\n (batch) => this.send(envelope, batch),\n )\n return results.every(Boolean)\n }\n\n private buildRequestBatches(\n envelope: RequestEnvelope,\n spans: EncodedSpan[],\n ): RequestBatch[] {\n const batches: RequestBatch[] = []\n let current: EncodedSpan[] = []\n let size = envelope.size\n\n for (const span of spans) {\n const addition =\n span.size + (current.length > 0 ? SPAN_SEPARATOR_BYTES : 0)\n if (\n current.length > 0 &&\n (current.length >= this.maxRequestBatchSize ||\n size + addition > this.maxRequestBytes)\n ) {\n batches.push({ spans: current, size })\n current = []\n size = envelope.size\n }\n current.push(span)\n size += span.size + (current.length > 1 ? SPAN_SEPARATOR_BYTES : 0)\n }\n\n if (current.length > 0) {\n batches.push({ spans: current, size })\n }\n return batches\n }\n\n private async send(\n envelope: RequestEnvelope,\n batch: RequestBatch,\n ): Promise<boolean> {\n if (batch.size > this.maxRequestBytes) {\n logError(\n \"a single OpenTelemetry span exceeded the configured request-size target and could not be exported\",\n )\n return false\n }\n try {\n await this.sendWithRetries(encodeRequest(envelope, batch.spans))\n return true\n } catch (error) {\n if (error instanceof OtlpPayloadTooLargeError) {\n logError(\n batch.spans.length === 1\n ? \"a single OpenTelemetry span exceeded the ingestion request limit and could not be exported\"\n : \"an OpenTelemetry span batch exceeded the ingestion request limit and could not be exported\",\n )\n return false\n }\n if (error instanceof OtlpPartialSuccessError) {\n return false\n }\n logError(\"failed to export an OpenTelemetry span batch\", error)\n return false\n }\n }\n\n /**\n * Retries transient failures. Span and trace-completion carriers are safe to\n * retry: the server keys them idempotently on `sourceSpanId`/`sourceTraceId`,\n * so a duplicate delivery cannot create a duplicate row.\n *\n * KNOWN LIMITATION: an `internal_trace` (a `call()` BAML trace) carries no\n * such key, so retrying a batch that holds one can create a duplicate trace -\n * including when a request times out client-side but the server goes on to\n * persist it. Accepted deliberately for now, matching the other SDKs, rather\n * than skipping retries for a whole batch or inventing an idempotency scheme\n * the server does not yet understand. The fix is a client-supplied\n * idempotency key that ingestion dedupes on.\n */\n private async sendWithRetries(body: string): Promise<void> {\n for (let attempt = 0; attempt < MAX_SEND_ATTEMPTS; attempt += 1) {\n try {\n const response = await this.directSender(\n OTLP_TRACES_ENDPOINT,\n body,\n EXPORT_TIMEOUT_MILLIS,\n )\n const partialSuccess = asRecord(response?.partialSuccess)\n const rejected = partialSuccess?.rejectedSpans\n if (rejected !== undefined && rejected !== \"0\" && rejected !== 0) {\n logError(\n `OTLP ingestion rejected ${rejected} span(s): ${\n partialSuccess?.errorMessage ?? \"no reason provided\"\n }`,\n )\n throw new OtlpPartialSuccessError()\n }\n return\n } catch (error) {\n if (error instanceof OtlpPartialSuccessError) {\n throw error\n }\n if (responseStatus(error) === 413) {\n throw new OtlpPayloadTooLargeError()\n }\n if (attempt === MAX_SEND_ATTEMPTS - 1 || !isRetryable(error)) {\n throw error\n }\n await delay(RETRY_DELAY_MILLIS)\n }\n }\n }\n\n async shutdown(): Promise<void> {}\n\n async forceFlush(): Promise<void> {}\n}\n\n/**\n * Counts export failures so `flush` can answer \"was this delivered?\" instead of\n * only \"did the processor queue drain?\". Without it a flush would report\n * success for a batch the exporter dropped, and replay would finalize a run\n * whose traces never landed.\n */\nclass DeliveryTrackingExporter implements SpanExporter {\n // Deliberately unscoped, matching the Python SDK. An export can outlive\n // OTel's export timeout and report failure after the flush that was waiting\n // on it already returned, so that failure surfaces on the NEXT flush instead.\n // That over-reports: a good flush can inherit an older failure. The\n // alternative - discarding failures from completed flush windows - under-\n // reports, and `BatchSpanProcessor` also runs scheduled exports that belong\n // to no flush at all, so their failures would vanish entirely. For a\n // telemetry SDK a false \"flush failed\" is investigable; a false \"flush\n // succeeded\" silently loses traces. We take the noisy direction on purpose.\n private failedExports = 0\n\n constructor(private readonly exporter: SpanExporter) {}\n\n export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n try {\n this.exporter.export(spans, (result) => {\n if (result.code !== ExportResultCode.SUCCESS) {\n this.failedExports += 1\n }\n resultCallback(result)\n })\n } catch (error) {\n this.failedExports += 1\n resultCallback({ code: ExportResultCode.FAILED, error: error as Error })\n }\n }\n\n takeFailedExports(): number {\n const failed = this.failedExports\n this.failedExports = 0\n return failed\n }\n\n shutdown(): Promise<void> {\n return this.exporter.shutdown()\n }\n\n forceFlush(): Promise<void> {\n return this.exporter.forceFlush?.() ?? Promise.resolve()\n }\n}\n\nexport interface OtelBatchTransportOptions {\n directSender: DirectBatchSender\n maxExportBatchSize?: number\n maxRequestBatchSize?: number\n maxQueueSize?: number\n exportConcurrency?: number\n maxRequestBytes?: number\n /** Overridable so tests can drive OTel's export-timeout path in ms, not 30s. */\n exportTimeoutMillis?: number\n}\n\nexport class OtelBatchTransport implements TraceTransport {\n private readonly provider: BasicTracerProvider\n private readonly processor: BatchSpanProcessor\n private readonly deliveryTracker: DeliveryTrackingExporter\n private readonly tracer: Tracer\n private closed = false\n private pendingFlush: Promise<boolean> | undefined\n\n constructor(options: OtelBatchTransportOptions) {\n const maxRequestBytes = options.maxRequestBytes ?? MAX_EXPORT_REQUEST_BYTES\n const maxRequestBatchSize =\n options.maxRequestBatchSize ?? DIRECT_MAX_REQUEST_BATCH_SIZE\n if (maxRequestBatchSize <= 0) {\n throw new BitfabError(\"maxRequestBatchSize must be a positive integer\")\n }\n\n this.deliveryTracker = new DeliveryTrackingExporter(\n new BitfabSpanExporter(\n options.directSender,\n maxRequestBytes,\n maxRequestBatchSize,\n options.exportConcurrency ?? DEFAULT_EXPORT_CONCURRENCY,\n ),\n )\n\n this.processor = new BatchSpanProcessor(this.deliveryTracker, {\n maxQueueSize: options.maxQueueSize ?? MAX_QUEUE_SIZE,\n maxExportBatchSize:\n options.maxExportBatchSize ?? DIRECT_MAX_EXPORT_BATCH_SIZE,\n scheduledDelayMillis: SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: options.exportTimeoutMillis ?? EXPORT_TIMEOUT_MILLIS,\n })\n\n // Every option is passed explicitly: `BasicTracerProvider` otherwise reads\n // OTEL_* defaults, so a host application's sampler or attribute-length\n // limit would silently drop or truncate Bitfab payloads.\n this.provider = new BasicTracerProvider({\n sampler: new AlwaysOnSampler(),\n resource: resourceFromAttributes({\n \"service.name\": \"bitfab-typescript-sdk\",\n \"service.version\": __version__,\n }),\n spanLimits: {\n attributeCountLimit: 2,\n attributeValueLengthLimit: Number.POSITIVE_INFINITY,\n },\n spanProcessors: [this.processor],\n })\n this.tracer = this.provider.getTracer(\"bitfab\", __version__)\n liveTransports.add(this)\n }\n\n submit(operation: TraceOperation, payload: Record<string, unknown>): void {\n recordTraceSubmission(operation, payload)\n if (this.closed) {\n warnOnce(\n \"otel-submit-after-shutdown\",\n \"OpenTelemetry transport is shut down; dropping spans\",\n )\n return\n }\n try {\n // Not a bare JSON.stringify: contexts, metadata and `call()` inputs\n // never pass through `serializeValue`, so one stray value here would\n // throw and drop the whole span rather than being stubbed. This is the\n // same backstop the pre-transport HTTP path applied.\n const { body, dropped } = serializePayloadBody(payload)\n if (dropped.length > 0) {\n warnOnce(\n \"otel-carrier-payload-stubbed\",\n `a span payload held non-serializable value(s) (${[\n ...new Set(dropped),\n ].join(\", \")}); they were stubbed so the span still ships, but the ` +\n \"trace may be incomplete or not replayable.\",\n )\n }\n const span = this.tracer.startSpan(spanName(operation, payload), {\n attributes: {\n [OPERATION_ATTRIBUTE]: operation,\n [PAYLOAD_ATTRIBUTE]: body,\n },\n startTime: payloadTimestamp(payload, \"started_at\"),\n })\n if (hasError(payload)) {\n span.setStatus({ code: SpanStatusCode.ERROR })\n }\n endSpan(span, payloadTimestamp(payload, \"ended_at\"))\n } catch (error) {\n logError(\"failed to queue an OpenTelemetry span\", error)\n }\n }\n\n async flush(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n // Serialized: two concurrent force-flushes would race for the same\n // delivery counter and one would report the other's failures as success.\n const pending = (this.pendingFlush ?? Promise.resolve(true)).then(() =>\n this.forceFlushOnce(),\n )\n this.pendingFlush = pending.catch(() => false)\n return withDeadline(pending, timeoutMs)\n }\n\n private async forceFlushOnce(): Promise<boolean> {\n try {\n await this.processor.forceFlush()\n } catch (error) {\n logError(\"failed to flush OpenTelemetry spans\", error)\n this.deliveryTracker.takeFailedExports()\n return false\n }\n return this.deliveryTracker.takeFailedExports() === 0\n }\n\n async shutdown(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n this.closed = true\n const flushed = await this.flush(Math.max(0, deadline - Date.now()))\n liveTransports.delete(this)\n const shutdownCompleted = await withDeadline(\n this.provider\n .shutdown()\n .then(() => true)\n .catch((error) => {\n logError(\"failed to shut down the OpenTelemetry transport\", error)\n return false\n }),\n Math.max(0, deadline - Date.now()),\n )\n return flushed && shutdownCompleted\n }\n}\n\nfunction endSpan(span: Span, endTime: number | undefined): void {\n span.end(endTime)\n}\n\nfunction spanName(\n operation: TraceOperation,\n payload: Record<string, unknown>,\n): string {\n if (operation === \"external_span\") {\n const spanData = asRecord(asRecord(payload.rawSpan)?.span_data)\n if (typeof spanData?.name === \"string\") {\n return spanData.name\n }\n }\n if (typeof payload.traceFunctionKey === \"string\") {\n return payload.traceFunctionKey\n }\n return `bitfab.${operation}`\n}\n\n/**\n * Milliseconds since the epoch for a payload timestamp, or `undefined` to let\n * OTel stamp the carrier with the current time.\n */\nfunction payloadTimestamp(\n payload: Record<string, unknown>,\n field: string,\n): number | undefined {\n const rawSpan = asRecord(payload.rawSpan)\n const rawTrace = asRecord(payload.externalTrace) ?? asRecord(payload.rawTrace)\n const raw = rawSpan?.[field] ?? rawTrace?.[field]\n if (typeof raw !== \"string\") {\n return undefined\n }\n const parsed = Date.parse(raw)\n return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction hasError(payload: Record<string, unknown>): boolean {\n const spanData = asRecord(asRecord(payload.rawSpan)?.span_data)\n if (spanData?.error != null) {\n return true\n }\n const errors = payload.errors\n return Array.isArray(errors) ? errors.length > 0 : Boolean(errors)\n}\n\nexport function createOtelTransport(options: {\n directSender: DirectBatchSender\n}): OtelBatchTransport {\n return new OtelBatchTransport({\n ...options,\n exportConcurrency: readBoundedIntEnv(\n EXPORT_CONCURRENCY_ENV,\n MAX_EXPORT_CONCURRENCY,\n DEFAULT_EXPORT_CONCURRENCY,\n \"otel-export-concurrency-invalid\",\n ),\n maxRequestBytes: readBoundedIntEnv(\n MAX_REQUEST_BYTES_ENV,\n MAX_EXPORT_REQUEST_BYTES,\n MAX_EXPORT_REQUEST_BYTES,\n \"otel-max-request-bytes-invalid\",\n ),\n })\n}\n\nasync function forEachLiveTransport(\n timeoutMs: number,\n run: (transport: OtelBatchTransport, remainingMs: number) => Promise<boolean>,\n): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n let succeeded = true\n for (const transport of [...liveTransports]) {\n succeeded =\n (await run(transport, Math.max(0, deadline - Date.now()))) && succeeded\n }\n return succeeded\n}\n\nexport function flushOtelTransports(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n): Promise<boolean> {\n return forEachLiveTransport(timeoutMs, (transport, remaining) =>\n transport.flush(remaining),\n )\n}\n\nexport function shutdownOtelTransports(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n): Promise<boolean> {\n return forEachLiveTransport(timeoutMs, (transport, remaining) =>\n transport.shutdown(remaining),\n )\n}\n\n/** Test-only: forget cross-run replay submission bookkeeping. */\nexport function _resetTraceSubmissions(): void {\n traceSubmissionSpanIds.clear()\n replayTraceSubmissions.clear()\n}\n","/**\n * Best-effort `unref()` on a timer handle so a pending timeout never keeps the\n * Node.js event loop alive on its own. An un-unref'd timeout would delay\n * process exit, prolong a serverless function's billed lifetime, and hang test\n * runners until it fires.\n *\n * In the browser `setTimeout` returns a number with no `unref`, so this is a\n * no-op there. Callers should still `clearTimeout` the handle once the work it\n * guards has settled.\n */\nexport function unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n const handle = timer as { unref?: () => void }\n if (typeof handle.unref === \"function\") {\n handle.unref()\n }\n}\n","/**\n * The single seam between the HTTP client and whichever transport implements\n * span delivery. Keeping the factory here (rather than importing `otel.ts`\n * from `http.ts` directly) is what lets the OpenTelemetry implementation\n * depend on `HttpClient`'s request path without an import cycle.\n */\n\nimport {\n createOtelTransport,\n flushOtelTransports,\n shutdownOtelTransports,\n takeReplaySpanCounts as takeOtelReplaySpanCounts,\n} from \"./otel.js\"\nimport type { DirectBatchSender, TraceTransport } from \"./transportTypes.js\"\n\nexport function createTraceTransport(options: {\n directSender: DirectBatchSender\n}): TraceTransport {\n return createOtelTransport(options)\n}\n\nexport function flushTraceTransports(timeoutMs?: number): Promise<boolean> {\n return flushOtelTransports(timeoutMs)\n}\n\nexport function shutdownTraceTransports(timeoutMs?: number): Promise<boolean> {\n return shutdownOtelTransports(timeoutMs)\n}\n\nexport function takeReplaySpanCounts(\n traceIds: string[],\n): Record<string, number> {\n return takeOtelReplaySpanCounts(traceIds)\n}\n","/**\n * HTTP client utilities for Bitfab API requests.\n *\n * This module provides:\n * - HttpClient class for making API requests\n * - awaitOnExit helper so deferred span work still gates process exit\n */\n\nimport { encodeRequestBody } from \"./compress.js\"\nimport { __version__ } from \"./constants.js\"\nimport type { DbSnapshotRef } from \"./dbSnapshot.js\"\nimport { BitfabError } from \"./errors.js\"\nimport {\n type DbBranchLease,\n type DbBranchSettings,\n replayContextReady,\n} from \"./replayContext.js\"\nimport { serializePayloadBody } from \"./serializePayload.js\"\nimport {\n createTraceTransport,\n flushTraceTransports,\n shutdownTraceTransports,\n} from \"./transport.js\"\nimport type { TraceTransport } from \"./transportTypes.js\"\nimport { unrefTimer } from \"./unrefTimer.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\n// BitfabError lives in `errors.ts` to break the http ↔ dbSnapshot import\n// cycle. Re-exported here for backwards compatibility with existing\n// callers that import it from \"./http.js\".\nexport { BitfabError }\nexport { serializePayloadBody }\n\nconst REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS = 300_000\nconst EXIT_FLUSH_TIMEOUT_MS = 5_000\nconst DEFAULT_LIFECYCLE_TIMEOUT_MS = 30_000\n\n// Global set to track pending trace creation promises\n// This prevents promises from being garbage collected before they complete\nconst pendingTracePromises = new Set<Promise<unknown>>()\n\n/**\n * Track a promise so `flushTraces()` and the exit hook wait for it.\n *\n * Exactly one caller remains: the deferred `finalize` chain, which hands its\n * span to the transport only after finalize settles. Everything else submits\n * synchronously, so the transport's own queue is the complete picture. Python\n * has no equivalent because its finalize runs inline.\n *\n * @param promise - The promise to track\n * @returns The same promise (for chaining)\n */\nexport function awaitOnExit<T>(promise: Promise<T>): Promise<T> {\n pendingTracePromises.add(promise)\n // Use void to prevent unhandled rejection warnings from the .finally() chain\n // The actual error handling is done by the caller's .catch() on the returned promise\n void promise\n .finally(() => {\n pendingTracePromises.delete(promise)\n })\n .catch(() => {\n // Swallow rejection in this chain - the caller handles errors via their own .catch()\n })\n return promise\n}\n\n/**\n * Wait for pending fire-and-forget requests AND every live span transport to\n * deliver, within one total deadline. Useful in tests and scripts to ensure all\n * data has been sent before asserting or exiting.\n *\n * Returns `false` when delivery failed or the deadline expired, so a caller\n * that depends on persistence (replay does) can react instead of assuming a\n * drained queue means the server has the data.\n *\n * @param timeoutMs - Maximum total time to wait in milliseconds (default: 5000)\n */\nexport async function flushTraces(timeoutMs: number = 5000): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n const requestsFlushed = await awaitPendingRequests(timeoutMs)\n const transportsFlushed = await flushTraceTransports(\n Math.max(0, deadline - Date.now()),\n )\n return requestsFlushed && transportsFlushed\n}\n\n/**\n * Wait for in-flight fire-and-forget requests and deferred span work, WITHOUT\n * flushing the transports.\n *\n * Replay needs this half on its own: a `finalize` span reaches the transport\n * only after its deferred chain settles, so the expected-span tally has to be\n * read after that work lands but before a flush is issued (which would be\n * wasted, and would emit a request, when the run submitted nothing).\n */\nexport async function awaitPendingRequests(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n): Promise<boolean> {\n // Async-context storage loads asynchronously, and spans traced before it\n // resolves have their recording deferred behind it. Without this, a script\n // that traces and immediately flushes or closes races its own first spans.\n await replayContextReady.catch(() => {})\n return waitForPromises(Array.from(pendingTracePromises), timeoutMs)\n}\n\n/**\n * Await `promises` within `timeoutMs`, reporting whether they all settled in\n * time rather than throwing. Rejections count as settled: a failed span upload\n * is already reported by its own catch handler, and the caller is asking about\n * completion, not success.\n */\nasync function waitForPromises(\n promises: Promise<unknown>[],\n timeoutMs: number,\n): Promise<boolean> {\n if (promises.length === 0) {\n return true\n }\n // Clear and unref the timeout so the loser of the race never leaves a\n // dangling timer holding the event loop open after flush resolves.\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n Promise.allSettled(promises).then(() => true),\n new Promise<boolean>((resolve) => {\n timer = setTimeout(() => resolve(false), timeoutMs)\n unrefTimer(timer)\n }),\n ])\n } finally {\n if (timer) {\n clearTimeout(timer)\n }\n }\n}\n\n// Register beforeExit handler to wait for pending traces (Node.js only)\n// This ensures traces are sent before the process exits (for scripts).\n// The transport is included: its batch worker sits on an unref'd timer, so a\n// script that ends without an explicit flush would otherwise exit with a queue\n// of spans still waiting on the scheduled delay.\nif (\n typeof process !== \"undefined\" &&\n process.versions != null &&\n process.versions.node != null\n) {\n let isFlushing = false\n process.on(\"beforeExit\", () => {\n if (isFlushing) {\n return\n }\n isFlushing = true\n // Awaiting here keeps the event loop alive until delivery settles.\n void Promise.allSettled([\n ...Array.from(pendingTracePromises).map((p) => p.catch(() => {})),\n shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false),\n ]).then(() => {\n isFlushing = false\n })\n })\n}\n\n/**\n * How the API key is supplied internally: either a literal string or a\n * function resolved each time the key is needed (at request/send time). The\n * function form is what defers key resolution past module-load construction\n * so an env var loaded after the client is built (the ESM dotenv-hoisting\n * case) is still picked up.\n */\nexport type ApiKeyInput = string | (() => string | undefined)\n\nexport interface HttpClientConfig {\n apiKey?: ApiKeyInput\n serviceUrl: string\n timeout?: number\n}\n\nexport type SpanOccurrence = \"first\" | \"last\" | number\n\nexport type SpanLookup =\n | { id: string; name?: never; occurrence?: never }\n | { name: string; id?: never; occurrence?: SpanOccurrence }\n\nexport interface CapturedSpan {\n id: string\n traceId: string\n parentSpanId: string | null\n name: string | null\n type: string\n input: unknown\n output: unknown\n contexts: Record<string, unknown>[]\n prompt: string | null\n metadata: Record<string, unknown>\n metrics: Record<string, unknown> | null\n errors: unknown\n startedAt: string | null\n endedAt: string | null\n}\n\n/**\n * HTTP client for Bitfab API requests.\n *\n * Provides methods for different API endpoints with proper error handling,\n * timeouts, and authentication.\n */\nexport class HttpClient {\n private readonly apiKey: ApiKeyInput | undefined\n private readonly serviceUrl: string\n private readonly timeout: number\n private traceTransport: TraceTransport | undefined\n // Deferred span work owned by THIS client. The module-global set backs the\n // process-wide `flushTraces()` and the exit hook, but per-client lifecycle\n // must not wait on another client's slow finalize: a false `close()` failure\n // caused by unrelated work is worse than no signal at all.\n private readonly deferredWork = new Set<Promise<unknown>>()\n private closed = false\n private closing: Promise<boolean> | undefined\n\n constructor(config: HttpClientConfig) {\n this.apiKey = config.apiKey\n this.serviceUrl = config.serviceUrl\n this.timeout = config.timeout ?? 120000\n }\n\n /**\n * Resolve the API key at the moment it is needed (request time), invoking\n * the function form if one was supplied. Never read at construction.\n */\n private resolveApiKey(): string | undefined {\n return typeof this.apiKey === \"function\" ? this.apiKey() : this.apiKey\n }\n\n /**\n * This client's span transport, built on first use.\n *\n * Lazy on purpose: a client that never sends a span must never start a batch\n * worker. Every framework integration created from a `Bitfab` client shares\n * the owning client's `HttpClient`, so handlers reuse this one worker instead\n * of each spinning up their own.\n */\n private getTraceTransport(): TraceTransport | undefined {\n if (this.closed) {\n warnOnce(\n \"http-client-closed\",\n \"the Bitfab client is closed; dropping spans\",\n )\n return undefined\n }\n if (!this.traceTransport) {\n this.traceTransport = createTraceTransport({\n directSender: (endpoint, body, timeoutMs) =>\n this.sendEncoded<Record<string, unknown>>(endpoint, body, {\n timeout: timeoutMs,\n }),\n })\n }\n return this.traceTransport\n }\n\n /**\n * Track deferred span work so this client's own lifecycle waits for it, and\n * so the process-wide flush and exit hook do too.\n */\n trackDeferred<T>(promise: Promise<T>): Promise<T> {\n this.deferredWork.add(promise)\n void promise\n .finally(() => this.deferredWork.delete(promise))\n .catch(() => {})\n return awaitOnExit(promise)\n }\n\n /**\n * Settle only THIS client's deferred span work. Scoped deliberately: the\n * global set can contain another client's long-running finalize, and\n * attributing its timeout here would fail a client whose own work succeeded.\n */\n async settleDeferredWork(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n await replayContextReady.catch(() => {})\n return waitForPromises(Array.from(this.deferredWork), timeoutMs)\n }\n\n /**\n * Wait for spans queued by this client to be delivered, within one deadline.\n * Returns false on delivery failure or timeout.\n */\n async waitForPendingRequests(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n const settled = await this.settleDeferredWork(timeoutMs)\n const flushed =\n (await this.traceTransport?.flush(Math.max(0, deadline - Date.now()))) ??\n true\n return settled && flushed\n }\n\n /**\n * Flush and permanently close this client's tracing transport. Idempotent:\n * a second call joins the first rather than tearing down a pipeline the\n * first call already owns.\n */\n close(timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS): Promise<boolean> {\n if (this.closing) {\n return this.closing\n }\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n this.closing = (async () => {\n // Settle deferred span work BEFORE refusing submissions. A span whose\n // recording is still queued (the `finalize` chain, or any call made\n // before async-context storage finished loading) has not reached the\n // transport yet; flipping `closed` first would reject it on arrival and\n // silently drop a span the caller had every reason to think was captured.\n const settled = await this.settleDeferredWork(\n Math.max(0, deadline - Date.now()),\n )\n this.closed = true\n const transport = this.traceTransport\n this.traceTransport = undefined\n const shutdownOk =\n (await transport?.shutdown(Math.max(0, deadline - Date.now()))) ?? true\n // Deferred work that outran the deadline will submit into a closed\n // client and be dropped, so close cannot report success for it.\n return settled && shutdownOk\n })()\n return this.closing\n }\n\n /**\n * Make an HTTP request to the Bitfab API. Defaults to POST; pass\n * `options.method` to use a different verb (e.g. \"PATCH\").\n *\n * @param endpoint - The API endpoint (without base URL)\n * @param payload - The request body\n * @param options - Optional request options\n * @returns The parsed JSON response\n * @throws {BitfabError} If the request fails\n */\n async request<T>(\n endpoint: string,\n payload: Record<string, unknown>,\n options?: { timeout?: number; method?: \"POST\" | \"PATCH\" | \"PUT\" },\n ): Promise<T> {\n // Serialize the payload so a stray non-serializable value (BigInt,\n // function, circular ref, a class instance that slipped past upstream\n // serialization) can never abort the send and silently drop the span.\n // Strays are stubbed in place, preserving span content, and a degraded\n // payload warns loudly.\n const { body, dropped } = serializePayloadBody(payload)\n if (dropped.length > 0) {\n try {\n console.warn(\n `Bitfab: request body to ${endpoint} held ${dropped.length} ` +\n `non-serializable value(s) (${[...new Set(dropped)].join(\", \")}); ` +\n \"they were stubbed so the span still sends, but the trace may be \" +\n \"incomplete or not replayable. Capture a JSON-safe projection of \" +\n \"this input to make it replayable.\",\n )\n } catch {}\n }\n return this.sendEncoded<T>(endpoint, body, options)\n }\n\n /**\n * POST an already-encoded body. The span transport encodes its own batches,\n * so routing them back through {@link HttpClient.request} would encode the\n * same data twice.\n */\n async sendEncoded<T>(\n endpoint: string,\n body: string,\n options?: { timeout?: number; method?: \"POST\" | \"PATCH\" | \"PUT\" },\n ): Promise<T> {\n const url = `${this.serviceUrl}${endpoint}`\n const timeout = options?.timeout ?? this.timeout\n const method = options?.method ?? \"POST\"\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n // Awaited only when compression actually runs, so an uncompressed request\n // still calls `fetch` synchronously the way it did before compression.\n const prepared = encodeRequestBody(body)\n const encoded = prepared instanceof Promise ? await prepared : prepared\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}`,\n }\n if (encoded.contentEncoding) {\n headers[\"Content-Encoding\"] = encoded.contentEncoding\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: encoded.body,\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n undefined,\n response.status,\n )\n }\n\n const result = await response.json()\n\n // Check for errors in the response\n if (result.error) {\n if (result.url) {\n throw new BitfabError(\n `${result.error} Configure it at: ${this.serviceUrl}${result.url}`,\n result.url,\n )\n }\n throw new BitfabError(result.error)\n }\n\n return result as T\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(`Request timed out after ${timeout}ms`)\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Look up a function by name.\n * Blocks until complete - needed for function execution.\n */\n async lookupFunction<T>(name: string): Promise<T> {\n return this.request<T>(\"/api/sdk/functions/lookup\", { name })\n }\n\n async getTraceSpan(\n traceId: string,\n lookup: SpanLookup,\n ): Promise<CapturedSpan | null> {\n const searchParams = new URLSearchParams()\n if (lookup.id !== undefined) {\n searchParams.set(\"id\", lookup.id)\n } else {\n searchParams.set(\"name\", lookup.name)\n searchParams.set(\"occurrence\", String(lookup.occurrence ?? \"last\"))\n }\n\n const endpoint = `/api/sdk/traces/${encodeURIComponent(traceId)}/span?${searchParams.toString()}`\n const response = await this.get<{ span: CapturedSpan | null }>(endpoint)\n return response.span\n }\n\n private async get<T>(endpoint: string): Promise<T> {\n const url = `${this.serviceUrl}${endpoint}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}` },\n signal: controller.signal,\n })\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n )\n }\n return (await response.json()) as T\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(`Request timed out after ${this.timeout}ms`)\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Queue an internal trace (from local BAML execution via `call()`) onto this\n * client's batching transport. `functionId` moves into the payload because\n * the OTLP carrier has no path to carry it.\n */\n sendInternalTrace(\n functionId: string,\n payload: Record<string, unknown>,\n ): void {\n this.getTraceTransport()?.submit(\"internal_trace\", {\n ...payload,\n functionId,\n sdkVersion: __version__,\n })\n }\n\n /**\n * Queue an external span (from withSpan wrapper or OpenAI tracing) onto this\n * client's batching transport. Fire-and-forget: the transport owns delivery,\n * so callers await `flushTraces()` or `close()` rather than a per-span\n * promise.\n */\n sendExternalSpan(payload: Record<string, unknown>): void {\n this.getTraceTransport()?.submit(\"external_span\", {\n ...payload,\n sdkVersion: __version__,\n })\n }\n\n /**\n * Queue an external trace completion (from OpenAI tracing) onto this\n * client's batching transport. Fire-and-forget for the same reason as\n * {@link HttpClient.sendExternalSpan}; replay confirms persistence with the\n * server-authoritative barrier in `replay.ts`, not by awaiting this call.\n */\n sendExternalTrace(payload: Record<string, unknown>): void {\n this.getTraceTransport()?.submit(\"external_trace\", {\n ...payload,\n sdkVersion: __version__,\n })\n }\n\n /**\n * Partial update of an existing trace identified by its Bitfab trace ID.\n * Used by the detached `client.getTrace(id)` handle.\n *\n * Blocking, like the other trace-API calls: it resolves once the server has\n * applied the change and rejects if the server refused it. A patch targets a\n * trace that is already closed, so there is no batch for it to ride along\n * with and no later signal that would reveal a silent failure.\n */\n async patchTrace(\n traceId: string,\n payload: {\n appendContexts?: Record<string, unknown>[]\n mergeMetadata?: Record<string, unknown>\n setSessionId?: string\n },\n ): Promise<void> {\n const endpoint = `/api/sdk/traces/${encodeURIComponent(traceId)}`\n await this.request(endpoint, payload, { method: \"PATCH\" })\n }\n\n /**\n * Start a replay session by fetching historical traces.\n * Blocking call - creates a test run and returns lightweight item references.\n */\n async startReplay(\n traceFunctionKey: string,\n limit: number | undefined,\n traceIds?: string[],\n name?: string,\n codeChangeDescription?: string | null,\n codeChangeFiles?: CodeChangeFile[] | null,\n includeDbBranchLease?: boolean,\n experimentGroupId?: string,\n datasetId?: string,\n graderIds?: string[],\n dbBranchSettings?: DbBranchSettings,\n ): Promise<StartReplayResponse> {\n // limit is only meaningful without traceIds (an explicit ID list\n // already determines the count), so it's omitted when undefined.\n const payload: Record<string, unknown> = { traceFunctionKey }\n if (limit !== undefined) {\n payload.limit = limit\n }\n if (traceIds) {\n payload.traceIds = traceIds\n }\n if (name !== undefined) {\n payload.name = name\n }\n if (codeChangeDescription !== undefined) {\n payload.codeChangeDescription = codeChangeDescription\n }\n if (codeChangeFiles !== undefined) {\n payload.codeChangeFiles = codeChangeFiles\n }\n if (includeDbBranchLease) {\n payload.includeDbBranchLease = true\n payload.lazyDbBranchLease = true\n }\n if (experimentGroupId !== undefined) {\n payload.experimentGroupId = experimentGroupId\n }\n if (datasetId !== undefined) {\n payload.datasetId = datasetId\n }\n if (graderIds !== undefined) {\n payload.graderIds = graderIds\n }\n if (dbBranchSettings !== undefined) {\n payload.dbBranchSettings = dbBranchSettings\n }\n // When DB branching is on, the server resolves a Neon preview branch\n // per item (snapshot + restore + poll), which can run ~5-10s each, and\n // runs any `warmupSql` against each branch on a 240s budget of its own.\n // The server gives up at 280s and answers, so this is a backstop for a\n // reply that never comes rather than the thing that normally fires; it\n // sits above the server's own ceiling so the server's error is the one\n // callers see. Not raisable in practice either: undici's default\n // `headersTimeout` is also 300s and `fetch` cannot override it per\n // request.\n const timeout = includeDbBranchLease\n ? REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS\n : 30_000\n return this.request<StartReplayResponse>(\"/api/sdk/replay/start\", payload, {\n timeout,\n })\n }\n\n /**\n * Fetch an external span by ID.\n * Blocking GET request.\n * The replay view limits rawData to input/output serialization fields.\n */\n async getExternalSpan(\n spanId: string,\n options?: { view?: \"full\" | \"replay\" },\n ): Promise<ExternalSpanResponse> {\n const query = options?.view === \"replay\" ? \"?view=replay\" : \"\"\n const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}${query}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), 30_000)\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}` },\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n )\n }\n\n return (await response.json()) as ExternalSpanResponse\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(\"Request timed out after 30000ms\")\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Fetch the span tree for a root span.\n * Blocking GET request.\n *\n * Pass `includeOutputs: false` for a payload-free tree (structure +\n * `externalSpanId` only), so recorded outputs are fetched lazily per mocked\n * span instead of all up front. Omit it (default eager) for `mock: \"all\"`.\n * Pass `includeRootOutput: false` when the root was already fetched.\n */\n async getSpanTree(\n externalSpanId: string,\n options?: { includeOutputs?: boolean; includeRootOutput?: boolean },\n ): Promise<SpanTreeResponse> {\n const searchParams = new URLSearchParams()\n if (options?.includeOutputs === false) {\n searchParams.set(\"includeOutputs\", \"false\")\n }\n if (options?.includeRootOutput === false) {\n searchParams.set(\"includeRootOutput\", \"false\")\n }\n const encodedQuery = searchParams.toString()\n const query = encodedQuery ? `?${encodedQuery}` : \"\"\n const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), 30_000)\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}` },\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n )\n }\n\n return (await response.json()) as SpanTreeResponse\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(\"Request timed out after 30000ms\")\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Read which of a replay run's traces the server has fully persisted.\n *\n * With `expectedSpanCounts`, a trace appears in the response only once it\n * has a final status AND at least that many persisted spans, which is what\n * makes this a real barrier rather than a \"the row exists\" check.\n */\n async getReplayStatus(\n testRunId: string,\n expectedSpanCounts: Record<string, number>,\n ): Promise<ReplayStatusResponse> {\n return this.request<ReplayStatusResponse>(\n \"/api/sdk/replay/status\",\n { testRunId, expectedSpanCounts },\n { timeout: 30_000 },\n )\n }\n\n /**\n * Mark a replay test run as completed.\n * Blocking call.\n */\n async completeReplay(testRunId: string): Promise<CompleteReplayResponse> {\n return this.request<CompleteReplayResponse>(\n \"/api/sdk/replay/complete\",\n { testRunId },\n { timeout: 30_000 },\n )\n }\n\n /**\n * Ask the server to materialize a per-trace DB branch lease from a\n * captured `dbSnapshotRef`. Blocking - the resolver creates a Neon\n * snapshot + preview branch and polls operations to readiness, which\n * can take seconds.\n */\n async resolveDbBranchLease(\n testRunId: string,\n traceId: string,\n dbBranchSettings?: DbBranchSettings,\n ): Promise<{\n dbSnapshotRef: DbSnapshotRef | null\n lease: DbBranchLease | null\n leaseError: { code: string; message: string } | null\n }> {\n return this.request<{\n dbSnapshotRef: DbSnapshotRef | null\n lease: DbBranchLease | null\n leaseError: { code: string; message: string } | null\n }>(\n \"/api/sdk/replay/resolveDbBranchLease\",\n { testRunId, traceId, dbBranchSettings },\n { timeout: REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS },\n )\n }\n\n /** Release a previously-resolved DB branch by deleting its Neon branch. Idempotent server-side. */\n async releaseDbBranchLease(neonBranchId: string): Promise<void> {\n await this.request<{ released: true }>(\n \"/api/sdk/replay/releaseDbBranchLease\",\n { neonBranchId },\n { timeout: 30_000 },\n )\n }\n}\n\nexport interface TokenUsage {\n input: number | null\n output: number | null\n cached: number | null\n total: number | null\n}\n\n/**\n * Describes a single file edited as part of a code change.\n *\n * - `path`: file path (relative to the repo root, or any consistent root)\n * - `before`: file contents before the change (\"\" for newly created files)\n * - `after`: file contents after the change (\"\" for deleted files)\n */\nexport interface CodeChangeFile {\n path: string\n before: string\n after: string\n}\n\nexport interface StartReplayResponse {\n testRunId: string\n testRunUrl: string\n items: Array<{\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId?: string\n /** External span ID the recorded inputs were read from (the original root span). */\n originalSpanId?: string\n /** @deprecated alias for `originalTraceId`; the only key emitted by servers that predate the rename. */\n sourceTraceId: string\n /** @deprecated alias for `originalSpanId`; the only key emitted by servers that predate the rename. */\n sourceSpanId: string\n durationMs: number | null\n tokens: TokenUsage | null\n model: string | null\n /**\n * The DB snapshot ref captured by the SDK at trace open. Surfaced so\n * the SDK can pass it to the lease-resolver step (or report when no\n * snapshot was captured for this trace).\n */\n dbSnapshotRef?: DbSnapshotRef\n /**\n * Populated once the server-side resolver has materialized a per-item\n * branch from `dbSnapshotRef`. The SDK exposes this to customer code\n * via `getCurrentReplayBranch()`. Absent until the resolver lands.\n */\n dbBranchLease?: DbBranchLease\n /**\n * Why the branch could not be resolved, when one was requested and the\n * attempt failed. Distinct from both fields being absent, which means the\n * trace carried no snapshot ref so nothing was attempted.\n */\n dbBranchLeaseError?: { code: string; message: string }\n }>\n}\n\nexport interface ExternalSpanResponse {\n id: string\n externalTraceId: string\n rawData: {\n span_data: {\n input: unknown\n output: unknown\n input_meta?: unknown\n output_meta?: unknown\n input_serialized?: { json: unknown; meta: unknown }\n output_serialized?: { json: unknown; meta: unknown }\n }\n }\n}\n\nexport interface ReplayStatusResponse {\n /**\n * Local replay trace id -> server trace row id, for the traces the server\n * considers fully persisted. Traces still short of their expected span count\n * are simply absent.\n */\n traceIds?: Record<string, string>\n}\n\nexport interface CompleteReplayResponse {\n id: string\n status: string\n traceIds?: Record<string, string>\n /**\n * Per-replay-trace token usage, keyed by the server trace id (the values of\n * `traceIds`). Aggregated server-side from the freshly-uploaded replay spans,\n * so it's the REPLAYED run's tokens (the same source Studio reads), not the\n * original trace's. The SDK maps each item onto this to set\n * `ReplayItem.tokens`. Absent on servers that predate this field.\n */\n tokens?: Record<string, TokenUsage | null>\n /**\n * Number of traces the server has persisted for this test run at\n * completion time. Lets the SDK distinguish \"uploads failed\" from\n * \"server never saw them\" when the trace-ID mapping is incomplete.\n */\n traceCount?: number\n}\n\nexport interface SpanTreeNode {\n /** Upstream platform span id. Stable structural identity; NOT the row id. */\n sourceSpanId: string\n /**\n * The `externalSpans` row id, accepted by {@link HttpClient.getExternalSpan}.\n * Distinct from `sourceSpanId`; used to lazily fetch this node's output when\n * the tree was fetched with `includeOutputs: false`. Optional so trees from\n * older servers (which omit it) still deserialize.\n */\n externalSpanId?: string\n traceFunctionKey: string\n spanName: string\n type: string\n /** Omitted when the tree was fetched payload-free (`includeOutputs: false`). */\n output?: unknown\n outputMeta?: unknown\n children: SpanTreeNode[]\n}\n\nexport interface SpanTreeResponse {\n root: SpanTreeNode\n}\n","/**\n * Selective mock overrides for replay.\n *\n * A mock override injects a custom value into a specific span (node) during\n * replay: the matched span short-circuits its real execution and returns the\n * value you supply, so downstream real code runs against the substituted\n * output. This is a third mock mode alongside \"run real code\" and \"replay\n * recorded output\" (see {@link MockStrategy}).\n *\n * The matcher and value are deliberately separate so matching stays cheap\n * (structural metadata only, no output fetch) and the recorded output is\n * fetched lazily - and only if the value function actually asks for it via\n * {@link MockOverrideCtx.getOriginalOutput}.\n */\n\n/**\n * Structural identity of a span during replay, passed to a {@link NodeMatcher}.\n * Carries no output payload - matching must not depend on the recorded output,\n * so the output fetch stays lazy and gated.\n */\nexport interface SpanNodeMeta {\n /** The `withSpan` key of the executing span (its code-side identity). */\n traceFunctionKey: string\n /** Resolved span name: `options.name ?? fn.name ?? traceFunctionKey`. */\n spanName: string\n /** Span type, e.g. \"llm\", \"agent\", \"tool\", \"custom\". */\n type: string\n /**\n * The id of this span in the original (replayed) trace, when it exists in\n * that trace's tree. Undefined when the live span has no recorded\n * counterpart (e.g. a span the changed code newly introduced).\n */\n originalSpanId?: string\n}\n\n/** Context passed to a {@link MockValue} function for a matched span. */\nexport interface MockOverrideCtx {\n /** The matched span's structural metadata. */\n node: SpanNodeMeta\n /** The live replay args passed to the wrapped function this run. */\n inputs: unknown[]\n /**\n * Lazily fetch this span's ORIGINAL recorded output (deserialized). The fetch\n * happens only when called and is memoized per replay item, so a purely flat\n * override that never calls it triggers zero output round trips. Rejects if\n * the span has no recorded counterpart. Being async, it is only usable for\n * spans wrapping async functions.\n */\n getOriginalOutput: () => Promise<unknown>\n}\n\n/** Selects which spans an override applies to. Runs on structural metadata. */\nexport type NodeMatcher = (node: SpanNodeMeta) => boolean\n\n/** The function form of {@link MockValue}, receiving the override context. */\nexport type MockValueFn = (ctx: MockOverrideCtx) => unknown | Promise<unknown>\n\n/**\n * The value injected for a matched span: either a flat value used as-is, or a\n * function of the {@link MockOverrideCtx} that returns one (or a Promise of\n * one). Full replacement - the value IS the span's output, no merge with the\n * recorded output.\n *\n * The flat side is spelled out (rather than `unknown`) so an inline function\n * still gets a typed `ctx`: `unknown | Fn` would collapse to `unknown` and drop\n * the contextual type. To inject a value that is itself a function, wrap it:\n * `value: () => theFunction`.\n */\nexport type MockValue =\n | MockValueFn\n | string\n | number\n | boolean\n | bigint\n | symbol\n | object\n | null\n | undefined\n\n/** One (match, value) pair. */\nexport interface MockOverride {\n match: NodeMatcher\n value: MockValue\n}\n\n/**\n * Resolve an override's `value`: call it with `ctx` when it's a function, else\n * use it as-is (a flat value).\n */\nexport function resolveMockValue(\n value: MockValue,\n ctx: MockOverrideCtx,\n): unknown | Promise<unknown> {\n return typeof value === \"function\"\n ? (value as (c: MockOverrideCtx) => unknown | Promise<unknown>)(ctx)\n : value\n}\n\n/**\n * Normalize the per-call `mockOverride` option (a single override, an array, or\n * nothing) into an array. First match wins downstream, so order is preserved.\n */\nexport function normalizeMockOverrides(\n mockOverride?: MockOverride | MockOverride[],\n): MockOverride[] {\n if (mockOverride === undefined) {\n return []\n }\n return Array.isArray(mockOverride) ? mockOverride : [mockOverride]\n}\n","/**\n * Generate a UUID v4 without assuming a global `crypto`.\n *\n * `crypto.randomUUID()` is the fast path and exists in every mainstream modern\n * runtime (Node >= 19, all browsers, Deno, Vercel edge, Cloudflare Workers).\n * But the SDK must NEVER crash a host app, and a few runtimes it can legitimately\n * run in lack a global `crypto` or `crypto.randomUUID` (Node < 19 without a\n * polyfill, older React Native, some sandboxes). There, an unguarded\n * `crypto.randomUUID()` throws on the user's call path. This helper falls back\n * to a `Math.random()`-based v4 string instead.\n *\n * The fallback is NOT cryptographically secure. That is fine: trace and span\n * IDs only need to be unique enough to correlate the spans of one trace; they\n * are never security-sensitive.\n */\nimport { warnOnce } from \"./warnOnce.js\"\n\nexport function randomUuid(): string {\n const globalCrypto = (\n globalThis as { crypto?: { randomUUID?: () => string } }\n ).crypto\n if (typeof globalCrypto?.randomUUID === \"function\") {\n try {\n return globalCrypto.randomUUID()\n } catch {\n // Fall through to the manual generator below.\n }\n }\n warnOnce(\n \"crypto-unavailable\",\n \"global crypto.randomUUID is unavailable; using a non-cryptographic fallback for trace/span ids. Tracing works normally (ids are correlation-only, not security-sensitive).\",\n )\n return fallbackUuidV4()\n}\n\n/**\n * RFC 4122 version 4 layout filled from `Math.random()`. Used only when a usable\n * global `crypto.randomUUID` is unavailable.\n */\nfunction fallbackUuidV4(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (char) => {\n const rand = (Math.random() * 16) | 0\n const value = char === \"x\" ? rand : (rand & 0x3) | 0x8\n return value.toString(16)\n })\n}\n","/**\n * Serialization utilities for Bitfab SDK.\n *\n * This module provides serialization with type metadata preservation,\n * using superjson for handling special JavaScript types like Date, Map,\n * Set, BigInt, undefined, etc.\n */\n\nimport superjson from \"superjson\"\nimport { MAX_SPAN_CARRIER_BYTES } from \"./payloadBudget.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\n/**\n * Serialized value with JSON data and optional superjson meta for type preservation.\n *\n * The json field contains the JSON-serializable data.\n * The meta field (if present) contains superjson type information for deserializing\n * special types like Date, Map, Set, BigInt, etc.\n */\nexport interface SerializedValue {\n json: unknown\n meta?: unknown\n}\n\n// Cap on a single serialized value. superjson can succeed on values like SDK\n// client instances (OpenAI, etc.) and produce hundreds of KB to MB of useless\n// internal state, so this is the cheap early-out that stops the walk before a\n// pathological object is carried any further. It is deliberately the same\n// number as the whole-span budget: one legitimately large value may use the\n// entire budget, and `serializePayloadBody` is what enforces the total once\n// every field is in. Anything past it is replaced with a stub so the span\n// still ships and the trace isn't dropped server-side.\nconst MAX_SERIALIZED_BYTES = MAX_SPAN_CARRIER_BYTES\n\n// The framework-capture path (toJsonSafe) shares that ceiling. Agent/graph\n// states (LangGraph, Claude Agent SDK) are legitimately larger than a single\n// function's args/return, and capping them lower than ordinary values only\n// discarded detail the span had room for.\nconst MAX_FRAMEWORK_SERIALIZED_BYTES = MAX_SPAN_CARRIER_BYTES\n\nfunction describeValue(value: unknown): string {\n try {\n const ctorName = (value as { constructor?: { name?: string } })?.constructor\n ?.name\n if (ctorName && ctorName !== \"Object\") {\n return ctorName\n }\n } catch {\n // Property access on `value` can throw (Proxy, poisoned getter).\n }\n return typeof value\n}\n\nfunction unserializableStub(value: unknown, reason: string): SerializedValue {\n // Normalize the byte count out of the key so a too_large warning dedups\n // across differently-sized payloads instead of warning once per size.\n warnOnce(\n `serialize:${reason.replace(/\\d+/g, \"N\")}`,\n `a value could not be fully serialized for a span (${reason}); it was replaced with a placeholder. The span still ships, but its captured input/output is incomplete.`,\n )\n let summary: string\n try {\n summary = `<unserializable: ${describeValue(value)} (${reason})>`\n } catch {\n summary = `<unserializable (${reason})>`\n }\n return { json: summary }\n}\n\n/**\n * Serialize a value using superjson for trace storage.\n *\n * Handles arbitrary JavaScript values including:\n * - Date, RegExp, Error\n * - Map, Set\n * - BigInt\n * - undefined (in objects/arrays)\n * - Circular references\n *\n * Guarantees:\n * - Never throws. Pathological inputs (SDK clients, proxies, poisoned\n * getters, circular graphs that defeat superjson) return a stub string.\n * - Never returns a payload larger than MAX_SERIALIZED_BYTES; oversized\n * inputs are replaced with a stub. Without this the wire-side\n * `JSON.stringify` in http.ts can produce a request that times out or\n * gets rejected, leaving a trace with zero spans.\n *\n * @param value - Any JavaScript value to serialize\n * @returns SerializedValue with 'json' field containing the data.\n * If type metadata is needed for reconstruction, includes 'meta' field.\n *\n * @example\n * ```typescript\n * const result = serializeValue(new Date('2024-01-15T10:30:00Z'))\n * // result.json contains the ISO string\n * // result.meta contains type info for Date reconstruction\n * ```\n */\nexport function serializeValue(value: unknown): SerializedValue {\n try {\n const { json, meta } = superjson.serialize(value)\n\n let size: number\n try {\n size = JSON.stringify(json).length\n } catch {\n return unserializableStub(value, \"stringify_failed_after_superjson\")\n }\n if (size > MAX_SERIALIZED_BYTES) {\n return unserializableStub(value, `too_large_${size}_bytes`)\n }\n\n return meta ? { json, meta } : { json }\n } catch {\n try {\n return { json: JSON.parse(JSON.stringify(value)) }\n } catch {\n return unserializableStub(value, \"json_stringify_failed\")\n }\n }\n}\n\n/**\n * Deserialize a value that was serialized with serializeValue.\n *\n * @param serialized - A SerializedValue object with 'json' and optional 'meta'\n * @returns The reconstructed JavaScript value\n *\n * @example\n * ```typescript\n * const serialized = serializeValue(new Date('2024-01-15'))\n * const date = deserializeValue(serialized)\n * // date is a Date object\n * ```\n */\nexport function deserializeValue(serialized: SerializedValue): unknown {\n if (serialized.meta === undefined) {\n // No metadata, return as-is\n return serialized.json\n }\n\n // Use superjson to deserialize with type reconstruction\n // Cast json to the expected superjson type\n type SuperJSONResult = Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize({\n json: serialized.json as SuperJSONResult[\"json\"],\n meta: serialized.meta as SuperJSONResult[\"meta\"],\n })\n}\n\nconst MAX_SAFE_DEPTH = 6\n\n/**\n * Convert any value to JSON-safe primitives, never throwing.\n *\n * Produces plain objects/arrays/scalars, recursing through `toJSON()` and\n * own-enumerable properties so no raw non-serializable value (a class, a\n * BigInt-bearing object) survives into a span payload. Cycles collapse to a\n * `<cycle ...>` marker; depth is capped.\n *\n * This is the single shared \"safe serialize\" used by the framework\n * integrations that capture raw objects (LangGraph, Claude Agent SDK). Keeping\n * the recurse-the-dump logic here, in one place, is what stops a new\n * integration from reintroducing the \"dump without recursing\" bug - see\n * `serializationInvariant.test.ts`.\n */\nexport function toJsonSafe(value: unknown): unknown {\n return toJsonSafeReport(value).safe\n}\n\n/**\n * Like {@link toJsonSafe}, but also reports what could not be faithfully\n * captured.\n *\n * Returns `{ safe, dropped }` where `dropped` lists the type name behind every\n * placeholder the walker had to emit: a cycle, a max-depth cut, an oversized\n * payload, or a value that could only be stringified (a function/symbol) or\n * stubbed after a throw. A non-empty `dropped` means the captured input/output\n * is lossy. Framework handlers carry it to the send boundary so a degraded\n * capture is marked non-replayable (`serialization_degraded`) instead of being\n * shipped as if it round-trips - mirrors the Python SDK's `to_json_safe_report`\n * + `finalize_span_payload`.\n */\nexport function toJsonSafeReport(value: unknown): {\n safe: unknown\n dropped: string[]\n} {\n const dropped: string[] = []\n const safe = toJsonSafeInner(value, 0, new WeakSet(), dropped)\n // Cap output size for parity with serializeValue. A multi-MB framework\n // payload (a large LangGraph state, a long message history) would otherwise\n // be JSON.stringify'd synchronously on the user's thread in http.ts and may\n // be rejected server-side, leaving a trace with zero spans. Stub it instead\n // so the span still ships. toJsonSafeInner produces only plain\n // objects/arrays/scalars/strings, so JSON.stringify here cannot throw; the\n // try is belt-and-suspenders.\n try {\n const size = JSON.stringify(safe)?.length ?? 0\n if (size > MAX_FRAMEWORK_SERIALIZED_BYTES) {\n warnOnce(\n \"toJsonSafe:too_large\",\n `a framework payload exceeded ${MAX_FRAMEWORK_SERIALIZED_BYTES} bytes and was replaced with a placeholder so the span still ships. The captured state for this span is incomplete.`,\n )\n // Keep any drops already accumulated by the walk (cycles, functions,\n // depth cuts); a payload can be both lossy AND oversized, and the\n // non-replayable marking needs the real types, not just the size stub.\n return {\n safe: `<unserializable: too_large_${size}_bytes>`,\n dropped: [...dropped, `too_large_${size}_bytes`],\n }\n }\n } catch {\n // Keep the recursed value; the http-layer sanitizer is the final backstop.\n }\n return { safe, dropped }\n}\n\nfunction toJsonSafeInner(\n value: unknown,\n depth: number,\n seen: WeakSet<object>,\n dropped: string[],\n): unknown {\n if (value === null || value === undefined) {\n return value\n }\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value\n }\n\n const className =\n (value as { constructor?: { name?: string } })?.constructor?.name ??\n typeof value\n if (depth > MAX_SAFE_DEPTH) {\n dropped.push(className)\n return `<${className}>`\n }\n\n // Non-object composites (bigint, function, symbol) stringify directly. A\n // bigint stringifies faithfully; a function/symbol becomes a lossy summary,\n // so those are reported as dropped.\n if (typeof value !== \"object\") {\n if (typeof value === \"function\" || typeof value === \"symbol\") {\n dropped.push(className)\n }\n try {\n return String(value)\n } catch {\n dropped.push(className)\n return `<${className}>`\n }\n }\n\n if (seen.has(value as object)) {\n dropped.push(className)\n return `<cycle ${className}>`\n }\n seen.add(value as object)\n\n let result: unknown\n if (Array.isArray(value)) {\n result = value.map((item) =>\n toJsonSafeInner(item, depth + 1, seen, dropped),\n )\n } else if (typeof (value as Record<string, unknown>).toJSON === \"function\") {\n // Recurse toJSON() output: it can still hold non-serializable values (e.g.\n // a LangChain tool whose schema is a class) that would otherwise survive\n // into the span payload and crash the wire-side JSON.stringify.\n try {\n result = toJsonSafeInner(\n (value as { toJSON(): unknown }).toJSON(),\n depth + 1,\n seen,\n dropped,\n )\n } catch {\n dropped.push(className)\n result = `<${className}>`\n }\n } else {\n try {\n const obj: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n if (!k.startsWith(\"_\")) {\n obj[k] = toJsonSafeInner(v, depth + 1, seen, dropped)\n }\n }\n result = obj\n } catch {\n dropped.push(className)\n result = `<${className}>`\n }\n }\n\n // Backtrack: keep only ancestors on the current path in `seen`, so a shared\n // (DAG) reference under sibling keys is serialized again rather than stubbed\n // as a false cycle. Real cycles (an ancestor referencing itself) are still\n // caught above.\n seen.delete(value as object)\n return result\n}\n","/**\n * Replay historical traces through a function and create a test run.\n *\n * The replay flow has three phases:\n * 1. Start: fetches historical traces from the server and creates a test run\n * 2. Execute: re-runs each trace's inputs through the provided function locally\n * 3. Complete: marks the test run as completed on the server\n */\n\nimport { resolveAutoCodeChange } from \"./codeChange.js\"\nimport type { DbSnapshotRef } from \"./dbSnapshot.js\"\nimport { BitfabError } from \"./errors.js\"\nimport {\n type CodeChangeFile,\n flushTraces,\n type HttpClient,\n type SpanTreeNode,\n type TokenUsage,\n} from \"./http.js\"\nimport type { MockOverride } from \"./mockOverride.js\"\nimport { normalizeMockOverrides } from \"./mockOverride.js\"\nimport { randomUuid } from \"./randomUuid.js\"\nimport type {\n DbBranchLease,\n DbBranchSettings,\n MockSpan,\n MockTree,\n} from \"./replayContext.js\"\nimport { replayContextReady, runWithReplayContext } from \"./replayContext.js\"\nimport { deserializeValue } from \"./serialize.js\"\nimport { takeReplaySpanCounts } from \"./transport.js\"\nimport { unrefTimer } from \"./unrefTimer.js\"\n\nexport type MockStrategy = \"none\" | \"all\" | \"marked\"\n\nconst REPLAY_PERSISTENCE_TIMEOUT_MS = 30_000\n\n/**\n * How the DB-snapshot branch each replay item runs against is sized and warmed.\n *\n * Every field is optional, so this object is only worth passing when you want\n * to override the mirror project's own sizing. To branch with those defaults,\n * pass `dbBranch: true` instead of an empty object.\n */\nexport interface DbBranchOptions {\n /**\n * Autoscaling floor for the branch's compute, in Neon Compute Units (0.25 to\n * 56). Omit to keep the mirror project's own default. Raise it when the\n * mirror is provisioned smaller than the database it stands in for, so\n * replay latency reflects your code rather than a cold, undersized branch.\n */\n minCu?: number\n /**\n * Autoscaling ceiling for the branch's compute, in Neon Compute Units.\n * Setting it equal to `minCu` pins the size, which keeps items comparable:\n * otherwise a later item can run against an endpoint that has already\n * scaled up and post a better number for the same code.\n */\n maxCu?: number\n /**\n * SQL that warms the branch's cache. The server appends it to the branch's\n * readiness check, so it runs BEFORE your function sees the branch and its\n * time is not charged to the replayed call. Invalid SQL fails the branch\n * rather than silently leaving it cold.\n */\n warmupSql?: string\n}\n\n/**\n * Whether the caller asked for database branching. `true` and a settings object\n * both turn it on; `false` and omission leave it off. Kept separate from\n * `resolveDbBranchSettings` because `dbBranch: true` enables branching while\n * contributing no settings, so presence of settings can't stand in for the\n * switch.\n */\nfunction dbBranchEnabled(\n dbBranch: DbBranchOptions | boolean | undefined,\n): boolean {\n return dbBranch !== undefined && dbBranch !== false\n}\n\n/**\n * Narrow the caller's branch options to the wire shape, dropping the object\n * entirely when nothing was set so the request stays byte-identical to what\n * older SDKs send. Booleans carry no settings: they only move the switch.\n */\nfunction resolveDbBranchSettings(\n dbBranch: DbBranchOptions | boolean | undefined,\n): DbBranchSettings | undefined {\n if (!dbBranch || dbBranch === true) {\n return undefined\n }\n const { minCu, maxCu, warmupSql } = dbBranch\n const settings: DbBranchSettings = {\n ...(minCu === undefined ? {} : { minCu }),\n ...(maxCu === undefined ? {} : { maxCu }),\n ...(warmupSql === undefined ? {} : { warmupSql }),\n }\n return Object.keys(settings).length === 0 ? undefined : settings\n}\n\nexport interface ReplayOptions {\n /**\n * Maximum number of traces to replay (1-100, default 5). Ignored when\n * `traceIds` is passed (with a warning): an explicit ID list already\n * determines how many traces replay.\n */\n limit?: number\n /** Optional list of specific trace IDs to replay (max 100). */\n traceIds?: string[]\n /** Optional display name for the resulting experiment/test run. */\n name?: string\n /** Maximum number of items to process in parallel. Set to 1 for sequential. Default 10. */\n maxConcurrency?: number\n /**\n * Description of the code change being tested in this replay. Stored on\n * the resulting experiment so the change can be reviewed alongside results.\n * Supplying a description without `codeChangeFiles` preserves this text\n * while the SDK automatically captures the files.\n * Pass `null` when the replay should have no description; use\n * `codeChangeFiles: null` to suppress automatic file capture.\n */\n codeChangeDescription?: string | null\n /**\n * Files edited as part of this code change. Each entry holds the file path\n * and the full `before`/`after` contents. The agent reads each file before\n * and after editing and passes the two strings. Use `\"\"` for newly created\n * files (`before`) or deleted files (`after`). Omit this field to capture\n * automatically, or pass `null` to suppress file capture for this replay.\n */\n codeChangeFiles?: CodeChangeFile[] | null\n /**\n * Mock strategy for child spans during replay.\n * - \"marked\": only spans tagged with { mockOnReplay: true } in SpanOptions are mocked (default)\n * - \"none\": everything runs real code\n * - \"all\": every child withSpan returns historical output\n */\n mock?: MockStrategy\n /**\n * Selective mock overrides: inject custom values into specific spans during\n * replay, so downstream real code runs against the substituted output. Each\n * override is a `{ match, value }` pair; the first matcher that\n * matches a span wins. These take precedence over any overrides registered on\n * the client via `registerMockOverride`, and over the base `mock` strategy - a\n * span no override matches falls back to that strategy. See {@link MockOverride}.\n */\n mockOverride?: MockOverride | MockOverride[]\n /**\n * Run each item against a database branch restored to the state its source\n * trace saw. Pass `true` to branch with the mirror project's own sizing, or a\n * {@link DbBranchOptions} object to tune how each branch is sized and warmed.\n * `false` and omission leave branching off. Inside `fn`, read the resolved\n * branch with `getCurrentReplayBranch()`.\n *\n * Items whose source trace carried no DB snapshot reference get no branch and\n * run against the live database. An item whose branch was requested but could\n * not be resolved fails instead of running, so a replay never silently\n * reports a result that did not use the historical data you asked for.\n */\n dbBranch?: DbBranchOptions | boolean\n /** Group ID to associate this replay with an experiment group for live streaming in Studio. */\n experimentGroupId?: string\n /**\n * Dataset this replay runs against. When set, the resulting experiment is\n * durably attributed to the dataset (stored on the test run), so it appears\n * under the dataset's experiments even if the trace lineage can't be\n * reconstructed. Validated server-side against the org.\n */\n datasetId?: string\n /**\n * Graders to attach directly to this experiment (test run), independent of any\n * graders already on the dataset. The resulting experiment is graded by the\n * union of these and the dataset's runnable graders at completion, so use this\n * to grade a single run with a check you don't want to add to the dataset\n * permanently. Each id must be an active/live grader belonging to the same\n * organization and trace function, otherwise the server rejects the replay.\n */\n graderIds?: string[]\n /**\n * Reshape recorded inputs before they are spread into `fn`.\n *\n * Replay pulls each trace's inputs exactly as they were captured against the\n * function's signature AT TRACE TIME. When the function's shape has since\n * changed (params renamed, reordered, collapsed into an options object, etc.),\n * the recorded inputs no longer line up and `fn(...inputs)` throws. This hook\n * lets a caller map the recorded inputs onto the current signature so replay\n * can still run.\n *\n * Receives the deserialized recorded inputs and a per-trace {@link AdaptContext}\n * (so a table-driven adapter can look up the adapted inputs by `traceId`), and\n * returns the array actually spread into `fn`. The returned array is also what\n * `ReplayItem.input` reports, so the experiment shows what was really run.\n *\n * Runs per item, inside the same try/catch as `fn`: if the adapter throws, the\n * failure is surfaced on that item's `error` rather than crashing the run.\n * Omit it to spread the recorded inputs unchanged.\n */\n adaptInputs?: (inputs: unknown[], ctx: AdaptContext) => unknown[]\n /**\n * Called once per item as it finishes, in completion order (not input\n * order), with running totals for the whole run. Use it to render replay\n * progress, for example a terminal progress bar. Replay does not know\n * pass/fail at this point (verdicts are assigned later), so the totals only\n * distinguish items whose function ran (`succeeded`) from items that threw\n * (`errored`).\n *\n * Invoked synchronously right after each item settles, so keep it cheap. A\n * throwing callback never crashes the run: the error is swallowed so progress\n * UI can't break replay.\n */\n onProgress?: (progress: ReplayProgress) => void\n}\n\n/** Running totals reported to {@link ReplayOptions.onProgress} as replay proceeds. */\nexport interface ReplayProgress {\n /**\n * Event kind. Omitted (or `\"item\"`) for the per-trace settle events streamed\n * during the run. `\"complete\"` marks the single terminal event emitted once\n * the run has settled and been enriched server-side; it carries the full\n * {@link ReplayProgress.result} and has no `item`. The Bitfab plugin reads\n * that terminal event to build the run's final result without parsing stdout.\n */\n type?: \"item\" | \"complete\"\n /**\n * The full {@link ReplayResult}, present only on the terminal `\"complete\"`\n * event. Lets the plugin ingest the enriched result (server-aggregated tokens,\n * server trace ids) over the same channel as progress, so a dependency logging\n * to stdout can never block it.\n */\n result?: ReplayResult<unknown>\n /** Test run ID created for this replay. */\n testRunId?: string\n /** Items that have finished so far, whether they succeeded or errored. */\n completed: number\n /** Total number of items in this replay run. */\n total: number\n /** Of the completed items, how many ran the function without throwing. */\n succeeded: number\n /** Of the completed items, how many threw (their `item.error` is set). */\n errored: number\n /**\n * The single item that just settled to produce this event. `traceId` is null\n * at this stage (the server replay id isn't known until the run completes);\n * `originalTraceId` is the original (historical) trace that was replayed (so\n * a UI can identify or link it); `error` is its replay error, or null when it\n * ran ok; `durationMs` is how long this one trace took to replay. Lets a\n * progress UI show per-trace pass/fail and timing as the run streams, without\n * waiting for the full {@link ReplayResult}.\n */\n item?: {\n /** Trace ID of the new replay trace (null during the run; the server id arrives at completion). */\n traceId?: string | null\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId: string | null\n /** External span ID the recorded inputs were read from (the original root span). */\n originalSpanId?: string | null\n /** @deprecated alias for `originalTraceId`. */\n sourceTraceId: string | null\n /** @deprecated alias for `originalSpanId`. */\n sourceSpanId?: string | null\n /** Deserialized inputs from the original trace. */\n input?: unknown[]\n /** The result returned by the replayed function, or undefined on error. */\n result?: unknown\n /** The original output from the historical trace. */\n originalOutput?: unknown\n error: string | null\n durationMs: number | null\n tokens?: TokenUsage | null\n model?: string | null\n dbSnapshotRef?: DbSnapshotRef | null\n }\n}\n\n/**\n * Wire prefix the Bitfab plugin scans for. Each line {@link reportReplayProgress}\n * writes is this prefix followed by the JSON of the running totals (plus the\n * settled `item`). The plugin polls these lines to report live progress while a\n * replay runs in the background; keep the SDK emitter and the plugin parser in\n * sync.\n */\nexport const BITFAB_PROGRESS_PREFIX = \"@@bitfab:progress \"\n\n/**\n * A ready-made {@link ReplayOptions.onProgress} callback for replay scripts.\n * Pass it straight in:\n *\n * ```ts\n * await bitfab.replay(\"my-fn\", fn, { limit, onProgress: reportReplayProgress })\n * ```\n *\n * It writes one `@@bitfab:progress` line per trace to stderr, which the Bitfab\n * plugin polls to report live progress while the replay runs in the background,\n * so scripts never hand-format the wire protocol.\n * stdout is left untouched for direct-run ReplayResult JSON. Outside Node (no\n * `process.stderr`, e.g. a browser) it is a no-op, and a write failure is\n * swallowed so progress can never crash a run.\n */\nexport function reportReplayProgress(progress: ReplayProgress): void {\n const stderr = typeof process !== \"undefined\" ? process.stderr : undefined\n if (!stderr) {\n return\n }\n try {\n stderr.write(`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress)}\\n`)\n } catch {\n // A progress reporter must never crash the replay run.\n }\n}\n\n/** Per-trace context passed to {@link ReplayOptions.adaptInputs}. */\nexport interface AdaptContext {\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId: string\n /** External span ID the recorded inputs were read from. */\n originalSpanId: string\n /** @deprecated alias for {@link AdaptContext.originalTraceId}. */\n sourceTraceId: string\n /** @deprecated alias for {@link AdaptContext.originalSpanId}. */\n sourceSpanId: string\n}\n\n/**\n * The shape an adapter module must export as `adaptInputs`.\n *\n * Author an adapter in its own file (e.g. `scripts/replay-adapters/<name>.ts`),\n * import it in your replay script, and pass it to `replay({ adaptInputs })`:\n *\n * ```ts\n * import type { AdaptInputsFn } from \"@bitfab/sdk\"\n * export const adaptInputs: AdaptInputsFn = (inputs, ctx) => [reshape(inputs)]\n * ```\n */\nexport type AdaptInputsFn = (inputs: unknown[], ctx: AdaptContext) => unknown[]\n\nexport interface ReplayItem<T> {\n /**\n * Server trace ID of the new replay trace this item produced. Written in by\n * `replay()` from the complete-replay response once the server has minted the\n * trace row; the client-side id used to correlate spans during the run is\n * never surfaced here. Null until completion, on older servers that omit the\n * mapping, or if the item produced no trace. Not the verdict-persistence key:\n * that is the original-trace lineage (`originalTraceId` + `testRunId`).\n */\n traceId: string | null\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId: string\n /** External span ID the recorded inputs were read from (the original root span). */\n originalSpanId: string\n /** @deprecated alias for {@link ReplayItem.originalTraceId}. */\n sourceTraceId: string\n /** @deprecated alias for {@link ReplayItem.originalSpanId}. */\n sourceSpanId: string\n /** Deserialized inputs from the original trace. */\n input: unknown[]\n /** The result returned by the function during replay, or undefined on error. */\n result: T | undefined\n /** The original output from the historical trace. */\n originalOutput: unknown\n /** Error message if the function threw, or null on success. */\n error: string | null\n /** Original trace duration in milliseconds, or null if timestamps are missing. */\n durationMs: number | null\n /**\n * Token usage from the REPLAYED run (this item's new execution), aggregated\n * server-side from the spans it produced, or null if the run captured no\n * token data. This is the \"new\" side of a token delta: compare it against\n * the original trace's recorded usage to see how the code change moved cost.\n * Matches what Studio's experiments view shows.\n */\n tokens: TokenUsage | null\n /** Model name from the original trace, or null if not captured. */\n model: string | null\n /**\n * The DB snapshot ref the SDK captured at trace open. Useful for debugging\n * (\"what state was this trace pinned to?\") and for customers building\n * their own resolvers. Undefined when the source trace was captured\n * without `dbSnapshot` configured.\n */\n dbSnapshotRef: DbSnapshotRef | null\n}\n\nexport type { CodeChangeFile, TokenUsage }\n\nexport interface ReplayResult<T> {\n /** Individual replay items with inputs, results, and comparison data. */\n items: ReplayItem<T>[]\n /** The test run ID created on the server. */\n testRunId: string\n /** Full URL to view the test run in the dashboard. */\n testRunUrl: string\n}\n\n/**\n * Deserialize inputs from a historical span's rawData.\n *\n * Prefers superjson-serialized `input_meta` for type preservation,\n * falls back to the raw `input` field.\n */\nfunction deserializeInputs(spanData: Record<string, unknown>): unknown[] {\n const inputMeta = spanData.input_meta as unknown\n const rawInput = spanData.input\n\n // If superjson meta is available, deserialize with type reconstruction\n if (inputMeta !== undefined && inputMeta !== null) {\n const deserialized = deserializeValue({ json: rawInput, meta: inputMeta })\n if (Array.isArray(deserialized)) {\n return deserialized\n }\n return deserialized !== undefined && deserialized !== null\n ? [deserialized]\n : []\n }\n\n // Fall back to raw input\n if (Array.isArray(rawInput)) {\n return rawInput\n }\n return rawInput !== undefined && rawInput !== null ? [rawInput] : []\n}\n\n/**\n * Deserialize the original output from a historical span's rawData.\n */\nfunction deserializeOutput(spanData: Record<string, unknown>): unknown {\n const outputMeta = spanData.output_meta as unknown\n const rawOutput = spanData.output\n\n if (outputMeta !== undefined && outputMeta !== null) {\n return deserializeValue({ json: rawOutput, meta: outputMeta })\n }\n\n return rawOutput\n}\n\n/**\n * Walk the children of a root span tree node in depth-first order and build\n * a MockTree keyed by `${traceFunctionKey}:${spanName}:${callIndex}`.\n *\n * The historical root itself is NOT walked. At replay time the runtime root\n * span has `isRootSpan === true` and never queries the mockTree (mock\n * interception is skipped for root spans by design), so the root has nothing\n * to look up. Walking it would just leave an unreachable entry in the table.\n *\n * The (key, name) compound match is what disambiguates same-key spans:\n * - A wrapped function's children commonly share its traceFunctionKey via\n * the fluent `getFunction(key).withSpan({ name }, ...)` pattern. They\n * disambiguate by `name`, never colliding with each other.\n * - Recursion: same (key, name) at every depth. callIndex per (key, name)\n * orders them correctly without leaking the historical root into the\n * nested call's slot.\n * - Outer-wrapper replay scripts: the outer wrapper's `name` is distinct\n * from anything in the historical tree (it only exists at replay), so\n * its presence never disturbs counters or lookups for spans that do\n * exist in the historical tree.\n */\nfunction buildMockTree(rootNode: SpanTreeNode): MockTree {\n const spans = new Map<string, MockSpan>()\n const counters = new Map<string, number>()\n\n function walk(node: SpanTreeNode): void {\n const key = node.traceFunctionKey\n if (key) {\n const name = node.spanName || key\n const counterKey = `${key}:${name}`\n const index = counters.get(counterKey) ?? 0\n counters.set(counterKey, index + 1)\n // `output`/`outputMeta` are undefined on a payload-free (lazy) tree;\n // `externalSpanId` is what the lazy path fetches them by. Both are copied\n // verbatim so eager and lazy trees build through the same walk.\n spans.set(`${counterKey}:${index}`, {\n sourceSpanId: node.sourceSpanId,\n externalSpanId: node.externalSpanId,\n output: node.output,\n outputMeta: node.outputMeta,\n })\n }\n for (const child of node.children) {\n walk(child)\n }\n }\n\n for (const child of rootNode.children) {\n walk(child)\n }\n\n return { spans }\n}\n\n/**\n * Execute a single replay item: fetch span data, deserialize inputs, call\n * the function within a replay context that injects testRunId into new spans.\n */\nasync function processItem<TReturn>(\n httpClient: HttpClient,\n serverItem: {\n originalTraceId?: string\n originalSpanId?: string\n /** @deprecated alias emitted by servers that predate the originalTraceId rename. */\n sourceTraceId: string\n /** @deprecated alias emitted by servers that predate the originalSpanId rename. */\n sourceSpanId: string\n durationMs: number | null\n model: string | null\n dbSnapshotRef?: DbSnapshotRef\n dbBranchLease?: DbBranchLease\n dbBranchLeaseError?: { code: string; message: string }\n },\n // biome-ignore lint/suspicious/noExplicitAny: replay deserializes inputs from historical data\n fn: (...args: any[]) => TReturn | Promise<TReturn>,\n testRunId: string,\n mockStrategy: MockStrategy,\n resolvedOverrides: MockOverride[],\n replayedTraceId: string,\n includeDbBranchLease: boolean,\n dbBranchSettings: DbBranchSettings | undefined,\n adaptInputs:\n | ((inputs: unknown[], ctx: AdaptContext) => unknown[])\n | undefined,\n): Promise<ReplayItem<TReturn>> {\n // The server-side resolver materializes a Neon preview branch per item\n // during `/api/sdk/replay/start` (when the customer passed `dbBranch`,\n // which triggers `includeDbBranchLease: true`). The lease arrives on the\n // server item; we just attach it to the replay context and release the\n // branch in `finally` so any throw (in fetch, mock-tree build, or the\n // customer fn) frees the Neon resource. Items whose source trace had no\n // snapshot ref arrive without a lease; `getCurrentReplayBranch()` returns\n // null for those, and replaying against the live database is correct.\n let lease = includeDbBranchLease ? serverItem.dbBranchLease : undefined\n // A resolve that was attempted and FAILED is different: the caller asked for\n // a branch, so running their function against live data would produce a\n // result that looks valid and isn't. Fail this item instead, loudly.\n let leaseError = includeDbBranchLease\n ? serverItem.dbBranchLeaseError\n : undefined\n let dbSnapshotRef = serverItem.dbSnapshotRef\n\n let inputs: unknown[] = []\n let originalOutput: unknown\n let result: TReturn | undefined\n let error: string | null = null\n\n // The ORIGINAL (historical) trace/span this item replays. Canonical server\n // keys are originalTraceId/originalSpanId; older servers only send the\n // deprecated sourceTraceId/sourceSpanId aliases.\n const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId\n const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId\n\n try {\n if (includeDbBranchLease && !lease && !leaseError) {\n const resolved = await httpClient.resolveDbBranchLease(\n testRunId,\n originalTraceId,\n dbBranchSettings,\n )\n lease = resolved.lease ?? undefined\n leaseError = resolved.leaseError ?? undefined\n dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef\n }\n\n if (leaseError) {\n throw new BitfabError(\n `Replay requested a database branch for trace ${originalTraceId} but it could not be resolved (${leaseError.code}): ${leaseError.message}. The function was not run, because replaying it against the live database would produce a result that looks valid but did not use the historical data you asked for.`,\n )\n }\n\n const span = await httpClient.getExternalSpan(originalSpanId, {\n view: \"replay\",\n })\n const spanData = (span.rawData?.span_data ?? {}) as Record<string, unknown>\n\n inputs = deserializeInputs(spanData)\n originalOutput = deserializeOutput(spanData)\n\n // Reshape the recorded inputs onto the current signature when an adapter\n // is supplied. Runs before the mock tree / fn call so the adapted array is\n // what fn receives and what `item.input` reports.\n if (adaptInputs) {\n inputs = adaptInputs(inputs, {\n originalTraceId,\n originalSpanId,\n // Deprecated aliases for originalTraceId/originalSpanId.\n sourceTraceId: originalTraceId,\n sourceSpanId: originalSpanId,\n })\n }\n\n // Build the mock tree whenever mocking could apply: any non-\"none\" strategy,\n // OR overrides are present (overrides substitute even under \"none\" - the\n // \"run real code but replace node X\" case). Only \"all\" needs outputs inline;\n // \"marked\"/overrides fetch a payload-free tree and pull outputs lazily so we\n // never drag down every span's recorded output when only a few get mocked.\n const hasOverrides = resolvedOverrides.length > 0\n const needTree =\n mockStrategy === \"all\" || mockStrategy === \"marked\" || hasOverrides\n const includeOutputs = mockStrategy === \"all\"\n\n let mockTree: MockTree | undefined\n if (needTree) {\n try {\n const treeResponse = await httpClient.getSpanTree(originalSpanId, {\n includeOutputs,\n includeRootOutput: false,\n })\n if (treeResponse.root) {\n mockTree = buildMockTree(treeResponse.root)\n } else if (mockStrategy === \"all\" || hasOverrides) {\n throw new BitfabError(\n `Replay mock strategy \"${mockStrategy}\"${hasOverrides ? \" with overrides\" : \"\"} requires a span tree root for original span ${originalSpanId}.`,\n )\n } else {\n mockTree = undefined\n }\n } catch (e) {\n // \"all\" and overrides both depend on the tree (\"all\" mocks every span\n // from it; overrides gate on its call-counter machinery), so a fetch\n // failure surfaces on the item rather than silently running real with\n // the overrides dropped. Bare \"marked\" degrades to no mocking (its\n // marked spans just re-run). Mirrors the Python/Ruby SDKs.\n if (mockStrategy === \"all\" || hasOverrides) {\n throw e\n }\n mockTree = undefined\n }\n }\n\n // Lazy per-span output fetch, memoized per item so a span read twice (once\n // as a marked mock, once via an override's getOriginalOutput) fetches once.\n // Present only when outputs were NOT fetched inline (not the eager \"all\"\n // path); its presence signals the mock path to fetch on demand.\n const outputCache = new Map<string, Promise<unknown>>()\n const fetchSpanOutput =\n mockTree && !includeOutputs\n ? (externalSpanId: string): Promise<unknown> => {\n let pending = outputCache.get(externalSpanId)\n if (!pending) {\n pending = httpClient\n .getExternalSpan(externalSpanId, { view: \"replay\" })\n .then((s) =>\n deserializeOutput(\n (s.rawData?.span_data ?? {}) as Record<string, unknown>,\n ),\n )\n outputCache.set(externalSpanId, pending)\n }\n return pending\n }\n : undefined\n\n const maybePromise = runWithReplayContext(\n {\n testRunId,\n traceId: replayedTraceId,\n inputSourceSpanId: span.id,\n inputSourceTraceId: span.externalTraceId,\n sourceBitfabTraceId: originalTraceId,\n mockTree,\n callCounters: mockTree ? new Map() : undefined,\n mockStrategy,\n mockOverrides: hasOverrides ? resolvedOverrides : undefined,\n fetchSpanOutput,\n dbBranchLease: lease,\n },\n () => fn(...inputs),\n )\n result = maybePromise instanceof Promise ? await maybePromise : maybePromise\n } catch (e) {\n error = e instanceof Error ? e.message : String(e)\n } finally {\n if (lease) {\n try {\n await httpClient.releaseDbBranchLease(lease.neonBranchId)\n } catch (e) {\n try {\n console.warn(\n `Bitfab: failed to release DB branch ${lease.neonBranchId} (TTL janitor will catch it): ${\n e instanceof Error ? e.message : String(e)\n }`,\n )\n } catch {\n // Never crash the host\n }\n }\n }\n }\n\n return {\n // Written in by replay() from the complete-replay response once the server\n // has minted this replay trace's row. Null until then: the client-side\n // correlation id (replayedTraceId) is never surfaced as the item's traceId.\n traceId: null,\n originalTraceId,\n originalSpanId,\n // Deprecated aliases for originalTraceId/originalSpanId.\n sourceTraceId: originalTraceId,\n sourceSpanId: originalSpanId,\n input: inputs,\n result,\n originalOutput,\n error,\n durationMs: serverItem.durationMs ?? null,\n // Filled in by replay() from the complete-replay response once the\n // replay traces are persisted and their spans aggregated server-side.\n // Null here (and on older servers) means \"replay tokens not known\".\n tokens: null,\n model: serverItem.model ?? null,\n dbSnapshotRef: dbSnapshotRef ?? null,\n }\n}\n\n/**\n * Block until the server has fully persisted every replay trace this run\n * submitted, or fail loudly.\n *\n * Flushing the transport only proves the SDK handed the spans off. The barrier\n * that matters is server-side: each trace must reach a final status AND hold at\n * least the number of spans this process submitted for it. Without that,\n * `completeReplay` can build its trace-ID mapping while spans are still in\n * flight, and every `item.traceId` comes back null.\n *\n * Span counts come from the transport's record of UNIQUE submitted span IDs,\n * which matches the server's idempotent span key: a retried or duplicated\n * submission can never make this wait for a row the server will never write.\n */\nasync function waitForReplayPersistence(\n httpClient: HttpClient,\n testRunId: string,\n replayedTraceIds: string[],\n): Promise<void> {\n // Settle deferred submissions before counting. A `finalize` root span only\n // reaches the transport once its finalize chain resolves, so tallying first\n // would under-count and let the barrier pass on a trace that is still short.\n // This waits for that work WITHOUT flushing: a run that submitted nothing\n // must not emit an export request just to discover it has nothing to wait on.\n const deferredSettled = await httpClient.settleDeferredWork(\n REPLAY_PERSISTENCE_TIMEOUT_MS,\n )\n\n // Checked BEFORE the tally: deferred work that never landed means no\n // completion may have registered at all, and an empty tally would then look\n // like \"nothing to wait for\" and finalize the run with root spans pending.\n if (!deferredSettled) {\n throw new BitfabError(\n `Replay could not settle deferred span work before the deadline, so the ` +\n `expected span counts are incomplete (testRunId ${testRunId}).`,\n )\n }\n\n const expectedSpanCounts = takeReplaySpanCounts(replayedTraceIds)\n if (Object.keys(expectedSpanCounts).length === 0) {\n return\n }\n\n // A failed flush is a hint, not a verdict. It means delivery was not\n // CONFIRMED within the deadline, which is not the same as lost: the export\n // timeout can fire while requests are still in flight and the server goes on\n // to persist every one of them. Throwing here failed runs whose data had\n // fully landed. The status poll below is the authority, because the server\n // answers only for traces that are final with all of their spans.\n const flushed = await flushTraces(REPLAY_PERSISTENCE_TIMEOUT_MS)\n\n // The poll gets its own budget. Sharing one deadline with the flush meant a\n // flush that used it all left zero polling window, so the barrier failed\n // after a single not-ready answer - exactly the case where the export is\n // still in flight and about to persist.\n const deadline = Date.now() + REPLAY_PERSISTENCE_TIMEOUT_MS\n\n let missing = Object.keys(expectedSpanCounts).length\n while (true) {\n const status = await httpClient.getReplayStatus(\n testRunId,\n expectedSpanCounts,\n )\n const ready = status.traceIds ?? {}\n missing = Object.keys(expectedSpanCounts).filter(\n (traceId) => ready[traceId] === undefined,\n ).length\n if (missing === 0) {\n return\n }\n if (Date.now() >= deadline) {\n break\n }\n await sleep(Math.min(100, Math.max(0, deadline - Date.now())))\n }\n\n // Only now is it a real failure: the server itself never confirmed these.\n // Surface the flush result as the likely cause rather than as the verdict.\n const cause = flushed\n ? \"\"\n : \" Delivery was also not confirmed before the flush deadline, so the \" +\n \"spans likely never reached the server.\"\n throw new BitfabError(\n `Replay traces were not fully persisted before the delivery deadline ` +\n `(testRunId ${testRunId}, missing ${missing} of ` +\n `${Object.keys(expectedSpanCounts).length} trace(s)).${cause}`,\n )\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms)\n unrefTimer(timer)\n })\n}\n\n/**\n * Run async tasks with a concurrency limit.\n * Each task factory is called when a slot opens; results preserve input order.\n */\nasync function mapWithConcurrency<T>(\n tasks: Array<() => Promise<T>>,\n maxConcurrency: number,\n onSettled?: (result: T, index: number) => void,\n): Promise<T[]> {\n const results: T[] = new Array(tasks.length)\n let nextIndex = 0\n\n async function worker(): Promise<void> {\n while (nextIndex < tasks.length) {\n const index = nextIndex++\n const result = await tasks[index]()\n results[index] = result\n onSettled?.(result, index)\n }\n }\n\n const workers = Array.from(\n { length: Math.min(maxConcurrency, tasks.length) },\n () => worker(),\n )\n await Promise.all(workers)\n return results\n}\n\n/**\n * Replay historical traces through a function and create a test run.\n *\n * @internal Called by Bitfab.replay, not part of the public API.\n */\nexport async function replay<TReturn>(\n httpClient: HttpClient,\n serviceUrl: string,\n traceFunctionKey: string,\n // biome-ignore lint/suspicious/noExplicitAny: replay deserializes inputs from historical data\n fn: (...args: any[]) => TReturn | Promise<TReturn>,\n options?: ReplayOptions,\n registeredOverrides: MockOverride[] = [],\n): Promise<ReplayResult<TReturn>> {\n if (options?.traceIds !== undefined) {\n if (options.traceIds.length === 0) {\n throw new BitfabError(\"traceIds must contain at least one trace ID.\")\n }\n if (options.traceIds.length > 100) {\n throw new BitfabError(\n `traceIds supports at most 100 trace IDs per replay (got ${options.traceIds.length}).`,\n )\n }\n }\n if (options?.limit !== undefined && options?.traceIds !== undefined) {\n try {\n console.warn(\n \"Bitfab: limit is ignored when traceIds is passed: the explicit trace ID list already determines how many traces replay.\",\n )\n } catch {\n // Never crash the host app\n }\n }\n\n await replayContextReady\n\n // Resolve the code change to attach to this experiment. codeChangeFiles is\n // the capture control: omitted auto-captures, an array wins, and null opts\n // out. A caller-supplied description is preserved when files are captured.\n let codeChangeDescription = options?.codeChangeDescription\n let codeChangeFiles = options?.codeChangeFiles\n if (codeChangeFiles === undefined) {\n const captured = await resolveAutoCodeChange(options?.name)\n if (captured) {\n codeChangeFiles = captured.files\n if (codeChangeDescription === undefined) {\n codeChangeDescription = captured.description\n }\n }\n }\n\n const {\n testRunId,\n testRunUrl,\n items: serverItems,\n } = await httpClient.startReplay(\n traceFunctionKey,\n // limit is meaningless with explicit traceIds (the ID list determines\n // the count), so it's omitted from the request entirely.\n options?.traceIds ? undefined : (options?.limit ?? 5),\n options?.traceIds,\n options?.name,\n codeChangeDescription,\n codeChangeFiles,\n dbBranchEnabled(options?.dbBranch), // includeDbBranchLease\n options?.experimentGroupId,\n options?.datasetId,\n options?.graderIds,\n resolveDbBranchSettings(options?.dbBranch),\n )\n\n const mockStrategy: MockStrategy = options?.mock ?? \"marked\"\n const maxConcurrency = options?.maxConcurrency ?? 10\n\n // Per-call overrides take precedence over registered ones: concatenating them\n // first means the first-match-wins scan hits per-call overrides before the\n // client-registered chain, and both before the base mock strategy.\n const resolvedOverrides = [\n ...normalizeMockOverrides(options?.mockOverride),\n ...registeredOverrides,\n ]\n\n // One client-side replay trace id per item. It tags that item's replay spans\n // during the run so the server can echo back the row id it minted for them\n // (resolved in the complete-replay mapping below). Kept out of the public\n // ReplayItem: it's a correlation handle, never an id callers use.\n const replayedTraceIds = serverItems.map(() => randomUuid())\n const tasks = serverItems.map(\n (serverItem, index) => () =>\n processItem(\n httpClient,\n serverItem,\n fn,\n testRunId,\n mockStrategy,\n resolvedOverrides,\n replayedTraceIds[index],\n dbBranchEnabled(options?.dbBranch),\n resolveDbBranchSettings(options?.dbBranch),\n options?.adaptInputs,\n ),\n )\n const total = tasks.length\n let completed = 0\n let succeeded = 0\n let errored = 0\n const resultItems = await mapWithConcurrency(\n tasks,\n maxConcurrency,\n options?.onProgress\n ? (item) => {\n completed += 1\n if (item.error === null) {\n succeeded += 1\n } else {\n errored += 1\n }\n try {\n options?.onProgress?.({\n testRunId,\n completed,\n total,\n succeeded,\n errored,\n item: {\n // The server replay trace id isn't known until completeReplay\n // runs (below), so it can't be reported mid-run and we never\n // emit the client-side placeholder. originalTraceId (the\n // historical trace) is known now and is what a UI keys on to\n // identify what just settled.\n traceId: null,\n originalTraceId: item.originalTraceId ?? null,\n originalSpanId: item.originalSpanId ?? null,\n // Deprecated aliases for originalTraceId/originalSpanId.\n sourceTraceId: item.originalTraceId ?? null,\n sourceSpanId: item.originalSpanId ?? null,\n input: item.input,\n result: item.result,\n originalOutput: item.originalOutput,\n error: item.error,\n durationMs: item.durationMs,\n tokens: item.tokens,\n model: item.model,\n dbSnapshotRef: item.dbSnapshotRef,\n },\n })\n } catch {\n // Progress UI must never crash the replay run.\n }\n }\n : undefined,\n )\n\n // Items submit their spans through the same batching transport live traffic\n // uses, so nothing here has waited on the network yet. Flush the transports,\n // then let the SERVER confirm each trace reached a final status with all of\n // its spans before finalizing: a drained queue is not proof that Bitfab\n // committed the data.\n await waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)\n\n // completeReplay finalizes the test run and returns the token/diagnostic\n // mapping; its failures propagate loudly because a run that never completed\n // can't be finalized and callers must hear about it.\n const completeResult = await httpClient.completeReplay(testRunId)\n const serverTraceIds = completeResult.traceIds\n // Per-replay-trace token usage, keyed by server trace id. The REPLAYED run's\n // tokens (span-aggregated server-side), used below to fill each item.tokens.\n const replayTokens = completeResult.tokens\n\n // `serverTraceIds` maps each item's client-side replay trace id (its entry in\n // `replayedTraceIds`, which tagged that item's spans during the run) to the\n // server's trace row id. We use it to (a) write the real server replay trace\n // id into `item.traceId` now that the row exists, (b) attach each item's\n // server-aggregated token usage, and (c) detect a systemic upload failure\n // early. Verdict persistence does NOT use this map: it is keyed by the\n // original-trace lineage (`originalTraceId` + `testRunId`), which needs no\n // client-held server id. Older servers that omit the map yield no replay\n // tokens and leave `item.traceId` null.\n if (serverTraceIds !== undefined) {\n const missing: string[] = []\n let completedCount = 0\n for (let index = 0; index < resultItems.length; index += 1) {\n const item = resultItems[index]\n const localId = replayedTraceIds[index]\n const mapped = localId ? serverTraceIds[localId] : undefined\n // Write the real server replay trace id in as it comes back; the item\n // held null until now (the client placeholder is never surfaced).\n item.traceId = mapped ?? null\n if (item.error === null) {\n completedCount += 1\n if (mapped === undefined) {\n missing.push(localId ?? item.originalTraceId)\n }\n }\n if (mapped !== undefined) {\n item.tokens = replayTokens?.[mapped] ?? null\n }\n }\n // ALL completed items missing → systemic (the replayed function isn't\n // wrapped with withSpan, or uploads are wholesale broken). Throw; the run's\n // traces never persisted, so nothing can be labeled and silence here is the\n // exact bug this guarantee exists to prevent.\n if (completedCount > 0 && missing.length === completedCount) {\n const serverCount =\n completeResult.traceCount !== undefined\n ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.`\n : \"\"\n throw new BitfabError(\n `Replay completed but the server has no persisted trace for any of the ${completedCount} completed item(s) (testRunId ${testRunId}).${serverCount} ` +\n `Trace uploads were awaited, so either the uploads failed (check for \"Bitfab: Failed to create\" errors above) or the replayed function is not wrapped with withSpan.`,\n )\n }\n // SOME completed items missing → per-item upload failure (transient blip,\n // one oversized payload). Log it, but return the run; the items that landed\n // can still be labeled via their lineage.\n if (missing.length > 0) {\n try {\n console.error(\n `Bitfab: server has no persisted trace for ${missing.length} of ${completedCount} completed replay item(s) (testRunId ${testRunId}). Their replay token usage is unavailable and they cannot be labeled.`,\n )\n } catch {\n // Never crash the host app\n }\n }\n }\n\n const result: ReplayResult<TReturn> = {\n items: resultItems,\n testRunId,\n testRunUrl: `${serviceUrl}${testRunUrl}`,\n }\n // Persist the enriched result two ways so the Bitfab plugin never has to parse\n // the replay's stdout (which a dependency's logging can corrupt): write it to\n // BITFAB_REPLAY_RESULT_PATH when the plugin set that env var, and stream a\n // terminal `complete` progress event. The plugin prefers the streamed event\n // and falls back to the file. The event routes through onProgress so only\n // progress-reporting runs emit it: a run with no reporter stays silent.\n await writeReplayResultFile(result)\n try {\n options?.onProgress?.({\n type: \"complete\",\n testRunId,\n completed: total,\n total,\n succeeded,\n errored,\n result,\n })\n } catch {\n // A progress reporter must never crash the replay run.\n }\n return result\n}\n\nasync function writeReplayResultFile(result: unknown): Promise<void> {\n const resultPath =\n typeof process !== \"undefined\"\n ? process.env?.BITFAB_REPLAY_RESULT_PATH\n : undefined\n if (!resultPath) {\n return\n }\n\n try {\n const [{ dirname }, { mkdir, writeFile }] = await Promise.all([\n import(\"node:path\"),\n import(\"node:fs/promises\"),\n ])\n await mkdir(dirname(resultPath), { recursive: true })\n await writeFile(resultPath, `${JSON.stringify(result, null, 2)}\\n`)\n } catch (err) {\n try {\n console.warn(\n `Bitfab: failed to write replay result to BITFAB_REPLAY_RESULT_PATH (${resultPath}): ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n } catch {\n // Never crash the host app.\n }\n }\n}\n"],"mappings":"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","names":["asRecord","takeReplaySpanCounts","DEFAULT_LIFECYCLE_TIMEOUT_MS","takeReplaySpanCounts","mapWithConcurrency"]}
1
+ {"version":3,"sources":["../src/codeChange.ts","../src/errors.ts","../src/readEnv.ts","../src/compress.ts","../src/version.generated.ts","../src/constants.ts","../src/asyncStorage.ts","../src/replayContext.ts","../src/payloadBudget.ts","../src/warnOnce.ts","../src/serializePayload.ts","../src/otel.ts","../src/unrefTimer.ts","../src/transport.ts","../src/http.ts","../src/mockOverride.ts","../src/randomUuid.ts","../src/serialize.ts","../src/replay.ts"],"sourcesContent":["import type { CodeChangeFile } from \"./http\"\n\n/**\n * Auto-capture the code change to attach to a replay, when the caller passed\n * none explicitly.\n *\n * This lives in the SDK (not a wrapper) on purpose: `replay()` is the only point\n * guaranteed to run on every replay, so capturing here works no matter how the\n * replay was launched (plugin wrapper, a hand-run script, CI). Precedence:\n *\n * 1. `BITFAB_CODE_CHANGE_PATH` file — an override a caller/tool can inject.\n * 2. `git diff` vs trunk — the default fallback.\n *\n * Both are best-effort and browser-safe: any failure (no git, no fs, not a repo,\n * bad JSON) yields `null` and the replay proceeds with no code change. The diff\n * is cumulative (whole branch vs trunk), not per-experiment; an explicit\n * `codeChangeFiles` on `replay()` always wins over this and is what carries a\n * precise per-experiment before/after.\n */\n\nexport interface ResolvedCodeChange {\n description?: string\n files?: CodeChangeFile[]\n}\n\n// Bounds so a large delta never bloats the experiment payload.\nconst MAX_FILES = 60\nconst MAX_FILE_BYTES = 500_000\nconst MAX_TOTAL_BYTES = 2_000_000\n\n// Candidate trunk refs, tried in order, when no explicit base is supplied.\nconst TRUNK_CANDIDATES = [\n \"origin/HEAD\",\n \"origin/main\",\n \"origin/master\",\n \"main\",\n \"master\",\n]\n\nconst NUL = String.fromCharCode(0)\n\n/**\n * Resolve an auto code change: the `BITFAB_CODE_CHANGE_PATH` override first,\n * then the git-vs-trunk diff. Returns null when neither yields anything.\n */\nexport async function resolveAutoCodeChange(\n label?: string,\n): Promise<ResolvedCodeChange | null> {\n if (typeof process === \"undefined\") {\n return null\n }\n if (process.env?.BITFAB_DISABLE_CODE_CHANGE_CAPTURE) {\n return null\n }\n const fromEnv = await readCodeChangeFile()\n if (fromEnv) {\n return fromEnv\n }\n return captureCodeChangeFromGit(process.cwd?.() ?? \".\", label)\n}\n\nasync function readCodeChangeFile(): Promise<ResolvedCodeChange | null> {\n const path = process.env?.BITFAB_CODE_CHANGE_PATH\n if (!path) {\n return null\n }\n try {\n const { readFile } = await import(\"node:fs/promises\")\n const parsed = JSON.parse(await readFile(path, \"utf8\"))\n // A malformed payload (non-array, or entries that aren't objects) must yield\n // no code change, never forward a bad shape to the start-replay request.\n const files =\n Array.isArray(parsed?.files) &&\n parsed.files.every(\n (f: unknown) =>\n typeof f === \"object\" && f !== null && !Array.isArray(f),\n )\n ? parsed.files\n : undefined\n const description =\n typeof parsed?.description === \"string\" ? parsed.description : undefined\n if (!files && description === undefined) {\n return null\n }\n return { description, files }\n } catch {\n return null\n }\n}\n\nasync function captureCodeChangeFromGit(\n cwd: string,\n label?: string,\n): Promise<ResolvedCodeChange | null> {\n let execFile: typeof import(\"node:child_process\").execFile\n let readFile: typeof import(\"node:fs/promises\").readFile\n try {\n ;({ execFile } = await import(\"node:child_process\"))\n ;({ readFile } = await import(\"node:fs/promises\"))\n } catch {\n // No child_process / fs (e.g. a browser bundle): capture is a no-op.\n return null\n }\n\n const git = (dir: string, args: string[]): Promise<string | null> =>\n new Promise((resolve) => {\n execFile(\n \"git\",\n args,\n // 30s timeout so a hung git (e.g. a network-touching ref op) can't\n // block the whole replay indefinitely.\n { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 30_000 },\n (err, stdout) => resolve(err ? null : stdout),\n )\n })\n\n try {\n const root = (await git(cwd, [\"rev-parse\", \"--show-toplevel\"]))?.trim()\n if (!root) {\n return null\n }\n\n const resolved = await resolveBase(git, root)\n if (!resolved) {\n return null\n }\n const { base, fromTrunk } = resolved\n\n // Size of a path on either side WITHOUT reading its contents: the git blob\n // size for `before`, a stat for the working `after`. Lets us skip an\n // oversized file before loading it into memory.\n const blobBytes = async (ref: string, path: string): Promise<number> => {\n const out = await git(root, [\"cat-file\", \"-s\", `${ref}:${path}`])\n const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN\n return Number.isFinite(n) ? n : 0\n }\n const workingBytes = async (path: string): Promise<number> => {\n try {\n const { stat } = await import(\"node:fs/promises\")\n const { join } = await import(\"node:path\")\n return (await stat(join(root, path))).size\n } catch {\n return 0\n }\n }\n\n // Tracked changes vs base. `:!.bitfab` keeps replay artifacts out.\n const tracked = await git(root, [\n \"diff\",\n \"--name-status\",\n \"--no-renames\",\n \"-z\",\n base,\n \"--\",\n \":!.bitfab\",\n ])\n // Untracked-but-not-ignored files (the diff above omits these).\n const untracked = await git(root, [\n \"ls-files\",\n \"--others\",\n \"--exclude-standard\",\n \"-z\",\n \"--\",\n \":!.bitfab\",\n ])\n\n const entries: Array<{ status: string; path: string }> = [\n ...parseNameStatusZ(tracked ?? \"\"),\n ...(untracked ?? \"\")\n .split(NUL)\n .filter((p) => p.length > 0)\n .map((path) => ({ status: \"A\", path })),\n ]\n if (entries.length === 0) {\n return null\n }\n\n const files: CodeChangeFile[] = []\n let totalBytes = 0\n for (const { status, path } of entries) {\n if (files.length >= MAX_FILES) {\n break\n }\n // Skip oversized files by size BEFORE reading their full contents, so a\n // huge changed file can't OOM/stall the replay just to be discarded.\n const beforeBytes = status === \"A\" ? 0 : await blobBytes(base, path)\n const afterBytes = status === \"D\" ? 0 : await workingBytes(path)\n if (beforeBytes > MAX_FILE_BYTES || afterBytes > MAX_FILE_BYTES) {\n continue\n }\n // Normalize CRLF -> LF on both sides: git's blob is already LF-normalized\n // (autocrlf clean), so a raw CRLF working file would otherwise skew every\n // line as changed. Comparing/storing LF keeps the diff meaningful.\n const before = (\n status === \"A\"\n ? \"\"\n : ((await git(root, [\"show\", `${base}:${path}`])) ?? \"\")\n ).replace(/\\r\\n/g, \"\\n\")\n const after = (\n status === \"D\" ? \"\" : await readWorkingFile(readFile, root, path)\n ).replace(/\\r\\n/g, \"\\n\")\n if (before === after) {\n continue\n }\n // Bytes, not chars: a multi-byte source file must count against the byte\n // cap the same way Ruby's `bytesize` does.\n const size =\n Buffer.byteLength(before, \"utf8\") + Buffer.byteLength(after, \"utf8\")\n if (\n totalBytes + size > MAX_TOTAL_BYTES ||\n looksBinary(before) ||\n looksBinary(after)\n ) {\n continue\n }\n totalBytes += size\n files.push({ path, before, after })\n }\n\n if (files.length === 0) {\n return null\n }\n\n const subject = (\n await git(root, [\"log\", \"-1\", \"--format=%s\", \"HEAD\"])\n )?.trim()\n const fileWord = files.length === 1 ? \"file\" : \"files\"\n const head = label?.trim() || subject || \"Working-tree change\"\n // \"vs trunk\" only when we actually diffed against a trunk merge-base; the\n // HEAD fallback captures uncommitted work only, so label it honestly.\n const against = fromTrunk ? \"vs trunk\" : \"uncommitted (vs HEAD)\"\n return {\n description: `${head} (${files.length} ${fileWord} changed ${against})`,\n files,\n }\n } catch {\n return null\n }\n}\n\nasync function resolveBase(\n git: (dir: string, args: string[]) => Promise<string | null>,\n root: string,\n): Promise<{ base: string; fromTrunk: boolean } | null> {\n const forced = process.env?.BITFAB_CODE_CHANGE_BASE\n if (forced && (await refExists(git, root, forced))) {\n const base =\n (await git(root, [\"merge-base\", \"HEAD\", forced]))?.trim() ||\n (await git(root, [\"rev-parse\", \"--verify\", forced]))?.trim() ||\n null\n return base ? { base, fromTrunk: true } : null\n }\n for (const candidate of TRUNK_CANDIDATES) {\n if (!(await refExists(git, root, candidate))) {\n continue\n }\n const mb = (await git(root, [\"merge-base\", \"HEAD\", candidate]))?.trim()\n if (mb) {\n return { base: mb, fromTrunk: true }\n }\n }\n return (await refExists(git, root, \"HEAD\"))\n ? { base: \"HEAD\", fromTrunk: false }\n : null\n}\n\nasync function refExists(\n git: (dir: string, args: string[]) => Promise<string | null>,\n root: string,\n ref: string,\n): Promise<boolean> {\n return (\n (await git(root, [\"rev-parse\", \"--verify\", `${ref}^{object}`])) !== null\n )\n}\n\nasync function readWorkingFile(\n readFile: typeof import(\"node:fs/promises\").readFile,\n root: string,\n path: string,\n): Promise<string> {\n try {\n const { join } = await import(\"node:path\")\n return await readFile(join(root, path), \"utf8\")\n } catch {\n return \"\"\n }\n}\n\nfunction parseNameStatusZ(\n raw: string,\n): Array<{ status: string; path: string }> {\n const parts = raw.split(NUL).filter((p) => p.length > 0)\n const out: Array<{ status: string; path: string }> = []\n for (let i = 0; i + 1 < parts.length; i += 2) {\n out.push({ status: parts[i].charAt(0), path: parts[i + 1] })\n }\n return out\n}\n\nfunction looksBinary(s: string): boolean {\n return s.slice(0, 8000).includes(NUL)\n}\n","/**\n * Shared error type for Bitfab SDK runtime errors. Lives in its own\n * module to avoid import cycles between `http.ts` and modules that need\n * to throw structured errors (e.g. `dbSnapshot.ts` validation).\n */\n\nexport class BitfabError extends Error {\n constructor(\n message: string,\n public readonly url?: string,\n /**\n * HTTP status the request failed with, when it failed with one. The\n * transport's retry policy needs the code itself (retry 408/425/429/5xx,\n * never a 4xx the server will reject again), which a formatted message\n * cannot supply. Absent for network failures and non-HTTP errors.\n */\n public readonly status?: number,\n ) {\n super(message)\n this.name = \"BitfabError\"\n }\n}\n","/**\n * Read an environment variable without throwing in non-Node runtimes\n * (browsers, edge workers) where `process` is absent. The SDK ships to\n * browsers, so this must never assume `process` exists.\n */\nexport function readEnv(name: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[name]\n }\n return undefined\n}\n","import { readEnv } from \"./readEnv.js\"\n\nconst DISABLE_COMPRESSION_ENV = \"BITFAB_DISABLE_COMPRESSION\"\n\n/**\n * Below this, compressing costs more than the saved bytes are worth, so small\n * requests (function lookups, replay status polls, single-span batches) ride\n * uncompressed.\n */\nconst MIN_COMPRESSED_BYTES = 8_192\n\nexport interface EncodedRequestBody {\n body: string | ArrayBuffer\n contentEncoding?: \"gzip\"\n}\n\n/**\n * Node's gzip, loaded dynamically so browser bundlers never have to resolve\n * `node:zlib`. Deliberately the async form: it runs on libuv's threadpool\n * rather than the event loop. Measured on 8 concurrent 1 MB bodies, the\n * synchronous form stalled the loop for 326ms and the async form for 1ms,\n * while also finishing 3.8x sooner because the threadpool compresses in\n * parallel. A tracing SDK must not block its host's event loop.\n */\nlet gzipNode: ((data: Uint8Array) => Promise<Uint8Array>) | undefined\n\ntype NodeZlib = {\n gzip: (\n data: Uint8Array,\n callback: (error: Error | null, result: Uint8Array) => void,\n ) => void\n}\n\nexport const _nodeGzipReady: Promise<void> = (\n typeof process !== \"undefined\" && process.versions?.node\n ? // The join trick hides \"node:zlib\" from static analysis so bundlers that\n // ban Node.js built-ins don't fail at build time. webpackIgnore tells\n // webpack/turbopack to emit a native import() so Node.js can resolve the\n // module at runtime. Same pattern as `asyncStorage.ts`.\n import(\n /* webpackIgnore: true */\n [\"node\", \"zlib\"].join(\":\")\n )\n .then(({ gzip }: NodeZlib) => {\n gzipNode = (data) =>\n new Promise((resolve, reject) => {\n gzip(data, (error, result) => {\n if (error) {\n reject(error)\n } else {\n resolve(result)\n }\n })\n })\n })\n .catch(() => {})\n : Promise.resolve()\n).then(() => {})\n\n/** Test seam for exercising the browser path on Node. */\nexport function _setNodeGzip(\n impl: ((data: Uint8Array) => Promise<Uint8Array>) | undefined,\n): void {\n gzipNode = impl\n}\n\nfunction toArrayBuffer(view: Uint8Array): ArrayBuffer {\n return view.buffer.slice(\n view.byteOffset,\n view.byteOffset + view.byteLength,\n ) as ArrayBuffer\n}\n\nasync function gzipViaStream(bytes: Uint8Array): Promise<ArrayBuffer> {\n const stream = new Blob([bytes as BlobPart])\n .stream()\n .pipeThrough(new CompressionStream(\"gzip\"))\n return await new Response(stream).arrayBuffer()\n}\n\n/**\n * Compression is best-effort: any failure sends the original body rather than\n * dropping the span. `CompressionStream` is absent on older browsers, so its\n * presence is checked rather than assumed.\n *\n * Returns a plain value (not a promise) whenever it can, so a request still\n * reaches `fetch` in the caller's tick rather than one microtask later. Callers\n * await the union.\n */\nexport function encodeRequestBody(\n body: string,\n): EncodedRequestBody | Promise<EncodedRequestBody> {\n if (readEnv(DISABLE_COMPRESSION_ENV)) {\n return { body }\n }\n const bytes = new TextEncoder().encode(body)\n if (bytes.byteLength < MIN_COMPRESSED_BYTES) {\n return { body }\n }\n if (gzipNode) {\n return gzipNode(bytes).then(\n (compressed) => ({\n body: toArrayBuffer(compressed),\n contentEncoding: \"gzip\" as const,\n }),\n () => ({ body }),\n )\n }\n if (typeof CompressionStream === \"undefined\") {\n return { body }\n }\n return gzipViaStream(bytes).then(\n (compressed) => ({ body: compressed, contentEncoding: \"gzip\" as const }),\n () => ({ body }),\n )\n}\n","/**\n * Auto-generated version file.\n * This file is generated by scripts/generate-version.ts during build.\n * DO NOT EDIT MANUALLY.\n */\n\n/**\n * SDK version from package.json (injected at build time)\n */\nexport const __version__ = \"0.36.3\"\n","/**\n * Constants for the Bitfab SDK.\n */\n\n/**\n * Default service URL for Bitfab API.\n */\nexport const DEFAULT_SERVICE_URL = \"https://bitfab.ai\"\n\n/**\n * SDK version from package.json (injected at build time)\n *\n * The version is generated at build time by scripts/generate-version.ts\n * to ensure compatibility with both Node.js and browser environments.\n */\nexport { __version__ } from \"./version.generated.js\"\n","/**\n * Shared AsyncLocalStorage loader.\n *\n * Provides two ways to initialize AsyncLocalStorage:\n *\n * 1. **Synchronous registration** (preferred for Node.js):\n * `asyncStorageNode.ts` calls `registerAsyncLocalStorageClass()` at module\n * evaluation time, so the class is available immediately - no async gap.\n * The `node.ts` entry point imports it before anything else.\n *\n * 2. **Async dynamic import** (fallback for the default entry point):\n * Loads `node:async_hooks` via a bundler-safe dynamic import. This is used\n * by the default `index.ts` entry point so the SDK works in browsers\n * (where the import silently fails) and in Node.js when imported via the\n * default entry point.\n *\n * ## Why the dynamic import looks like this\n *\n * We need to handle three environments:\n *\n * 1. **Pure Node.js** - `import(\"node:async_hooks\")` works natively.\n * 2. **Webpack/Turbopack (Next.js server)** - The bundler processes\n * `import()` calls at build time. The `webpackIgnore` magic comment tells\n * webpack (and turbopack) to emit a native `import()` call instead of\n * trying to resolve it, so Node.js handles it at runtime.\n * 3. **Browsers / Edge** - The `process.versions?.node` guard prevents\n * execution entirely. If it somehow runs, `.catch(() => {})` swallows\n * the failure.\n */\n\nexport interface AsyncLocalStorageLike<T> {\n getStore(): T | undefined\n run<R>(store: T, fn: () => R): R\n}\n\nlet AsyncLocalStorageClass: (new () => AsyncLocalStorageLike<unknown>) | null =\n null\nlet initDone = false\n\n/**\n * Register the AsyncLocalStorage class synchronously.\n *\n * Called by `asyncStorageNode.ts` at module evaluation time so the class\n * is available before any span is created - no async gap, no race condition.\n *\n * Safe to call multiple times; subsequent calls are no-ops.\n */\nexport function registerAsyncLocalStorageClass(\n cls: new () => AsyncLocalStorageLike<unknown>,\n): void {\n if (!AsyncLocalStorageClass) {\n AsyncLocalStorageClass = cls\n }\n initDone = true\n}\n\n/**\n * Assert that AsyncLocalStorage was registered successfully.\n *\n * Called by `node.ts` after importing `asyncStorageNode.ts` to catch\n * import-order bugs at startup rather than silently degrading to the\n * browser fallback (flat spans with no nesting).\n *\n * This should ONLY be called from the Node.js entry point where we\n * know `node:async_hooks` must be available.\n */\nexport function assertAsyncStorageRegistered(): void {\n if (!AsyncLocalStorageClass) {\n console.warn(\n \"Bitfab: AsyncLocalStorage not available - nested span context will not propagate.\",\n )\n }\n}\n\nexport const asyncStorageReady: Promise<void> = (\n typeof process !== \"undefined\" && process.versions?.node\n ? // The join trick hides \"node:async_hooks\" from static analysis so\n // bundlers that ban Node.js built-ins don't fail at build time.\n // webpackIgnore tells webpack/turbopack to emit a native import()\n // so Node.js can resolve the module at runtime.\n import(\n /* webpackIgnore: true */\n [\"node\", \"async_hooks\"].join(\":\")\n )\n .then(\n (mod: {\n AsyncLocalStorage: new () => AsyncLocalStorageLike<unknown>\n }) => {\n registerAsyncLocalStorageClass(mod.AsyncLocalStorage)\n },\n )\n .catch(() => {})\n : Promise.resolve()\n).then(() => {\n initDone = true\n})\n\nexport function isAsyncStorageInitDone(): boolean {\n return initDone\n}\n\nexport function createAsyncLocalStorage<T>(): AsyncLocalStorageLike<T> | null {\n return AsyncLocalStorageClass\n ? (new AsyncLocalStorageClass() as AsyncLocalStorageLike<T>)\n : null\n}\n","/**\n * Replay context propagation via AsyncLocalStorage.\n *\n * When set, the withSpan wrapper injects testRunId into the span payload\n * so that new spans created during replay are linked to the test run.\n * Optionally carries a mock tree so child spans can return historical\n * outputs instead of executing.\n */\n\nimport {\n type AsyncLocalStorageLike,\n asyncStorageReady,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\nimport type { MockOverride } from \"./mockOverride.js\"\n\n/**\n * A single span entry in the mock tree.\n *\n * Under the eager path (`mock: \"all\"`) `output`/`outputMeta` are populated\n * inline. Under the lazy path (`marked` / overrides) they are absent and the\n * recorded output is fetched on demand via `externalSpanId` - see\n * {@link ReplayContext.fetchSpanOutput}.\n */\nexport interface MockSpan {\n sourceSpanId: string\n /** Row id accepted by `getExternalSpan`, for the lazy per-span output fetch. */\n externalSpanId?: string\n output?: unknown\n outputMeta?: unknown\n}\n\n/**\n * Per-item DB branch resolved by the Bitfab service from the source\n * trace's `dbSnapshotRef`. Carried on the replay context so that\n * customer code reads `databaseUrl` through `getCurrentReplayBranch()`, and so\n * the process-isolated replay runner can materialize it into a `.env`\n * overlay file before customer code initializes its DB client.\n *\n * `neonBranchId` is the literal Neon branch id; passing it to\n * `releaseDbBranchLease` deletes that branch.\n */\nexport interface DbBranchLease {\n neonBranchId: string\n /** Env var name the customer's app reads, e.g. \"DATABASE_URL\". */\n envKey: string\n databaseUrl: string\n expiresAt: string\n /**\n * The instant the branch was pinned to (the source trace's wall clock).\n * Echoed back in `db_snapshot_usage` on the replayed trace's completion.\n */\n snapshotTimestamp?: string\n providerConsoleUrl?: string\n readOnly?: boolean\n /**\n * The branch's region, e.g. `aws-us-east-1`. A compute runs in its project's\n * region, so a runner elsewhere pays that round trip on every query.\n */\n region?: string\n}\n\n/**\n * Wire shape of the caller's `ReplayOptions.dbBranch`, sent to\n * `/api/sdk/replay/start` and applied per lease.\n */\nexport interface DbBranchSettings {\n minCu?: number\n maxCu?: number\n warmupSql?: string\n}\n\n/**\n * Pre-built lookup table of historical span outputs.\n * Keys are `${traceFunctionKey}:${spanName}:${callIndex}` so that repeated\n * calls with the same (key, name) are matched by call order, but spans\n * sharing only the traceFunctionKey (different name) do not collide.\n */\nexport interface MockTree {\n spans: Map<string, MockSpan>\n}\n\nexport interface ReplayContext {\n testRunId: string\n traceId?: string\n inputSourceSpanId?: string\n /**\n * External trace ID from `external_traces.id`. Used for span-chain\n * lookup against the source platform's trace tree (Braintrust, etc.).\n * NOT the same as the Bitfab `traceId` - see `sourceBitfabTraceId`.\n */\n inputSourceTraceId?: string\n /**\n * The Bitfab `traces.id` of the historical trace that produced this\n * replay item's input. This is what customer-facing surfaces (e.g.\n * `ReplayBranch.traceId`) should expose, since it's the ID the\n * customer sees in the Bitfab dashboard.\n */\n sourceBitfabTraceId?: string\n mockTree?: MockTree\n callCounters?: Map<string, number>\n mockStrategy?: \"none\" | \"all\" | \"marked\"\n /**\n * Resolved override chain for this replay, per-call overrides first then\n * registered ones (first matcher wins). Empty/absent when no overrides apply.\n */\n mockOverrides?: MockOverride[]\n /**\n * Memoized lazy fetch of a span's recorded output (deserialized), keyed by\n * `externalSpanId`. Present ONLY on the lazy path (`marked` / overrides);\n * absent under `mock: \"all\"`, where outputs are inline on the mock tree. Its\n * presence is the signal that outputs must be fetched rather than read inline.\n */\n fetchSpanOutput?: (externalSpanId: string) => Promise<unknown>\n dbBranchLease?: DbBranchLease\n /**\n * Set to true by `ReplayBranch` the first time customer code actually\n * obtains `databaseUrl` for this item. Reported on the trace completion inside\n * `db_snapshot_usage` so the server can distinguish \"branch was\n * provisioned and exposed\" from \"branch URL was actually consumed\".\n * Only an explicit `databaseUrl` read may set it. A path that hands the URL\n * over by other means (e.g. a process-isolated runner writing an env\n * overlay) must leave it alone: setting it there would make every such\n * replay report `accessed` for free, and the flag would stop separating\n * \"branch was used\" from \"branch was offered\".\n */\n dbSnapshotAccessed?: boolean\n}\n\nlet replayContextStorage: AsyncLocalStorageLike<ReplayContext | null> | null =\n null\nconst REPLAY_CONTEXT_STORAGE_SYMBOL = Symbol.for(\"bitfab.replayContextStorage\")\n\nexport const replayContextReady: Promise<void> = asyncStorageReady.then(() => {\n const shared = globalThis as typeof globalThis & Record<symbol, unknown>\n const existing = shared[REPLAY_CONTEXT_STORAGE_SYMBOL] as\n | AsyncLocalStorageLike<ReplayContext | null>\n | undefined\n if (existing) {\n replayContextStorage = existing\n return\n }\n const created = createAsyncLocalStorage<ReplayContext | null>()\n if (created) {\n shared[REPLAY_CONTEXT_STORAGE_SYMBOL] = created\n replayContextStorage = created\n }\n})\n\n/** Get the current replay context, if any. */\nexport function getReplayContext(): ReplayContext | null {\n return replayContextStorage?.getStore() ?? null\n}\n\n/** Run a function within a replay context. */\nexport function runWithReplayContext<T>(ctx: ReplayContext, fn: () => T): T {\n if (replayContextStorage) {\n return replayContextStorage.run(ctx, fn)\n }\n return fn()\n}\n","/**\n * The ceiling on a span's encoded carrier, and the trimming that enforces it.\n *\n * A span's whole payload (input, output, contexts, prompt, metadata) ships as\n * a single `bitfab.payload` string attribute, and the exporter drops any\n * carrier that exceeds the per-request byte ceiling outright rather than\n * trimming it. Capping each value on its own cannot prevent that: two values\n * that each fit can still add up to an undeliverable span. So the budget is\n * enforced on the whole span, and an oversized one ships with its largest\n * fields stubbed instead of vanishing.\n *\n * The budget is measured on the *carrier* (the payload re-escaped into the\n * OTLP attribute), not on the payload body, because the carrier is what the\n * exporter weighs. Bounding the body instead leaves escape-heavy content to\n * blow the request ceiling anyway: a body of escaped JSON, Windows paths, or\n * regexes is nearly all backslashes, and every one of them doubles. Measured\n * on a body sized exactly to a 2.4 MB cap, prose produced a 2.4 MB carrier but\n * backslash-dense content produced 4.8 MB, which the exporter dropped.\n *\n * 2.8 MB leaves room beneath the 3 MB request ceiling for the span and request\n * envelopes wrapped around the attribute.\n */\nexport const MAX_SPAN_CARRIER_BYTES = 2_800_000\n\nconst textEncoder =\n typeof TextEncoder !== \"undefined\" ? new TextEncoder() : null\n\nexport function byteLength(value: string): number {\n return textEncoder ? textEncoder.encode(value).length : value.length\n}\n\n/**\n * The byte length `body` occupies once re-escaped as a JSON string value.\n *\n * `body` is itself JSON text, so the first encode already replaced every\n * control character with a `\\uXXXX` sequence, leaving only `\"` and `\\` to\n * escape at one extra byte each.\n *\n * Counts UTF-8 width and escapes in the same pass and allocates nothing.\n * `TextEncoder.encode().length` would be the obvious way to get the byte count,\n * but it copies the entire body into a fresh array just to read its length,\n * which on a multi-megabyte span costs more than producing the body did.\n */\nexport function carrierByteLength(body: string): number {\n return carrierBytesOf(textEncoder ? textEncoder.encode(body) : null, body)\n}\n\n/**\n * Counts escapes over the UTF-8 bytes rather than the UTF-16 string. Bytes\n * `0x22` and `0x5c` are unambiguous there (a multi-byte sequence never uses a\n * byte below `0x80`), so a flat byte scan is exact, and it reuses the array the\n * byte count already had to produce instead of walking the string a second\n * time. Measured ~2x faster than the equivalent `charCodeAt` loop.\n */\nfunction carrierBytesOf(encoded: Uint8Array | null, body: string): number {\n if (!encoded) {\n // No TextEncoder (a browser old enough to lack it). Fall back to the string,\n // where `length` is the best available byte estimate.\n return body.length + 2\n }\n let extra = 2 // the quotes wrapping the attribute value\n for (let i = 0; i < encoded.length; i++) {\n const byte = encoded[i]\n if (byte === 34 || byte === 92) {\n extra += 1 // `\"` and `\\` take a leading backslash\n } else if (byte < 0x20) {\n extra +=\n byte === 8 || byte === 9 || byte === 10 || byte === 12 || byte === 13\n ? 1 // \\b \\f \\n \\r \\t\n : 5 // \\uXXXX\n }\n }\n return encoded.length + extra\n}\n\n/**\n * The most carrier bytes one UTF-16 code unit of a *JSON body* can become.\n *\n * A unit is at most 3 UTF-8 bytes, and the only characters that grow under\n * escaping are `\"` and `\\`, which are one byte and become two. A unit cannot be\n * both, so 3 is the ceiling. This holds because every caller passes the output\n * of a JSON encoder, which by specification never emits a raw control character\n * (the case that would otherwise expand to a 6-byte `\\uXXXX`); the invariant is\n * pinned by a test so a future caller that broke it would fail loudly rather\n * than silently ship an oversized carrier.\n */\nconst MAX_BYTES_PER_UNIT = 3\n\n/**\n * Whether `body` fits the carrier budget, escalating only as far as it must.\n *\n * `body.length` is O(1) and brackets the answer for both ordinary spans (far\n * under the budget) and hopeless ones (already past it on raw length alone),\n * which is every span in normal traffic: neither case touches the string. Only\n * a body near the budget is measured exactly, and that costs one encode plus\n * one byte scan.\n */\nexport function fitsCarrierBudget(body: string): boolean {\n const units = body.length\n if (units * MAX_BYTES_PER_UNIT + 2 <= MAX_SPAN_CARRIER_BYTES) {\n return true\n }\n if (units + 2 > MAX_SPAN_CARRIER_BYTES) {\n return false\n }\n return carrierByteLength(body) <= MAX_SPAN_CARRIER_BYTES\n}\n\n/**\n * Span fields that identify the span rather than carry user data. Trimming one\n * would leave a span that no longer says what it is, so they stay whatever the\n * payload costs.\n */\nconst STRUCTURAL_SPAN_KEYS = new Set([\n \"name\",\n \"type\",\n \"function_name\",\n \"error_source\",\n])\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\ninterface Candidate {\n container: Record<string, unknown>\n key: string\n size: number\n}\n\n/**\n * The records holding user data, cloned so trimming never mutates the caller's\n * objects. Returns the payload copy to encode plus the containers to trim.\n */\nfunction cloneTrimmable(payload: Record<string, unknown>): {\n copy: Record<string, unknown>\n containers: Record<string, unknown>[]\n} {\n const copy = { ...payload }\n const containers: Record<string, unknown>[] = []\n\n const spanData = asRecord(copy.span_data)\n if (spanData) {\n const clone = { ...spanData }\n copy.span_data = clone\n containers.push(clone)\n }\n\n const rawSpan = asRecord(copy.rawSpan)\n const rawSpanData = rawSpan && asRecord(rawSpan.span_data)\n if (rawSpan && rawSpanData) {\n const clone = { ...rawSpanData }\n copy.rawSpan = { ...rawSpan, span_data: clone }\n containers.push(clone)\n }\n\n // No span_data anywhere: a trace-level or otherwise unfamiliar payload. Trim\n // its own fields rather than give up, so an oversized body still ships.\n if (containers.length === 0) {\n containers.push(copy)\n }\n\n return { copy, containers }\n}\n\nfunction collectCandidates(containers: Record<string, unknown>[]): Candidate[] {\n const candidates: Candidate[] = []\n for (const container of containers) {\n for (const [key, value] of Object.entries(container)) {\n if (STRUCTURAL_SPAN_KEYS.has(key) || value == null) {\n continue\n }\n let size: number\n try {\n size = byteLength(JSON.stringify(value) ?? \"\")\n } catch {\n continue\n }\n candidates.push({ container, key, size })\n }\n }\n return candidates.sort((a, b) => b.size - a.size)\n}\n\n/**\n * Stub the largest payload fields until the encoded body fits the budget.\n *\n * Returns the trimmed payload and the names of the fields that were stubbed, or\n * `undefined` when nothing could be trimmed (the caller then ships the\n * oversized body and lets the exporter report the drop, which is still better\n * than silently emptying a span).\n */\nexport function trimPayloadToBudget(\n payload: Record<string, unknown>,\n encode: (value: Record<string, unknown>) => string,\n): { value: Record<string, unknown>; trimmed: string[] } | undefined {\n const { copy, containers } = cloneTrimmable(payload)\n const candidates = collectCandidates(containers)\n if (candidates.length === 0) {\n return undefined\n }\n\n const trimmed: string[] = []\n for (const candidate of candidates) {\n candidate.container[candidate.key] =\n `<unserializable: too_large_${candidate.size}_bytes>`\n trimmed.push(candidate.key)\n let body: string\n try {\n body = encode(copy)\n } catch {\n return undefined\n }\n if (fitsCarrierBudget(body)) {\n return { value: copy, trimmed }\n }\n }\n return undefined\n}\n\n/**\n * Record a trim in the payload's own `errors`, which is what the server reads\n * to flag a trace as incomplete.\n */\nexport function markPayloadTrimmed(\n value: Record<string, unknown>,\n trimmed: string[],\n): void {\n const existing = Array.isArray(value.errors) ? value.errors : []\n value.errors = [\n ...existing,\n {\n source: \"sdk\",\n step: \"payload_budget\",\n error: `trimmed oversized field(s) to fit the ${MAX_SPAN_CARRIER_BYTES}-byte span carrier budget: ${[\n ...new Set(trimmed),\n ].join(\", \")}`,\n },\n ]\n}\n","/**\n * Emit a `console.warn` at most once per distinct `key` for the life of the\n * process.\n *\n * The SDK must NEVER crash a host app, so every failure on the user's path\n * degrades silently (a span is dropped, a call runs untraced, a payload is\n * stubbed). Silent is safe but undebuggable: a user who suddenly has no traces,\n * or sees `<unserializable>` in a span, has no signal as to why. A one-time\n * warning per distinct issue restores that signal without spamming the console\n * from a hot path.\n *\n * Keys should identify the specific degradation (e.g. include the traced\n * function key) so each distinct issue warns once, not just the first one seen.\n */\nconst warned = new Set<string>()\n\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key)) {\n return\n }\n warned.add(key)\n try {\n console.warn(`[bitfab] ${message}`)\n } catch {\n // Logging must never crash the host app (e.g. a closed/replaced console).\n }\n}\n\n/** Test-only: clear the dedup set so a warning can fire again. */\nexport function _resetWarnOnce(): void {\n warned.clear()\n}\n","/**\n * Defensive payload encoding, shared by the HTTP path and the OTel carrier\n * path. Lives in its own module because `otel.ts` needs it and importing it\n * from `http.ts` would close an http -> transport -> otel -> http cycle.\n */\n\nimport {\n fitsCarrierBudget,\n MAX_SPAN_CARRIER_BYTES,\n markPayloadTrimmed,\n trimPayloadToBudget,\n} from \"./payloadBudget.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\n/**\n * JSON-encode a request body without ever throwing on a stray value, and\n * within the per-span byte budget.\n *\n * Upstream serialization (`serializeValue` / the LangGraph handler's\n * `safeSerialize`) should already have flattened user data. This is the\n * boundary backstop: if anything non-serializable still slips through\n * (BigInt, function, symbol, circular ref), it is stubbed in place instead of\n * letting `JSON.stringify` throw and drop the whole span/trace silently.\n *\n * The fast path is a plain `JSON.stringify`; the sanitizing replacer only runs\n * when that throws, so happy-path payloads (and shared non-circular refs) are\n * untouched. Returns `dropped` (the stubbed type names) so the caller can warn\n * loudly rather than ship a degraded payload in silence.\n */\nexport function serializePayloadBody(payload: Record<string, unknown>): {\n body: string\n dropped: string[]\n} {\n const encoded = encodePayloadBody(payload)\n if (fitsCarrierBudget(encoded.body)) {\n return { body: encoded.body, dropped: encoded.dropped }\n }\n return applyPayloadBudget(encoded)\n}\n\n/**\n * Trim an over-budget payload, preferring its largest fields, so the span\n * ships degraded rather than being dropped whole by the exporter.\n *\n * Trims the value that was actually encoded, not the caller's original: a\n * cyclic or otherwise non-encodable field cannot be sized (`JSON.stringify`\n * throws on it), so on the original graph the biggest field is skipped as a\n * trim candidate and the oversized body ships anyway. The sanitized copy has\n * those values already replaced with stubs, so every field is sizeable.\n */\nfunction applyPayloadBudget(encoded: EncodedPayload): {\n body: string\n dropped: string[]\n} {\n const result = encoded.value\n ? trimPayloadToBudget(\n encoded.value,\n (value) => encodePayloadBody(value).body,\n )\n : undefined\n if (!result) {\n return { body: encoded.body, dropped: encoded.dropped }\n }\n warnOnce(\n \"payload:over-budget\",\n `a span payload exceeded the ${MAX_SPAN_CARRIER_BYTES}-byte carrier budget; its largest field(s) (${[\n ...new Set(result.trimmed),\n ].join(\n \", \",\n )}) were replaced with placeholders so the span still ships. The span is incomplete and may not be replayable.`,\n )\n markPayloadTrimmed(result.value, result.trimmed)\n // `dropped` names values that could not be encoded, which drives the\n // \"non-serializable value(s)\" warning. A budget trim is a size decision, not\n // an encoding failure, and already has its own warning and `payload_budget`\n // error entry, so it must not be reported as one.\n return {\n body: encodePayloadBody(result.value).body,\n dropped: encoded.dropped,\n }\n}\n\ninterface EncodedPayload {\n body: string\n dropped: string[]\n /**\n * The value the body was encoded from: the payload itself, or its sanitized\n * copy. Undefined when the encoded value isn't an object, which leaves\n * nothing with named fields to trim.\n */\n value: Record<string, unknown> | undefined\n}\n\nfunction encodePayloadBody(payload: Record<string, unknown>): EncodedPayload {\n try {\n return { body: JSON.stringify(payload), dropped: [], value: payload }\n } catch {\n const dropped: string[] = []\n // An explicit backtracking walk, not a JSON.stringify replacer: a replacer\n // gets no subtree-exit signal, so a single WeakSet would mis-tag a shared\n // (DAG) reference under sibling keys as a cycle. Tracking only the\n // current-path ancestors stubs real cycles while serializing DAGs in full.\n const sanitize = (value: unknown, seen: WeakSet<object>): unknown => {\n const t = typeof value\n if (\n value === null ||\n t === \"string\" ||\n t === \"number\" ||\n t === \"boolean\"\n ) {\n return value\n }\n if (t === \"bigint\") {\n dropped.push(\"BigInt\")\n return \"<unserializable: BigInt>\"\n }\n if (t === \"function\") {\n const name = (value as { name?: string }).name || \"Function\"\n dropped.push(name)\n return `<unserializable: ${name}>`\n }\n if (t === \"symbol\") {\n dropped.push(\"Symbol\")\n return \"<unserializable: Symbol>\"\n }\n if (t !== \"object\") {\n return undefined // e.g. undefined; JSON omits/normalizes it\n }\n const obj = value as object\n const className =\n (obj as { constructor?: { name?: string } }).constructor?.name ||\n \"object\"\n if (seen.has(obj)) {\n dropped.push(className)\n return `<cycle: ${className}>`\n }\n seen.add(obj)\n let result: unknown\n if (Array.isArray(obj)) {\n result = obj.map((item) => sanitize(item, seen))\n } else if (typeof (obj as { toJSON?: unknown }).toJSON === \"function\") {\n try {\n result = sanitize((obj as { toJSON(): unknown }).toJSON(), seen)\n } catch {\n dropped.push(className)\n result = `<unserializable: ${className}>`\n }\n } else {\n try {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(obj)) {\n out[k] = sanitize(v, seen)\n }\n result = out\n } catch {\n // A throwing getter or Proxy on `obj` can make `Object.entries`\n // throw. Stub just this object instead of failing the whole payload\n // (which would drop every span field). Mirrors the toJSON branch.\n warnOnce(\n \"payload:field-getter-threw\",\n \"a value with a throwing getter/proxy could not be serialized into a span payload; it was replaced with a placeholder. The span still ships with its other fields intact.\",\n )\n dropped.push(className)\n result = `<unserializable: ${className}>`\n }\n }\n seen.delete(obj) // backtrack: only ancestors stay tracked\n return result\n }\n let sanitized: unknown\n try {\n sanitized = sanitize(payload, new WeakSet())\n } catch (error) {\n // Truly pathological. Still never drop silently: send a marker body.\n const message = error instanceof Error ? error.message : String(error)\n const marker = { error: `payload_serialize_failed: ${message}` }\n return { body: JSON.stringify(marker), dropped, value: marker }\n }\n // Keep the server-side signal that the SDK had to stub values, so the\n // trace can be flagged as possibly incomplete / not replayable, while the\n // span content (everything that did serialize) is preserved.\n const isRecord =\n typeof sanitized === \"object\" &&\n sanitized !== null &&\n !Array.isArray(sanitized)\n if (dropped.length > 0 && isRecord) {\n const obj = sanitized as Record<string, unknown>\n const existing = Array.isArray(obj.errors) ? obj.errors : []\n obj.errors = [\n ...existing,\n {\n source: \"sdk\",\n step: \"json_serialize\",\n error: `stubbed non-serializable value(s): ${[\n ...new Set(dropped),\n ].join(\", \")}`,\n },\n ]\n }\n return {\n body: JSON.stringify(sanitized),\n dropped,\n value: isRecord ? (sanitized as Record<string, unknown>) : undefined,\n }\n }\n}\n","/**\n * OpenTelemetry transport for Bitfab spans and trace completions.\n *\n * OTel is used here as a queueing, batching, and delivery engine only. Bitfab\n * keeps ownership of logical trace identity: every payload travels inside an\n * internal *carrier* span whose `bitfab.payload` attribute holds the encoded\n * Bitfab body, and the server reconstructs the stored tree from that payload\n * rather than from the carrier's OTel topology. The provider and processor are\n * private to each client, so an application's own OTel traces are never mixed\n * into Bitfab traces and the global provider is never replaced.\n */\n\nimport { type Span, SpanStatusCode, type Tracer } from \"@opentelemetry/api\"\nimport {\n type ExportResult,\n ExportResultCode,\n type InstrumentationScope,\n} from \"@opentelemetry/core\"\nimport { resourceFromAttributes } from \"@opentelemetry/resources\"\nimport {\n AlwaysOnSampler,\n BasicTracerProvider,\n BatchSpanProcessor,\n type ReadableSpan,\n type SpanExporter,\n} from \"@opentelemetry/sdk-trace-base\"\nimport { __version__ } from \"./constants.js\"\nimport { BitfabError } from \"./errors.js\"\nimport { byteLength } from \"./payloadBudget.js\"\nimport { readEnv } from \"./readEnv.js\"\nimport { serializePayloadBody } from \"./serializePayload.js\"\nimport type {\n DirectBatchSender,\n TraceOperation,\n TraceTransport,\n} from \"./transportTypes.js\"\nimport { unrefTimer } from \"./unrefTimer.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\nconst OPERATION_ATTRIBUTE = \"bitfab.operation\"\nconst PAYLOAD_ATTRIBUTE = \"bitfab.payload\"\nconst OTLP_TRACES_ENDPOINT = \"/api/sdk/otel/v1/traces\"\nconst MAX_EXPORT_REQUEST_BYTES = 3_000_000\nconst MAX_REQUEST_BYTES_ENV = \"BITFAB_OTEL_MAX_REQUEST_BYTES\"\nconst EXPORT_CONCURRENCY_ENV = \"BITFAB_OTEL_EXPORT_CONCURRENCY\"\nconst MAX_QUEUE_SIZE = 8_192\nconst DIRECT_MAX_EXPORT_BATCH_SIZE = 512\nconst DIRECT_MAX_REQUEST_BATCH_SIZE = 8\nconst DEFAULT_EXPORT_CONCURRENCY = 32\nconst MAX_EXPORT_CONCURRENCY = 64\nconst SCHEDULE_DELAY_MILLIS = 5_000\nconst EXPORT_TIMEOUT_MILLIS = 30_000\nconst RETRY_DELAY_MILLIS = 100\nconst MAX_SEND_ATTEMPTS = 3\nconst DEFAULT_LIFECYCLE_TIMEOUT_MS = 30_000\n\nconst RETRYABLE_STATUSES = new Set([408, 425, 429])\n\nconst liveTransports = new Set<OtelBatchTransport>()\nconst traceSubmissionSpanIds = new Map<string, Set<string>>()\nconst replayTraceSubmissions = new Set<string>()\nlet submissionCounter = 0\n\nfunction readBoundedIntEnv(\n name: string,\n max: number,\n fallback: number,\n warnKey: string,\n): number {\n const raw = readEnv(name)\n if (raw === undefined) {\n return fallback\n }\n const value = Number(raw)\n if (Number.isInteger(value) && value > 0 && value <= max) {\n return value\n }\n warnOnce(\n warnKey,\n `${name} must be a positive integer no greater than ${max}; using ${fallback}`,\n )\n return fallback\n}\n\nfunction logError(message: string, error?: unknown): void {\n try {\n if (error === undefined) {\n console.error(`[bitfab] ${message}`)\n } else {\n console.error(`[bitfab] ${message}`, error)\n }\n } catch {\n // Logging must never crash the host app.\n }\n}\n\n/**\n * Record what a payload contributes to its replay trace's expected persisted\n * span count. Counts unique source span IDs rather than delivery attempts, so\n * a duplicate submission cannot make replay wait for a duplicate database row\n * that the server's idempotent span key will never create.\n */\nfunction recordTraceSubmission(\n operation: TraceOperation,\n payload: Record<string, unknown>,\n): void {\n const sourceTraceId = resolveSourceTraceId(payload)\n if (sourceTraceId === undefined) {\n return\n }\n\n if (operation === \"external_span\") {\n const rawSpan = asRecord(payload.rawSpan)\n if (typeof rawSpan?.id !== \"string\") {\n submissionCounter += 1\n }\n const sourceSpanId =\n typeof rawSpan?.id === \"string\"\n ? rawSpan.id\n : `submission-${submissionCounter}`\n const existing = traceSubmissionSpanIds.get(sourceTraceId)\n if (existing) {\n existing.add(sourceSpanId)\n } else {\n traceSubmissionSpanIds.set(sourceTraceId, new Set([sourceSpanId]))\n }\n return\n }\n\n if (payload.completed !== true) {\n return\n }\n if (typeof payload.testRunId === \"string\") {\n replayTraceSubmissions.add(sourceTraceId)\n if (!traceSubmissionSpanIds.has(sourceTraceId)) {\n traceSubmissionSpanIds.set(sourceTraceId, new Set())\n }\n } else {\n traceSubmissionSpanIds.delete(sourceTraceId)\n }\n}\n\n/**\n * Consume the per-trace expected span counts for a finished replay run. Only\n * traces that actually submitted a replay completion are returned, so a caller\n * never waits on a trace the transport never saw.\n */\nexport function takeReplaySpanCounts(\n traceIds: string[],\n): Record<string, number> {\n const counts: Record<string, number> = {}\n for (const traceId of traceIds) {\n if (!replayTraceSubmissions.has(traceId)) {\n continue\n }\n counts[traceId] = traceSubmissionSpanIds.get(traceId)?.size ?? 0\n traceSubmissionSpanIds.delete(traceId)\n replayTraceSubmissions.delete(traceId)\n }\n return counts\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\nfunction resolveSourceTraceId(\n payload: Record<string, unknown>,\n): string | undefined {\n if (typeof payload.sourceTraceId === \"string\") {\n return payload.sourceTraceId\n }\n const rawTrace = asRecord(payload.externalTrace) ?? asRecord(payload.rawTrace)\n return typeof rawTrace?.id === \"string\" ? rawTrace.id : undefined\n}\n\nfunction otlpValue(value: unknown): Record<string, unknown> {\n if (typeof value === \"boolean\") {\n return { boolValue: value }\n }\n if (typeof value === \"number\") {\n return Number.isInteger(value)\n ? { intValue: String(value) }\n : { doubleValue: value }\n }\n if (typeof value === \"string\") {\n return { stringValue: value }\n }\n if (Array.isArray(value)) {\n return { arrayValue: { values: value.map(otlpValue) } }\n }\n return { stringValue: String(value) }\n}\n\nfunction otlpAttributes(\n attributes: Record<string, unknown> | undefined,\n): Record<string, unknown>[] {\n if (!attributes) {\n return []\n }\n return Object.entries(attributes)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => ({ key, value: otlpValue(value) }))\n}\n\n/**\n * Nanoseconds since the epoch as a decimal string. Built by concatenation\n * rather than arithmetic because the value exceeds `Number.MAX_SAFE_INTEGER`,\n * so multiplying seconds out would silently lose the low digits.\n */\nfunction hrTimeToNanoString(time: [number, number] | undefined): string {\n if (!time) {\n return \"0\"\n }\n return `${time[0]}${String(time[1]).padStart(9, \"0\")}`\n}\n\nfunction spanToOtlp(span: ReadableSpan): Record<string, unknown> {\n const spanContext = span.spanContext()\n const result: Record<string, unknown> = {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n name: span.name,\n kind: span.kind + 1,\n startTimeUnixNano: hrTimeToNanoString(span.startTime),\n endTimeUnixNano: hrTimeToNanoString(span.endTime),\n attributes: otlpAttributes(span.attributes as Record<string, unknown>),\n droppedAttributesCount: span.droppedAttributesCount,\n droppedEventsCount: span.droppedEventsCount,\n droppedLinksCount: span.droppedLinksCount,\n status: {\n code: span.status.code,\n ...(span.status.message ? { message: span.status.message } : {}),\n },\n flags: spanContext.traceFlags,\n }\n const parentSpanId = span.parentSpanContext?.spanId\n if (parentSpanId) {\n result.parentSpanId = parentSpanId\n }\n if (spanContext.traceState) {\n result.traceState = spanContext.traceState.serialize()\n }\n return result\n}\n\n/**\n * A span encoded exactly as it will appear on the wire, carrying its own byte\n * count. Encoding once and remembering the size is what keeps request packing\n * linear: sizing a candidate batch by re-encoding the whole request re-escapes\n * every carrier's `bitfab.payload` string on every span considered.\n */\ninterface EncodedSpan {\n json: string\n size: number\n}\n\ninterface RequestBatch {\n spans: EncodedSpan[]\n size: number\n}\n\n/**\n * The invariant head and tail of an OTLP request for one export window. Key\n * order matches what `JSON.stringify` emits for the equivalent object, so a\n * body assembled by concatenation is byte-identical to encoding that object.\n */\ninterface RequestEnvelope {\n head: string\n tail: string\n size: number\n}\n\n/** The comma `join` puts between adjacent spans in the request's span list. */\nconst SPAN_SEPARATOR_BYTES = 1\n\nfunction encodeSpan(span: ReadableSpan): EncodedSpan {\n const json = JSON.stringify(spanToOtlp(span))\n return { json, size: byteLength(json) }\n}\n\nfunction requestEnvelope(first: ReadableSpan): RequestEnvelope {\n const scope = first.instrumentationScope as InstrumentationScope\n const resource = JSON.stringify({\n attributes: otlpAttributes(\n first.resource.attributes as Record<string, unknown>,\n ),\n })\n const scopeJson = JSON.stringify({\n name: scope.name,\n version: scope.version ?? \"\",\n })\n const head = `{\"resourceSpans\":[{\"resource\":${resource},\"scopeSpans\":[{\"scope\":${scopeJson},\"spans\":[`\n const tail = \"]}]}]}\"\n return { head, tail, size: byteLength(head) + byteLength(tail) }\n}\n\nfunction encodeRequest(\n envelope: RequestEnvelope,\n spans: EncodedSpan[],\n): string {\n return (\n envelope.head + spans.map((span) => span.json).join(\",\") + envelope.tail\n )\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms)\n unrefTimer(timer)\n })\n}\n\n/**\n * Race `work` against `timeoutMs`. Resolves `false` when the deadline wins, so\n * a wedged export can never hold a flush or shutdown open past its budget.\n */\nasync function withDeadline(\n work: Promise<boolean>,\n timeoutMs: number,\n): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n work,\n new Promise<boolean>((resolve) => {\n timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs))\n unrefTimer(timer)\n }),\n ])\n } finally {\n if (timer) {\n clearTimeout(timer)\n }\n }\n}\n\n/** Run `task` over `items` with at most `limit` in flight at any moment. */\nasync function mapWithConcurrency<T, R>(\n items: T[],\n limit: number,\n task: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n const workers = Array.from(\n { length: Math.min(Math.max(limit, 1), items.length) },\n async () => {\n while (next < items.length) {\n const index = next\n next += 1\n results[index] = await task(items[index])\n }\n },\n )\n await Promise.all(workers)\n return results\n}\n\nclass OtlpPayloadTooLargeError extends Error {}\nclass OtlpPartialSuccessError extends Error {}\n\nfunction responseStatus(error: unknown): number | undefined {\n return error instanceof BitfabError ? error.status : undefined\n}\n\nfunction isRetryable(error: unknown): boolean {\n const status = responseStatus(error)\n if (status === undefined) {\n return true\n }\n return RETRYABLE_STATUSES.has(status) || status >= 500\n}\n\n/**\n * Direct delivery to Bitfab's OTLP/JSON ingress.\n *\n * OTel hands this exporter one batch as a candidate window. The window is\n * repacked into requests bounded by both a carrier count and the exact encoded\n * request size, and those complete requests are sent concurrently. That keeps\n * OTel's queue, scheduling, force-flush and shutdown while restoring the small\n * independent requests Bitfab's serverless ingress is built to scale.\n */\nexport class BitfabSpanExporter implements SpanExporter {\n constructor(\n private readonly directSender: DirectBatchSender,\n private readonly maxRequestBytes: number,\n private readonly maxRequestBatchSize: number,\n private readonly exportConcurrency: number,\n ) {}\n\n export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n void this.exportAsync(spans).then(\n (succeeded) => {\n resultCallback({\n code: succeeded ? ExportResultCode.SUCCESS : ExportResultCode.FAILED,\n })\n },\n (error) => {\n resultCallback({ code: ExportResultCode.FAILED, error })\n },\n )\n }\n\n private async exportAsync(spans: ReadableSpan[]): Promise<boolean> {\n if (spans.length === 0) {\n return true\n }\n let encoded: EncodedSpan[]\n let envelope: RequestEnvelope\n try {\n encoded = spans.map(encodeSpan)\n envelope = requestEnvelope(spans[0])\n } catch (error) {\n logError(\"failed to encode an OpenTelemetry span batch\", error)\n return false\n }\n\n const batches = this.buildRequestBatches(envelope, encoded)\n const results = await mapWithConcurrency(\n batches,\n this.exportConcurrency,\n (batch) => this.send(envelope, batch),\n )\n return results.every(Boolean)\n }\n\n private buildRequestBatches(\n envelope: RequestEnvelope,\n spans: EncodedSpan[],\n ): RequestBatch[] {\n const batches: RequestBatch[] = []\n let current: EncodedSpan[] = []\n let size = envelope.size\n\n for (const span of spans) {\n const addition =\n span.size + (current.length > 0 ? SPAN_SEPARATOR_BYTES : 0)\n if (\n current.length > 0 &&\n (current.length >= this.maxRequestBatchSize ||\n size + addition > this.maxRequestBytes)\n ) {\n batches.push({ spans: current, size })\n current = []\n size = envelope.size\n }\n current.push(span)\n size += span.size + (current.length > 1 ? SPAN_SEPARATOR_BYTES : 0)\n }\n\n if (current.length > 0) {\n batches.push({ spans: current, size })\n }\n return batches\n }\n\n private async send(\n envelope: RequestEnvelope,\n batch: RequestBatch,\n ): Promise<boolean> {\n if (batch.size > this.maxRequestBytes) {\n logError(\n \"a single OpenTelemetry span exceeded the configured request-size target and could not be exported\",\n )\n return false\n }\n try {\n await this.sendWithRetries(encodeRequest(envelope, batch.spans))\n return true\n } catch (error) {\n if (error instanceof OtlpPayloadTooLargeError) {\n logError(\n batch.spans.length === 1\n ? \"a single OpenTelemetry span exceeded the ingestion request limit and could not be exported\"\n : \"an OpenTelemetry span batch exceeded the ingestion request limit and could not be exported\",\n )\n return false\n }\n if (error instanceof OtlpPartialSuccessError) {\n return false\n }\n logError(\"failed to export an OpenTelemetry span batch\", error)\n return false\n }\n }\n\n /**\n * Retries transient failures. Span and trace-completion carriers are safe to\n * retry: the server keys them idempotently on `sourceSpanId`/`sourceTraceId`,\n * so a duplicate delivery cannot create a duplicate row.\n *\n * KNOWN LIMITATION: an `internal_trace` (a `call()` BAML trace) carries no\n * such key, so retrying a batch that holds one can create a duplicate trace -\n * including when a request times out client-side but the server goes on to\n * persist it. Accepted deliberately for now, matching the other SDKs, rather\n * than skipping retries for a whole batch or inventing an idempotency scheme\n * the server does not yet understand. The fix is a client-supplied\n * idempotency key that ingestion dedupes on.\n */\n private async sendWithRetries(body: string): Promise<void> {\n for (let attempt = 0; attempt < MAX_SEND_ATTEMPTS; attempt += 1) {\n try {\n const response = await this.directSender(\n OTLP_TRACES_ENDPOINT,\n body,\n EXPORT_TIMEOUT_MILLIS,\n )\n const partialSuccess = asRecord(response?.partialSuccess)\n const rejected = partialSuccess?.rejectedSpans\n if (rejected !== undefined && rejected !== \"0\" && rejected !== 0) {\n logError(\n `OTLP ingestion rejected ${rejected} span(s): ${\n partialSuccess?.errorMessage ?? \"no reason provided\"\n }`,\n )\n throw new OtlpPartialSuccessError()\n }\n return\n } catch (error) {\n if (error instanceof OtlpPartialSuccessError) {\n throw error\n }\n if (responseStatus(error) === 413) {\n throw new OtlpPayloadTooLargeError()\n }\n if (attempt === MAX_SEND_ATTEMPTS - 1 || !isRetryable(error)) {\n throw error\n }\n await delay(RETRY_DELAY_MILLIS)\n }\n }\n }\n\n async shutdown(): Promise<void> {}\n\n async forceFlush(): Promise<void> {}\n}\n\n/**\n * Counts export failures so `flush` can answer \"was this delivered?\" instead of\n * only \"did the processor queue drain?\". Without it a flush would report\n * success for a batch the exporter dropped, and replay would finalize a run\n * whose traces never landed.\n */\nclass DeliveryTrackingExporter implements SpanExporter {\n // Deliberately unscoped, matching the Python SDK. An export can outlive\n // OTel's export timeout and report failure after the flush that was waiting\n // on it already returned, so that failure surfaces on the NEXT flush instead.\n // That over-reports: a good flush can inherit an older failure. The\n // alternative - discarding failures from completed flush windows - under-\n // reports, and `BatchSpanProcessor` also runs scheduled exports that belong\n // to no flush at all, so their failures would vanish entirely. For a\n // telemetry SDK a false \"flush failed\" is investigable; a false \"flush\n // succeeded\" silently loses traces. We take the noisy direction on purpose.\n private failedExports = 0\n\n constructor(private readonly exporter: SpanExporter) {}\n\n export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void,\n ): void {\n try {\n this.exporter.export(spans, (result) => {\n if (result.code !== ExportResultCode.SUCCESS) {\n this.failedExports += 1\n }\n resultCallback(result)\n })\n } catch (error) {\n this.failedExports += 1\n resultCallback({ code: ExportResultCode.FAILED, error: error as Error })\n }\n }\n\n takeFailedExports(): number {\n const failed = this.failedExports\n this.failedExports = 0\n return failed\n }\n\n shutdown(): Promise<void> {\n return this.exporter.shutdown()\n }\n\n forceFlush(): Promise<void> {\n return this.exporter.forceFlush?.() ?? Promise.resolve()\n }\n}\n\nexport interface OtelBatchTransportOptions {\n directSender: DirectBatchSender\n maxExportBatchSize?: number\n maxRequestBatchSize?: number\n maxQueueSize?: number\n exportConcurrency?: number\n maxRequestBytes?: number\n /** Overridable so tests can drive OTel's export-timeout path in ms, not 30s. */\n exportTimeoutMillis?: number\n}\n\nexport class OtelBatchTransport implements TraceTransport {\n private readonly provider: BasicTracerProvider\n private readonly processor: BatchSpanProcessor\n private readonly deliveryTracker: DeliveryTrackingExporter\n private readonly tracer: Tracer\n private closed = false\n private pendingFlush: Promise<boolean> | undefined\n\n constructor(options: OtelBatchTransportOptions) {\n const maxRequestBytes = options.maxRequestBytes ?? MAX_EXPORT_REQUEST_BYTES\n const maxRequestBatchSize =\n options.maxRequestBatchSize ?? DIRECT_MAX_REQUEST_BATCH_SIZE\n if (maxRequestBatchSize <= 0) {\n throw new BitfabError(\"maxRequestBatchSize must be a positive integer\")\n }\n\n this.deliveryTracker = new DeliveryTrackingExporter(\n new BitfabSpanExporter(\n options.directSender,\n maxRequestBytes,\n maxRequestBatchSize,\n options.exportConcurrency ?? DEFAULT_EXPORT_CONCURRENCY,\n ),\n )\n\n this.processor = new BatchSpanProcessor(this.deliveryTracker, {\n maxQueueSize: options.maxQueueSize ?? MAX_QUEUE_SIZE,\n maxExportBatchSize:\n options.maxExportBatchSize ?? DIRECT_MAX_EXPORT_BATCH_SIZE,\n scheduledDelayMillis: SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: options.exportTimeoutMillis ?? EXPORT_TIMEOUT_MILLIS,\n })\n\n // Every option is passed explicitly: `BasicTracerProvider` otherwise reads\n // OTEL_* defaults, so a host application's sampler or attribute-length\n // limit would silently drop or truncate Bitfab payloads.\n this.provider = new BasicTracerProvider({\n sampler: new AlwaysOnSampler(),\n resource: resourceFromAttributes({\n \"service.name\": \"bitfab-typescript-sdk\",\n \"service.version\": __version__,\n }),\n spanLimits: {\n attributeCountLimit: 2,\n attributeValueLengthLimit: Number.POSITIVE_INFINITY,\n },\n spanProcessors: [this.processor],\n })\n this.tracer = this.provider.getTracer(\"bitfab\", __version__)\n liveTransports.add(this)\n }\n\n submit(operation: TraceOperation, payload: Record<string, unknown>): void {\n recordTraceSubmission(operation, payload)\n if (this.closed) {\n warnOnce(\n \"otel-submit-after-shutdown\",\n \"OpenTelemetry transport is shut down; dropping spans\",\n )\n return\n }\n try {\n // Not a bare JSON.stringify: contexts, metadata and `call()` inputs\n // never pass through `serializeValue`, so one stray value here would\n // throw and drop the whole span rather than being stubbed. This is the\n // same backstop the pre-transport HTTP path applied.\n const { body, dropped } = serializePayloadBody(payload)\n if (dropped.length > 0) {\n warnOnce(\n \"otel-carrier-payload-stubbed\",\n `a span payload held non-serializable value(s) (${[\n ...new Set(dropped),\n ].join(\", \")}); they were stubbed so the span still ships, but the ` +\n \"trace may be incomplete or not replayable.\",\n )\n }\n const span = this.tracer.startSpan(spanName(operation, payload), {\n attributes: {\n [OPERATION_ATTRIBUTE]: operation,\n [PAYLOAD_ATTRIBUTE]: body,\n },\n startTime: payloadTimestamp(payload, \"started_at\"),\n })\n if (hasError(payload)) {\n span.setStatus({ code: SpanStatusCode.ERROR })\n }\n endSpan(span, payloadTimestamp(payload, \"ended_at\"))\n } catch (error) {\n logError(\"failed to queue an OpenTelemetry span\", error)\n }\n }\n\n async flush(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n // Serialized: two concurrent force-flushes would race for the same\n // delivery counter and one would report the other's failures as success.\n const pending = (this.pendingFlush ?? Promise.resolve(true)).then(() =>\n this.forceFlushOnce(),\n )\n this.pendingFlush = pending.catch(() => false)\n return withDeadline(pending, timeoutMs)\n }\n\n private async forceFlushOnce(): Promise<boolean> {\n try {\n await this.processor.forceFlush()\n } catch (error) {\n logError(\"failed to flush OpenTelemetry spans\", error)\n this.deliveryTracker.takeFailedExports()\n return false\n }\n return this.deliveryTracker.takeFailedExports() === 0\n }\n\n async shutdown(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n this.closed = true\n const flushed = await this.flush(Math.max(0, deadline - Date.now()))\n liveTransports.delete(this)\n const shutdownCompleted = await withDeadline(\n this.provider\n .shutdown()\n .then(() => true)\n .catch((error) => {\n logError(\"failed to shut down the OpenTelemetry transport\", error)\n return false\n }),\n Math.max(0, deadline - Date.now()),\n )\n return flushed && shutdownCompleted\n }\n}\n\nfunction endSpan(span: Span, endTime: number | undefined): void {\n span.end(endTime)\n}\n\nfunction spanName(\n operation: TraceOperation,\n payload: Record<string, unknown>,\n): string {\n if (operation === \"external_span\") {\n const spanData = asRecord(asRecord(payload.rawSpan)?.span_data)\n if (typeof spanData?.name === \"string\") {\n return spanData.name\n }\n }\n if (typeof payload.traceFunctionKey === \"string\") {\n return payload.traceFunctionKey\n }\n return `bitfab.${operation}`\n}\n\n/**\n * Milliseconds since the epoch for a payload timestamp, or `undefined` to let\n * OTel stamp the carrier with the current time.\n */\nfunction payloadTimestamp(\n payload: Record<string, unknown>,\n field: string,\n): number | undefined {\n const rawSpan = asRecord(payload.rawSpan)\n const rawTrace = asRecord(payload.externalTrace) ?? asRecord(payload.rawTrace)\n const raw = rawSpan?.[field] ?? rawTrace?.[field]\n if (typeof raw !== \"string\") {\n return undefined\n }\n const parsed = Date.parse(raw)\n return Number.isNaN(parsed) ? undefined : parsed\n}\n\nfunction hasError(payload: Record<string, unknown>): boolean {\n const spanData = asRecord(asRecord(payload.rawSpan)?.span_data)\n if (spanData?.error != null) {\n return true\n }\n const errors = payload.errors\n return Array.isArray(errors) ? errors.length > 0 : Boolean(errors)\n}\n\nexport function createOtelTransport(options: {\n directSender: DirectBatchSender\n}): OtelBatchTransport {\n return new OtelBatchTransport({\n ...options,\n exportConcurrency: readBoundedIntEnv(\n EXPORT_CONCURRENCY_ENV,\n MAX_EXPORT_CONCURRENCY,\n DEFAULT_EXPORT_CONCURRENCY,\n \"otel-export-concurrency-invalid\",\n ),\n maxRequestBytes: readBoundedIntEnv(\n MAX_REQUEST_BYTES_ENV,\n MAX_EXPORT_REQUEST_BYTES,\n MAX_EXPORT_REQUEST_BYTES,\n \"otel-max-request-bytes-invalid\",\n ),\n })\n}\n\nasync function forEachLiveTransport(\n timeoutMs: number,\n run: (transport: OtelBatchTransport, remainingMs: number) => Promise<boolean>,\n): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n let succeeded = true\n for (const transport of [...liveTransports]) {\n succeeded =\n (await run(transport, Math.max(0, deadline - Date.now()))) && succeeded\n }\n return succeeded\n}\n\nexport function flushOtelTransports(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n): Promise<boolean> {\n return forEachLiveTransport(timeoutMs, (transport, remaining) =>\n transport.flush(remaining),\n )\n}\n\nexport function shutdownOtelTransports(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n): Promise<boolean> {\n return forEachLiveTransport(timeoutMs, (transport, remaining) =>\n transport.shutdown(remaining),\n )\n}\n\n/** Test-only: forget cross-run replay submission bookkeeping. */\nexport function _resetTraceSubmissions(): void {\n traceSubmissionSpanIds.clear()\n replayTraceSubmissions.clear()\n}\n","/**\n * Best-effort `unref()` on a timer handle so a pending timeout never keeps the\n * Node.js event loop alive on its own. An un-unref'd timeout would delay\n * process exit, prolong a serverless function's billed lifetime, and hang test\n * runners until it fires.\n *\n * In the browser `setTimeout` returns a number with no `unref`, so this is a\n * no-op there. Callers should still `clearTimeout` the handle once the work it\n * guards has settled.\n */\nexport function unrefTimer(timer: ReturnType<typeof setTimeout>): void {\n const handle = timer as { unref?: () => void }\n if (typeof handle.unref === \"function\") {\n handle.unref()\n }\n}\n","/**\n * The single seam between the HTTP client and whichever transport implements\n * span delivery. Keeping the factory here (rather than importing `otel.ts`\n * from `http.ts` directly) is what lets the OpenTelemetry implementation\n * depend on `HttpClient`'s request path without an import cycle.\n */\n\nimport {\n createOtelTransport,\n flushOtelTransports,\n shutdownOtelTransports,\n takeReplaySpanCounts as takeOtelReplaySpanCounts,\n} from \"./otel.js\"\nimport type { DirectBatchSender, TraceTransport } from \"./transportTypes.js\"\n\nexport function createTraceTransport(options: {\n directSender: DirectBatchSender\n}): TraceTransport {\n return createOtelTransport(options)\n}\n\nexport function flushTraceTransports(timeoutMs?: number): Promise<boolean> {\n return flushOtelTransports(timeoutMs)\n}\n\nexport function shutdownTraceTransports(timeoutMs?: number): Promise<boolean> {\n return shutdownOtelTransports(timeoutMs)\n}\n\nexport function takeReplaySpanCounts(\n traceIds: string[],\n): Record<string, number> {\n return takeOtelReplaySpanCounts(traceIds)\n}\n","/**\n * HTTP client utilities for Bitfab API requests.\n *\n * This module provides:\n * - HttpClient class for making API requests\n * - awaitOnExit helper so deferred span work still gates process exit\n */\n\nimport { encodeRequestBody } from \"./compress.js\"\nimport { __version__ } from \"./constants.js\"\nimport type { DbSnapshotRef } from \"./dbSnapshot.js\"\nimport { BitfabError } from \"./errors.js\"\nimport {\n type DbBranchLease,\n type DbBranchSettings,\n replayContextReady,\n} from \"./replayContext.js\"\nimport { serializePayloadBody } from \"./serializePayload.js\"\nimport {\n createTraceTransport,\n flushTraceTransports,\n shutdownTraceTransports,\n} from \"./transport.js\"\nimport type { TraceTransport } from \"./transportTypes.js\"\nimport { unrefTimer } from \"./unrefTimer.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\n// BitfabError lives in `errors.ts` to break the http ↔ dbSnapshot import\n// cycle. Re-exported here for backwards compatibility with existing\n// callers that import it from \"./http.js\".\nexport { BitfabError }\nexport { serializePayloadBody }\n\nconst REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS = 300_000\nconst EXIT_FLUSH_TIMEOUT_MS = 5_000\nconst DEFAULT_LIFECYCLE_TIMEOUT_MS = 30_000\n\n// Global set to track pending trace creation promises\n// This prevents promises from being garbage collected before they complete\nconst pendingTracePromises = new Set<Promise<unknown>>()\n\n/**\n * Track a promise so `flushTraces()` and the exit hook wait for it.\n *\n * Exactly one caller remains: the deferred `finalize` chain, which hands its\n * span to the transport only after finalize settles. Everything else submits\n * synchronously, so the transport's own queue is the complete picture. Python\n * has no equivalent because its finalize runs inline.\n *\n * @param promise - The promise to track\n * @returns The same promise (for chaining)\n */\nexport function awaitOnExit<T>(promise: Promise<T>): Promise<T> {\n pendingTracePromises.add(promise)\n // Use void to prevent unhandled rejection warnings from the .finally() chain\n // The actual error handling is done by the caller's .catch() on the returned promise\n void promise\n .finally(() => {\n pendingTracePromises.delete(promise)\n })\n .catch(() => {\n // Swallow rejection in this chain - the caller handles errors via their own .catch()\n })\n return promise\n}\n\n/**\n * Wait for pending fire-and-forget requests AND every live span transport to\n * deliver, within one total deadline. Useful in tests and scripts to ensure all\n * data has been sent before asserting or exiting.\n *\n * Returns `false` when delivery failed or the deadline expired, so a caller\n * that depends on persistence (replay does) can react instead of assuming a\n * drained queue means the server has the data.\n *\n * @param timeoutMs - Maximum total time to wait in milliseconds (default: 5000)\n */\nexport async function flushTraces(timeoutMs: number = 5000): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n const requestsFlushed = await awaitPendingRequests(timeoutMs)\n const transportsFlushed = await flushTraceTransports(\n Math.max(0, deadline - Date.now()),\n )\n return requestsFlushed && transportsFlushed\n}\n\n/**\n * Wait for in-flight fire-and-forget requests and deferred span work, WITHOUT\n * flushing the transports.\n *\n * Replay needs this half on its own: a `finalize` span reaches the transport\n * only after its deferred chain settles, so the expected-span tally has to be\n * read after that work lands but before a flush is issued (which would be\n * wasted, and would emit a request, when the run submitted nothing).\n */\nexport async function awaitPendingRequests(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n): Promise<boolean> {\n // Async-context storage loads asynchronously, and spans traced before it\n // resolves have their recording deferred behind it. Without this, a script\n // that traces and immediately flushes or closes races its own first spans.\n await replayContextReady.catch(() => {})\n return waitForPromises(Array.from(pendingTracePromises), timeoutMs)\n}\n\n/**\n * Await `promises` within `timeoutMs`, reporting whether they all settled in\n * time rather than throwing. Rejections count as settled: a failed span upload\n * is already reported by its own catch handler, and the caller is asking about\n * completion, not success.\n */\nasync function waitForPromises(\n promises: Promise<unknown>[],\n timeoutMs: number,\n): Promise<boolean> {\n if (promises.length === 0) {\n return true\n }\n // Clear and unref the timeout so the loser of the race never leaves a\n // dangling timer holding the event loop open after flush resolves.\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n Promise.allSettled(promises).then(() => true),\n new Promise<boolean>((resolve) => {\n timer = setTimeout(() => resolve(false), timeoutMs)\n unrefTimer(timer)\n }),\n ])\n } finally {\n if (timer) {\n clearTimeout(timer)\n }\n }\n}\n\n// Register beforeExit handler to wait for pending traces (Node.js only)\n// This ensures traces are sent before the process exits (for scripts).\n// The transport is included: its batch worker sits on an unref'd timer, so a\n// script that ends without an explicit flush would otherwise exit with a queue\n// of spans still waiting on the scheduled delay.\nif (\n typeof process !== \"undefined\" &&\n process.versions != null &&\n process.versions.node != null\n) {\n let isFlushing = false\n process.on(\"beforeExit\", () => {\n if (isFlushing) {\n return\n }\n isFlushing = true\n // Awaiting here keeps the event loop alive until delivery settles.\n void Promise.allSettled([\n ...Array.from(pendingTracePromises).map((p) => p.catch(() => {})),\n shutdownTraceTransports(EXIT_FLUSH_TIMEOUT_MS).catch(() => false),\n ]).then(() => {\n isFlushing = false\n })\n })\n}\n\n/**\n * How the API key is supplied internally: either a literal string or a\n * function resolved each time the key is needed (at request/send time). The\n * function form is what defers key resolution past module-load construction\n * so an env var loaded after the client is built (the ESM dotenv-hoisting\n * case) is still picked up.\n */\nexport type ApiKeyInput = string | (() => string | undefined)\n\nexport interface HttpClientConfig {\n apiKey?: ApiKeyInput\n serviceUrl: string\n timeout?: number\n}\n\nexport type SpanOccurrence = \"first\" | \"last\" | number\n\nexport type SpanLookup =\n | { id: string; name?: never; occurrence?: never }\n | { name: string; id?: never; occurrence?: SpanOccurrence }\n\nexport interface CapturedSpan {\n id: string\n traceId: string\n parentSpanId: string | null\n name: string | null\n type: string\n input: unknown\n output: unknown\n contexts: Record<string, unknown>[]\n prompt: string | null\n metadata: Record<string, unknown>\n metrics: Record<string, unknown> | null\n errors: unknown\n startedAt: string | null\n endedAt: string | null\n}\n\n/**\n * HTTP client for Bitfab API requests.\n *\n * Provides methods for different API endpoints with proper error handling,\n * timeouts, and authentication.\n */\nexport class HttpClient {\n private readonly apiKey: ApiKeyInput | undefined\n private readonly serviceUrl: string\n private readonly timeout: number\n private traceTransport: TraceTransport | undefined\n // Deferred span work owned by THIS client. The module-global set backs the\n // process-wide `flushTraces()` and the exit hook, but per-client lifecycle\n // must not wait on another client's slow finalize: a false `close()` failure\n // caused by unrelated work is worse than no signal at all.\n private readonly deferredWork = new Set<Promise<unknown>>()\n private closed = false\n private closing: Promise<boolean> | undefined\n\n constructor(config: HttpClientConfig) {\n this.apiKey = config.apiKey\n this.serviceUrl = config.serviceUrl\n this.timeout = config.timeout ?? 120000\n }\n\n /**\n * Resolve the API key at the moment it is needed (request time), invoking\n * the function form if one was supplied. Never read at construction.\n */\n private resolveApiKey(): string | undefined {\n return typeof this.apiKey === \"function\" ? this.apiKey() : this.apiKey\n }\n\n /**\n * This client's span transport, built on first use.\n *\n * Lazy on purpose: a client that never sends a span must never start a batch\n * worker. Every framework integration created from a `Bitfab` client shares\n * the owning client's `HttpClient`, so handlers reuse this one worker instead\n * of each spinning up their own.\n */\n private getTraceTransport(): TraceTransport | undefined {\n if (this.closed) {\n warnOnce(\n \"http-client-closed\",\n \"the Bitfab client is closed; dropping spans\",\n )\n return undefined\n }\n if (!this.traceTransport) {\n this.traceTransport = createTraceTransport({\n directSender: (endpoint, body, timeoutMs) =>\n this.sendEncoded<Record<string, unknown>>(endpoint, body, {\n timeout: timeoutMs,\n }),\n })\n }\n return this.traceTransport\n }\n\n /**\n * Track deferred span work so this client's own lifecycle waits for it, and\n * so the process-wide flush and exit hook do too.\n */\n trackDeferred<T>(promise: Promise<T>): Promise<T> {\n this.deferredWork.add(promise)\n void promise\n .finally(() => this.deferredWork.delete(promise))\n .catch(() => {})\n return awaitOnExit(promise)\n }\n\n /**\n * Settle only THIS client's deferred span work. Scoped deliberately: the\n * global set can contain another client's long-running finalize, and\n * attributing its timeout here would fail a client whose own work succeeded.\n */\n async settleDeferredWork(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n await replayContextReady.catch(() => {})\n return waitForPromises(Array.from(this.deferredWork), timeoutMs)\n }\n\n /**\n * Wait for spans queued by this client to be delivered, within one deadline.\n * Returns false on delivery failure or timeout.\n */\n async waitForPendingRequests(\n timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS,\n ): Promise<boolean> {\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n const settled = await this.settleDeferredWork(timeoutMs)\n const flushed =\n (await this.traceTransport?.flush(Math.max(0, deadline - Date.now()))) ??\n true\n return settled && flushed\n }\n\n /**\n * Flush and permanently close this client's tracing transport. Idempotent:\n * a second call joins the first rather than tearing down a pipeline the\n * first call already owns.\n */\n close(timeoutMs: number = DEFAULT_LIFECYCLE_TIMEOUT_MS): Promise<boolean> {\n if (this.closing) {\n return this.closing\n }\n const deadline = Date.now() + Math.max(timeoutMs, 0)\n this.closing = (async () => {\n // Settle deferred span work BEFORE refusing submissions. A span whose\n // recording is still queued (the `finalize` chain, or any call made\n // before async-context storage finished loading) has not reached the\n // transport yet; flipping `closed` first would reject it on arrival and\n // silently drop a span the caller had every reason to think was captured.\n const settled = await this.settleDeferredWork(\n Math.max(0, deadline - Date.now()),\n )\n this.closed = true\n const transport = this.traceTransport\n this.traceTransport = undefined\n const shutdownOk =\n (await transport?.shutdown(Math.max(0, deadline - Date.now()))) ?? true\n // Deferred work that outran the deadline will submit into a closed\n // client and be dropped, so close cannot report success for it.\n return settled && shutdownOk\n })()\n return this.closing\n }\n\n /**\n * Make an HTTP request to the Bitfab API. Defaults to POST; pass\n * `options.method` to use a different verb (e.g. \"PATCH\").\n *\n * @param endpoint - The API endpoint (without base URL)\n * @param payload - The request body\n * @param options - Optional request options\n * @returns The parsed JSON response\n * @throws {BitfabError} If the request fails\n */\n async request<T>(\n endpoint: string,\n payload: Record<string, unknown>,\n options?: { timeout?: number; method?: \"POST\" | \"PATCH\" | \"PUT\" },\n ): Promise<T> {\n // Serialize the payload so a stray non-serializable value (BigInt,\n // function, circular ref, a class instance that slipped past upstream\n // serialization) can never abort the send and silently drop the span.\n // Strays are stubbed in place, preserving span content, and a degraded\n // payload warns loudly.\n const { body, dropped } = serializePayloadBody(payload)\n if (dropped.length > 0) {\n try {\n console.warn(\n `Bitfab: request body to ${endpoint} held ${dropped.length} ` +\n `non-serializable value(s) (${[...new Set(dropped)].join(\", \")}); ` +\n \"they were stubbed so the span still sends, but the trace may be \" +\n \"incomplete or not replayable. Capture a JSON-safe projection of \" +\n \"this input to make it replayable.\",\n )\n } catch {}\n }\n return this.sendEncoded<T>(endpoint, body, options)\n }\n\n /**\n * POST an already-encoded body. The span transport encodes its own batches,\n * so routing them back through {@link HttpClient.request} would encode the\n * same data twice.\n */\n async sendEncoded<T>(\n endpoint: string,\n body: string,\n options?: { timeout?: number; method?: \"POST\" | \"PATCH\" | \"PUT\" },\n ): Promise<T> {\n const url = `${this.serviceUrl}${endpoint}`\n const timeout = options?.timeout ?? this.timeout\n const method = options?.method ?? \"POST\"\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n // Awaited only when compression actually runs, so an uncompressed request\n // still calls `fetch` synchronously the way it did before compression.\n const prepared = encodeRequestBody(body)\n const encoded = prepared instanceof Promise ? await prepared : prepared\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}`,\n }\n if (encoded.contentEncoding) {\n headers[\"Content-Encoding\"] = encoded.contentEncoding\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: encoded.body,\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n undefined,\n response.status,\n )\n }\n\n const result = await response.json()\n\n // Check for errors in the response\n if (result.error) {\n if (result.url) {\n throw new BitfabError(\n `${result.error} Configure it at: ${this.serviceUrl}${result.url}`,\n result.url,\n )\n }\n throw new BitfabError(result.error)\n }\n\n return result as T\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(`Request timed out after ${timeout}ms`)\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Look up a function by name.\n * Blocks until complete - needed for function execution.\n */\n async lookupFunction<T>(name: string): Promise<T> {\n return this.request<T>(\"/api/sdk/functions/lookup\", { name })\n }\n\n async getTraceSpan(\n traceId: string,\n lookup: SpanLookup,\n ): Promise<CapturedSpan | null> {\n const searchParams = new URLSearchParams()\n if (lookup.id !== undefined) {\n searchParams.set(\"id\", lookup.id)\n } else {\n searchParams.set(\"name\", lookup.name)\n searchParams.set(\"occurrence\", String(lookup.occurrence ?? \"last\"))\n }\n\n const endpoint = `/api/sdk/traces/${encodeURIComponent(traceId)}/span?${searchParams.toString()}`\n const response = await this.get<{ span: CapturedSpan | null }>(endpoint)\n return response.span\n }\n\n private async get<T>(endpoint: string): Promise<T> {\n const url = `${this.serviceUrl}${endpoint}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), this.timeout)\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}` },\n signal: controller.signal,\n })\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n )\n }\n return (await response.json()) as T\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(`Request timed out after ${this.timeout}ms`)\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Queue an internal trace (from local BAML execution via `call()`) onto this\n * client's batching transport. `functionId` moves into the payload because\n * the OTLP carrier has no path to carry it.\n */\n sendInternalTrace(\n functionId: string,\n payload: Record<string, unknown>,\n ): void {\n this.getTraceTransport()?.submit(\"internal_trace\", {\n ...payload,\n functionId,\n sdkVersion: __version__,\n })\n }\n\n /**\n * Queue an external span (from withSpan wrapper or OpenAI tracing) onto this\n * client's batching transport. Fire-and-forget: the transport owns delivery,\n * so callers await `flushTraces()` or `close()` rather than a per-span\n * promise.\n */\n sendExternalSpan(payload: Record<string, unknown>): void {\n this.getTraceTransport()?.submit(\"external_span\", {\n ...payload,\n sdkVersion: __version__,\n })\n }\n\n /**\n * Queue an external trace completion (from OpenAI tracing) onto this\n * client's batching transport. Fire-and-forget for the same reason as\n * {@link HttpClient.sendExternalSpan}; replay confirms persistence with the\n * server-authoritative barrier in `replay.ts`, not by awaiting this call.\n */\n sendExternalTrace(payload: Record<string, unknown>): void {\n this.getTraceTransport()?.submit(\"external_trace\", {\n ...payload,\n sdkVersion: __version__,\n })\n }\n\n /**\n * Partial update of an existing trace identified by its Bitfab trace ID.\n * Used by the detached `client.getTrace(id)` handle.\n *\n * Blocking, like the other trace-API calls: it resolves once the server has\n * applied the change and rejects if the server refused it. A patch targets a\n * trace that is already closed, so there is no batch for it to ride along\n * with and no later signal that would reveal a silent failure.\n */\n async patchTrace(\n traceId: string,\n payload: {\n appendContexts?: Record<string, unknown>[]\n mergeMetadata?: Record<string, unknown>\n setSessionId?: string\n },\n ): Promise<void> {\n const endpoint = `/api/sdk/traces/${encodeURIComponent(traceId)}`\n await this.request(endpoint, payload, { method: \"PATCH\" })\n }\n\n /**\n * Start a replay session by fetching historical traces.\n * Blocking call - creates a test run and returns lightweight item references.\n */\n async startReplay(\n traceFunctionKey: string,\n limit: number | undefined,\n traceIds?: string[],\n name?: string,\n codeChangeDescription?: string | null,\n codeChangeFiles?: CodeChangeFile[] | null,\n includeDbBranchLease?: boolean,\n experimentGroupId?: string,\n datasetId?: string,\n graderIds?: string[],\n dbBranchSettings?: DbBranchSettings,\n ): Promise<StartReplayResponse> {\n // limit is only meaningful without traceIds (an explicit ID list\n // already determines the count), so it's omitted when undefined.\n const payload: Record<string, unknown> = { traceFunctionKey }\n if (limit !== undefined) {\n payload.limit = limit\n }\n if (traceIds) {\n payload.traceIds = traceIds\n }\n if (name !== undefined) {\n payload.name = name\n }\n if (codeChangeDescription !== undefined) {\n payload.codeChangeDescription = codeChangeDescription\n }\n if (codeChangeFiles !== undefined) {\n payload.codeChangeFiles = codeChangeFiles\n }\n if (includeDbBranchLease) {\n payload.includeDbBranchLease = true\n payload.lazyDbBranchLease = true\n }\n if (experimentGroupId !== undefined) {\n payload.experimentGroupId = experimentGroupId\n }\n if (datasetId !== undefined) {\n payload.datasetId = datasetId\n }\n if (graderIds !== undefined) {\n payload.graderIds = graderIds\n }\n if (dbBranchSettings !== undefined) {\n payload.dbBranchSettings = dbBranchSettings\n }\n // When DB branching is on, the server resolves a Neon preview branch\n // per item (snapshot + restore + poll), which can run ~5-10s each, and\n // runs any `warmupSql` against each branch on a 240s budget of its own.\n // The server gives up at 280s and answers, so this is a backstop for a\n // reply that never comes rather than the thing that normally fires; it\n // sits above the server's own ceiling so the server's error is the one\n // callers see. Not raisable in practice either: undici's default\n // `headersTimeout` is also 300s and `fetch` cannot override it per\n // request.\n const timeout = includeDbBranchLease\n ? REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS\n : 30_000\n return this.request<StartReplayResponse>(\"/api/sdk/replay/start\", payload, {\n timeout,\n })\n }\n\n /**\n * Fetch an external span by ID.\n * Blocking GET request.\n * The replay view limits rawData to input/output serialization fields.\n */\n async getExternalSpan(\n spanId: string,\n options?: { view?: \"full\" | \"replay\" },\n ): Promise<ExternalSpanResponse> {\n const query = options?.view === \"replay\" ? \"?view=replay\" : \"\"\n const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}${query}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), 30_000)\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}` },\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n )\n }\n\n return (await response.json()) as ExternalSpanResponse\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(\"Request timed out after 30000ms\")\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Fetch the span tree for a root span.\n * Blocking GET request.\n *\n * Pass `includeOutputs: false` for a payload-free tree (structure +\n * `externalSpanId` only), so recorded outputs are fetched lazily per mocked\n * span instead of all up front. Omit it (default eager) for `mock: \"all\"`.\n * Pass `includeRootOutput: false` when the root was already fetched.\n */\n async getSpanTree(\n externalSpanId: string,\n options?: { includeOutputs?: boolean; includeRootOutput?: boolean },\n ): Promise<SpanTreeResponse> {\n const searchParams = new URLSearchParams()\n if (options?.includeOutputs === false) {\n searchParams.set(\"includeOutputs\", \"false\")\n }\n if (options?.includeRootOutput === false) {\n searchParams.set(\"includeRootOutput\", \"false\")\n }\n const encodedQuery = searchParams.toString()\n const query = encodedQuery ? `?${encodedQuery}` : \"\"\n const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), 30_000)\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Authorization: `Bearer ${this.resolveApiKey() ?? \"\"}` },\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new BitfabError(\n `HTTP ${response.status}: ${errorText.slice(0, 500)}`,\n )\n }\n\n return (await response.json()) as SpanTreeResponse\n } catch (error) {\n if (error instanceof BitfabError) {\n throw error\n }\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n throw new BitfabError(\"Request timed out after 30000ms\")\n }\n throw new BitfabError(error.message)\n }\n throw new BitfabError(\"Unknown error occurred\")\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Read which of a replay run's traces the server has fully persisted.\n *\n * With `expectedSpanCounts`, a trace appears in the response only once it\n * has a final status AND at least that many persisted spans, which is what\n * makes this a real barrier rather than a \"the row exists\" check.\n */\n async getReplayStatus(\n testRunId: string,\n expectedSpanCounts: Record<string, number>,\n ): Promise<ReplayStatusResponse> {\n return this.request<ReplayStatusResponse>(\n \"/api/sdk/replay/status\",\n { testRunId, expectedSpanCounts },\n { timeout: 30_000 },\n )\n }\n\n /**\n * Mark a replay test run as completed.\n * Blocking call.\n */\n async completeReplay(testRunId: string): Promise<CompleteReplayResponse> {\n return this.request<CompleteReplayResponse>(\n \"/api/sdk/replay/complete\",\n { testRunId },\n { timeout: 30_000 },\n )\n }\n\n /**\n * Ask the server to materialize a per-trace DB branch lease from a\n * captured `dbSnapshotRef`. Blocking - the resolver creates a Neon\n * snapshot + preview branch and polls operations to readiness, which\n * can take seconds.\n */\n async resolveDbBranchLease(\n testRunId: string,\n traceId: string,\n dbBranchSettings?: DbBranchSettings,\n ): Promise<{\n dbSnapshotRef: DbSnapshotRef | null\n lease: DbBranchLease | null\n leaseError: { code: string; message: string } | null\n }> {\n return this.request<{\n dbSnapshotRef: DbSnapshotRef | null\n lease: DbBranchLease | null\n leaseError: { code: string; message: string } | null\n }>(\n \"/api/sdk/replay/resolveDbBranchLease\",\n { testRunId, traceId, dbBranchSettings },\n { timeout: REPLAY_DB_BRANCH_REQUEST_TIMEOUT_MS },\n )\n }\n\n /** Release a previously-resolved DB branch by deleting its Neon branch. Idempotent server-side. */\n async releaseDbBranchLease(neonBranchId: string): Promise<void> {\n await this.request<{ released: true }>(\n \"/api/sdk/replay/releaseDbBranchLease\",\n { neonBranchId },\n { timeout: 30_000 },\n )\n }\n}\n\nexport interface TokenUsage {\n input: number | null\n output: number | null\n cached: number | null\n total: number | null\n}\n\n/**\n * Describes a single file edited as part of a code change.\n *\n * - `path`: file path (relative to the repo root, or any consistent root)\n * - `before`: file contents before the change (\"\" for newly created files)\n * - `after`: file contents after the change (\"\" for deleted files)\n */\nexport interface CodeChangeFile {\n path: string\n before: string\n after: string\n}\n\nexport interface StartReplayResponse {\n testRunId: string\n testRunUrl: string\n items: Array<{\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId?: string\n /** External span ID the recorded inputs were read from (the original root span). */\n originalSpanId?: string\n /** @deprecated alias for `originalTraceId`; the only key emitted by servers that predate the rename. */\n sourceTraceId: string\n /** @deprecated alias for `originalSpanId`; the only key emitted by servers that predate the rename. */\n sourceSpanId: string\n durationMs: number | null\n tokens: TokenUsage | null\n model: string | null\n /**\n * The DB snapshot ref captured by the SDK at trace open. Surfaced so\n * the SDK can pass it to the lease-resolver step (or report when no\n * snapshot was captured for this trace).\n */\n dbSnapshotRef?: DbSnapshotRef\n /**\n * Populated once the server-side resolver has materialized a per-item\n * branch from `dbSnapshotRef`. The SDK exposes this to customer code\n * via `getCurrentReplayBranch()`. Absent until the resolver lands.\n */\n dbBranchLease?: DbBranchLease\n /**\n * Why the branch could not be resolved, when one was requested and the\n * attempt failed. Distinct from both fields being absent, which means the\n * trace carried no snapshot ref so nothing was attempted.\n */\n dbBranchLeaseError?: { code: string; message: string }\n }>\n}\n\nexport interface ExternalSpanResponse {\n id: string\n externalTraceId: string\n rawData: {\n span_data: {\n input: unknown\n output: unknown\n input_meta?: unknown\n output_meta?: unknown\n input_serialized?: { json: unknown; meta: unknown }\n output_serialized?: { json: unknown; meta: unknown }\n }\n }\n}\n\nexport interface ReplayStatusResponse {\n /**\n * Local replay trace id -> server trace row id, for the traces the server\n * considers fully persisted. Traces still short of their expected span count\n * are simply absent.\n */\n traceIds?: Record<string, string>\n}\n\nexport interface CompleteReplayResponse {\n id: string\n status: string\n traceIds?: Record<string, string>\n /**\n * Per-replay-trace token usage, keyed by the server trace id (the values of\n * `traceIds`). Aggregated server-side from the freshly-uploaded replay spans,\n * so it's the REPLAYED run's tokens (the same source Studio reads), not the\n * original trace's. The SDK maps each item onto this to set\n * `ReplayItem.tokens`. Absent on servers that predate this field.\n */\n tokens?: Record<string, TokenUsage | null>\n /**\n * Number of traces the server has persisted for this test run at\n * completion time. Lets the SDK distinguish \"uploads failed\" from\n * \"server never saw them\" when the trace-ID mapping is incomplete.\n */\n traceCount?: number\n}\n\nexport interface SpanTreeNode {\n /** Upstream platform span id. Stable structural identity; NOT the row id. */\n sourceSpanId: string\n /**\n * The `externalSpans` row id, accepted by {@link HttpClient.getExternalSpan}.\n * Distinct from `sourceSpanId`; used to lazily fetch this node's output when\n * the tree was fetched with `includeOutputs: false`. Optional so trees from\n * older servers (which omit it) still deserialize.\n */\n externalSpanId?: string\n traceFunctionKey: string\n spanName: string\n type: string\n /** Omitted when the tree was fetched payload-free (`includeOutputs: false`). */\n output?: unknown\n outputMeta?: unknown\n children: SpanTreeNode[]\n}\n\nexport interface SpanTreeResponse {\n root: SpanTreeNode\n}\n","/**\n * Selective mock overrides for replay.\n *\n * A mock override injects a custom value into a specific span (node) during\n * replay: the matched span short-circuits its real execution and returns the\n * value you supply, so downstream real code runs against the substituted\n * output. This is a third mock mode alongside \"run real code\" and \"replay\n * recorded output\" (see {@link MockStrategy}).\n *\n * The matcher and value are deliberately separate so matching stays cheap\n * (structural metadata only, no output fetch) and the recorded output is\n * fetched lazily - and only if the value function actually asks for it via\n * {@link MockOverrideCtx.getOriginalOutput}.\n */\n\n/**\n * Structural identity of a span during replay, passed to a {@link NodeMatcher}.\n * Carries no output payload - matching must not depend on the recorded output,\n * so the output fetch stays lazy and gated.\n */\nexport interface SpanNodeMeta {\n /** The `withSpan` key of the executing span (its code-side identity). */\n traceFunctionKey: string\n /** Resolved span name: `options.name ?? fn.name ?? traceFunctionKey`. */\n spanName: string\n /** Span type, e.g. \"llm\", \"agent\", \"tool\", \"custom\". */\n type: string\n /**\n * The id of this span in the original (replayed) trace, when it exists in\n * that trace's tree. Undefined when the live span has no recorded\n * counterpart (e.g. a span the changed code newly introduced).\n */\n originalSpanId?: string\n}\n\n/** Context passed to a {@link MockValue} function for a matched span. */\nexport interface MockOverrideCtx {\n /** The matched span's structural metadata. */\n node: SpanNodeMeta\n /** The live replay args passed to the wrapped function this run. */\n inputs: unknown[]\n /**\n * Lazily fetch this span's ORIGINAL recorded output (deserialized). The fetch\n * happens only when called and is memoized per replay item, so a purely flat\n * override that never calls it triggers zero output round trips. Rejects if\n * the span has no recorded counterpart. Being async, it is only usable for\n * spans wrapping async functions.\n */\n getOriginalOutput: () => Promise<unknown>\n}\n\n/** Selects which spans an override applies to. Runs on structural metadata. */\nexport type NodeMatcher = (node: SpanNodeMeta) => boolean\n\n/** The function form of {@link MockValue}, receiving the override context. */\nexport type MockValueFn = (ctx: MockOverrideCtx) => unknown | Promise<unknown>\n\n/**\n * The value injected for a matched span: either a flat value used as-is, or a\n * function of the {@link MockOverrideCtx} that returns one (or a Promise of\n * one). Full replacement - the value IS the span's output, no merge with the\n * recorded output.\n *\n * The flat side is spelled out (rather than `unknown`) so an inline function\n * still gets a typed `ctx`: `unknown | Fn` would collapse to `unknown` and drop\n * the contextual type. To inject a value that is itself a function, wrap it:\n * `value: () => theFunction`.\n */\nexport type MockValue =\n | MockValueFn\n | string\n | number\n | boolean\n | bigint\n | symbol\n | object\n | null\n | undefined\n\n/** One (match, value) pair. */\nexport interface MockOverride {\n match: NodeMatcher\n value: MockValue\n}\n\n/**\n * Resolve an override's `value`: call it with `ctx` when it's a function, else\n * use it as-is (a flat value).\n */\nexport function resolveMockValue(\n value: MockValue,\n ctx: MockOverrideCtx,\n): unknown | Promise<unknown> {\n return typeof value === \"function\"\n ? (value as (c: MockOverrideCtx) => unknown | Promise<unknown>)(ctx)\n : value\n}\n\n/**\n * Normalize the per-call `mockOverride` option (a single override, an array, or\n * nothing) into an array. First match wins downstream, so order is preserved.\n */\nexport function normalizeMockOverrides(\n mockOverride?: MockOverride | MockOverride[],\n): MockOverride[] {\n if (mockOverride === undefined) {\n return []\n }\n return Array.isArray(mockOverride) ? mockOverride : [mockOverride]\n}\n","/**\n * Generate a UUID v4 without assuming a global `crypto`.\n *\n * `crypto.randomUUID()` is the fast path and exists in every mainstream modern\n * runtime (Node >= 19, all browsers, Deno, Vercel edge, Cloudflare Workers).\n * But the SDK must NEVER crash a host app, and a few runtimes it can legitimately\n * run in lack a global `crypto` or `crypto.randomUUID` (Node < 19 without a\n * polyfill, older React Native, some sandboxes). There, an unguarded\n * `crypto.randomUUID()` throws on the user's call path. This helper falls back\n * to a `Math.random()`-based v4 string instead.\n *\n * The fallback is NOT cryptographically secure. That is fine: trace and span\n * IDs only need to be unique enough to correlate the spans of one trace; they\n * are never security-sensitive.\n */\nimport { warnOnce } from \"./warnOnce.js\"\n\nexport function randomUuid(): string {\n const globalCrypto = (\n globalThis as { crypto?: { randomUUID?: () => string } }\n ).crypto\n if (typeof globalCrypto?.randomUUID === \"function\") {\n try {\n return globalCrypto.randomUUID()\n } catch {\n // Fall through to the manual generator below.\n }\n }\n warnOnce(\n \"crypto-unavailable\",\n \"global crypto.randomUUID is unavailable; using a non-cryptographic fallback for trace/span ids. Tracing works normally (ids are correlation-only, not security-sensitive).\",\n )\n return fallbackUuidV4()\n}\n\n/**\n * RFC 4122 version 4 layout filled from `Math.random()`. Used only when a usable\n * global `crypto.randomUUID` is unavailable.\n */\nfunction fallbackUuidV4(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (char) => {\n const rand = (Math.random() * 16) | 0\n const value = char === \"x\" ? rand : (rand & 0x3) | 0x8\n return value.toString(16)\n })\n}\n","/**\n * Serialization utilities for Bitfab SDK.\n *\n * This module provides serialization with type metadata preservation,\n * using superjson for handling special JavaScript types like Date, Map,\n * Set, BigInt, undefined, etc.\n */\n\nimport superjson from \"superjson\"\nimport { MAX_SPAN_CARRIER_BYTES } from \"./payloadBudget.js\"\nimport { warnOnce } from \"./warnOnce.js\"\n\n/**\n * Serialized value with JSON data and optional superjson meta for type preservation.\n *\n * The json field contains the JSON-serializable data.\n * The meta field (if present) contains superjson type information for deserializing\n * special types like Date, Map, Set, BigInt, etc.\n */\nexport interface SerializedValue {\n json: unknown\n meta?: unknown\n}\n\n// Cap on a single serialized value. superjson can succeed on values like SDK\n// client instances (OpenAI, etc.) and produce hundreds of KB to MB of useless\n// internal state, so this is the cheap early-out that stops the walk before a\n// pathological object is carried any further. It is deliberately the same\n// number as the whole-span budget: one legitimately large value may use the\n// entire budget, and `serializePayloadBody` is what enforces the total once\n// every field is in. Anything past it is replaced with a stub so the span\n// still ships and the trace isn't dropped server-side.\nconst MAX_SERIALIZED_BYTES = MAX_SPAN_CARRIER_BYTES\n\n// The framework-capture path (toJsonSafe) shares that ceiling. Agent/graph\n// states (LangGraph, Claude Agent SDK) are legitimately larger than a single\n// function's args/return, and capping them lower than ordinary values only\n// discarded detail the span had room for.\nconst MAX_FRAMEWORK_SERIALIZED_BYTES = MAX_SPAN_CARRIER_BYTES\n\nfunction describeValue(value: unknown): string {\n try {\n const ctorName = (value as { constructor?: { name?: string } })?.constructor\n ?.name\n if (ctorName && ctorName !== \"Object\") {\n return ctorName\n }\n } catch {\n // Property access on `value` can throw (Proxy, poisoned getter).\n }\n return typeof value\n}\n\nfunction unserializableStub(value: unknown, reason: string): SerializedValue {\n // Normalize the byte count out of the key so a too_large warning dedups\n // across differently-sized payloads instead of warning once per size.\n warnOnce(\n `serialize:${reason.replace(/\\d+/g, \"N\")}`,\n `a value could not be fully serialized for a span (${reason}); it was replaced with a placeholder. The span still ships, but its captured input/output is incomplete.`,\n )\n let summary: string\n try {\n summary = `<unserializable: ${describeValue(value)} (${reason})>`\n } catch {\n summary = `<unserializable (${reason})>`\n }\n return { json: summary }\n}\n\n/**\n * Serialize a value using superjson for trace storage.\n *\n * Handles arbitrary JavaScript values including:\n * - Date, RegExp, Error\n * - Map, Set\n * - BigInt\n * - undefined (in objects/arrays)\n * - Circular references\n *\n * Guarantees:\n * - Never throws. Pathological inputs (SDK clients, proxies, poisoned\n * getters, circular graphs that defeat superjson) return a stub string.\n * - Never returns a payload larger than MAX_SERIALIZED_BYTES; oversized\n * inputs are replaced with a stub. Without this the wire-side\n * `JSON.stringify` in http.ts can produce a request that times out or\n * gets rejected, leaving a trace with zero spans.\n *\n * @param value - Any JavaScript value to serialize\n * @returns SerializedValue with 'json' field containing the data.\n * If type metadata is needed for reconstruction, includes 'meta' field.\n *\n * @example\n * ```typescript\n * const result = serializeValue(new Date('2024-01-15T10:30:00Z'))\n * // result.json contains the ISO string\n * // result.meta contains type info for Date reconstruction\n * ```\n */\nexport function serializeValue(value: unknown): SerializedValue {\n try {\n const { json, meta } = superjson.serialize(value)\n\n let size: number\n try {\n size = JSON.stringify(json).length\n } catch {\n return unserializableStub(value, \"stringify_failed_after_superjson\")\n }\n if (size > MAX_SERIALIZED_BYTES) {\n return unserializableStub(value, `too_large_${size}_bytes`)\n }\n\n return meta ? { json, meta } : { json }\n } catch {\n try {\n return { json: JSON.parse(JSON.stringify(value)) }\n } catch {\n return unserializableStub(value, \"json_stringify_failed\")\n }\n }\n}\n\n/**\n * Deserialize a value that was serialized with serializeValue.\n *\n * @param serialized - A SerializedValue object with 'json' and optional 'meta'\n * @returns The reconstructed JavaScript value\n *\n * @example\n * ```typescript\n * const serialized = serializeValue(new Date('2024-01-15'))\n * const date = deserializeValue(serialized)\n * // date is a Date object\n * ```\n */\nexport function deserializeValue(serialized: SerializedValue): unknown {\n if (serialized.meta === undefined) {\n // No metadata, return as-is\n return serialized.json\n }\n\n // Use superjson to deserialize with type reconstruction\n // Cast json to the expected superjson type\n type SuperJSONResult = Parameters<typeof superjson.deserialize>[0]\n return superjson.deserialize({\n json: serialized.json as SuperJSONResult[\"json\"],\n meta: serialized.meta as SuperJSONResult[\"meta\"],\n })\n}\n\nconst MAX_SAFE_DEPTH = 6\n\n/**\n * Convert any value to JSON-safe primitives, never throwing.\n *\n * Produces plain objects/arrays/scalars, recursing through `toJSON()` and\n * own-enumerable properties so no raw non-serializable value (a class, a\n * BigInt-bearing object) survives into a span payload. Cycles collapse to a\n * `<cycle ...>` marker; depth is capped.\n *\n * This is the single shared \"safe serialize\" used by the framework\n * integrations that capture raw objects (LangGraph, Claude Agent SDK). Keeping\n * the recurse-the-dump logic here, in one place, is what stops a new\n * integration from reintroducing the \"dump without recursing\" bug - see\n * `serializationInvariant.test.ts`.\n */\nexport function toJsonSafe(value: unknown): unknown {\n return toJsonSafeReport(value).safe\n}\n\n/**\n * Like {@link toJsonSafe}, but also reports what could not be faithfully\n * captured.\n *\n * Returns `{ safe, dropped }` where `dropped` lists the type name behind every\n * placeholder the walker had to emit: a cycle, a max-depth cut, an oversized\n * payload, or a value that could only be stringified (a function/symbol) or\n * stubbed after a throw. A non-empty `dropped` means the captured input/output\n * is lossy. Framework handlers carry it to the send boundary so a degraded\n * capture is marked non-replayable (`serialization_degraded`) instead of being\n * shipped as if it round-trips - mirrors the Python SDK's `to_json_safe_report`\n * + `finalize_span_payload`.\n */\nexport function toJsonSafeReport(value: unknown): {\n safe: unknown\n dropped: string[]\n} {\n const dropped: string[] = []\n const safe = toJsonSafeInner(value, 0, new WeakSet(), dropped)\n // Cap output size for parity with serializeValue. A multi-MB framework\n // payload (a large LangGraph state, a long message history) would otherwise\n // be JSON.stringify'd synchronously on the user's thread in http.ts and may\n // be rejected server-side, leaving a trace with zero spans. Stub it instead\n // so the span still ships. toJsonSafeInner produces only plain\n // objects/arrays/scalars/strings, so JSON.stringify here cannot throw; the\n // try is belt-and-suspenders.\n try {\n const size = JSON.stringify(safe)?.length ?? 0\n if (size > MAX_FRAMEWORK_SERIALIZED_BYTES) {\n warnOnce(\n \"toJsonSafe:too_large\",\n `a framework payload exceeded ${MAX_FRAMEWORK_SERIALIZED_BYTES} bytes and was replaced with a placeholder so the span still ships. The captured state for this span is incomplete.`,\n )\n // Keep any drops already accumulated by the walk (cycles, functions,\n // depth cuts); a payload can be both lossy AND oversized, and the\n // non-replayable marking needs the real types, not just the size stub.\n return {\n safe: `<unserializable: too_large_${size}_bytes>`,\n dropped: [...dropped, `too_large_${size}_bytes`],\n }\n }\n } catch {\n // Keep the recursed value; the http-layer sanitizer is the final backstop.\n }\n return { safe, dropped }\n}\n\nfunction toJsonSafeInner(\n value: unknown,\n depth: number,\n seen: WeakSet<object>,\n dropped: string[],\n): unknown {\n if (value === null || value === undefined) {\n return value\n }\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value\n }\n\n const className =\n (value as { constructor?: { name?: string } })?.constructor?.name ??\n typeof value\n if (depth > MAX_SAFE_DEPTH) {\n dropped.push(className)\n return `<${className}>`\n }\n\n // Non-object composites (bigint, function, symbol) stringify directly. A\n // bigint stringifies faithfully; a function/symbol becomes a lossy summary,\n // so those are reported as dropped.\n if (typeof value !== \"object\") {\n if (typeof value === \"function\" || typeof value === \"symbol\") {\n dropped.push(className)\n }\n try {\n return String(value)\n } catch {\n dropped.push(className)\n return `<${className}>`\n }\n }\n\n if (seen.has(value as object)) {\n dropped.push(className)\n return `<cycle ${className}>`\n }\n seen.add(value as object)\n\n let result: unknown\n if (Array.isArray(value)) {\n result = value.map((item) =>\n toJsonSafeInner(item, depth + 1, seen, dropped),\n )\n } else if (typeof (value as Record<string, unknown>).toJSON === \"function\") {\n // Recurse toJSON() output: it can still hold non-serializable values (e.g.\n // a LangChain tool whose schema is a class) that would otherwise survive\n // into the span payload and crash the wire-side JSON.stringify.\n try {\n result = toJsonSafeInner(\n (value as { toJSON(): unknown }).toJSON(),\n depth + 1,\n seen,\n dropped,\n )\n } catch {\n dropped.push(className)\n result = `<${className}>`\n }\n } else {\n try {\n const obj: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n if (!k.startsWith(\"_\")) {\n obj[k] = toJsonSafeInner(v, depth + 1, seen, dropped)\n }\n }\n result = obj\n } catch {\n dropped.push(className)\n result = `<${className}>`\n }\n }\n\n // Backtrack: keep only ancestors on the current path in `seen`, so a shared\n // (DAG) reference under sibling keys is serialized again rather than stubbed\n // as a false cycle. Real cycles (an ancestor referencing itself) are still\n // caught above.\n seen.delete(value as object)\n return result\n}\n","/**\n * Replay historical traces through a function and create a test run.\n *\n * The replay flow has three phases:\n * 1. Start: fetches historical traces from the server and creates a test run\n * 2. Execute: re-runs each trace's inputs through the provided function locally\n * 3. Complete: marks the test run as completed on the server\n */\n\nimport { resolveAutoCodeChange } from \"./codeChange.js\"\nimport type { DbSnapshotRef } from \"./dbSnapshot.js\"\nimport { BitfabError } from \"./errors.js\"\nimport {\n type CodeChangeFile,\n flushTraces,\n type HttpClient,\n type SpanTreeNode,\n type TokenUsage,\n} from \"./http.js\"\nimport type { MockOverride } from \"./mockOverride.js\"\nimport { normalizeMockOverrides } from \"./mockOverride.js\"\nimport { randomUuid } from \"./randomUuid.js\"\nimport type {\n DbBranchLease,\n DbBranchSettings,\n MockSpan,\n MockTree,\n} from \"./replayContext.js\"\nimport { replayContextReady, runWithReplayContext } from \"./replayContext.js\"\nimport { deserializeValue } from \"./serialize.js\"\nimport { takeReplaySpanCounts } from \"./transport.js\"\nimport { unrefTimer } from \"./unrefTimer.js\"\n\nexport type MockStrategy = \"none\" | \"all\" | \"marked\"\n\nconst REPLAY_PERSISTENCE_TIMEOUT_MS = 30_000\n\n/**\n * How the DB-snapshot branch each replay item runs against is sized and warmed.\n *\n * Every field is optional, so this object is only worth passing when you want\n * to override the mirror project's own sizing. To branch with those defaults,\n * pass `dbBranch: true` instead of an empty object.\n */\nexport interface DbBranchOptions {\n /**\n * Autoscaling floor for the branch's compute, in Neon Compute Units (0.25 to\n * 56). Omit to keep the mirror project's own default. Raise it when the\n * mirror is provisioned smaller than the database it stands in for, so\n * replay latency reflects your code rather than a cold, undersized branch.\n */\n minCu?: number\n /**\n * Autoscaling ceiling for the branch's compute, in Neon Compute Units.\n * Setting it equal to `minCu` pins the size, which keeps items comparable:\n * otherwise a later item can run against an endpoint that has already\n * scaled up and post a better number for the same code.\n */\n maxCu?: number\n /**\n * SQL that warms the branch's cache. The server appends it to the branch's\n * readiness check, so it runs BEFORE your function sees the branch and its\n * time is not charged to the replayed call. Invalid SQL fails the branch\n * rather than silently leaving it cold.\n */\n warmupSql?: string\n}\n\n/**\n * Whether the caller asked for database branching. `true` and a settings object\n * both turn it on; `false` and omission leave it off. Kept separate from\n * `resolveDbBranchSettings` because `dbBranch: true` enables branching while\n * contributing no settings, so presence of settings can't stand in for the\n * switch.\n */\nfunction dbBranchEnabled(\n dbBranch: DbBranchOptions | boolean | undefined,\n): boolean {\n return dbBranch !== undefined && dbBranch !== false\n}\n\n/**\n * Narrow the caller's branch options to the wire shape, dropping the object\n * entirely when nothing was set so the request stays byte-identical to what\n * older SDKs send. Booleans carry no settings: they only move the switch.\n */\nfunction resolveDbBranchSettings(\n dbBranch: DbBranchOptions | boolean | undefined,\n): DbBranchSettings | undefined {\n if (!dbBranch || dbBranch === true) {\n return undefined\n }\n const { minCu, maxCu, warmupSql } = dbBranch\n const settings: DbBranchSettings = {\n ...(minCu === undefined ? {} : { minCu }),\n ...(maxCu === undefined ? {} : { maxCu }),\n ...(warmupSql === undefined ? {} : { warmupSql }),\n }\n return Object.keys(settings).length === 0 ? undefined : settings\n}\n\nexport interface ReplayOptions {\n /**\n * Maximum number of traces to replay (1-100, default 5). Ignored when\n * `traceIds` is passed (with a warning): an explicit ID list already\n * determines how many traces replay.\n */\n limit?: number\n /** Optional list of specific trace IDs to replay (max 100). */\n traceIds?: string[]\n /** Optional display name for the resulting experiment/test run. */\n name?: string\n /** Maximum number of items to process in parallel. Set to 1 for sequential. Default 10. */\n maxConcurrency?: number\n /**\n * Description of the code change being tested in this replay. Stored on\n * the resulting experiment so the change can be reviewed alongside results.\n * Supplying a description without `codeChangeFiles` preserves this text\n * while the SDK automatically captures the files.\n * Pass `null` when the replay should have no description; use\n * `codeChangeFiles: null` to suppress automatic file capture.\n */\n codeChangeDescription?: string | null\n /**\n * Files edited as part of this code change. Each entry holds the file path\n * and the full `before`/`after` contents. The agent reads each file before\n * and after editing and passes the two strings. Use `\"\"` for newly created\n * files (`before`) or deleted files (`after`). Omit this field to capture\n * automatically, or pass `null` to suppress file capture for this replay.\n */\n codeChangeFiles?: CodeChangeFile[] | null\n /**\n * Mock strategy for child spans during replay.\n * - \"marked\": only spans tagged with { mockOnReplay: true } in SpanOptions are mocked (default)\n * - \"none\": everything runs real code\n * - \"all\": every child withSpan returns historical output\n */\n mock?: MockStrategy\n /**\n * Selective mock overrides: inject custom values into specific spans during\n * replay, so downstream real code runs against the substituted output. Each\n * override is a `{ match, value }` pair; the first matcher that\n * matches a span wins. These take precedence over any overrides registered on\n * the client via `registerMockOverride`, and over the base `mock` strategy - a\n * span no override matches falls back to that strategy. See {@link MockOverride}.\n */\n mockOverride?: MockOverride | MockOverride[]\n /**\n * Run each item against a database branch restored to the state its source\n * trace saw. Pass `true` to branch with the mirror project's own sizing, or a\n * {@link DbBranchOptions} object to tune how each branch is sized and warmed.\n * `false` and omission leave branching off. Inside `fn`, read the resolved\n * branch with `getCurrentReplayBranch()`.\n *\n * Items whose source trace carried no DB snapshot reference get no branch and\n * run against the live database. An item whose branch was requested but could\n * not be resolved fails instead of running, so a replay never silently\n * reports a result that did not use the historical data you asked for.\n */\n dbBranch?: DbBranchOptions | boolean\n /** Group ID to associate this replay with an experiment group for live streaming in Studio. */\n experimentGroupId?: string\n /**\n * Dataset this replay runs against. When set, the resulting experiment is\n * durably attributed to the dataset (stored on the test run), so it appears\n * under the dataset's experiments even if the trace lineage can't be\n * reconstructed. Validated server-side against the org.\n */\n datasetId?: string\n /**\n * Graders to attach directly to this experiment (test run), independent of any\n * graders already on the dataset. The resulting experiment is graded by the\n * union of these and the dataset's runnable graders at completion, so use this\n * to grade a single run with a check you don't want to add to the dataset\n * permanently. Each id must be an active/live grader belonging to the same\n * organization and trace function, otherwise the server rejects the replay.\n */\n graderIds?: string[]\n /**\n * Reshape recorded inputs before they are spread into `fn`.\n *\n * Replay pulls each trace's inputs exactly as they were captured against the\n * function's signature AT TRACE TIME. When the function's shape has since\n * changed (params renamed, reordered, collapsed into an options object, etc.),\n * the recorded inputs no longer line up and `fn(...inputs)` throws. This hook\n * lets a caller map the recorded inputs onto the current signature so replay\n * can still run.\n *\n * Receives the deserialized recorded inputs and a per-trace {@link AdaptContext}\n * (so a table-driven adapter can look up the adapted inputs by `traceId`), and\n * returns the array actually spread into `fn`. The returned array is also what\n * `ReplayItem.input` reports, so the experiment shows what was really run.\n *\n * Runs per item, inside the same try/catch as `fn`: if the adapter throws, the\n * failure is surfaced on that item's `error` rather than crashing the run.\n * Omit it to spread the recorded inputs unchanged.\n */\n adaptInputs?: (inputs: unknown[], ctx: AdaptContext) => unknown[]\n /**\n * Called once per item as it finishes, in completion order (not input\n * order), with running totals for the whole run. Use it to render replay\n * progress, for example a terminal progress bar. Replay does not know\n * pass/fail at this point (verdicts are assigned later), so the totals only\n * distinguish items whose function ran (`succeeded`) from items that threw\n * (`errored`).\n *\n * Invoked synchronously right after each item settles, so keep it cheap. A\n * throwing callback never crashes the run: the error is swallowed so progress\n * UI can't break replay.\n */\n onProgress?: (progress: ReplayProgress) => void\n}\n\n/** Running totals reported to {@link ReplayOptions.onProgress} as replay proceeds. */\nexport interface ReplayProgress {\n /**\n * Event kind. Omitted (or `\"item\"`) for the per-trace settle events streamed\n * during the run. `\"complete\"` marks the single terminal event emitted once\n * the run has settled and been enriched server-side; it carries the full\n * {@link ReplayProgress.result} and has no `item`. The Bitfab plugin reads\n * that terminal event to build the run's final result without parsing stdout.\n */\n type?: \"item\" | \"complete\"\n /**\n * The full {@link ReplayResult}, present only on the terminal `\"complete\"`\n * event. Lets the plugin ingest the enriched result (server-aggregated tokens,\n * server trace ids) over the same channel as progress, so a dependency logging\n * to stdout can never block it.\n */\n result?: ReplayResult<unknown>\n /** Test run ID created for this replay. */\n testRunId?: string\n /** Items that have finished so far, whether they succeeded or errored. */\n completed: number\n /** Total number of items in this replay run. */\n total: number\n /** Of the completed items, how many finished without a code or replay error. */\n succeeded: number\n /** Of the completed items, how many have `item.error` set. */\n errored: number\n /**\n * The single item that just settled to produce this event. `traceId` is null\n * at this stage (the server replay id isn't known until the run completes);\n * `originalTraceId` is the original (historical) trace that was replayed (so\n * a UI can identify or link it); `error` is its replay error, or null when it\n * ran ok; `durationMs` is how long this one trace took to replay. Lets a\n * progress UI show per-trace pass/fail and timing as the run streams, without\n * waiting for the full {@link ReplayResult}.\n */\n item?: {\n /** Trace ID of the new replay trace (null during the run; the server id arrives at completion). */\n traceId?: string | null\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId: string | null\n /** External span ID the recorded inputs were read from (the original root span). */\n originalSpanId?: string | null\n /** @deprecated alias for `originalTraceId`. */\n sourceTraceId: string | null\n /** @deprecated alias for `originalSpanId`. */\n sourceSpanId?: string | null\n /** Deserialized inputs from the original trace. */\n input?: unknown[]\n /** The result returned by the replayed function, or undefined on error. */\n result?: unknown\n /** The original output from the historical trace. */\n originalOutput?: unknown\n /** Backward-compatible message for either error kind. */\n error: string | null\n /** The actual value thrown by the replayed customer function. */\n traceError: unknown | null\n /** The actual value thrown while Bitfab prepared this replay item. */\n replayError: unknown | null\n durationMs: number | null\n tokens?: TokenUsage | null\n model?: string | null\n dbSnapshotRef?: DbSnapshotRef | null\n }\n}\n\n/**\n * Wire prefix the Bitfab plugin scans for. Each line {@link reportReplayProgress}\n * writes is this prefix followed by the JSON of the running totals (plus the\n * settled `item`). The plugin polls these lines to report live progress while a\n * replay runs in the background; keep the SDK emitter and the plugin parser in\n * sync.\n */\nexport const BITFAB_PROGRESS_PREFIX = \"@@bitfab:progress \"\n\n/**\n * A ready-made {@link ReplayOptions.onProgress} callback for replay scripts.\n * Pass it straight in:\n *\n * ```ts\n * await bitfab.replay(\"my-fn\", fn, { limit, onProgress: reportReplayProgress })\n * ```\n *\n * It writes one `@@bitfab:progress` line per trace to stderr, which the Bitfab\n * plugin polls to report live progress while the replay runs in the background,\n * so scripts never hand-format the wire protocol.\n * stdout is left untouched for direct-run ReplayResult JSON. Outside Node (no\n * `process.stderr`, e.g. a browser) it is a no-op, and a write failure is\n * swallowed so progress can never crash a run.\n */\nexport function reportReplayProgress(progress: ReplayProgress): void {\n const stderr = typeof process !== \"undefined\" ? process.stderr : undefined\n if (!stderr) {\n return\n }\n try {\n stderr.write(\n `${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress, replayJsonReplacer)}\\n`,\n )\n } catch {\n // A progress reporter must never crash the replay run.\n }\n}\n\n/** Per-trace context passed to {@link ReplayOptions.adaptInputs}. */\nexport interface AdaptContext {\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId: string\n /** External span ID the recorded inputs were read from. */\n originalSpanId: string\n /** @deprecated alias for {@link AdaptContext.originalTraceId}. */\n sourceTraceId: string\n /** @deprecated alias for {@link AdaptContext.originalSpanId}. */\n sourceSpanId: string\n}\n\n/**\n * The shape an adapter module must export as `adaptInputs`.\n *\n * Author an adapter in its own file (e.g. `scripts/replay-adapters/<name>.ts`),\n * import it in your replay script, and pass it to `replay({ adaptInputs })`:\n *\n * ```ts\n * import type { AdaptInputsFn } from \"@bitfab/sdk\"\n * export const adaptInputs: AdaptInputsFn = (inputs, ctx) => [reshape(inputs)]\n * ```\n */\nexport type AdaptInputsFn = (inputs: unknown[], ctx: AdaptContext) => unknown[]\n\nexport interface ReplayItem<T> {\n /**\n * Server trace ID of the new replay trace this item produced. Written in by\n * `replay()` from the complete-replay response once the server has minted the\n * trace row; the client-side id used to correlate spans during the run is\n * never surfaced here. Null until completion, on older servers that omit the\n * mapping, or if the item produced no trace. Not the verdict-persistence key:\n * that is the original-trace lineage (`originalTraceId` + `testRunId`).\n */\n traceId: string | null\n /** Bitfab trace ID of the original (historical) trace being replayed. */\n originalTraceId: string\n /** External span ID the recorded inputs were read from (the original root span). */\n originalSpanId: string\n /** @deprecated alias for {@link ReplayItem.originalTraceId}. */\n sourceTraceId: string\n /** @deprecated alias for {@link ReplayItem.originalSpanId}. */\n sourceSpanId: string\n /** Deserialized inputs from the original trace. */\n input: unknown[]\n /** The result returned by the function during replay, or undefined on error. */\n result: T | undefined\n /** The original output from the historical trace. */\n originalOutput: unknown\n /**\n * Backward-compatible message for either error kind. Prefer `traceError` and\n * `replayError` when callers need the original exception and its source.\n */\n error: string | null\n /** The actual value thrown by the replayed customer function. */\n traceError: unknown | null\n /**\n * The actual value thrown by replay setup before the customer function ran,\n * such as database warmup, input hydration, or mock preparation.\n */\n replayError: unknown | null\n /** Original trace duration in milliseconds, or null if timestamps are missing. */\n durationMs: number | null\n /**\n * Token usage from the REPLAYED run (this item's new execution), aggregated\n * server-side from the spans it produced, or null if the run captured no\n * token data. This is the \"new\" side of a token delta: compare it against\n * the original trace's recorded usage to see how the code change moved cost.\n * Matches what Studio's experiments view shows.\n */\n tokens: TokenUsage | null\n /** Model name from the original trace, or null if not captured. */\n model: string | null\n /**\n * The DB snapshot ref the SDK captured at trace open. Useful for debugging\n * (\"what state was this trace pinned to?\") and for customers building\n * their own resolvers. Undefined when the source trace was captured\n * without `dbSnapshot` configured.\n */\n dbSnapshotRef: DbSnapshotRef | null\n}\n\nexport type { CodeChangeFile, TokenUsage }\n\nexport interface ReplayResult<T> {\n /** Individual replay items with inputs, results, and comparison data. */\n items: ReplayItem<T>[]\n /** The test run ID created on the server. */\n testRunId: string\n /** Full URL to view the test run in the dashboard. */\n testRunUrl: string\n}\n\n/**\n * Whole-run replay failure that preserves every item collected before the run\n * failed. The original whole-run exception is available as `cause`.\n */\nexport class ReplayError<T = unknown> extends BitfabError {\n constructor(\n message: string,\n public readonly items: ReplayItem<T>[],\n public readonly testRunId: string,\n public readonly testRunUrl: string,\n public readonly cause: unknown,\n ) {\n super(message, testRunUrl)\n this.name = \"ReplayError\"\n }\n}\n\n/**\n * A database branch requested for one replay item could not be resolved.\n *\n * The server's resolver code and message are retained as structured fields so\n * callers can handle failures such as `branch_create_failed` and\n * `snapshot_from_replaced_origin` without parsing the compatible `item.error`\n * string.\n */\nexport class DbBranchReplayError extends BitfabError {\n constructor(\n public readonly code: string,\n message: string,\n public readonly originalTraceId: string,\n public readonly cause?: unknown,\n ) {\n super(message)\n this.name = \"DbBranchReplayError\"\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction replayItemErrorMessage(error: unknown): string {\n if (error instanceof DbBranchReplayError) {\n return `Replay requested a database branch for trace ${error.originalTraceId} but it could not be resolved (${error.code}): ${error.message}. The function was not run, because replaying it against the live database would produce a result that looks valid but did not use the historical data you asked for.`\n }\n return errorMessage(error)\n}\n\nfunction replayJsonReplacer(_key: string, value: unknown): unknown {\n if (value instanceof Error) {\n const serialized: Record<string, unknown> = {\n name: value.name,\n message: value.message,\n stack: value.stack,\n }\n if (value instanceof DbBranchReplayError) {\n serialized.code = value.code\n serialized.originalTraceId = value.originalTraceId\n if (value.cause !== undefined) {\n serialized.cause = value.cause\n }\n }\n return serialized\n }\n return value\n}\n\n/**\n * Serialize a replay result as JSON while retaining structured trace and replay\n * errors. Use this for direct-run stdout instead of raw `JSON.stringify`, which\n * drops the useful fields on JavaScript `Error` objects.\n */\nexport function serializeReplayResult<T>(result: ReplayResult<T>): string {\n return JSON.stringify(result, replayJsonReplacer, 2)\n}\n\nasync function preserveReplayFailure<T, TItem>(\n operation: () => Promise<T>,\n items: ReplayItem<TItem>[],\n testRunId: string,\n testRunUrl: string,\n): Promise<T> {\n try {\n return await operation()\n } catch (cause) {\n if (cause instanceof ReplayError) {\n throw cause\n }\n throw new ReplayError(\n errorMessage(cause),\n items,\n testRunId,\n testRunUrl,\n cause,\n )\n }\n}\n\n/**\n * Deserialize inputs from a historical span's rawData.\n *\n * Prefers superjson-serialized `input_meta` for type preservation,\n * falls back to the raw `input` field.\n */\nfunction deserializeInputs(spanData: Record<string, unknown>): unknown[] {\n const inputMeta = spanData.input_meta as unknown\n const rawInput = spanData.input\n\n // If superjson meta is available, deserialize with type reconstruction\n if (inputMeta !== undefined && inputMeta !== null) {\n const deserialized = deserializeValue({ json: rawInput, meta: inputMeta })\n if (Array.isArray(deserialized)) {\n return deserialized\n }\n return deserialized !== undefined && deserialized !== null\n ? [deserialized]\n : []\n }\n\n // Fall back to raw input\n if (Array.isArray(rawInput)) {\n return rawInput\n }\n return rawInput !== undefined && rawInput !== null ? [rawInput] : []\n}\n\n/**\n * Deserialize the original output from a historical span's rawData.\n */\nfunction deserializeOutput(spanData: Record<string, unknown>): unknown {\n const outputMeta = spanData.output_meta as unknown\n const rawOutput = spanData.output\n\n if (outputMeta !== undefined && outputMeta !== null) {\n return deserializeValue({ json: rawOutput, meta: outputMeta })\n }\n\n return rawOutput\n}\n\n/**\n * Walk the children of a root span tree node in depth-first order and build\n * a MockTree keyed by `${traceFunctionKey}:${spanName}:${callIndex}`.\n *\n * The historical root itself is NOT walked. At replay time the runtime root\n * span has `isRootSpan === true` and never queries the mockTree (mock\n * interception is skipped for root spans by design), so the root has nothing\n * to look up. Walking it would just leave an unreachable entry in the table.\n *\n * The (key, name) compound match is what disambiguates same-key spans:\n * - A wrapped function's children commonly share its traceFunctionKey via\n * the fluent `getFunction(key).withSpan({ name }, ...)` pattern. They\n * disambiguate by `name`, never colliding with each other.\n * - Recursion: same (key, name) at every depth. callIndex per (key, name)\n * orders them correctly without leaking the historical root into the\n * nested call's slot.\n * - Outer-wrapper replay scripts: the outer wrapper's `name` is distinct\n * from anything in the historical tree (it only exists at replay), so\n * its presence never disturbs counters or lookups for spans that do\n * exist in the historical tree.\n */\nfunction buildMockTree(rootNode: SpanTreeNode): MockTree {\n const spans = new Map<string, MockSpan>()\n const counters = new Map<string, number>()\n\n function walk(node: SpanTreeNode): void {\n const key = node.traceFunctionKey\n if (key) {\n const name = node.spanName || key\n const counterKey = `${key}:${name}`\n const index = counters.get(counterKey) ?? 0\n counters.set(counterKey, index + 1)\n // `output`/`outputMeta` are undefined on a payload-free (lazy) tree;\n // `externalSpanId` is what the lazy path fetches them by. Both are copied\n // verbatim so eager and lazy trees build through the same walk.\n spans.set(`${counterKey}:${index}`, {\n sourceSpanId: node.sourceSpanId,\n externalSpanId: node.externalSpanId,\n output: node.output,\n outputMeta: node.outputMeta,\n })\n }\n for (const child of node.children) {\n walk(child)\n }\n }\n\n for (const child of rootNode.children) {\n walk(child)\n }\n\n return { spans }\n}\n\n/**\n * Execute a single replay item: fetch span data, deserialize inputs, call\n * the function within a replay context that injects testRunId into new spans.\n */\nasync function processItem<TReturn>(\n httpClient: HttpClient,\n serverItem: {\n originalTraceId?: string\n originalSpanId?: string\n /** @deprecated alias emitted by servers that predate the originalTraceId rename. */\n sourceTraceId: string\n /** @deprecated alias emitted by servers that predate the originalSpanId rename. */\n sourceSpanId: string\n durationMs: number | null\n model: string | null\n dbSnapshotRef?: DbSnapshotRef\n dbBranchLease?: DbBranchLease\n dbBranchLeaseError?: { code: string; message: string }\n },\n // biome-ignore lint/suspicious/noExplicitAny: replay deserializes inputs from historical data\n fn: (...args: any[]) => TReturn | Promise<TReturn>,\n testRunId: string,\n mockStrategy: MockStrategy,\n resolvedOverrides: MockOverride[],\n replayedTraceId: string,\n includeDbBranchLease: boolean,\n dbBranchSettings: DbBranchSettings | undefined,\n adaptInputs:\n | ((inputs: unknown[], ctx: AdaptContext) => unknown[])\n | undefined,\n): Promise<ReplayItem<TReturn>> {\n // The server-side resolver materializes a Neon preview branch per item\n // during `/api/sdk/replay/start` (when the customer passed `dbBranch`,\n // which triggers `includeDbBranchLease: true`). The lease arrives on the\n // server item; we just attach it to the replay context and release the\n // branch in `finally` so any throw (in fetch, mock-tree build, or the\n // customer fn) frees the Neon resource. Items whose source trace had no\n // snapshot ref arrive without a lease; `getCurrentReplayBranch()` returns\n // null for those, and replaying against the live database is correct.\n let lease = includeDbBranchLease ? serverItem.dbBranchLease : undefined\n // A resolve that was attempted and FAILED is different: the caller asked for\n // a branch, so running their function against live data would produce a\n // result that looks valid and isn't. Fail this item instead, loudly.\n let leaseError = includeDbBranchLease\n ? serverItem.dbBranchLeaseError\n : undefined\n let dbSnapshotRef = serverItem.dbSnapshotRef\n\n let inputs: unknown[] = []\n let originalOutput: unknown\n let result: TReturn | undefined\n let error: string | null = null\n let traceError: unknown | null = null\n let replayError: unknown | null = null\n\n // The ORIGINAL (historical) trace/span this item replays. Canonical server\n // keys are originalTraceId/originalSpanId; older servers only send the\n // deprecated sourceTraceId/sourceSpanId aliases.\n const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId\n const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId\n\n try {\n if (includeDbBranchLease && !lease && !leaseError) {\n let resolved: Awaited<ReturnType<HttpClient[\"resolveDbBranchLease\"]>>\n try {\n resolved = await httpClient.resolveDbBranchLease(\n testRunId,\n originalTraceId,\n dbBranchSettings,\n )\n } catch (cause) {\n throw new DbBranchReplayError(\n \"lease_request_failed\",\n `Bitfab could not request the database branch: ${errorMessage(cause)}`,\n originalTraceId,\n cause,\n )\n }\n lease = resolved.lease ?? undefined\n leaseError = resolved.leaseError ?? undefined\n dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef\n }\n\n if (leaseError) {\n throw new DbBranchReplayError(\n leaseError.code,\n leaseError.message,\n originalTraceId,\n )\n }\n\n const span = await httpClient.getExternalSpan(originalSpanId, {\n view: \"replay\",\n })\n const spanData = (span.rawData?.span_data ?? {}) as Record<string, unknown>\n\n inputs = deserializeInputs(spanData)\n originalOutput = deserializeOutput(spanData)\n\n // Reshape the recorded inputs onto the current signature when an adapter\n // is supplied. Runs before the mock tree / fn call so the adapted array is\n // what fn receives and what `item.input` reports.\n if (adaptInputs) {\n inputs = adaptInputs(inputs, {\n originalTraceId,\n originalSpanId,\n // Deprecated aliases for originalTraceId/originalSpanId.\n sourceTraceId: originalTraceId,\n sourceSpanId: originalSpanId,\n })\n }\n\n // Build the mock tree whenever mocking could apply: any non-\"none\" strategy,\n // OR overrides are present (overrides substitute even under \"none\" - the\n // \"run real code but replace node X\" case). Only \"all\" needs outputs inline;\n // \"marked\"/overrides fetch a payload-free tree and pull outputs lazily so we\n // never drag down every span's recorded output when only a few get mocked.\n const hasOverrides = resolvedOverrides.length > 0\n const needTree =\n mockStrategy === \"all\" || mockStrategy === \"marked\" || hasOverrides\n const includeOutputs = mockStrategy === \"all\"\n\n let mockTree: MockTree | undefined\n if (needTree) {\n try {\n const treeResponse = await httpClient.getSpanTree(originalSpanId, {\n includeOutputs,\n includeRootOutput: false,\n })\n if (treeResponse.root) {\n mockTree = buildMockTree(treeResponse.root)\n } else if (mockStrategy === \"all\" || hasOverrides) {\n throw new BitfabError(\n `Replay mock strategy \"${mockStrategy}\"${hasOverrides ? \" with overrides\" : \"\"} requires a span tree root for original span ${originalSpanId}.`,\n )\n } else {\n mockTree = undefined\n }\n } catch (e) {\n // \"all\" and overrides both depend on the tree (\"all\" mocks every span\n // from it; overrides gate on its call-counter machinery), so a fetch\n // failure surfaces on the item rather than silently running real with\n // the overrides dropped. Bare \"marked\" degrades to no mocking (its\n // marked spans just re-run). Mirrors the Python/Ruby SDKs.\n if (mockStrategy === \"all\" || hasOverrides) {\n throw e\n }\n mockTree = undefined\n }\n }\n\n // Lazy per-span output fetch, memoized per item so a span read twice (once\n // as a marked mock, once via an override's getOriginalOutput) fetches once.\n // Present only when outputs were NOT fetched inline (not the eager \"all\"\n // path); its presence signals the mock path to fetch on demand.\n const outputCache = new Map<string, Promise<unknown>>()\n const fetchSpanOutput =\n mockTree && !includeOutputs\n ? (externalSpanId: string): Promise<unknown> => {\n let pending = outputCache.get(externalSpanId)\n if (!pending) {\n pending = httpClient\n .getExternalSpan(externalSpanId, { view: \"replay\" })\n .then((s) =>\n deserializeOutput(\n (s.rawData?.span_data ?? {}) as Record<string, unknown>,\n ),\n )\n outputCache.set(externalSpanId, pending)\n }\n return pending\n }\n : undefined\n\n try {\n const maybePromise = runWithReplayContext(\n {\n testRunId,\n traceId: replayedTraceId,\n inputSourceSpanId: span.id,\n inputSourceTraceId: span.externalTraceId,\n sourceBitfabTraceId: originalTraceId,\n mockTree,\n callCounters: mockTree ? new Map() : undefined,\n mockStrategy,\n mockOverrides: hasOverrides ? resolvedOverrides : undefined,\n fetchSpanOutput,\n dbBranchLease: lease,\n },\n () => fn(...inputs),\n )\n result =\n maybePromise instanceof Promise ? await maybePromise : maybePromise\n } catch (e) {\n traceError = e\n error = errorMessage(e)\n }\n } catch (e) {\n replayError = e\n error = replayItemErrorMessage(e)\n } finally {\n if (lease) {\n try {\n await httpClient.releaseDbBranchLease(lease.neonBranchId)\n } catch (e) {\n try {\n console.warn(\n `Bitfab: failed to release DB branch ${lease.neonBranchId} (TTL janitor will catch it): ${\n e instanceof Error ? e.message : String(e)\n }`,\n )\n } catch {\n // Never crash the host\n }\n }\n }\n }\n\n return {\n // Written in by replay() from the complete-replay response once the server\n // has minted this replay trace's row. Null until then: the client-side\n // correlation id (replayedTraceId) is never surfaced as the item's traceId.\n traceId: null,\n originalTraceId,\n originalSpanId,\n // Deprecated aliases for originalTraceId/originalSpanId.\n sourceTraceId: originalTraceId,\n sourceSpanId: originalSpanId,\n input: inputs,\n result,\n originalOutput,\n error,\n traceError,\n replayError,\n durationMs: serverItem.durationMs ?? null,\n // Filled in by replay() from the complete-replay response once the\n // replay traces are persisted and their spans aggregated server-side.\n // Null here (and on older servers) means \"replay tokens not known\".\n tokens: null,\n model: serverItem.model ?? null,\n dbSnapshotRef: dbSnapshotRef ?? null,\n }\n}\n\n/**\n * Block until the server has fully persisted every replay trace this run\n * submitted, or fail loudly.\n *\n * Flushing the transport only proves the SDK handed the spans off. The barrier\n * that matters is server-side: each trace must reach a final status AND hold at\n * least the number of spans this process submitted for it. Without that,\n * `completeReplay` can build its trace-ID mapping while spans are still in\n * flight, and every `item.traceId` comes back null.\n *\n * Span counts come from the transport's record of UNIQUE submitted span IDs,\n * which matches the server's idempotent span key: a retried or duplicated\n * submission can never make this wait for a row the server will never write.\n */\nasync function waitForReplayPersistence(\n httpClient: HttpClient,\n testRunId: string,\n replayedTraceIds: string[],\n): Promise<void> {\n // Settle deferred submissions before counting. A `finalize` root span only\n // reaches the transport once its finalize chain resolves, so tallying first\n // would under-count and let the barrier pass on a trace that is still short.\n // This waits for that work WITHOUT flushing: a run that submitted nothing\n // must not emit an export request just to discover it has nothing to wait on.\n const deferredSettled = await httpClient.settleDeferredWork(\n REPLAY_PERSISTENCE_TIMEOUT_MS,\n )\n\n // Checked BEFORE the tally: deferred work that never landed means no\n // completion may have registered at all, and an empty tally would then look\n // like \"nothing to wait for\" and finalize the run with root spans pending.\n if (!deferredSettled) {\n throw new BitfabError(\n `Replay could not settle deferred span work before the deadline, so the ` +\n `expected span counts are incomplete (testRunId ${testRunId}).`,\n )\n }\n\n const expectedSpanCounts = takeReplaySpanCounts(replayedTraceIds)\n if (Object.keys(expectedSpanCounts).length === 0) {\n return\n }\n\n // A failed flush is a hint, not a verdict. It means delivery was not\n // CONFIRMED within the deadline, which is not the same as lost: the export\n // timeout can fire while requests are still in flight and the server goes on\n // to persist every one of them. Throwing here failed runs whose data had\n // fully landed. The status poll below is the authority, because the server\n // answers only for traces that are final with all of their spans.\n const flushed = await flushTraces(REPLAY_PERSISTENCE_TIMEOUT_MS)\n\n // The poll gets its own budget. Sharing one deadline with the flush meant a\n // flush that used it all left zero polling window, so the barrier failed\n // after a single not-ready answer - exactly the case where the export is\n // still in flight and about to persist.\n const deadline = Date.now() + REPLAY_PERSISTENCE_TIMEOUT_MS\n\n let missing = Object.keys(expectedSpanCounts).length\n while (true) {\n const status = await httpClient.getReplayStatus(\n testRunId,\n expectedSpanCounts,\n )\n const ready = status.traceIds ?? {}\n missing = Object.keys(expectedSpanCounts).filter(\n (traceId) => ready[traceId] === undefined,\n ).length\n if (missing === 0) {\n return\n }\n if (Date.now() >= deadline) {\n break\n }\n await sleep(Math.min(100, Math.max(0, deadline - Date.now())))\n }\n\n // Only now is it a real failure: the server itself never confirmed these.\n // Surface the flush result as the likely cause rather than as the verdict.\n const cause = flushed\n ? \"\"\n : \" Delivery was also not confirmed before the flush deadline, so the \" +\n \"spans likely never reached the server.\"\n throw new BitfabError(\n `Replay traces were not fully persisted before the delivery deadline ` +\n `(testRunId ${testRunId}, missing ${missing} of ` +\n `${Object.keys(expectedSpanCounts).length} trace(s)).${cause}`,\n )\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms)\n unrefTimer(timer)\n })\n}\n\n/**\n * Run async tasks with a concurrency limit.\n * Each task factory is called when a slot opens; results preserve input order.\n */\nasync function mapWithConcurrency<T>(\n tasks: Array<() => Promise<T>>,\n maxConcurrency: number,\n onSettled?: (result: T, index: number) => void,\n): Promise<T[]> {\n const results: T[] = new Array(tasks.length)\n let nextIndex = 0\n\n async function worker(): Promise<void> {\n while (nextIndex < tasks.length) {\n const index = nextIndex++\n const result = await tasks[index]()\n results[index] = result\n onSettled?.(result, index)\n }\n }\n\n const workers = Array.from(\n { length: Math.min(maxConcurrency, tasks.length) },\n () => worker(),\n )\n await Promise.all(workers)\n return results\n}\n\n/**\n * Replay historical traces through a function and create a test run.\n *\n * @internal Called by Bitfab.replay, not part of the public API.\n */\nexport async function replay<TReturn>(\n httpClient: HttpClient,\n serviceUrl: string,\n traceFunctionKey: string,\n // biome-ignore lint/suspicious/noExplicitAny: replay deserializes inputs from historical data\n fn: (...args: any[]) => TReturn | Promise<TReturn>,\n options?: ReplayOptions,\n registeredOverrides: MockOverride[] = [],\n): Promise<ReplayResult<TReturn>> {\n if (options?.traceIds !== undefined) {\n if (options.traceIds.length === 0) {\n throw new BitfabError(\"traceIds must contain at least one trace ID.\")\n }\n if (options.traceIds.length > 100) {\n throw new BitfabError(\n `traceIds supports at most 100 trace IDs per replay (got ${options.traceIds.length}).`,\n )\n }\n }\n if (options?.limit !== undefined && options?.traceIds !== undefined) {\n try {\n console.warn(\n \"Bitfab: limit is ignored when traceIds is passed: the explicit trace ID list already determines how many traces replay.\",\n )\n } catch {\n // Never crash the host app\n }\n }\n\n await replayContextReady\n\n // Resolve the code change to attach to this experiment. codeChangeFiles is\n // the capture control: omitted auto-captures, an array wins, and null opts\n // out. A caller-supplied description is preserved when files are captured.\n let codeChangeDescription = options?.codeChangeDescription\n let codeChangeFiles = options?.codeChangeFiles\n if (codeChangeFiles === undefined) {\n const captured = await resolveAutoCodeChange(options?.name)\n if (captured) {\n codeChangeFiles = captured.files\n if (codeChangeDescription === undefined) {\n codeChangeDescription = captured.description\n }\n }\n }\n\n const {\n testRunId,\n testRunUrl,\n items: serverItems,\n } = await httpClient.startReplay(\n traceFunctionKey,\n // limit is meaningless with explicit traceIds (the ID list determines\n // the count), so it's omitted from the request entirely.\n options?.traceIds ? undefined : (options?.limit ?? 5),\n options?.traceIds,\n options?.name,\n codeChangeDescription,\n codeChangeFiles,\n dbBranchEnabled(options?.dbBranch), // includeDbBranchLease\n options?.experimentGroupId,\n options?.datasetId,\n options?.graderIds,\n resolveDbBranchSettings(options?.dbBranch),\n )\n\n const mockStrategy: MockStrategy = options?.mock ?? \"marked\"\n const maxConcurrency = options?.maxConcurrency ?? 10\n const fullTestRunUrl = `${serviceUrl}${testRunUrl}`\n\n // Per-call overrides take precedence over registered ones: concatenating them\n // first means the first-match-wins scan hits per-call overrides before the\n // client-registered chain, and both before the base mock strategy.\n const resolvedOverrides = [\n ...normalizeMockOverrides(options?.mockOverride),\n ...registeredOverrides,\n ]\n\n // One client-side replay trace id per item. It tags that item's replay spans\n // during the run so the server can echo back the row id it minted for them\n // (resolved in the complete-replay mapping below). Kept out of the public\n // ReplayItem: it's a correlation handle, never an id callers use.\n const replayedTraceIds = serverItems.map(() => randomUuid())\n const tasks = serverItems.map(\n (serverItem, index) => () =>\n processItem(\n httpClient,\n serverItem,\n fn,\n testRunId,\n mockStrategy,\n resolvedOverrides,\n replayedTraceIds[index],\n dbBranchEnabled(options?.dbBranch),\n resolveDbBranchSettings(options?.dbBranch),\n options?.adaptInputs,\n ),\n )\n const total = tasks.length\n let completed = 0\n let succeeded = 0\n let errored = 0\n const resultItems = await mapWithConcurrency(\n tasks,\n maxConcurrency,\n options?.onProgress\n ? (item) => {\n completed += 1\n if (item.error === null) {\n succeeded += 1\n } else {\n errored += 1\n }\n try {\n options?.onProgress?.({\n testRunId,\n completed,\n total,\n succeeded,\n errored,\n item: {\n // The server replay trace id isn't known until completeReplay\n // runs (below), so it can't be reported mid-run and we never\n // emit the client-side placeholder. originalTraceId (the\n // historical trace) is known now and is what a UI keys on to\n // identify what just settled.\n traceId: null,\n originalTraceId: item.originalTraceId ?? null,\n originalSpanId: item.originalSpanId ?? null,\n // Deprecated aliases for originalTraceId/originalSpanId.\n sourceTraceId: item.originalTraceId ?? null,\n sourceSpanId: item.originalSpanId ?? null,\n input: item.input,\n result: item.result,\n originalOutput: item.originalOutput,\n error: item.error,\n traceError: item.traceError,\n replayError: item.replayError,\n durationMs: item.durationMs,\n tokens: item.tokens,\n model: item.model,\n dbSnapshotRef: item.dbSnapshotRef,\n },\n })\n } catch {\n // Progress UI must never crash the replay run.\n }\n }\n : undefined,\n )\n\n // Items submit their spans through the same batching transport live traffic\n // uses, so nothing here has waited on the network yet. Flush the transports,\n // then let the SERVER confirm each trace reached a final status with all of\n // its spans before finalizing: a drained queue is not proof that Bitfab\n // committed the data.\n await preserveReplayFailure(\n () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),\n resultItems,\n testRunId,\n fullTestRunUrl,\n )\n\n // completeReplay finalizes the test run and returns the token/diagnostic\n // mapping; its failures propagate loudly because a run that never completed\n // can't be finalized and callers must hear about it.\n const completeResult = await preserveReplayFailure(\n () => httpClient.completeReplay(testRunId),\n resultItems,\n testRunId,\n fullTestRunUrl,\n )\n const serverTraceIds = completeResult.traceIds\n // Per-replay-trace token usage, keyed by server trace id. The REPLAYED run's\n // tokens (span-aggregated server-side), used below to fill each item.tokens.\n const replayTokens = completeResult.tokens\n\n // `serverTraceIds` maps each item's client-side replay trace id (its entry in\n // `replayedTraceIds`, which tagged that item's spans during the run) to the\n // server's trace row id. We use it to (a) write the real server replay trace\n // id into `item.traceId` now that the row exists, (b) attach each item's\n // server-aggregated token usage, and (c) detect a systemic upload failure\n // early. Verdict persistence does NOT use this map: it is keyed by the\n // original-trace lineage (`originalTraceId` + `testRunId`), which needs no\n // client-held server id. Older servers that omit the map yield no replay\n // tokens and leave `item.traceId` null.\n if (serverTraceIds !== undefined) {\n const missing: string[] = []\n let completedCount = 0\n for (let index = 0; index < resultItems.length; index += 1) {\n const item = resultItems[index]\n const localId = replayedTraceIds[index]\n const mapped = localId ? serverTraceIds[localId] : undefined\n // Write the real server replay trace id in as it comes back; the item\n // held null until now (the client placeholder is never surfaced).\n item.traceId = mapped ?? null\n if (item.error === null) {\n completedCount += 1\n if (mapped === undefined) {\n missing.push(localId ?? item.originalTraceId)\n }\n }\n if (mapped !== undefined) {\n item.tokens = replayTokens?.[mapped] ?? null\n }\n }\n // ALL completed items missing → systemic (the replayed function isn't\n // wrapped with withSpan, or uploads are wholesale broken). Throw; the run's\n // traces never persisted, so nothing can be labeled and silence here is the\n // exact bug this guarantee exists to prevent.\n if (completedCount > 0 && missing.length === completedCount) {\n const serverCount =\n completeResult.traceCount !== undefined\n ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.`\n : \"\"\n const cause = new BitfabError(\n `Replay completed but the server has no persisted trace for any of the ${completedCount} completed item(s) (testRunId ${testRunId}).${serverCount} ` +\n `Trace uploads were awaited, so either the uploads failed (check for \"Bitfab: Failed to create\" errors above) or the replayed function is not wrapped with withSpan.`,\n )\n throw new ReplayError(\n cause.message,\n resultItems,\n testRunId,\n fullTestRunUrl,\n cause,\n )\n }\n // SOME completed items missing → per-item upload failure (transient blip,\n // one oversized payload). Log it, but return the run; the items that landed\n // can still be labeled via their lineage.\n if (missing.length > 0) {\n try {\n console.error(\n `Bitfab: server has no persisted trace for ${missing.length} of ${completedCount} completed replay item(s) (testRunId ${testRunId}). Their replay token usage is unavailable and they cannot be labeled.`,\n )\n } catch {\n // Never crash the host app\n }\n }\n }\n\n const result: ReplayResult<TReturn> = {\n items: resultItems,\n testRunId,\n testRunUrl: fullTestRunUrl,\n }\n // Persist the enriched result two ways so the Bitfab plugin never has to parse\n // the replay's stdout (which a dependency's logging can corrupt): write it to\n // BITFAB_REPLAY_RESULT_PATH when the plugin set that env var, and stream a\n // terminal `complete` progress event. The plugin prefers the streamed event\n // and falls back to the file. The event routes through onProgress so only\n // progress-reporting runs emit it: a run with no reporter stays silent.\n await writeReplayResultFile(result)\n try {\n options?.onProgress?.({\n type: \"complete\",\n testRunId,\n completed: total,\n total,\n succeeded,\n errored,\n result,\n })\n } catch {\n // A progress reporter must never crash the replay run.\n }\n return result\n}\n\nasync function writeReplayResultFile(\n result: ReplayResult<unknown>,\n): Promise<void> {\n const resultPath =\n typeof process !== \"undefined\"\n ? process.env?.BITFAB_REPLAY_RESULT_PATH\n : undefined\n if (!resultPath) {\n return\n }\n\n try {\n const [{ dirname }, { mkdir, writeFile }] = await Promise.all([\n import(\"node:path\"),\n import(\"node:fs/promises\"),\n ])\n await mkdir(dirname(resultPath), { recursive: true })\n await writeFile(resultPath, `${serializeReplayResult(result)}\\n`)\n } catch (err) {\n try {\n console.warn(\n `Bitfab: failed to write replay result to BITFAB_REPLAY_RESULT_PATH (${resultPath}): ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n } catch {\n // Never crash the host app.\n }\n }\n}\n"],"mappings":"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","names":["asRecord","takeReplaySpanCounts","DEFAULT_LIFECYCLE_TIMEOUT_MS","takeReplaySpanCounts","mapWithConcurrency"]}