@bitfab/sdk 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
@@ -88,7 +88,7 @@ var __version__, __packageName__;
88
88
  var init_version_generated = __esm({
89
89
  "src/version.generated.ts"() {
90
90
  "use strict";
91
- __version__ = "0.38.1";
91
+ __version__ = "0.38.3";
92
92
  __packageName__ = "@bitfab/sdk";
93
93
  }
94
94
  });
@@ -819,7 +819,7 @@ var init_otel = __esm({
819
819
  EXPORT_CONCURRENCY_ENV = "BITFAB_OTEL_EXPORT_CONCURRENCY";
820
820
  MAX_QUEUE_SIZE = 8192;
821
821
  DIRECT_MAX_EXPORT_BATCH_SIZE = 512;
822
- DIRECT_MAX_REQUEST_BATCH_SIZE = 8;
822
+ DIRECT_MAX_REQUEST_BATCH_SIZE = 128;
823
823
  DEFAULT_EXPORT_CONCURRENCY = 32;
824
824
  MAX_EXPORT_CONCURRENCY = 64;
825
825
  SCHEDULE_DELAY_MILLIS = 5e3;
@@ -1711,6 +1711,12 @@ var init_http = __esm({
1711
1711
  async lookupFunction(name) {
1712
1712
  return this.request("/api/sdk/functions/lookup", { name });
1713
1713
  }
1714
+ async getAutoTracePolicy(traceFunctionKey, protocol) {
1715
+ return this.request("/api/sdk/auto-trace/policy", {
1716
+ traceFunctionKey,
1717
+ protocol
1718
+ });
1719
+ }
1714
1720
  async getTraceSpan(traceId, lookup) {
1715
1721
  const searchParams = new URLSearchParams();
1716
1722
  if (lookup.id !== void 0) {
@@ -2805,6 +2811,11 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2805
2811
  );
2806
2812
  }
2807
2813
  }
2814
+ if (options?.traceIds !== void 0 && options?.datasetId !== void 0) {
2815
+ throw new BitfabError(
2816
+ "traceIds and datasetId select different replay sources and cannot be used together."
2817
+ );
2818
+ }
2808
2819
  if (options?.limit !== void 0 && options?.traceIds !== void 0) {
2809
2820
  try {
2810
2821
  console.warn(
@@ -3132,6 +3143,7 @@ __export(node_exports, {
3132
3143
  ReplayError: () => ReplayError,
3133
3144
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
3134
3145
  __version__: () => __version__,
3146
+ defineReplayRegistry: () => defineReplayRegistry,
3135
3147
  finalizers: () => finalizers,
3136
3148
  flushTraces: () => flushTraces,
3137
3149
  getCurrentReplayBranch: () => getCurrentReplayBranch,
@@ -3763,6 +3775,80 @@ var BitfabClaudeAgentHandler = class {
3763
3775
  // src/client.ts
3764
3776
  init_asyncStorage();
3765
3777
 
3778
+ // src/autoTrace.ts
3779
+ init_asyncStorage();
3780
+ var autoTraceGlobal = globalThis;
3781
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
3782
+ storage: null,
3783
+ browserScope: void 0,
3784
+ capturePolicies: /* @__PURE__ */ new WeakMap(),
3785
+ activeRoots: 0
3786
+ };
3787
+ autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
3788
+ function initializeAutoTraceStorage() {
3789
+ autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
3790
+ }
3791
+ function runWithAutoTraceContext(context, fn, depth = 0) {
3792
+ initializeAutoTraceStorage();
3793
+ const scope = { context, depth };
3794
+ if (autoTraceState.storage) {
3795
+ return autoTraceState.storage.run(scope, fn);
3796
+ }
3797
+ const previous = autoTraceState.browserScope;
3798
+ autoTraceState.browserScope = scope;
3799
+ try {
3800
+ return fn();
3801
+ } finally {
3802
+ autoTraceState.browserScope = previous;
3803
+ }
3804
+ }
3805
+ function runWithAutoTraceRootContext(context, fn) {
3806
+ autoTraceState.activeRoots += 1;
3807
+ let result;
3808
+ try {
3809
+ result = runWithAutoTraceContext(context, fn);
3810
+ } catch (error) {
3811
+ autoTraceState.activeRoots -= 1;
3812
+ throw error;
3813
+ }
3814
+ if (isAutoTraceAsyncGenerator(result)) {
3815
+ autoTraceState.activeRoots -= 1;
3816
+ return wrapAutoTraceAsyncGenerator(context, result);
3817
+ }
3818
+ if (result instanceof Promise) {
3819
+ return result.finally(() => {
3820
+ autoTraceState.activeRoots -= 1;
3821
+ });
3822
+ }
3823
+ autoTraceState.activeRoots -= 1;
3824
+ return result;
3825
+ }
3826
+ function isAutoTraceAsyncGenerator(value) {
3827
+ if (value === null || typeof value !== "object") {
3828
+ return false;
3829
+ }
3830
+ const candidate = value;
3831
+ return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
3832
+ }
3833
+ function wrapAutoTraceAsyncGenerator(context, source) {
3834
+ const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
3835
+ const wrapped = {
3836
+ next: (value) => step("next", value),
3837
+ return: (value) => step("return", value),
3838
+ throw: (error) => step("throw", error),
3839
+ [Symbol.asyncIterator]: () => wrapped
3840
+ };
3841
+ return wrapped;
3842
+ }
3843
+ function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
3844
+ const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
3845
+ policies.set(traceFunctionKey, new Set(functionIds));
3846
+ autoTraceState.capturePolicies.set(client, policies);
3847
+ }
3848
+ function getAutoTraceCapturePolicy(client, traceFunctionKey) {
3849
+ return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
3850
+ }
3851
+
3766
3852
  // src/optionalPeer.ts
3767
3853
  function importOptionalPeer(specifierParts) {
3768
3854
  const specifier = specifierParts.join("/");
@@ -5504,6 +5590,14 @@ function readEnv2(name) {
5504
5590
  }
5505
5591
  return void 0;
5506
5592
  }
5593
+ var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
5594
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
5595
+ var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
5596
+ var AUTO_TRACE_POLICY_REFRESH_MS = 6e4;
5597
+ var AUTO_TRACE_POLICY_RETRY_MS = 1e4;
5598
+ function autoTraceLimit(value, fallback) {
5599
+ return value !== void 0 && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
5600
+ }
5507
5601
  var Bitfab = class {
5508
5602
  /**
5509
5603
  * Initialize the Bitfab client.
@@ -5513,6 +5607,7 @@ var Bitfab = class {
5513
5607
  constructor(config) {
5514
5608
  /** Gate the empty-key warning to fire at most once. */
5515
5609
  this.apiKeyWarned = false;
5610
+ this.autoTracePolicyRefreshes = /* @__PURE__ */ new Map();
5516
5611
  /**
5517
5612
  * Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
5518
5613
  * to every `replay` on this client (after any per-call `mockOverride`). In
@@ -5536,6 +5631,178 @@ var Bitfab = class {
5536
5631
  timeout: this.timeout
5537
5632
  });
5538
5633
  }
5634
+ /**
5635
+ * Decorate a class method as an automatically expanded trace root.
5636
+ *
5637
+ * Build instrumentation turns repository functions called beneath this
5638
+ * method into nested spans. Every generated span preserves structure; only
5639
+ * function IDs selected by the capture policy include inputs and output.
5640
+ * Without a compatible build transform, this still records the decorated
5641
+ * method as a normal rich root span but cannot discover child calls.
5642
+ *
5643
+ * @param traceFunctionKey - Groups traces and their capture policy.
5644
+ * @param options - Root presentation, subtree bounds, and exclusions.
5645
+ * @experimental Automatic child-call instrumentation is experimental.
5646
+ */
5647
+ trace(traceFunctionKey, options = {}) {
5648
+ const decorator = (...args) => {
5649
+ if (args.length === 3) {
5650
+ const propertyKey = args[1];
5651
+ const descriptor = args[2];
5652
+ if (!descriptor || typeof descriptor.value !== "function") {
5653
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5654
+ }
5655
+ if (!this.explicitlyEnabled) {
5656
+ return;
5657
+ }
5658
+ descriptor.value = this.createAutoTraceRoot(
5659
+ traceFunctionKey,
5660
+ String(propertyKey),
5661
+ options,
5662
+ descriptor.value
5663
+ );
5664
+ return;
5665
+ }
5666
+ const method = args[0];
5667
+ const context = args[1];
5668
+ if (typeof method !== "function" || context?.kind !== "method" || context.name === void 0) {
5669
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5670
+ }
5671
+ if (!this.explicitlyEnabled) {
5672
+ return method;
5673
+ }
5674
+ return this.createAutoTraceRoot(
5675
+ traceFunctionKey,
5676
+ String(context.name),
5677
+ options,
5678
+ method
5679
+ );
5680
+ };
5681
+ return decorator;
5682
+ }
5683
+ withTrace(traceFunctionKey, optionsOrFn, maybeFn) {
5684
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
5685
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
5686
+ if (!fn) {
5687
+ throw new BitfabError("bitfab.withTrace requires a function");
5688
+ }
5689
+ if (!this.explicitlyEnabled) {
5690
+ return fn;
5691
+ }
5692
+ const name = fn.name !== "" ? fn.name : traceFunctionKey;
5693
+ return this.createAutoTraceRoot(traceFunctionKey, name, options, fn);
5694
+ }
5695
+ createAutoTraceRoot(traceFunctionKey, name, options, fn) {
5696
+ const self = this;
5697
+ const maxDepth = autoTraceLimit(
5698
+ options.maxDepth,
5699
+ DEFAULT_AUTO_TRACE_MAX_DEPTH
5700
+ );
5701
+ const maxSpans = autoTraceLimit(
5702
+ options.maxSpans,
5703
+ DEFAULT_AUTO_TRACE_MAX_SPANS
5704
+ );
5705
+ const excluded = new Set(options.exclude ?? []);
5706
+ const includeWrappers = options.includeWrappers ?? false;
5707
+ const tracedRoot = this.withSpan(
5708
+ traceFunctionKey,
5709
+ { name: options.name ?? name, type: options.type ?? "custom" },
5710
+ function(...args) {
5711
+ const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
5712
+ self.refreshAutoTraceCapturePolicy(traceFunctionKey);
5713
+ let spansUsed = 0;
5714
+ let truncated = false;
5715
+ const warnTruncated = () => {
5716
+ if (!truncated) {
5717
+ truncated = true;
5718
+ getCurrentTrace().setMetadata({
5719
+ bitfabAutoTrace: {
5720
+ protocol: AUTO_TRACE_PROTOCOL,
5721
+ truncated: true,
5722
+ maxDepth,
5723
+ maxSpans
5724
+ }
5725
+ });
5726
+ }
5727
+ warnOnce(
5728
+ `auto-trace-truncated:${traceFunctionKey}`,
5729
+ `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
5730
+ );
5731
+ };
5732
+ const autoTraceContext = {
5733
+ invoke(definition, inputs, invokeFn, depth) {
5734
+ const nameParts = definition.name.split(".");
5735
+ const simpleName = nameParts[nameParts.length - 1];
5736
+ if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || definition.wrapper === true && !includeWrappers) {
5737
+ return invokeFn();
5738
+ }
5739
+ if (depth >= maxDepth || spansUsed >= maxSpans) {
5740
+ warnTruncated();
5741
+ return invokeFn();
5742
+ }
5743
+ spansUsed += 1;
5744
+ const childOptions = {
5745
+ name: definition.name,
5746
+ type: "function",
5747
+ captureWhen: "nested",
5748
+ functionId: definition.id,
5749
+ captureContent: capturePolicy.has(definition.id),
5750
+ autoTraceDefinition: definition
5751
+ };
5752
+ const tracedChild = self.withSpan(
5753
+ traceFunctionKey,
5754
+ childOptions,
5755
+ (..._inputs) => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1)
5756
+ );
5757
+ return tracedChild(...inputs);
5758
+ }
5759
+ };
5760
+ return runWithAutoTraceRootContext(
5761
+ autoTraceContext,
5762
+ () => fn.apply(this, args)
5763
+ );
5764
+ }
5765
+ );
5766
+ const autoTraceRoot = function(...args) {
5767
+ if (!self.isTracingEnabled()) {
5768
+ return fn.apply(this, args);
5769
+ }
5770
+ return tracedRoot.apply(this, args);
5771
+ };
5772
+ Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
5773
+ value: traceFunctionKey
5774
+ });
5775
+ return autoTraceRoot;
5776
+ }
5777
+ refreshAutoTraceCapturePolicy(traceFunctionKey) {
5778
+ const now = Date.now();
5779
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
5780
+ refreshAfter: 0
5781
+ };
5782
+ if (state.inFlight || now < state.refreshAfter) {
5783
+ return;
5784
+ }
5785
+ const request = this.httpClient.getAutoTracePolicy(
5786
+ traceFunctionKey,
5787
+ AUTO_TRACE_PROTOCOL
5788
+ ).then((policy) => {
5789
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
5790
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5791
+ return;
5792
+ }
5793
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
5794
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
5795
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
5796
+ __setBitfabAutoTraceCapturePolicy(this, traceFunctionKey, functionIds);
5797
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
5798
+ }).catch(() => {
5799
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5800
+ }).finally(() => {
5801
+ state.inFlight = void 0;
5802
+ });
5803
+ state.inFlight = request;
5804
+ this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
5805
+ }
5539
5806
  /**
5540
5807
  * Flush and permanently close this client's tracing resources: its pending
5541
5808
  * requests and the single span-transport worker shared by its decorators and
@@ -6082,7 +6349,10 @@ var Bitfab = class {
6082
6349
  parentSpanId,
6083
6350
  inputs,
6084
6351
  startedAt,
6085
- spanType: options.type ?? "custom"
6352
+ spanType: options.type ?? "custom",
6353
+ functionId: options.functionId,
6354
+ captureContent: options.captureContent ?? true,
6355
+ autoTraceDefinition: options.autoTraceDefinition
6086
6356
  };
6087
6357
  const sendSpan = async (params) => {
6088
6358
  const replayCtx = getReplayContext();
@@ -6247,7 +6517,16 @@ var Bitfab = class {
6247
6517
  }
6248
6518
  };
6249
6519
  executeWithContext = () => {
6250
- const result = fn.apply(this, args);
6520
+ let result;
6521
+ try {
6522
+ result = fn.apply(this, args);
6523
+ } catch (error) {
6524
+ void sendSpan({
6525
+ result: void 0,
6526
+ error: error instanceof Error ? error.message : String(error)
6527
+ });
6528
+ throw error;
6529
+ }
6251
6530
  if (result instanceof Promise) {
6252
6531
  return result.then((resolvedResult) => {
6253
6532
  recordSpan(resolvedResult);
@@ -6488,8 +6767,8 @@ var Bitfab = class {
6488
6767
  * Queued on the client's span transport; delivery is the transport's job.
6489
6768
  */
6490
6769
  sendWrapperSpan(params) {
6491
- const serializedInputs = serializeValue(params.inputs);
6492
- const serializedResult = serializeValue(params.result);
6770
+ const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
6771
+ const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
6493
6772
  const externalSpan = {
6494
6773
  id: params.spanId,
6495
6774
  trace_id: params.traceId,
@@ -6498,26 +6777,38 @@ var Bitfab = class {
6498
6777
  span_data: {
6499
6778
  name: params.spanName,
6500
6779
  type: params.spanType,
6501
- input: serializedInputs.json,
6502
- output: serializedResult.json,
6503
- // Include superjson meta for type preservation
6504
- ...serializedInputs.meta !== void 0 && {
6505
- input_meta: serializedInputs.meta
6780
+ ...params.functionId !== void 0 && {
6781
+ function_id: params.functionId,
6782
+ content_captured: params.captureContent
6783
+ },
6784
+ ...params.autoTraceDefinition !== void 0 && {
6785
+ function_file: params.autoTraceDefinition.file,
6786
+ function_line: params.autoTraceDefinition.line,
6787
+ function_column: params.autoTraceDefinition.column
6506
6788
  },
6507
- ...serializedResult.meta !== void 0 && {
6508
- output_meta: serializedResult.meta
6789
+ ...serializedInputs !== void 0 && {
6790
+ input: serializedInputs.json,
6791
+ ...serializedInputs.meta !== void 0 && {
6792
+ input_meta: serializedInputs.meta
6793
+ }
6794
+ },
6795
+ ...serializedResult !== void 0 && {
6796
+ output: serializedResult.json,
6797
+ ...serializedResult.meta !== void 0 && {
6798
+ output_meta: serializedResult.meta
6799
+ }
6509
6800
  },
6510
6801
  ...params.functionName !== void 0 && {
6511
6802
  function_name: params.functionName
6512
6803
  },
6513
- ...params.error !== void 0 && {
6804
+ ...params.captureContent && params.error !== void 0 && {
6514
6805
  error: params.error,
6515
6806
  error_source: "code"
6516
6807
  },
6517
- ...params.contexts && params.contexts.length > 0 && {
6808
+ ...params.captureContent && params.contexts && params.contexts.length > 0 && {
6518
6809
  contexts: params.contexts
6519
6810
  },
6520
- ...params.prompt !== void 0 && { prompt: params.prompt }
6811
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
6521
6812
  }
6522
6813
  };
6523
6814
  if (params.parentSpanId) {
@@ -6793,6 +7084,13 @@ var finalizers = {
6793
7084
  init_http();
6794
7085
  init_replay();
6795
7086
 
7087
+ // src/replayRegistry.ts
7088
+ init_errors();
7089
+ init_replay();
7090
+ function defineReplayRegistry(registry) {
7091
+ return registry;
7092
+ }
7093
+
6796
7094
  // src/node.ts
6797
7095
  init_asyncStorage();
6798
7096
  assertAsyncStorageRegistered();
@@ -6814,6 +7112,7 @@ assertAsyncStorageRegistered();
6814
7112
  ReplayError,
6815
7113
  SUPPORTED_PROVIDERS,
6816
7114
  __version__,
7115
+ defineReplayRegistry,
6817
7116
  finalizers,
6818
7117
  flushTraces,
6819
7118
  getCurrentReplayBranch,