@bitfab/sdk 0.38.1 → 0.38.2

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/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__, __packageName__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.38.1";
45
+ __version__ = "0.38.2";
46
46
  __packageName__ = "@bitfab/sdk";
47
47
  }
48
48
  });
@@ -812,7 +812,7 @@ var init_otel = __esm({
812
812
  EXPORT_CONCURRENCY_ENV = "BITFAB_OTEL_EXPORT_CONCURRENCY";
813
813
  MAX_QUEUE_SIZE = 8192;
814
814
  DIRECT_MAX_EXPORT_BATCH_SIZE = 512;
815
- DIRECT_MAX_REQUEST_BATCH_SIZE = 8;
815
+ DIRECT_MAX_REQUEST_BATCH_SIZE = 128;
816
816
  DEFAULT_EXPORT_CONCURRENCY = 32;
817
817
  MAX_EXPORT_CONCURRENCY = 64;
818
818
  SCHEDULE_DELAY_MILLIS = 5e3;
@@ -1704,6 +1704,12 @@ var init_http = __esm({
1704
1704
  async lookupFunction(name) {
1705
1705
  return this.request("/api/sdk/functions/lookup", { name });
1706
1706
  }
1707
+ async getAutoTracePolicy(traceFunctionKey, protocol) {
1708
+ return this.request("/api/sdk/auto-trace/policy", {
1709
+ traceFunctionKey,
1710
+ protocol
1711
+ });
1712
+ }
1707
1713
  async getTraceSpan(traceId, lookup) {
1708
1714
  const searchParams = new URLSearchParams();
1709
1715
  if (lookup.id !== void 0) {
@@ -3749,6 +3755,80 @@ var BitfabClaudeAgentHandler = class {
3749
3755
  // src/client.ts
3750
3756
  init_asyncStorage();
3751
3757
 
3758
+ // src/autoTrace.ts
3759
+ init_asyncStorage();
3760
+ var autoTraceGlobal = globalThis;
3761
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
3762
+ storage: null,
3763
+ browserScope: void 0,
3764
+ capturePolicies: /* @__PURE__ */ new WeakMap(),
3765
+ activeRoots: 0
3766
+ };
3767
+ autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
3768
+ function initializeAutoTraceStorage() {
3769
+ autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
3770
+ }
3771
+ function runWithAutoTraceContext(context, fn, depth = 0) {
3772
+ initializeAutoTraceStorage();
3773
+ const scope = { context, depth };
3774
+ if (autoTraceState.storage) {
3775
+ return autoTraceState.storage.run(scope, fn);
3776
+ }
3777
+ const previous = autoTraceState.browserScope;
3778
+ autoTraceState.browserScope = scope;
3779
+ try {
3780
+ return fn();
3781
+ } finally {
3782
+ autoTraceState.browserScope = previous;
3783
+ }
3784
+ }
3785
+ function runWithAutoTraceRootContext(context, fn) {
3786
+ autoTraceState.activeRoots += 1;
3787
+ let result;
3788
+ try {
3789
+ result = runWithAutoTraceContext(context, fn);
3790
+ } catch (error) {
3791
+ autoTraceState.activeRoots -= 1;
3792
+ throw error;
3793
+ }
3794
+ if (isAutoTraceAsyncGenerator(result)) {
3795
+ autoTraceState.activeRoots -= 1;
3796
+ return wrapAutoTraceAsyncGenerator(context, result);
3797
+ }
3798
+ if (result instanceof Promise) {
3799
+ return result.finally(() => {
3800
+ autoTraceState.activeRoots -= 1;
3801
+ });
3802
+ }
3803
+ autoTraceState.activeRoots -= 1;
3804
+ return result;
3805
+ }
3806
+ function isAutoTraceAsyncGenerator(value) {
3807
+ if (value === null || typeof value !== "object") {
3808
+ return false;
3809
+ }
3810
+ const candidate = value;
3811
+ return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
3812
+ }
3813
+ function wrapAutoTraceAsyncGenerator(context, source) {
3814
+ const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
3815
+ const wrapped = {
3816
+ next: (value) => step("next", value),
3817
+ return: (value) => step("return", value),
3818
+ throw: (error) => step("throw", error),
3819
+ [Symbol.asyncIterator]: () => wrapped
3820
+ };
3821
+ return wrapped;
3822
+ }
3823
+ function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
3824
+ const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
3825
+ policies.set(traceFunctionKey, new Set(functionIds));
3826
+ autoTraceState.capturePolicies.set(client, policies);
3827
+ }
3828
+ function getAutoTraceCapturePolicy(client, traceFunctionKey) {
3829
+ return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
3830
+ }
3831
+
3752
3832
  // src/optionalPeer.ts
3753
3833
  function importOptionalPeer(specifierParts) {
3754
3834
  const specifier = specifierParts.join("/");
@@ -5490,6 +5570,14 @@ function readEnv2(name) {
5490
5570
  }
5491
5571
  return void 0;
5492
5572
  }
5573
+ var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
5574
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
5575
+ var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
5576
+ var AUTO_TRACE_POLICY_REFRESH_MS = 6e4;
5577
+ var AUTO_TRACE_POLICY_RETRY_MS = 1e4;
5578
+ function autoTraceLimit(value, fallback) {
5579
+ return value !== void 0 && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
5580
+ }
5493
5581
  var Bitfab = class {
5494
5582
  /**
5495
5583
  * Initialize the Bitfab client.
@@ -5499,6 +5587,7 @@ var Bitfab = class {
5499
5587
  constructor(config) {
5500
5588
  /** Gate the empty-key warning to fire at most once. */
5501
5589
  this.apiKeyWarned = false;
5590
+ this.autoTracePolicyRefreshes = /* @__PURE__ */ new Map();
5502
5591
  /**
5503
5592
  * Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
5504
5593
  * to every `replay` on this client (after any per-call `mockOverride`). In
@@ -5522,6 +5611,178 @@ var Bitfab = class {
5522
5611
  timeout: this.timeout
5523
5612
  });
5524
5613
  }
5614
+ /**
5615
+ * Decorate a class method as an automatically expanded trace root.
5616
+ *
5617
+ * Build instrumentation turns repository functions called beneath this
5618
+ * method into nested spans. Every generated span preserves structure; only
5619
+ * function IDs selected by the capture policy include inputs and output.
5620
+ * Without a compatible build transform, this still records the decorated
5621
+ * method as a normal rich root span but cannot discover child calls.
5622
+ *
5623
+ * @param traceFunctionKey - Groups traces and their capture policy.
5624
+ * @param options - Root presentation, subtree bounds, and exclusions.
5625
+ * @experimental Automatic child-call instrumentation is experimental.
5626
+ */
5627
+ trace(traceFunctionKey, options = {}) {
5628
+ const decorator = (...args) => {
5629
+ if (args.length === 3) {
5630
+ const propertyKey = args[1];
5631
+ const descriptor = args[2];
5632
+ if (!descriptor || typeof descriptor.value !== "function") {
5633
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5634
+ }
5635
+ if (!this.explicitlyEnabled) {
5636
+ return;
5637
+ }
5638
+ descriptor.value = this.createAutoTraceRoot(
5639
+ traceFunctionKey,
5640
+ String(propertyKey),
5641
+ options,
5642
+ descriptor.value
5643
+ );
5644
+ return;
5645
+ }
5646
+ const method = args[0];
5647
+ const context = args[1];
5648
+ if (typeof method !== "function" || context?.kind !== "method" || context.name === void 0) {
5649
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5650
+ }
5651
+ if (!this.explicitlyEnabled) {
5652
+ return method;
5653
+ }
5654
+ return this.createAutoTraceRoot(
5655
+ traceFunctionKey,
5656
+ String(context.name),
5657
+ options,
5658
+ method
5659
+ );
5660
+ };
5661
+ return decorator;
5662
+ }
5663
+ withTrace(traceFunctionKey, optionsOrFn, maybeFn) {
5664
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
5665
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
5666
+ if (!fn) {
5667
+ throw new BitfabError("bitfab.withTrace requires a function");
5668
+ }
5669
+ if (!this.explicitlyEnabled) {
5670
+ return fn;
5671
+ }
5672
+ const name = fn.name !== "" ? fn.name : traceFunctionKey;
5673
+ return this.createAutoTraceRoot(traceFunctionKey, name, options, fn);
5674
+ }
5675
+ createAutoTraceRoot(traceFunctionKey, name, options, fn) {
5676
+ const self = this;
5677
+ const maxDepth = autoTraceLimit(
5678
+ options.maxDepth,
5679
+ DEFAULT_AUTO_TRACE_MAX_DEPTH
5680
+ );
5681
+ const maxSpans = autoTraceLimit(
5682
+ options.maxSpans,
5683
+ DEFAULT_AUTO_TRACE_MAX_SPANS
5684
+ );
5685
+ const excluded = new Set(options.exclude ?? []);
5686
+ const includeWrappers = options.includeWrappers ?? false;
5687
+ const tracedRoot = this.withSpan(
5688
+ traceFunctionKey,
5689
+ { name: options.name ?? name, type: options.type ?? "custom" },
5690
+ function(...args) {
5691
+ const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
5692
+ self.refreshAutoTraceCapturePolicy(traceFunctionKey);
5693
+ let spansUsed = 0;
5694
+ let truncated = false;
5695
+ const warnTruncated = () => {
5696
+ if (!truncated) {
5697
+ truncated = true;
5698
+ getCurrentTrace().setMetadata({
5699
+ bitfabAutoTrace: {
5700
+ protocol: AUTO_TRACE_PROTOCOL,
5701
+ truncated: true,
5702
+ maxDepth,
5703
+ maxSpans
5704
+ }
5705
+ });
5706
+ }
5707
+ warnOnce(
5708
+ `auto-trace-truncated:${traceFunctionKey}`,
5709
+ `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
5710
+ );
5711
+ };
5712
+ const autoTraceContext = {
5713
+ invoke(definition, inputs, invokeFn, depth) {
5714
+ const nameParts = definition.name.split(".");
5715
+ const simpleName = nameParts[nameParts.length - 1];
5716
+ if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || definition.wrapper === true && !includeWrappers) {
5717
+ return invokeFn();
5718
+ }
5719
+ if (depth >= maxDepth || spansUsed >= maxSpans) {
5720
+ warnTruncated();
5721
+ return invokeFn();
5722
+ }
5723
+ spansUsed += 1;
5724
+ const childOptions = {
5725
+ name: definition.name,
5726
+ type: "function",
5727
+ captureWhen: "nested",
5728
+ functionId: definition.id,
5729
+ captureContent: capturePolicy.has(definition.id),
5730
+ autoTraceDefinition: definition
5731
+ };
5732
+ const tracedChild = self.withSpan(
5733
+ traceFunctionKey,
5734
+ childOptions,
5735
+ (..._inputs) => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1)
5736
+ );
5737
+ return tracedChild(...inputs);
5738
+ }
5739
+ };
5740
+ return runWithAutoTraceRootContext(
5741
+ autoTraceContext,
5742
+ () => fn.apply(this, args)
5743
+ );
5744
+ }
5745
+ );
5746
+ const autoTraceRoot = function(...args) {
5747
+ if (!self.isTracingEnabled()) {
5748
+ return fn.apply(this, args);
5749
+ }
5750
+ return tracedRoot.apply(this, args);
5751
+ };
5752
+ Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
5753
+ value: traceFunctionKey
5754
+ });
5755
+ return autoTraceRoot;
5756
+ }
5757
+ refreshAutoTraceCapturePolicy(traceFunctionKey) {
5758
+ const now = Date.now();
5759
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
5760
+ refreshAfter: 0
5761
+ };
5762
+ if (state.inFlight || now < state.refreshAfter) {
5763
+ return;
5764
+ }
5765
+ const request = this.httpClient.getAutoTracePolicy(
5766
+ traceFunctionKey,
5767
+ AUTO_TRACE_PROTOCOL
5768
+ ).then((policy) => {
5769
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
5770
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5771
+ return;
5772
+ }
5773
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
5774
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
5775
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
5776
+ __setBitfabAutoTraceCapturePolicy(this, traceFunctionKey, functionIds);
5777
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
5778
+ }).catch(() => {
5779
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5780
+ }).finally(() => {
5781
+ state.inFlight = void 0;
5782
+ });
5783
+ state.inFlight = request;
5784
+ this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
5785
+ }
5525
5786
  /**
5526
5787
  * Flush and permanently close this client's tracing resources: its pending
5527
5788
  * requests and the single span-transport worker shared by its decorators and
@@ -6068,7 +6329,10 @@ var Bitfab = class {
6068
6329
  parentSpanId,
6069
6330
  inputs,
6070
6331
  startedAt,
6071
- spanType: options.type ?? "custom"
6332
+ spanType: options.type ?? "custom",
6333
+ functionId: options.functionId,
6334
+ captureContent: options.captureContent ?? true,
6335
+ autoTraceDefinition: options.autoTraceDefinition
6072
6336
  };
6073
6337
  const sendSpan = async (params) => {
6074
6338
  const replayCtx = getReplayContext();
@@ -6233,7 +6497,16 @@ var Bitfab = class {
6233
6497
  }
6234
6498
  };
6235
6499
  executeWithContext = () => {
6236
- const result = fn.apply(this, args);
6500
+ let result;
6501
+ try {
6502
+ result = fn.apply(this, args);
6503
+ } catch (error) {
6504
+ void sendSpan({
6505
+ result: void 0,
6506
+ error: error instanceof Error ? error.message : String(error)
6507
+ });
6508
+ throw error;
6509
+ }
6237
6510
  if (result instanceof Promise) {
6238
6511
  return result.then((resolvedResult) => {
6239
6512
  recordSpan(resolvedResult);
@@ -6474,8 +6747,8 @@ var Bitfab = class {
6474
6747
  * Queued on the client's span transport; delivery is the transport's job.
6475
6748
  */
6476
6749
  sendWrapperSpan(params) {
6477
- const serializedInputs = serializeValue(params.inputs);
6478
- const serializedResult = serializeValue(params.result);
6750
+ const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
6751
+ const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
6479
6752
  const externalSpan = {
6480
6753
  id: params.spanId,
6481
6754
  trace_id: params.traceId,
@@ -6484,26 +6757,38 @@ var Bitfab = class {
6484
6757
  span_data: {
6485
6758
  name: params.spanName,
6486
6759
  type: params.spanType,
6487
- input: serializedInputs.json,
6488
- output: serializedResult.json,
6489
- // Include superjson meta for type preservation
6490
- ...serializedInputs.meta !== void 0 && {
6491
- input_meta: serializedInputs.meta
6760
+ ...params.functionId !== void 0 && {
6761
+ function_id: params.functionId,
6762
+ content_captured: params.captureContent
6763
+ },
6764
+ ...params.autoTraceDefinition !== void 0 && {
6765
+ function_file: params.autoTraceDefinition.file,
6766
+ function_line: params.autoTraceDefinition.line,
6767
+ function_column: params.autoTraceDefinition.column
6492
6768
  },
6493
- ...serializedResult.meta !== void 0 && {
6494
- output_meta: serializedResult.meta
6769
+ ...serializedInputs !== void 0 && {
6770
+ input: serializedInputs.json,
6771
+ ...serializedInputs.meta !== void 0 && {
6772
+ input_meta: serializedInputs.meta
6773
+ }
6774
+ },
6775
+ ...serializedResult !== void 0 && {
6776
+ output: serializedResult.json,
6777
+ ...serializedResult.meta !== void 0 && {
6778
+ output_meta: serializedResult.meta
6779
+ }
6495
6780
  },
6496
6781
  ...params.functionName !== void 0 && {
6497
6782
  function_name: params.functionName
6498
6783
  },
6499
- ...params.error !== void 0 && {
6784
+ ...params.captureContent && params.error !== void 0 && {
6500
6785
  error: params.error,
6501
6786
  error_source: "code"
6502
6787
  },
6503
- ...params.contexts && params.contexts.length > 0 && {
6788
+ ...params.captureContent && params.contexts && params.contexts.length > 0 && {
6504
6789
  contexts: params.contexts
6505
6790
  },
6506
- ...params.prompt !== void 0 && { prompt: params.prompt }
6791
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
6507
6792
  }
6508
6793
  };
6509
6794
  if (params.parentSpanId) {