bitfab 0.38.0 → 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
@@ -47,11 +47,12 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
47
47
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
48
48
 
49
49
  // src/version.generated.ts
50
- var __version__;
50
+ var __version__, __packageName__;
51
51
  var init_version_generated = __esm({
52
52
  "src/version.generated.ts"() {
53
53
  "use strict";
54
- __version__ = "0.38.0";
54
+ __version__ = "0.38.2";
55
+ __packageName__ = "bitfab";
55
56
  }
56
57
  });
57
58
 
@@ -820,7 +821,7 @@ var init_otel = __esm({
820
821
  EXPORT_CONCURRENCY_ENV = "BITFAB_OTEL_EXPORT_CONCURRENCY";
821
822
  MAX_QUEUE_SIZE = 8192;
822
823
  DIRECT_MAX_EXPORT_BATCH_SIZE = 512;
823
- DIRECT_MAX_REQUEST_BATCH_SIZE = 8;
824
+ DIRECT_MAX_REQUEST_BATCH_SIZE = 128;
824
825
  DEFAULT_EXPORT_CONCURRENCY = 32;
825
826
  MAX_EXPORT_CONCURRENCY = 64;
826
827
  SCHEDULE_DELAY_MILLIS = 5e3;
@@ -1712,6 +1713,12 @@ var init_http = __esm({
1712
1713
  async lookupFunction(name) {
1713
1714
  return this.request("/api/sdk/functions/lookup", { name });
1714
1715
  }
1716
+ async getAutoTracePolicy(traceFunctionKey, protocol) {
1717
+ return this.request("/api/sdk/auto-trace/policy", {
1718
+ traceFunctionKey,
1719
+ protocol
1720
+ });
1721
+ }
1715
1722
  async getTraceSpan(traceId, lookup) {
1716
1723
  const searchParams = new URLSearchParams();
1717
1724
  if (lookup.id !== void 0) {
@@ -1762,7 +1769,12 @@ var init_http = __esm({
1762
1769
  * the OTLP carrier has no path to carry it.
1763
1770
  */
1764
1771
  sendInternalTrace(functionId, payload) {
1765
- const body = { ...payload, functionId, sdkVersion: __version__ };
1772
+ const body = {
1773
+ ...payload,
1774
+ functionId,
1775
+ sdkPackage: __packageName__,
1776
+ sdkVersion: __version__
1777
+ };
1766
1778
  this.getTraceTransport()?.submit(
1767
1779
  "internal_trace",
1768
1780
  body,
@@ -1791,7 +1803,11 @@ var init_http = __esm({
1791
1803
  sendExternalTrace(payload) {
1792
1804
  this.getTraceTransport()?.submit(
1793
1805
  "external_trace",
1794
- { ...payload, sdkVersion: __version__ },
1806
+ {
1807
+ ...payload,
1808
+ sdkPackage: __packageName__,
1809
+ sdkVersion: __version__
1810
+ },
1795
1811
  this.recordedMeta(
1796
1812
  "external_trace",
1797
1813
  payload,
@@ -3748,6 +3764,80 @@ var BitfabClaudeAgentHandler = class {
3748
3764
  // src/client.ts
3749
3765
  init_asyncStorage();
3750
3766
 
3767
+ // src/autoTrace.ts
3768
+ init_asyncStorage();
3769
+ var autoTraceGlobal = globalThis;
3770
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
3771
+ storage: null,
3772
+ browserScope: void 0,
3773
+ capturePolicies: /* @__PURE__ */ new WeakMap(),
3774
+ activeRoots: 0
3775
+ };
3776
+ autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
3777
+ function initializeAutoTraceStorage() {
3778
+ autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
3779
+ }
3780
+ function runWithAutoTraceContext(context, fn, depth = 0) {
3781
+ initializeAutoTraceStorage();
3782
+ const scope = { context, depth };
3783
+ if (autoTraceState.storage) {
3784
+ return autoTraceState.storage.run(scope, fn);
3785
+ }
3786
+ const previous = autoTraceState.browserScope;
3787
+ autoTraceState.browserScope = scope;
3788
+ try {
3789
+ return fn();
3790
+ } finally {
3791
+ autoTraceState.browserScope = previous;
3792
+ }
3793
+ }
3794
+ function runWithAutoTraceRootContext(context, fn) {
3795
+ autoTraceState.activeRoots += 1;
3796
+ let result;
3797
+ try {
3798
+ result = runWithAutoTraceContext(context, fn);
3799
+ } catch (error) {
3800
+ autoTraceState.activeRoots -= 1;
3801
+ throw error;
3802
+ }
3803
+ if (isAutoTraceAsyncGenerator(result)) {
3804
+ autoTraceState.activeRoots -= 1;
3805
+ return wrapAutoTraceAsyncGenerator(context, result);
3806
+ }
3807
+ if (result instanceof Promise) {
3808
+ return result.finally(() => {
3809
+ autoTraceState.activeRoots -= 1;
3810
+ });
3811
+ }
3812
+ autoTraceState.activeRoots -= 1;
3813
+ return result;
3814
+ }
3815
+ function isAutoTraceAsyncGenerator(value) {
3816
+ if (value === null || typeof value !== "object") {
3817
+ return false;
3818
+ }
3819
+ const candidate = value;
3820
+ return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
3821
+ }
3822
+ function wrapAutoTraceAsyncGenerator(context, source) {
3823
+ const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
3824
+ const wrapped = {
3825
+ next: (value) => step("next", value),
3826
+ return: (value) => step("return", value),
3827
+ throw: (error) => step("throw", error),
3828
+ [Symbol.asyncIterator]: () => wrapped
3829
+ };
3830
+ return wrapped;
3831
+ }
3832
+ function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
3833
+ const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
3834
+ policies.set(traceFunctionKey, new Set(functionIds));
3835
+ autoTraceState.capturePolicies.set(client, policies);
3836
+ }
3837
+ function getAutoTraceCapturePolicy(client, traceFunctionKey) {
3838
+ return autoTraceState.capturePolicies.get(client)?.get(traceFunctionKey) ?? /* @__PURE__ */ new Set();
3839
+ }
3840
+
3751
3841
  // src/optionalPeer.ts
3752
3842
  function importOptionalPeer(specifierParts) {
3753
3843
  const specifier = specifierParts.join("/");
@@ -5489,6 +5579,14 @@ function readEnv2(name) {
5489
5579
  }
5490
5580
  return void 0;
5491
5581
  }
5582
+ var DEFAULT_AUTO_TRACE_MAX_DEPTH = 30;
5583
+ var DEFAULT_AUTO_TRACE_MAX_SPANS = 500;
5584
+ var AUTO_TRACE_PROTOCOL = "ts-auto-v1";
5585
+ var AUTO_TRACE_POLICY_REFRESH_MS = 6e4;
5586
+ var AUTO_TRACE_POLICY_RETRY_MS = 1e4;
5587
+ function autoTraceLimit(value, fallback) {
5588
+ return value !== void 0 && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
5589
+ }
5492
5590
  var Bitfab = class {
5493
5591
  /**
5494
5592
  * Initialize the Bitfab client.
@@ -5498,6 +5596,7 @@ var Bitfab = class {
5498
5596
  constructor(config) {
5499
5597
  /** Gate the empty-key warning to fire at most once. */
5500
5598
  this.apiKeyWarned = false;
5599
+ this.autoTracePolicyRefreshes = /* @__PURE__ */ new Map();
5501
5600
  /**
5502
5601
  * Mock overrides registered via {@link Bitfab.registerMockOverride}, applied
5503
5602
  * to every `replay` on this client (after any per-call `mockOverride`). In
@@ -5521,6 +5620,178 @@ var Bitfab = class {
5521
5620
  timeout: this.timeout
5522
5621
  });
5523
5622
  }
5623
+ /**
5624
+ * Decorate a class method as an automatically expanded trace root.
5625
+ *
5626
+ * Build instrumentation turns repository functions called beneath this
5627
+ * method into nested spans. Every generated span preserves structure; only
5628
+ * function IDs selected by the capture policy include inputs and output.
5629
+ * Without a compatible build transform, this still records the decorated
5630
+ * method as a normal rich root span but cannot discover child calls.
5631
+ *
5632
+ * @param traceFunctionKey - Groups traces and their capture policy.
5633
+ * @param options - Root presentation, subtree bounds, and exclusions.
5634
+ * @experimental Automatic child-call instrumentation is experimental.
5635
+ */
5636
+ trace(traceFunctionKey, options = {}) {
5637
+ const decorator = (...args) => {
5638
+ if (args.length === 3) {
5639
+ const propertyKey = args[1];
5640
+ const descriptor = args[2];
5641
+ if (!descriptor || typeof descriptor.value !== "function") {
5642
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5643
+ }
5644
+ if (!this.explicitlyEnabled) {
5645
+ return;
5646
+ }
5647
+ descriptor.value = this.createAutoTraceRoot(
5648
+ traceFunctionKey,
5649
+ String(propertyKey),
5650
+ options,
5651
+ descriptor.value
5652
+ );
5653
+ return;
5654
+ }
5655
+ const method = args[0];
5656
+ const context = args[1];
5657
+ if (typeof method !== "function" || context?.kind !== "method" || context.name === void 0) {
5658
+ throw new BitfabError("@bitfab.trace can only decorate methods");
5659
+ }
5660
+ if (!this.explicitlyEnabled) {
5661
+ return method;
5662
+ }
5663
+ return this.createAutoTraceRoot(
5664
+ traceFunctionKey,
5665
+ String(context.name),
5666
+ options,
5667
+ method
5668
+ );
5669
+ };
5670
+ return decorator;
5671
+ }
5672
+ withTrace(traceFunctionKey, optionsOrFn, maybeFn) {
5673
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
5674
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
5675
+ if (!fn) {
5676
+ throw new BitfabError("bitfab.withTrace requires a function");
5677
+ }
5678
+ if (!this.explicitlyEnabled) {
5679
+ return fn;
5680
+ }
5681
+ const name = fn.name !== "" ? fn.name : traceFunctionKey;
5682
+ return this.createAutoTraceRoot(traceFunctionKey, name, options, fn);
5683
+ }
5684
+ createAutoTraceRoot(traceFunctionKey, name, options, fn) {
5685
+ const self = this;
5686
+ const maxDepth = autoTraceLimit(
5687
+ options.maxDepth,
5688
+ DEFAULT_AUTO_TRACE_MAX_DEPTH
5689
+ );
5690
+ const maxSpans = autoTraceLimit(
5691
+ options.maxSpans,
5692
+ DEFAULT_AUTO_TRACE_MAX_SPANS
5693
+ );
5694
+ const excluded = new Set(options.exclude ?? []);
5695
+ const includeWrappers = options.includeWrappers ?? false;
5696
+ const tracedRoot = this.withSpan(
5697
+ traceFunctionKey,
5698
+ { name: options.name ?? name, type: options.type ?? "custom" },
5699
+ function(...args) {
5700
+ const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
5701
+ self.refreshAutoTraceCapturePolicy(traceFunctionKey);
5702
+ let spansUsed = 0;
5703
+ let truncated = false;
5704
+ const warnTruncated = () => {
5705
+ if (!truncated) {
5706
+ truncated = true;
5707
+ getCurrentTrace().setMetadata({
5708
+ bitfabAutoTrace: {
5709
+ protocol: AUTO_TRACE_PROTOCOL,
5710
+ truncated: true,
5711
+ maxDepth,
5712
+ maxSpans
5713
+ }
5714
+ });
5715
+ }
5716
+ warnOnce(
5717
+ `auto-trace-truncated:${traceFunctionKey}`,
5718
+ `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
5719
+ );
5720
+ };
5721
+ const autoTraceContext = {
5722
+ invoke(definition, inputs, invokeFn, depth) {
5723
+ const nameParts = definition.name.split(".");
5724
+ const simpleName = nameParts[nameParts.length - 1];
5725
+ if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || definition.wrapper === true && !includeWrappers) {
5726
+ return invokeFn();
5727
+ }
5728
+ if (depth >= maxDepth || spansUsed >= maxSpans) {
5729
+ warnTruncated();
5730
+ return invokeFn();
5731
+ }
5732
+ spansUsed += 1;
5733
+ const childOptions = {
5734
+ name: definition.name,
5735
+ type: "function",
5736
+ captureWhen: "nested",
5737
+ functionId: definition.id,
5738
+ captureContent: capturePolicy.has(definition.id),
5739
+ autoTraceDefinition: definition
5740
+ };
5741
+ const tracedChild = self.withSpan(
5742
+ traceFunctionKey,
5743
+ childOptions,
5744
+ (..._inputs) => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1)
5745
+ );
5746
+ return tracedChild(...inputs);
5747
+ }
5748
+ };
5749
+ return runWithAutoTraceRootContext(
5750
+ autoTraceContext,
5751
+ () => fn.apply(this, args)
5752
+ );
5753
+ }
5754
+ );
5755
+ const autoTraceRoot = function(...args) {
5756
+ if (!self.isTracingEnabled()) {
5757
+ return fn.apply(this, args);
5758
+ }
5759
+ return tracedRoot.apply(this, args);
5760
+ };
5761
+ Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
5762
+ value: traceFunctionKey
5763
+ });
5764
+ return autoTraceRoot;
5765
+ }
5766
+ refreshAutoTraceCapturePolicy(traceFunctionKey) {
5767
+ const now = Date.now();
5768
+ const state = this.autoTracePolicyRefreshes.get(traceFunctionKey) ?? {
5769
+ refreshAfter: 0
5770
+ };
5771
+ if (state.inFlight || now < state.refreshAfter) {
5772
+ return;
5773
+ }
5774
+ const request = this.httpClient.getAutoTracePolicy(
5775
+ traceFunctionKey,
5776
+ AUTO_TRACE_PROTOCOL
5777
+ ).then((policy) => {
5778
+ if (policy.protocol !== AUTO_TRACE_PROTOCOL) {
5779
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5780
+ return;
5781
+ }
5782
+ const functionIds = Array.isArray(policy.functionIds) ? policy.functionIds.filter(
5783
+ (id) => typeof id === "string" && id.startsWith(`${AUTO_TRACE_PROTOCOL}:`)
5784
+ ).slice(0, DEFAULT_AUTO_TRACE_MAX_SPANS) : [];
5785
+ __setBitfabAutoTraceCapturePolicy(this, traceFunctionKey, functionIds);
5786
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_REFRESH_MS;
5787
+ }).catch(() => {
5788
+ state.refreshAfter = Date.now() + AUTO_TRACE_POLICY_RETRY_MS;
5789
+ }).finally(() => {
5790
+ state.inFlight = void 0;
5791
+ });
5792
+ state.inFlight = request;
5793
+ this.autoTracePolicyRefreshes.set(traceFunctionKey, state);
5794
+ }
5524
5795
  /**
5525
5796
  * Flush and permanently close this client's tracing resources: its pending
5526
5797
  * requests and the single span-transport worker shared by its decorators and
@@ -6067,7 +6338,10 @@ var Bitfab = class {
6067
6338
  parentSpanId,
6068
6339
  inputs,
6069
6340
  startedAt,
6070
- spanType: options.type ?? "custom"
6341
+ spanType: options.type ?? "custom",
6342
+ functionId: options.functionId,
6343
+ captureContent: options.captureContent ?? true,
6344
+ autoTraceDefinition: options.autoTraceDefinition
6071
6345
  };
6072
6346
  const sendSpan = async (params) => {
6073
6347
  const replayCtx = getReplayContext();
@@ -6232,7 +6506,16 @@ var Bitfab = class {
6232
6506
  }
6233
6507
  };
6234
6508
  executeWithContext = () => {
6235
- const result = fn.apply(this, args);
6509
+ let result;
6510
+ try {
6511
+ result = fn.apply(this, args);
6512
+ } catch (error) {
6513
+ void sendSpan({
6514
+ result: void 0,
6515
+ error: error instanceof Error ? error.message : String(error)
6516
+ });
6517
+ throw error;
6518
+ }
6236
6519
  if (result instanceof Promise) {
6237
6520
  return result.then((resolvedResult) => {
6238
6521
  recordSpan(resolvedResult);
@@ -6473,8 +6756,8 @@ var Bitfab = class {
6473
6756
  * Queued on the client's span transport; delivery is the transport's job.
6474
6757
  */
6475
6758
  sendWrapperSpan(params) {
6476
- const serializedInputs = serializeValue(params.inputs);
6477
- const serializedResult = serializeValue(params.result);
6759
+ const serializedInputs = params.captureContent ? serializeValue(params.inputs) : void 0;
6760
+ const serializedResult = params.captureContent ? serializeValue(params.result) : void 0;
6478
6761
  const externalSpan = {
6479
6762
  id: params.spanId,
6480
6763
  trace_id: params.traceId,
@@ -6483,26 +6766,38 @@ var Bitfab = class {
6483
6766
  span_data: {
6484
6767
  name: params.spanName,
6485
6768
  type: params.spanType,
6486
- input: serializedInputs.json,
6487
- output: serializedResult.json,
6488
- // Include superjson meta for type preservation
6489
- ...serializedInputs.meta !== void 0 && {
6490
- input_meta: serializedInputs.meta
6769
+ ...params.functionId !== void 0 && {
6770
+ function_id: params.functionId,
6771
+ content_captured: params.captureContent
6772
+ },
6773
+ ...params.autoTraceDefinition !== void 0 && {
6774
+ function_file: params.autoTraceDefinition.file,
6775
+ function_line: params.autoTraceDefinition.line,
6776
+ function_column: params.autoTraceDefinition.column
6491
6777
  },
6492
- ...serializedResult.meta !== void 0 && {
6493
- output_meta: serializedResult.meta
6778
+ ...serializedInputs !== void 0 && {
6779
+ input: serializedInputs.json,
6780
+ ...serializedInputs.meta !== void 0 && {
6781
+ input_meta: serializedInputs.meta
6782
+ }
6783
+ },
6784
+ ...serializedResult !== void 0 && {
6785
+ output: serializedResult.json,
6786
+ ...serializedResult.meta !== void 0 && {
6787
+ output_meta: serializedResult.meta
6788
+ }
6494
6789
  },
6495
6790
  ...params.functionName !== void 0 && {
6496
6791
  function_name: params.functionName
6497
6792
  },
6498
- ...params.error !== void 0 && {
6793
+ ...params.captureContent && params.error !== void 0 && {
6499
6794
  error: params.error,
6500
6795
  error_source: "code"
6501
6796
  },
6502
- ...params.contexts && params.contexts.length > 0 && {
6797
+ ...params.captureContent && params.contexts && params.contexts.length > 0 && {
6503
6798
  contexts: params.contexts
6504
6799
  },
6505
- ...params.prompt !== void 0 && { prompt: params.prompt }
6800
+ ...params.captureContent && params.prompt !== void 0 && { prompt: params.prompt }
6506
6801
  }
6507
6802
  };
6508
6803
  if (params.parentSpanId) {