@bitfab/sdk 0.38.2 → 0.38.4

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.
@@ -28,6 +28,29 @@ function runWithAutoTraceContext(context, fn, depth = 0) {
28
28
  autoTraceState.browserScope = previous;
29
29
  }
30
30
  }
31
+ function runWithAutoTraceNodeConfiguration(nodeConfiguration, fn) {
32
+ const scope = currentAutoTraceScope();
33
+ if (!scope) {
34
+ return fn();
35
+ }
36
+ const configuredScope = { ...scope, nodeConfiguration };
37
+ let result;
38
+ if (autoTraceState.storage) {
39
+ result = autoTraceState.storage.run(configuredScope, fn);
40
+ } else {
41
+ const previous = autoTraceState.browserScope;
42
+ autoTraceState.browserScope = configuredScope;
43
+ try {
44
+ result = fn();
45
+ } finally {
46
+ autoTraceState.browserScope = previous;
47
+ }
48
+ }
49
+ if (isAutoTraceAsyncGenerator(result)) {
50
+ return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result);
51
+ }
52
+ return result;
53
+ }
31
54
  function runWithAutoTraceRootContext(context, fn) {
32
55
  autoTraceState.activeRoots += 1;
33
56
  let result;
@@ -66,12 +89,34 @@ function wrapAutoTraceAsyncGenerator(context, source) {
66
89
  };
67
90
  return wrapped;
68
91
  }
92
+ function wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, source) {
93
+ const step = (method, value) => runWithAutoTraceNodeConfiguration(
94
+ nodeConfiguration,
95
+ () => source[method](value)
96
+ );
97
+ const wrapped = {
98
+ next: (value) => step("next", value),
99
+ return: (value) => step("return", value),
100
+ throw: (error) => step("throw", error),
101
+ [Symbol.asyncIterator]: () => wrapped
102
+ };
103
+ return wrapped;
104
+ }
69
105
  function __bitfabAutoSpan(definition, inputs, fn) {
70
106
  const scope = currentAutoTraceScope();
71
107
  if (!scope) {
72
108
  return fn();
73
109
  }
74
- return scope.context.invoke(definition, inputs, fn, scope.depth);
110
+ const nameParts = definition.name.split(".");
111
+ const simpleName = nameParts[nameParts.length - 1];
112
+ const nodeConfiguration = simpleName === scope.nodeConfiguration?.functionName ? scope.nodeConfiguration : void 0;
113
+ return scope.context.invoke(
114
+ definition,
115
+ inputs,
116
+ fn,
117
+ scope.depth,
118
+ nodeConfiguration
119
+ );
75
120
  }
76
121
  function __bitfabAutoWrap(definition, fn) {
77
122
  if (fn.name === "") {
@@ -119,6 +164,7 @@ function getAutoTraceCapturePolicy(client, traceFunctionKey) {
119
164
 
120
165
  export {
121
166
  runWithAutoTraceContext,
167
+ runWithAutoTraceNodeConfiguration,
122
168
  runWithAutoTraceRootContext,
123
169
  __bitfabAutoSpan,
124
170
  __bitfabAutoWrap,
@@ -126,4 +172,4 @@ export {
126
172
  __setBitfabAutoTraceCapturePolicy,
127
173
  getAutoTraceCapturePolicy
128
174
  };
129
- //# sourceMappingURL=chunk-GFBQ2AMO.js.map
175
+ //# sourceMappingURL=chunk-J47KPS77.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/autoTrace.ts"],"sourcesContent":["import {\n type AsyncLocalStorageLike,\n createAsyncLocalStorage,\n} from \"./asyncStorage.js\"\n\nexport interface AutoTraceFunctionDefinition {\n id: string\n name: string\n file: string\n line: number\n column: number\n async?: boolean\n wrapper?: boolean\n}\n\nexport interface AutoTraceNodeConfiguration {\n functionName: string\n name?: string\n type?: \"llm\" | \"agent\" | \"function\" | \"guardrail\" | \"handoff\" | \"custom\"\n capture: boolean\n testRunId?: string\n mockOnReplay?: boolean\n // biome-ignore lint/suspicious/noExplicitAny: node finalizers receive the configured function's result, whose type is owned by the caller\n finalize?: (result: any) => unknown | Promise<unknown>\n}\n\nexport interface AutoTraceContext {\n invoke<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n depth: number,\n nodeConfiguration?: AutoTraceNodeConfiguration,\n ): T\n}\n\ninterface AutoTraceScope {\n context: AutoTraceContext\n depth: number\n nodeConfiguration?: AutoTraceNodeConfiguration\n}\n\ninterface AutoTraceState {\n storage: AsyncLocalStorageLike<AutoTraceScope> | null\n browserScope: AutoTraceScope | undefined\n capturePolicies: WeakMap<object, Map<string, ReadonlySet<string>>>\n activeRoots: number\n}\n\ninterface AutoTraceGlobal {\n __bitfabAutoTraceStateV3?: AutoTraceState\n}\n\ninterface AutoTraceAsyncGenerator {\n next(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n return(value?: unknown): Promise<IteratorResult<unknown, unknown>>\n throw(error?: unknown): Promise<IteratorResult<unknown, unknown>>\n [Symbol.asyncIterator](): AutoTraceAsyncGenerator\n}\n\nconst autoTraceGlobal = globalThis as unknown as AutoTraceGlobal\nconst autoTraceState: AutoTraceState =\n autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {\n storage: null,\n browserScope: undefined,\n capturePolicies: new WeakMap(),\n activeRoots: 0,\n }\nautoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState\n\nfunction initializeAutoTraceStorage(): void {\n autoTraceState.storage ??= createAsyncLocalStorage<AutoTraceScope>()\n}\n\nexport function runWithAutoTraceContext<T>(\n context: AutoTraceContext,\n fn: () => T,\n depth = 0,\n): T {\n initializeAutoTraceStorage()\n const scope = { context, depth }\n if (autoTraceState.storage) {\n return autoTraceState.storage.run(scope, fn)\n }\n\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = scope\n try {\n return fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n}\n\nexport function runWithAutoTraceNodeConfiguration<T>(\n nodeConfiguration: AutoTraceNodeConfiguration,\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope) {\n return fn()\n }\n\n const configuredScope = { ...scope, nodeConfiguration }\n let result: T\n if (autoTraceState.storage) {\n result = autoTraceState.storage.run(configuredScope, fn)\n } else {\n const previous = autoTraceState.browserScope\n autoTraceState.browserScope = configuredScope\n try {\n result = fn()\n } finally {\n autoTraceState.browserScope = previous\n }\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result) as T\n }\n return result\n}\n\nexport function runWithAutoTraceRootContext<T>(\n context: AutoTraceContext,\n fn: () => T,\n): T {\n autoTraceState.activeRoots += 1\n let result: T\n try {\n result = runWithAutoTraceContext(context, fn)\n } catch (error) {\n autoTraceState.activeRoots -= 1\n throw error\n }\n\n if (isAutoTraceAsyncGenerator(result)) {\n autoTraceState.activeRoots -= 1\n return wrapAutoTraceAsyncGenerator(context, result) as T\n }\n\n if (result instanceof Promise) {\n return result.finally(() => {\n autoTraceState.activeRoots -= 1\n }) as T\n }\n\n autoTraceState.activeRoots -= 1\n return result\n}\n\nfunction isAutoTraceAsyncGenerator(\n value: unknown,\n): value is AutoTraceAsyncGenerator {\n if (value === null || typeof value !== \"object\") {\n return false\n }\n const candidate = value as Record<PropertyKey, unknown>\n return (\n typeof candidate.next === \"function\" &&\n typeof candidate.return === \"function\" &&\n typeof candidate.throw === \"function\" &&\n typeof candidate[Symbol.asyncIterator] === \"function\"\n )\n}\n\nfunction wrapAutoTraceAsyncGenerator(\n context: AutoTraceContext,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceRootContext(context, () => source[method](value))\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nfunction wrapAutoTraceNodeAsyncGenerator(\n nodeConfiguration: AutoTraceNodeConfiguration,\n source: AutoTraceAsyncGenerator,\n): AutoTraceAsyncGenerator {\n const step = (\n method: \"next\" | \"return\" | \"throw\",\n value?: unknown,\n ): Promise<IteratorResult<unknown, unknown>> =>\n runWithAutoTraceNodeConfiguration(nodeConfiguration, () =>\n source[method](value),\n )\n const wrapped: AutoTraceAsyncGenerator = {\n next: (value) => step(\"next\", value),\n return: (value) => step(\"return\", value),\n throw: (error) => step(\"throw\", error),\n [Symbol.asyncIterator]: () => wrapped,\n }\n return wrapped\n}\n\nexport function __bitfabAutoSpan<T>(\n definition: AutoTraceFunctionDefinition,\n inputs: unknown[],\n fn: () => T,\n): T {\n const scope = currentAutoTraceScope()\n if (!scope) {\n return fn()\n }\n const nameParts = definition.name.split(\".\")\n const simpleName = nameParts[nameParts.length - 1]\n const nodeConfiguration =\n simpleName === scope.nodeConfiguration?.functionName\n ? scope.nodeConfiguration\n : undefined\n return scope.context.invoke(\n definition,\n inputs,\n fn,\n scope.depth,\n nodeConfiguration,\n )\n}\n\n/**\n * Preserve a function's original call arguments for transform cases where\n * parameter bindings discard them, such as destructured arrow parameters.\n *\n * This helper is internal transform/runtime protocol. The proxy preserves the\n * target's callability, arity, async identity, and non-constructibility while\n * only allocating a trace closure beneath an active automatic trace root.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoWrap<T extends (...args: never[]) => unknown>(\n definition: AutoTraceFunctionDefinition,\n fn: T,\n): T {\n if (fn.name === \"\") {\n const nameParts = definition.name.split(\".\")\n const inferredName = nameParts[nameParts.length - 1]\n if (inferredName !== undefined) {\n Object.defineProperty(fn, \"name\", {\n configurable: true,\n value: inferredName,\n })\n }\n }\n\n const target = fn as unknown as (...args: unknown[]) => unknown\n return new Proxy(target, {\n apply(callTarget, thisArg, args) {\n if (!__bitfabAutoTraceActive()) {\n return Reflect.apply(callTarget, thisArg, args)\n }\n return __bitfabAutoSpan(definition, args, () =>\n Reflect.apply(callTarget, thisArg, args),\n )\n },\n }) as unknown as T\n}\n\n/**\n * Return whether the current call is inside an automatic trace root.\n *\n * Build transforms use this before allocating function metadata, captured\n * inputs, or an invocation closure. It is internal transform/runtime protocol,\n * not a supported application API.\n *\n * @experimental The automatic tracing protocol may change.\n */\nexport function __bitfabAutoTraceActive(): boolean {\n if (autoTraceState.activeRoots === 0) {\n return false\n }\n return currentAutoTraceScope() !== undefined\n}\n\nfunction currentAutoTraceScope(): AutoTraceScope | undefined {\n initializeAutoTraceStorage()\n return autoTraceState.storage?.getStore() ?? autoTraceState.browserScope\n}\n\nexport function __setBitfabAutoTraceCapturePolicy(\n client: object,\n traceFunctionKey: string,\n functionIds: Iterable<string>,\n): void {\n const policies = autoTraceState.capturePolicies.get(client) ?? new Map()\n policies.set(traceFunctionKey, new Set(functionIds))\n autoTraceState.capturePolicies.set(client, policies)\n}\n\nexport function getAutoTraceCapturePolicy(\n client: object,\n traceFunctionKey: string,\n): ReadonlySet<string> {\n return (\n autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ??\n new Set()\n )\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +1,11 @@
1
1
  import {
2
+ __bitfabAutoTraceActive,
2
3
  __setBitfabAutoTraceCapturePolicy,
3
4
  getAutoTraceCapturePolicy,
4
5
  runWithAutoTraceContext,
6
+ runWithAutoTraceNodeConfiguration,
5
7
  runWithAutoTraceRootContext
6
- } from "./chunk-GFBQ2AMO.js";
8
+ } from "./chunk-J47KPS77.js";
7
9
  import {
8
10
  BitfabError,
9
11
  DEFAULT_SERVICE_URL,
@@ -16,7 +18,7 @@ import {
16
18
  toJsonSafe,
17
19
  toJsonSafeReport,
18
20
  warnOnce
19
- } from "./chunk-SU7EAKOV.js";
21
+ } from "./chunk-5GWBJGYZ.js";
20
22
  import {
21
23
  __privateAdd,
22
24
  __privateGet,
@@ -2447,6 +2449,102 @@ var Bitfab = class {
2447
2449
  const name = fn.name !== "" ? fn.name : traceFunctionKey;
2448
2450
  return this.createAutoTraceRoot(traceFunctionKey, name, options, fn);
2449
2451
  }
2452
+ /**
2453
+ * Configure a transformed class method when it is discovered beneath a
2454
+ * {@link Bitfab.trace} root.
2455
+ *
2456
+ * The decorator creates no span or trace by itself. Beneath an active trace,
2457
+ * it can rename or retype the discovered call, capture its contents, mark it
2458
+ * for recorded-output replay, finalize its output, or omit it while leaving
2459
+ * captured descendants attached to the nearest captured parent.
2460
+ *
2461
+ * @param options - Trace-owned call configuration.
2462
+ * @experimental Automatic child-call instrumentation is experimental.
2463
+ */
2464
+ node(options = {}) {
2465
+ const configuration = this.resolveNodeConfiguration(options);
2466
+ const decorator = (...args) => {
2467
+ if (args.length === 3) {
2468
+ const descriptor = args[2];
2469
+ if (!descriptor || typeof descriptor.value !== "function") {
2470
+ throw new BitfabError("@bitfab.node can only decorate methods");
2471
+ }
2472
+ if (!this.explicitlyEnabled) {
2473
+ return;
2474
+ }
2475
+ descriptor.value = this.createAutoTraceNode(
2476
+ configuration,
2477
+ descriptor.value,
2478
+ String(args[1])
2479
+ );
2480
+ return;
2481
+ }
2482
+ const method = args[0];
2483
+ const context = args[1];
2484
+ if (typeof method !== "function" || context?.kind !== "method") {
2485
+ throw new BitfabError("@bitfab.node can only decorate methods");
2486
+ }
2487
+ if (!this.explicitlyEnabled) {
2488
+ return method;
2489
+ }
2490
+ return this.createAutoTraceNode(
2491
+ configuration,
2492
+ method,
2493
+ String(context.name)
2494
+ );
2495
+ };
2496
+ return decorator;
2497
+ }
2498
+ withNode(optionsOrFn, maybeFn, internalFunctionName) {
2499
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
2500
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
2501
+ if (!fn) {
2502
+ throw new BitfabError("bitfab.withNode requires a function");
2503
+ }
2504
+ const configuration = this.resolveNodeConfiguration(options);
2505
+ if (!this.explicitlyEnabled) {
2506
+ return fn;
2507
+ }
2508
+ const functionName = internalFunctionName ?? fn.name;
2509
+ if (functionName === "") {
2510
+ throw new BitfabError(
2511
+ "bitfab.withNode requires a named function so the subtree transform can bind its configuration to the correct call."
2512
+ );
2513
+ }
2514
+ return this.createAutoTraceNode(configuration, fn, functionName);
2515
+ }
2516
+ resolveNodeConfiguration(options) {
2517
+ const capture = options.capture ?? true;
2518
+ if (!capture && options.mockOnReplay === true) {
2519
+ throw new BitfabError(
2520
+ "bitfab.node({ capture: false }) cannot use mockOnReplay: true because an uncaptured node has no recorded output."
2521
+ );
2522
+ }
2523
+ return {
2524
+ capture,
2525
+ type: options.type ?? "custom",
2526
+ ...options.name !== void 0 && { name: options.name },
2527
+ ...options.testRunId !== void 0 && {
2528
+ testRunId: options.testRunId
2529
+ },
2530
+ ...options.mockOnReplay !== void 0 && {
2531
+ mockOnReplay: options.mockOnReplay
2532
+ },
2533
+ ...options.finalize !== void 0 && { finalize: options.finalize }
2534
+ };
2535
+ }
2536
+ createAutoTraceNode(configuration, fn, functionName) {
2537
+ const nodeConfiguration = { ...configuration, functionName };
2538
+ return function(...args) {
2539
+ if (!__bitfabAutoTraceActive()) {
2540
+ return fn.apply(this, args);
2541
+ }
2542
+ return runWithAutoTraceNodeConfiguration(
2543
+ nodeConfiguration,
2544
+ () => fn.apply(this, args)
2545
+ );
2546
+ };
2547
+ }
2450
2548
  createAutoTraceRoot(traceFunctionKey, name, options, fn) {
2451
2549
  const self = this;
2452
2550
  const maxDepth = autoTraceLimit(
@@ -2485,29 +2583,51 @@ var Bitfab = class {
2485
2583
  );
2486
2584
  };
2487
2585
  const autoTraceContext = {
2488
- invoke(definition, inputs, invokeFn, depth) {
2586
+ invoke(definition, inputs, invokeFn, depth, nodeConfiguration) {
2489
2587
  const nameParts = definition.name.split(".");
2490
2588
  const simpleName = nameParts[nameParts.length - 1];
2491
- if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || definition.wrapper === true && !includeWrappers) {
2492
- return invokeFn();
2589
+ const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
2590
+ if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || nodeConfiguration === void 0 && definition.wrapper === true && !includeWrappers) {
2591
+ return invokeWithoutNode();
2592
+ }
2593
+ if (nodeConfiguration?.capture === false) {
2594
+ return runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
2493
2595
  }
2494
2596
  if (depth >= maxDepth || spansUsed >= maxSpans) {
2495
2597
  warnTruncated();
2496
- return invokeFn();
2598
+ return invokeWithoutNode();
2497
2599
  }
2498
2600
  spansUsed += 1;
2499
2601
  const childOptions = {
2500
- name: definition.name,
2501
- type: "function",
2602
+ name: nodeConfiguration?.name ?? definition.name,
2603
+ type: nodeConfiguration?.type ?? "function",
2502
2604
  captureWhen: "nested",
2503
2605
  functionId: definition.id,
2504
- captureContent: capturePolicy.has(definition.id),
2505
- autoTraceDefinition: definition
2606
+ captureContent: nodeConfiguration !== void 0 || capturePolicy.has(definition.id),
2607
+ autoTraceDefinition: definition,
2608
+ ...nodeConfiguration?.testRunId !== void 0 && {
2609
+ testRunId: nodeConfiguration.testRunId
2610
+ },
2611
+ ...nodeConfiguration?.mockOnReplay !== void 0 && {
2612
+ mockOnReplay: nodeConfiguration.mockOnReplay
2613
+ },
2614
+ ...nodeConfiguration?.finalize !== void 0 && {
2615
+ finalize: nodeConfiguration.finalize
2616
+ }
2506
2617
  };
2618
+ const invokeWithAutoTraceContext = () => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1);
2619
+ if (definition.async === true) {
2620
+ const tracedAsyncChild = self.withSpan(
2621
+ traceFunctionKey,
2622
+ childOptions,
2623
+ async (..._inputs) => await invokeWithAutoTraceContext()
2624
+ );
2625
+ return tracedAsyncChild(...inputs);
2626
+ }
2507
2627
  const tracedChild = self.withSpan(
2508
2628
  traceFunctionKey,
2509
2629
  childOptions,
2510
- (..._inputs) => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1)
2630
+ (..._inputs) => invokeWithAutoTraceContext()
2511
2631
  );
2512
2632
  return tracedChild(...inputs);
2513
2633
  }
@@ -3077,18 +3197,17 @@ var Bitfab = class {
3077
3197
  newStack = [...currentStack, newContext];
3078
3198
  const inputs = args;
3079
3199
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3200
+ const replayCtxAtStart = getReplayContext();
3201
+ const testRunId = replayCtxAtStart?.testRunId ?? options.testRunId;
3080
3202
  if (isRootSpan && !activeTraceStates.has(traceId)) {
3081
- const replayCtxAtRoot = getReplayContext();
3082
3203
  const dbSnapshotRef = buildSnapshotRef(self.dbSnapshot, startedAt);
3083
3204
  activeTraceStates.set(traceId, {
3084
3205
  traceId,
3085
3206
  startedAt,
3086
3207
  contexts: [],
3087
- ...replayCtxAtRoot?.testRunId && {
3088
- testRunId: replayCtxAtRoot.testRunId
3089
- },
3090
- ...replayCtxAtRoot?.inputSourceTraceId && {
3091
- inputSourceTraceId: replayCtxAtRoot.inputSourceTraceId
3208
+ ...testRunId !== void 0 && { testRunId },
3209
+ ...replayCtxAtStart?.inputSourceTraceId && {
3210
+ inputSourceTraceId: replayCtxAtStart.inputSourceTraceId
3092
3211
  },
3093
3212
  dbSnapshotRef
3094
3213
  });
@@ -3121,9 +3240,7 @@ var Bitfab = class {
3121
3240
  contexts: newContext.contexts,
3122
3241
  prompt: newContext.prompt,
3123
3242
  endedAt,
3124
- ...replayCtx?.testRunId && {
3125
- testRunId: replayCtx.testRunId
3126
- },
3243
+ ...testRunId !== void 0 && { testRunId },
3127
3244
  ...replayCtx?.inputSourceSpanId && {
3128
3245
  inputSourceSpanId: replayCtx.inputSourceSpanId
3129
3246
  }
@@ -3608,7 +3725,7 @@ var Bitfab = class {
3608
3725
  `Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
3609
3726
  );
3610
3727
  }
3611
- const { replay: doReplay } = await import("./replay-A5UVFNZ3.js");
3728
+ const { replay: doReplay } = await import("./replay-O2WFIRM4.js");
3612
3729
  return doReplay(
3613
3730
  this.httpClient,
3614
3731
  this.serviceUrl,
@@ -3832,6 +3949,11 @@ var finalizers = {
3832
3949
  readableStream
3833
3950
  };
3834
3951
 
3952
+ // src/replayRegistry.ts
3953
+ function defineReplayRegistry(registry) {
3954
+ return registry;
3955
+ }
3956
+
3835
3957
  export {
3836
3958
  BitfabClaudeAgentHandler,
3837
3959
  SUPPORTED_PROVIDERS,
@@ -3844,6 +3966,7 @@ export {
3844
3966
  getCurrentTrace,
3845
3967
  Bitfab,
3846
3968
  BitfabFunction,
3847
- finalizers
3969
+ finalizers,
3970
+ defineReplayRegistry
3848
3971
  };
3849
- //# sourceMappingURL=chunk-CWXCVY75.js.map
3972
+ //# sourceMappingURL=chunk-NKX3EY35.js.map