bitfab 0.38.1 → 0.38.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.
package/dist/node.cjs CHANGED
@@ -97,7 +97,7 @@ var __version__, __packageName__;
97
97
  var init_version_generated = __esm({
98
98
  "src/version.generated.ts"() {
99
99
  "use strict";
100
- __version__ = "0.38.1";
100
+ __version__ = "0.38.3";
101
101
  __packageName__ = "bitfab";
102
102
  }
103
103
  });
@@ -828,7 +828,7 @@ var init_otel = __esm({
828
828
  EXPORT_CONCURRENCY_ENV = "BITFAB_OTEL_EXPORT_CONCURRENCY";
829
829
  MAX_QUEUE_SIZE = 8192;
830
830
  DIRECT_MAX_EXPORT_BATCH_SIZE = 512;
831
- DIRECT_MAX_REQUEST_BATCH_SIZE = 8;
831
+ DIRECT_MAX_REQUEST_BATCH_SIZE = 128;
832
832
  DEFAULT_EXPORT_CONCURRENCY = 32;
833
833
  MAX_EXPORT_CONCURRENCY = 64;
834
834
  SCHEDULE_DELAY_MILLIS = 5e3;
@@ -1720,6 +1720,12 @@ var init_http = __esm({
1720
1720
  async lookupFunction(name) {
1721
1721
  return this.request("/api/sdk/functions/lookup", { name });
1722
1722
  }
1723
+ async getAutoTracePolicy(traceFunctionKey, protocol) {
1724
+ return this.request("/api/sdk/auto-trace/policy", {
1725
+ traceFunctionKey,
1726
+ protocol
1727
+ });
1728
+ }
1723
1729
  async getTraceSpan(traceId, lookup) {
1724
1730
  const searchParams = new URLSearchParams();
1725
1731
  if (lookup.id !== void 0) {
@@ -2814,6 +2820,11 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2814
2820
  );
2815
2821
  }
2816
2822
  }
2823
+ if (options?.traceIds !== void 0 && options?.datasetId !== void 0) {
2824
+ throw new BitfabError(
2825
+ "traceIds and datasetId select different replay sources and cannot be used together."
2826
+ );
2827
+ }
2817
2828
  if (options?.limit !== void 0 && options?.traceIds !== void 0) {
2818
2829
  try {
2819
2830
  console.warn(
@@ -3141,6 +3152,7 @@ __export(node_exports, {
3141
3152
  ReplayError: () => ReplayError,
3142
3153
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
3143
3154
  __version__: () => __version__,
3155
+ defineReplayRegistry: () => defineReplayRegistry,
3144
3156
  finalizers: () => finalizers,
3145
3157
  flushTraces: () => flushTraces,
3146
3158
  getCurrentReplayBranch: () => getCurrentReplayBranch,
@@ -3772,6 +3784,80 @@ var BitfabClaudeAgentHandler = class {
3772
3784
  // src/client.ts
3773
3785
  init_asyncStorage();
3774
3786
 
3787
+ // src/autoTrace.ts
3788
+ init_asyncStorage();
3789
+ var autoTraceGlobal = globalThis;
3790
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
3791
+ storage: null,
3792
+ browserScope: void 0,
3793
+ capturePolicies: /* @__PURE__ */ new WeakMap(),
3794
+ activeRoots: 0
3795
+ };
3796
+ autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
3797
+ function initializeAutoTraceStorage() {
3798
+ autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
3799
+ }
3800
+ function runWithAutoTraceContext(context, fn, depth = 0) {
3801
+ initializeAutoTraceStorage();
3802
+ const scope = { context, depth };
3803
+ if (autoTraceState.storage) {
3804
+ return autoTraceState.storage.run(scope, fn);
3805
+ }
3806
+ const previous = autoTraceState.browserScope;
3807
+ autoTraceState.browserScope = scope;
3808
+ try {
3809
+ return fn();
3810
+ } finally {
3811
+ autoTraceState.browserScope = previous;
3812
+ }
3813
+ }
3814
+ function runWithAutoTraceRootContext(context, fn) {
3815
+ autoTraceState.activeRoots += 1;
3816
+ let result;
3817
+ try {
3818
+ result = runWithAutoTraceContext(context, fn);
3819
+ } catch (error) {
3820
+ autoTraceState.activeRoots -= 1;
3821
+ throw error;
3822
+ }
3823
+ if (isAutoTraceAsyncGenerator(result)) {
3824
+ autoTraceState.activeRoots -= 1;
3825
+ return wrapAutoTraceAsyncGenerator(context, result);
3826
+ }
3827
+ if (result instanceof Promise) {
3828
+ return result.finally(() => {
3829
+ autoTraceState.activeRoots -= 1;
3830
+ });
3831
+ }
3832
+ autoTraceState.activeRoots -= 1;
3833
+ return result;
3834
+ }
3835
+ function isAutoTraceAsyncGenerator(value) {
3836
+ if (value === null || typeof value !== "object") {
3837
+ return false;
3838
+ }
3839
+ const candidate = value;
3840
+ return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
3841
+ }
3842
+ function wrapAutoTraceAsyncGenerator(context, source) {
3843
+ const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
3844
+ const wrapped = {
3845
+ next: (value) => step("next", value),
3846
+ return: (value) => step("return", value),
3847
+ throw: (error) => step("throw", error),
3848
+ [Symbol.asyncIterator]: () => wrapped
3849
+ };
3850
+ return wrapped;
3851
+ }
3852
+ function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
3853
+ const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
3854
+ policies.set(traceFunctionKey, new Set(functionIds));
3855
+ autoTraceState.capturePolicies.set(client, policies);
3856
+ }
3857
+ function getAutoTraceCapturePolicy(client, traceFunctionKey) {
3858
+ return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
3859
+ }
3860
+
3775
3861
  // src/optionalPeer.ts
3776
3862
  function importOptionalPeer(specifierParts) {
3777
3863
  const specifier = specifierParts.join("/");
@@ -5513,6 +5599,14 @@ function readEnv2(name) {
5513
5599
  }
5514
5600
  return void 0;
5515
5601
  }
5602
+ var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
5603
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
5604
+ var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
5605
+ var AUTO_TRACE_POLICY_REFRESH_MS = 6e4;
5606
+ var AUTO_TRACE_POLICY_RETRY_MS = 1e4;
5607
+ function autoTraceLimit(value, fallback) {
5608
+ return value !== void 0 && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
5609
+ }
5516
5610
  var Bitfab = class {
5517
5611
  /**
5518
5612
  * Initialize the Bitfab client.
@@ -5522,6 +5616,7 @@ var Bitfab = class {
5522
5616
  constructor(config) {
5523
5617
  /** Gate the empty-key warning to fire at most once. */
5524
5618
  this.apiKeyWarned = false;
5619
+ this.autoTracePolicyRefreshes = /* @__PURE__ */ new Map();
5525
5620
  /**
5526
5621
  * Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
5527
5622
  * to every `replay` on this client (after any per-call `mockOverride`). In
@@ -5545,6 +5640,178 @@ var Bitfab = class {
5545
5640
  timeout: this.timeout
5546
5641
  });
5547
5642
  }
5643
+ /**
5644
+ * Decorate a class method as an automatically expanded trace root.
5645
+ *
5646
+ * Build instrumentation turns repository functions called beneath this
5647
+ * method into nested spans. Every generated span preserves structure; only
5648
+ * function IDs selected by the capture policy include inputs and output.
5649
+ * Without a compatible build transform, this still records the decorated
5650
+ * method as a normal rich root span but cannot discover child calls.
5651
+ *
5652
+ * @param traceFunctionKey - Groups traces and their capture policy.
5653
+ * @param options - Root presentation, subtree bounds, and exclusions.
5654
+ * @experimental Automatic child-call instrumentation is experimental.
5655
+ */
5656
+ trace(traceFunctionKey, options = {}) {
5657
+ const decorator = (...args) => {
5658
+ if (args.length === 3) {
5659
+ const propertyKey = args[1];
5660
+ const descriptor = args[2];
5661
+ if (!descriptor || typeof descriptor.value !== "function") {
5662
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5663
+ }
5664
+ if (!this.explicitlyEnabled) {
5665
+ return;
5666
+ }
5667
+ descriptor.value = this.createAutoTraceRoot(
5668
+ traceFunctionKey,
5669
+ String(propertyKey),
5670
+ options,
5671
+ descriptor.value
5672
+ );
5673
+ return;
5674
+ }
5675
+ const method = args[0];
5676
+ const context = args[1];
5677
+ if (typeof method !== "function" || context?.kind !== "method" || context.name === void 0) {
5678
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5679
+ }
5680
+ if (!this.explicitlyEnabled) {
5681
+ return method;
5682
+ }
5683
+ return this.createAutoTraceRoot(
5684
+ traceFunctionKey,
5685
+ String(context.name),
5686
+ options,
5687
+ method
5688
+ );
5689
+ };
5690
+ return decorator;
5691
+ }
5692
+ withTrace(traceFunctionKey, optionsOrFn, maybeFn) {
5693
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
5694
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
5695
+ if (!fn) {
5696
+ throw new BitfabError("bitfab.withTrace requires a function");
5697
+ }
5698
+ if (!this.explicitlyEnabled) {
5699
+ return fn;
5700
+ }
5701
+ const name = fn.name !== "" ? fn.name : traceFunctionKey;
5702
+ return this.createAutoTraceRoot(traceFunctionKey, name, options, fn);
5703
+ }
5704
+ createAutoTraceRoot(traceFunctionKey, name, options, fn) {
5705
+ const self = this;
5706
+ const maxDepth = autoTraceLimit(
5707
+ options.maxDepth,
5708
+ DEFAULT_AUTO_TRACE_MAX_DEPTH
5709
+ );
5710
+ const maxSpans = autoTraceLimit(
5711
+ options.maxSpans,
5712
+ DEFAULT_AUTO_TRACE_MAX_SPANS
5713
+ );
5714
+ const excluded = new Set(options.exclude ?? []);
5715
+ const includeWrappers = options.includeWrappers ?? false;
5716
+ const tracedRoot = this.withSpan(
5717
+ traceFunctionKey,
5718
+ { name: options.name ?? name, type: options.type ?? "custom" },
5719
+ function(...args) {
5720
+ const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
5721
+ self.refreshAutoTraceCapturePolicy(traceFunctionKey);
5722
+ let spansUsed = 0;
5723
+ let truncated = false;
5724
+ const warnTruncated = () => {
5725
+ if (!truncated) {
5726
+ truncated = true;
5727
+ getCurrentTrace().setMetadata({
5728
+ bitfabAutoTrace: {
5729
+ protocol: AUTO_TRACE_PROTOCOL,
5730
+ truncated: true,
5731
+ maxDepth,
5732
+ maxSpans
5733
+ }
5734
+ });
5735
+ }
5736
+ warnOnce(
5737
+ `auto-trace-truncated:${traceFunctionKey}`,
5738
+ `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
5739
+ );
5740
+ };
5741
+ const autoTraceContext = {
5742
+ invoke(definition, inputs, invokeFn, depth) {
5743
+ const nameParts = definition.name.split(".");
5744
+ const simpleName = nameParts[nameParts.length - 1];
5745
+ if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || definition.wrapper === true && !includeWrappers) {
5746
+ return invokeFn();
5747
+ }
5748
+ if (depth >= maxDepth || spansUsed >= maxSpans) {
5749
+ warnTruncated();
5750
+ return invokeFn();
5751
+ }
5752
+ spansUsed += 1;
5753
+ const childOptions = {
5754
+ name: definition.name,
5755
+ type: "function",
5756
+ captureWhen: "nested",
5757
+ functionId: definition.id,
5758
+ captureContent: capturePolicy.has(definition.id),
5759
+ autoTraceDefinition: definition
5760
+ };
5761
+ const tracedChild = self.withSpan(
5762
+ traceFunctionKey,
5763
+ childOptions,
5764
+ (..._inputs) => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1)
5765
+ );
5766
+ return tracedChild(...inputs);
5767
+ }
5768
+ };
5769
+ return runWithAutoTraceRootContext(
5770
+ autoTraceContext,
5771
+ () => fn.apply(this, args)
5772
+ );
5773
+ }
5774
+ );
5775
+ const autoTraceRoot = function(...args) {
5776
+ if (!self.isTracingEnabled()) {
5777
+ return fn.apply(this, args);
5778
+ }
5779
+ return tracedRoot.apply(this, args);
5780
+ };
5781
+ Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
5782
+ value: traceFunctionKey
5783
+ });
5784
+ return autoTraceRoot;
5785
+ }
5786
+ refreshAutoTraceCapturePolicy(traceFunctionKey) {
5787
+ const now = Date.now();
5788
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
5789
+ refreshAfter: 0
5790
+ };
5791
+ if (state.inFlight || now < state.refreshAfter) {
5792
+ return;
5793
+ }
5794
+ const request = this.httpClient.getAutoTracePolicy(
5795
+ traceFunctionKey,
5796
+ AUTO_TRACE_PROTOCOL
5797
+ ).then((policy) => {
5798
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
5799
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5800
+ return;
5801
+ }
5802
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
5803
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
5804
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
5805
+ __setBitfabAutoTraceCapturePolicy(this, traceFunctionKey, functionIds);
5806
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
5807
+ }).catch(() => {
5808
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5809
+ }).finally(() => {
5810
+ state.inFlight = void 0;
5811
+ });
5812
+ state.inFlight = request;
5813
+ this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
5814
+ }
5548
5815
  /**
5549
5816
  * Flush and permanently close this client's tracing resources: its pending
5550
5817
  * requests and the single span-transport worker shared by its decorators and
@@ -6091,7 +6358,10 @@ var Bitfab = class {
6091
6358
  parentSpanId,
6092
6359
  inputs,
6093
6360
  startedAt,
6094
- spanType: options.type ?? "custom"
6361
+ spanType: options.type ?? "custom",
6362
+ functionId: options.functionId,
6363
+ captureContent: options.captureContent ?? true,
6364
+ autoTraceDefinition: options.autoTraceDefinition
6095
6365
  };
6096
6366
  const sendSpan = async (params) => {
6097
6367
  const replayCtx = getReplayContext();
@@ -6256,7 +6526,16 @@ var Bitfab = class {
6256
6526
  }
6257
6527
  };
6258
6528
  executeWithContext = () => {
6259
- const result = fn.apply(this, args);
6529
+ let result;
6530
+ try {
6531
+ result = fn.apply(this, args);
6532
+ } catch (error) {
6533
+ void sendSpan({
6534
+ result: void 0,
6535
+ error: error instanceof Error ? error.message : String(error)
6536
+ });
6537
+ throw error;
6538
+ }
6260
6539
  if (result instanceof Promise) {
6261
6540
  return result.then((resolvedResult) => {
6262
6541
  recordSpan(resolvedResult);
@@ -6497,8 +6776,8 @@ var Bitfab = class {
6497
6776
  * Queued on the client's span transport; delivery is the transport's job.
6498
6777
  */
6499
6778
  sendWrapperSpan(params) {
6500
- const serializedInputs = serializeValue(params.inputs);
6501
- const serializedResult = serializeValue(params.result);
6779
+ const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
6780
+ const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
6502
6781
  const externalSpan = {
6503
6782
  id: params.spanId,
6504
6783
  trace_id: params.traceId,
@@ -6507,26 +6786,38 @@ var Bitfab = class {
6507
6786
  span_data: {
6508
6787
  name: params.spanName,
6509
6788
  type: params.spanType,
6510
- input: serializedInputs.json,
6511
- output: serializedResult.json,
6512
- // Include superjson meta for type preservation
6513
- ...serializedInputs.meta !== void 0 && {
6514
- input_meta: serializedInputs.meta
6789
+ ...params.functionId !== void 0 && {
6790
+ function_id: params.functionId,
6791
+ content_captured: params.captureContent
6792
+ },
6793
+ ...params.autoTraceDefinition !== void 0 && {
6794
+ function_file: params.autoTraceDefinition.file,
6795
+ function_line: params.autoTraceDefinition.line,
6796
+ function_column: params.autoTraceDefinition.column
6515
6797
  },
6516
- ...serializedResult.meta !== void 0 && {
6517
- output_meta: serializedResult.meta
6798
+ ...serializedInputs !== void 0 && {
6799
+ input: serializedInputs.json,
6800
+ ...serializedInputs.meta !== void 0 && {
6801
+ input_meta: serializedInputs.meta
6802
+ }
6803
+ },
6804
+ ...serializedResult !== void 0 && {
6805
+ output: serializedResult.json,
6806
+ ...serializedResult.meta !== void 0 && {
6807
+ output_meta: serializedResult.meta
6808
+ }
6518
6809
  },
6519
6810
  ...params.functionName !== void 0 && {
6520
6811
  function_name: params.functionName
6521
6812
  },
6522
- ...params.error !== void 0 && {
6813
+ ...params.captureContent && params.error !== void 0 && {
6523
6814
  error: params.error,
6524
6815
  error_source: "code"
6525
6816
  },
6526
- ...params.contexts && params.contexts.length > 0 && {
6817
+ ...params.captureContent && params.contexts && params.contexts.length > 0 && {
6527
6818
  contexts: params.contexts
6528
6819
  },
6529
- ...params.prompt !== void 0 && { prompt: params.prompt }
6820
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
6530
6821
  }
6531
6822
  };
6532
6823
  if (params.parentSpanId) {
@@ -6802,6 +7093,13 @@ var finalizers = {
6802
7093
  init_http();
6803
7094
  init_replay();
6804
7095
 
7096
+ // src/replayRegistry.ts
7097
+ init_errors();
7098
+ init_replay();
7099
+ function defineReplayRegistry(registry) {
7100
+ return registry;
7101
+ }
7102
+
6805
7103
  // src/node.ts
6806
7104
  init_asyncStorage();
6807
7105
  assertAsyncStorageRegistered();
@@ -6823,6 +7121,7 @@ assertAsyncStorageRegistered();
6823
7121
  ReplayError,
6824
7122
  SUPPORTED_PROVIDERS,
6825
7123
  __version__,
7124
+ defineReplayRegistry,
6826
7125
  finalizers,
6827
7126
  flushTraces,
6828
7127
  getCurrentReplayBranch,