bitfab 0.12.2 → 0.13.1
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.
- package/dist/{chunk-HUSTKOQI.js → chunk-3JCQD7E5.js} +52 -5
- package/dist/chunk-3JCQD7E5.js.map +1 -0
- package/dist/{chunk-3HBV4GQO.js → chunk-HIDM5UYA.js} +75 -3
- package/dist/chunk-HIDM5UYA.js.map +1 -0
- package/dist/index.cjs +124 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -2
- package/dist/index.d.ts +55 -2
- package/dist/index.js +2 -2
- package/dist/node.cjs +124 -5
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/{replay-RJZGLEHI.js → replay-NTGRDVES.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-3HBV4GQO.js.map +0 -1
- package/dist/chunk-HUSTKOQI.js.map +0 -1
- /package/dist/{replay-RJZGLEHI.js.map → replay-NTGRDVES.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.generated.ts
|
|
2
|
-
var __version__ = "0.
|
|
2
|
+
var __version__ = "0.13.1";
|
|
3
3
|
|
|
4
4
|
// src/constants.ts
|
|
5
5
|
var DEFAULT_SERVICE_URL = "https://bitfab.ai";
|
|
@@ -55,7 +55,8 @@ var HttpClient = class {
|
|
|
55
55
|
this.timeout = config.timeout ?? 12e4;
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* Make an HTTP
|
|
58
|
+
* Make an HTTP request to the Bitfab API. Defaults to POST; pass
|
|
59
|
+
* `options.method` to use a different verb (e.g. "PATCH").
|
|
59
60
|
*
|
|
60
61
|
* @param endpoint - The API endpoint (without base URL)
|
|
61
62
|
* @param payload - The request body
|
|
@@ -66,6 +67,7 @@ var HttpClient = class {
|
|
|
66
67
|
async request(endpoint, payload, options) {
|
|
67
68
|
const url = `${this.serviceUrl}${endpoint}`;
|
|
68
69
|
const timeout = options?.timeout ?? this.timeout;
|
|
70
|
+
const method = options?.method ?? "POST";
|
|
69
71
|
const controller = new AbortController();
|
|
70
72
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
71
73
|
let body;
|
|
@@ -86,7 +88,7 @@ var HttpClient = class {
|
|
|
86
88
|
}
|
|
87
89
|
try {
|
|
88
90
|
const response = await fetch(url, {
|
|
89
|
-
method
|
|
91
|
+
method,
|
|
90
92
|
headers: {
|
|
91
93
|
"Content-Type": "application/json",
|
|
92
94
|
Authorization: `Bearer ${this.apiKey}`
|
|
@@ -185,6 +187,22 @@ var HttpClient = class {
|
|
|
185
187
|
}
|
|
186
188
|
});
|
|
187
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Partial update of an existing external trace identified by sourceTraceId.
|
|
192
|
+
* Used by the detached `client.getTrace(id)` handle. Fire-and-forget;
|
|
193
|
+
* returns a tracked promise that callers may optionally await.
|
|
194
|
+
*/
|
|
195
|
+
patchTrace(sourceTraceId, payload) {
|
|
196
|
+
const endpoint = `/api/sdk/externalTraces/${encodeURIComponent(sourceTraceId)}`;
|
|
197
|
+
return awaitOnExit(
|
|
198
|
+
this.request(endpoint, payload, { method: "PATCH" })
|
|
199
|
+
).catch((error) => {
|
|
200
|
+
try {
|
|
201
|
+
console.error("Bitfab: Failed to patch trace:", error);
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
188
206
|
/**
|
|
189
207
|
* Start a replay session by fetching historical traces.
|
|
190
208
|
* Blocking call — creates a test run and returns lightweight item references.
|
|
@@ -346,15 +364,44 @@ function runWithReplayContext(ctx, fn) {
|
|
|
346
364
|
|
|
347
365
|
// src/serialize.ts
|
|
348
366
|
import superjson from "superjson";
|
|
367
|
+
var MAX_SERIALIZED_BYTES = 512e3;
|
|
368
|
+
function describeValue(value) {
|
|
369
|
+
try {
|
|
370
|
+
const ctorName = value?.constructor?.name;
|
|
371
|
+
if (ctorName && ctorName !== "Object") {
|
|
372
|
+
return ctorName;
|
|
373
|
+
}
|
|
374
|
+
} catch {
|
|
375
|
+
}
|
|
376
|
+
return typeof value;
|
|
377
|
+
}
|
|
378
|
+
function unserializableStub(value, reason) {
|
|
379
|
+
let summary;
|
|
380
|
+
try {
|
|
381
|
+
summary = `<unserializable: ${describeValue(value)} (${reason})>`;
|
|
382
|
+
} catch {
|
|
383
|
+
summary = `<unserializable (${reason})>`;
|
|
384
|
+
}
|
|
385
|
+
return { json: summary };
|
|
386
|
+
}
|
|
349
387
|
function serializeValue(value) {
|
|
350
388
|
try {
|
|
351
389
|
const { json, meta } = superjson.serialize(value);
|
|
390
|
+
let size;
|
|
391
|
+
try {
|
|
392
|
+
size = JSON.stringify(json).length;
|
|
393
|
+
} catch {
|
|
394
|
+
return unserializableStub(value, "stringify_failed_after_superjson");
|
|
395
|
+
}
|
|
396
|
+
if (size > MAX_SERIALIZED_BYTES) {
|
|
397
|
+
return unserializableStub(value, `too_large_${size}_bytes`);
|
|
398
|
+
}
|
|
352
399
|
return meta ? { json, meta } : { json };
|
|
353
400
|
} catch {
|
|
354
401
|
try {
|
|
355
402
|
return { json: JSON.parse(JSON.stringify(value)) };
|
|
356
403
|
} catch {
|
|
357
|
-
return
|
|
404
|
+
return unserializableStub(value, "json_stringify_failed");
|
|
358
405
|
}
|
|
359
406
|
}
|
|
360
407
|
}
|
|
@@ -385,4 +432,4 @@ export {
|
|
|
385
432
|
serializeValue,
|
|
386
433
|
deserializeValue
|
|
387
434
|
};
|
|
388
|
-
//# sourceMappingURL=chunk-
|
|
435
|
+
//# sourceMappingURL=chunk-3JCQD7E5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/version.generated.ts","../src/constants.ts","../src/http.ts","../src/asyncStorage.ts","../src/replayContext.ts","../src/serialize.ts"],"sourcesContent":["/**\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.13.1\"\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 * HTTP client utilities for Bitfab API requests.\n *\n * This module provides:\n * - HttpClient class for making API requests\n * - awaitOnExit helper for fire-and-forget operations that must complete before process exit\n */\n\nimport { __version__ } from \"./constants.js\"\n\n/**\n * Error class for Bitfab API errors.\n */\nexport class BitfabError extends Error {\n constructor(\n message: string,\n public readonly url?: string,\n ) {\n super(message)\n this.name = \"BitfabError\"\n }\n}\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 to prevent it from being garbage collected.\n * The promise will be removed from tracking when it completes (success or failure).\n * Useful for fire-and-forget operations that need to complete before process exit.\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 all pending fire-and-forget operations (spans, traces) to complete.\n * Useful in tests and scripts to ensure all data has been sent before asserting or exiting.\n *\n * @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)\n */\nexport async function flushTraces(timeoutMs: number = 5000): Promise<void> {\n if (pendingTracePromises.size === 0) {\n return\n }\n await Promise.race([\n Promise.allSettled(Array.from(pendingTracePromises)),\n new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),\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)\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 (pendingTracePromises.size > 0 && !isFlushing) {\n isFlushing = true\n // Wait for all pending traces to complete\n // This keeps the event loop alive until promises resolve\n Promise.allSettled(\n Array.from(pendingTracePromises).map((p) =>\n p.catch(() => {\n // Silently ignore individual trace failures\n }),\n ),\n )\n .then(() => {\n isFlushing = false\n })\n .catch(() => {\n isFlushing = false\n })\n }\n })\n}\n\nexport interface HttpClientConfig {\n apiKey?: string\n serviceUrl: string\n timeout?: number\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: string | undefined\n private readonly serviceUrl: string\n private readonly timeout: number\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 * 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 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 // Serialize payload, handling circular references\n let body: string\n let serializationError: string | undefined\n try {\n body = JSON.stringify(payload)\n } catch (error) {\n serializationError =\n error instanceof Error ? error.message : String(error)\n // Create fallback payload with error info\n body = JSON.stringify({\n ...Object.fromEntries(\n Object.entries(payload).filter(\n ([, v]) => typeof v === \"string\" || typeof v === \"number\",\n ),\n ),\n rawSpan: {},\n errors: [{ step: \"json_serialize\", error: serializationError }],\n })\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n 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 )\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 /**\n * Send an internal trace (from BAML execution).\n * Fire-and-forget with awaitOnExit - doesn't block the caller.\n */\n sendInternalTrace(\n functionId: string,\n payload: Record<string, unknown>,\n ): void {\n void awaitOnExit(\n this.request(`/api/sdk/functions/${functionId}/traces`, {\n ...payload,\n sdkVersion: __version__,\n }),\n ).catch((error) => {\n try {\n console.error(\"Bitfab: Failed to create trace:\", error)\n } catch {}\n })\n }\n\n /**\n * Send an external span (from withSpan wrapper or OpenAI tracing).\n * Fire-and-forget with awaitOnExit - doesn't block the caller.\n * Returns the tracked promise so callers can optionally await it.\n */\n sendExternalSpan(payload: Record<string, unknown>): Promise<unknown> {\n return awaitOnExit(\n this.request(\"/api/sdk/externalSpans\", {\n ...payload,\n sdkVersion: __version__,\n }),\n ).catch((error) => {\n try {\n console.error(\"Bitfab: Failed to create external span:\", error)\n } catch {}\n })\n }\n\n /**\n * Send an external trace (from OpenAI tracing).\n * Fire-and-forget with awaitOnExit - doesn't block the caller.\n */\n sendExternalTrace(payload: Record<string, unknown>): void {\n void awaitOnExit(\n this.request(\"/api/sdk/externalTraces\", {\n ...payload,\n sdkVersion: __version__,\n }),\n ).catch((error) => {\n try {\n console.error(\"Bitfab: Failed to create external trace:\", error)\n } catch {}\n })\n }\n\n /**\n * Partial update of an existing external trace identified by sourceTraceId.\n * Used by the detached `client.getTrace(id)` handle. Fire-and-forget;\n * returns a tracked promise that callers may optionally await.\n */\n patchTrace(\n sourceTraceId: string,\n payload: {\n appendContexts?: Record<string, unknown>[]\n mergeMetadata?: Record<string, unknown>\n setSessionId?: string\n },\n ): Promise<unknown> {\n const endpoint = `/api/sdk/externalTraces/${encodeURIComponent(sourceTraceId)}`\n return awaitOnExit(\n this.request(endpoint, payload, { method: \"PATCH\" }),\n ).catch((error) => {\n try {\n console.error(\"Bitfab: Failed to patch trace:\", error)\n } catch {}\n })\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,\n traceIds?: string[],\n codeChangeDescription?: string,\n codeChangeFiles?: CodeChangeFile[],\n ): Promise<StartReplayResponse> {\n const payload: Record<string, unknown> = { traceFunctionKey, limit }\n if (traceIds) {\n payload.traceIds = traceIds\n }\n if (codeChangeDescription !== undefined) {\n payload.codeChangeDescription = codeChangeDescription\n }\n if (codeChangeFiles !== undefined) {\n payload.codeChangeFiles = codeChangeFiles\n }\n return this.request<StartReplayResponse>(\"/api/sdk/replay/start\", payload, {\n timeout: 30_000,\n })\n }\n\n /**\n * Fetch an external span by ID.\n * Blocking GET request.\n */\n async getExternalSpan(spanId: string): Promise<ExternalSpanResponse> {\n const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}`\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.apiKey}` },\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 async getSpanTree(externalSpanId: string): Promise<SpanTreeResponse> {\n const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}`\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.apiKey}` },\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 * 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\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 traceId: string\n externalSpanId: string\n durationMs: number | null\n tokens: TokenUsage | null\n model: string | null\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 CompleteReplayResponse {\n id: string\n status: string\n}\n\nexport interface SpanTreeNode {\n sourceSpanId: string\n traceFunctionKey: string\n spanName: string\n type: string\n output: unknown\n outputMeta?: unknown\n children: SpanTreeNode[]\n}\n\nexport interface SpanTreeResponse {\n root: SpanTreeNode\n}\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\"\n\n/** A single span entry in the mock tree with its historical output. */\nexport interface MockSpan {\n sourceSpanId: string\n output: unknown\n outputMeta?: unknown\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 inputSourceSpanId?: string\n inputSourceTraceId?: string\n mockTree?: MockTree\n callCounters?: Map<string, number>\n mockStrategy?: \"none\" | \"all\" | \"marked\"\n}\n\nlet replayContextStorage: AsyncLocalStorageLike<ReplayContext | null> | null =\n null\n\nexport const replayContextReady: Promise<void> = asyncStorageReady.then(() => {\n replayContextStorage = createAsyncLocalStorage<ReplayContext | null>()\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 * 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\"\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 serialized payload size. superjson can succeed on values like SDK\n// client instances (OpenAI, etc.) and produce hundreds of KB to MB of useless\n// internal state. Anything beyond this is replaced with a stub so the span\n// still ships and the trace isn't dropped server-side.\nconst MAX_SERIALIZED_BYTES = 512_000\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 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"],"mappings":"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","names":[]}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
getReplayContext,
|
|
9
9
|
isAsyncStorageInitDone,
|
|
10
10
|
serializeValue
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-3JCQD7E5.js";
|
|
12
12
|
|
|
13
13
|
// src/claudeAgentSdk.ts
|
|
14
14
|
function nowIso() {
|
|
@@ -1607,6 +1607,23 @@ function extractContextFromCollector(collector) {
|
|
|
1607
1607
|
return null;
|
|
1608
1608
|
}
|
|
1609
1609
|
}
|
|
1610
|
+
var TRACE_ID_PATTERN = /^[a-zA-Z0-9_\-.:]+$/;
|
|
1611
|
+
var TRACE_ID_MAX_LENGTH = 256;
|
|
1612
|
+
function validateTraceId(traceId) {
|
|
1613
|
+
if (typeof traceId !== "string" || traceId.length === 0) {
|
|
1614
|
+
throw new BitfabError("traceId is required and must be a non-empty string");
|
|
1615
|
+
}
|
|
1616
|
+
if (traceId.length > TRACE_ID_MAX_LENGTH) {
|
|
1617
|
+
throw new BitfabError(
|
|
1618
|
+
`traceId must be ${TRACE_ID_MAX_LENGTH} characters or fewer`
|
|
1619
|
+
);
|
|
1620
|
+
}
|
|
1621
|
+
if (!TRACE_ID_PATTERN.test(traceId)) {
|
|
1622
|
+
throw new BitfabError(
|
|
1623
|
+
`traceId may only contain letters, digits, "_", "-", ".", ":"`
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1610
1627
|
var noOpSpan = {
|
|
1611
1628
|
traceId: "",
|
|
1612
1629
|
addContext() {
|
|
@@ -2148,6 +2165,61 @@ var Bitfab = class {
|
|
|
2148
2165
|
};
|
|
2149
2166
|
return wrappedFn;
|
|
2150
2167
|
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Get a detached handle to a previously-created trace, looked up by the
|
|
2170
|
+
* caller-supplied id (the same id passed at trace creation).
|
|
2171
|
+
*
|
|
2172
|
+
* The returned handle is not tied to AsyncLocalStorage — each method sends
|
|
2173
|
+
* to the server immediately. Useful for adding context to a trace from a
|
|
2174
|
+
* different process or thread than the one that created it.
|
|
2175
|
+
*
|
|
2176
|
+
* Throws synchronously if `traceId` is malformed (empty, too long, or
|
|
2177
|
+
* contains characters outside `[a-zA-Z0-9_\-.:]`). Server returns 404 if
|
|
2178
|
+
* no trace exists with that id in the org; the failure surfaces as a
|
|
2179
|
+
* logged warning (fire-and-forget) or via the awaited promise.
|
|
2180
|
+
*
|
|
2181
|
+
* Example:
|
|
2182
|
+
* ```typescript
|
|
2183
|
+
* const trace = client.getTrace("order_abc_123");
|
|
2184
|
+
* await trace.addContext({ refund_status: "approved" });
|
|
2185
|
+
* await trace.setMetadata({ region: "us-west" });
|
|
2186
|
+
* ```
|
|
2187
|
+
*/
|
|
2188
|
+
getTrace(traceId) {
|
|
2189
|
+
validateTraceId(traceId);
|
|
2190
|
+
return {
|
|
2191
|
+
traceId,
|
|
2192
|
+
addContext: (context) => {
|
|
2193
|
+
if (!this.enabled) {
|
|
2194
|
+
return Promise.resolve();
|
|
2195
|
+
}
|
|
2196
|
+
if (typeof context !== "object" || context === null) {
|
|
2197
|
+
return Promise.resolve();
|
|
2198
|
+
}
|
|
2199
|
+
return this.httpClient.patchTrace(traceId, {
|
|
2200
|
+
appendContexts: [context]
|
|
2201
|
+
});
|
|
2202
|
+
},
|
|
2203
|
+
setMetadata: (metadata) => {
|
|
2204
|
+
if (!this.enabled) {
|
|
2205
|
+
return Promise.resolve();
|
|
2206
|
+
}
|
|
2207
|
+
if (typeof metadata !== "object" || metadata === null) {
|
|
2208
|
+
return Promise.resolve();
|
|
2209
|
+
}
|
|
2210
|
+
return this.httpClient.patchTrace(traceId, { mergeMetadata: metadata });
|
|
2211
|
+
},
|
|
2212
|
+
setSessionId: (sessionId) => {
|
|
2213
|
+
if (!this.enabled) {
|
|
2214
|
+
return Promise.resolve();
|
|
2215
|
+
}
|
|
2216
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
2217
|
+
return Promise.resolve();
|
|
2218
|
+
}
|
|
2219
|
+
return this.httpClient.patchTrace(traceId, { setSessionId: sessionId });
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2151
2223
|
/**
|
|
2152
2224
|
* Get a function wrapper for a specific trace function key.
|
|
2153
2225
|
*
|
|
@@ -2265,7 +2337,7 @@ var Bitfab = class {
|
|
|
2265
2337
|
* @returns ReplayResult with items, testRunId, and testRunUrl
|
|
2266
2338
|
*/
|
|
2267
2339
|
async replay(traceFunctionKey, fn, options) {
|
|
2268
|
-
const { replay: doReplay } = await import("./replay-
|
|
2340
|
+
const { replay: doReplay } = await import("./replay-NTGRDVES.js");
|
|
2269
2341
|
return doReplay(
|
|
2270
2342
|
this.httpClient,
|
|
2271
2343
|
this.serviceUrl,
|
|
@@ -2333,4 +2405,4 @@ export {
|
|
|
2333
2405
|
Bitfab,
|
|
2334
2406
|
BitfabFunction
|
|
2335
2407
|
};
|
|
2336
|
-
//# sourceMappingURL=chunk-
|
|
2408
|
+
//# sourceMappingURL=chunk-HIDM5UYA.js.map
|