bitfab 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.
package/dist/index.cjs CHANGED
@@ -51,7 +51,7 @@ var __version__, __packageName__;
51
51
  var init_version_generated = __esm({
52
52
  "src/version.generated.ts"() {
53
53
  "use strict";
54
- __version__ = "0.38.2";
54
+ __version__ = "0.38.4";
55
55
  __packageName__ = "bitfab";
56
56
  }
57
57
  });
@@ -2813,6 +2813,11 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2813
2813
  );
2814
2814
  }
2815
2815
  }
2816
+ if (options?.traceIds !== void 0 && options?.datasetId !== void 0) {
2817
+ throw new BitfabError(
2818
+ "traceIds and datasetId select different replay sources and cannot be used together."
2819
+ );
2820
+ }
2816
2821
  if (options?.limit !== void 0 && options?.traceIds !== void 0) {
2817
2822
  try {
2818
2823
  console.warn(
@@ -3140,6 +3145,7 @@ __export(index_exports, {
3140
3145
  ReplayError: () => ReplayError,
3141
3146
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
3142
3147
  __version__: () => __version__,
3148
+ defineReplayRegistry: () => defineReplayRegistry,
3143
3149
  finalizers: () => finalizers,
3144
3150
  flushTraces: () => flushTraces,
3145
3151
  getCurrentReplayBranch: () => getCurrentReplayBranch,
@@ -3791,6 +3797,29 @@ function runWithAutoTraceContext(context, fn, depth = 0) {
3791
3797
  autoTraceState.browserScope = previous;
3792
3798
  }
3793
3799
  }
3800
+ function runWithAutoTraceNodeConfiguration(nodeConfiguration, fn) {
3801
+ const scope = currentAutoTraceScope();
3802
+ if (!scope) {
3803
+ return fn();
3804
+ }
3805
+ const configuredScope = { ...scope, nodeConfiguration };
3806
+ let result;
3807
+ if (autoTraceState.storage) {
3808
+ result = autoTraceState.storage.run(configuredScope, fn);
3809
+ } else {
3810
+ const previous = autoTraceState.browserScope;
3811
+ autoTraceState.browserScope = configuredScope;
3812
+ try {
3813
+ result = fn();
3814
+ } finally {
3815
+ autoTraceState.browserScope = previous;
3816
+ }
3817
+ }
3818
+ if (isAutoTraceAsyncGenerator(result)) {
3819
+ return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result);
3820
+ }
3821
+ return result;
3822
+ }
3794
3823
  function runWithAutoTraceRootContext(context, fn) {
3795
3824
  autoTraceState.activeRoots += 1;
3796
3825
  let result;
@@ -3829,6 +3858,29 @@ function wrapAutoTraceAsyncGenerator(context, source) {
3829
3858
  };
3830
3859
  return wrapped;
3831
3860
  }
3861
+ function wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, source) {
3862
+ const step = (method, value) => runWithAutoTraceNodeConfiguration(
3863
+ nodeConfiguration,
3864
+ () => source[method](value)
3865
+ );
3866
+ const wrapped = {
3867
+ next: (value) => step("next", value),
3868
+ return: (value) => step("return", value),
3869
+ throw: (error) => step("throw", error),
3870
+ [Symbol.asyncIterator]: () => wrapped
3871
+ };
3872
+ return wrapped;
3873
+ }
3874
+ function __bitfabAutoTraceActive() {
3875
+ if (autoTraceState.activeRoots === 0) {
3876
+ return false;
3877
+ }
3878
+ return currentAutoTraceScope() !== void 0;
3879
+ }
3880
+ function currentAutoTraceScope() {
3881
+ initializeAutoTraceStorage();
3882
+ return autoTraceState.storage?.getStore() ?? autoTraceState.browserScope;
3883
+ }
3832
3884
  function __setBitfabAutoTraceCapturePolicy(client, traceFunctionKey, functionIds) {
3833
3885
  const policies = autoTraceState.capturePolicies.get(client) ?? /* @__PURE__ */ new Map();
3834
3886
  policies.set(traceFunctionKey, new Set(functionIds));
@@ -5681,6 +5733,102 @@ var Bitfab = class {
5681
5733
  const name = fn.name !== "" ? fn.name : traceFunctionKey;
5682
5734
  return this.createAutoTraceRoot(traceFunctionKey, name, options, fn);
5683
5735
  }
5736
+ /**
5737
+ * Configure a transformed class method when it is discovered beneath a
5738
+ * {@link Bitfab.trace} root.
5739
+ *
5740
+ * The decorator creates no span or trace by itself. Beneath an active trace,
5741
+ * it can rename or retype the discovered call, capture its contents, mark it
5742
+ * for recorded-output replay, finalize its output, or omit it while leaving
5743
+ * captured descendants attached to the nearest captured parent.
5744
+ *
5745
+ * @param options - Trace-owned call configuration.
5746
+ * @experimental Automatic child-call instrumentation is experimental.
5747
+ */
5748
+ node(options = {}) {
5749
+ const configuration = this.resolveNodeConfiguration(options);
5750
+ const decorator = (...args) => {
5751
+ if (args.length === 3) {
5752
+ const descriptor = args[2];
5753
+ if (!descriptor || typeof descriptor.value !== "function") {
5754
+ throw new BitfabError("@bitfab.node can only decorate methods");
5755
+ }
5756
+ if (!this.explicitlyEnabled) {
5757
+ return;
5758
+ }
5759
+ descriptor.value = this.createAutoTraceNode(
5760
+ configuration,
5761
+ descriptor.value,
5762
+ String(args[1])
5763
+ );
5764
+ return;
5765
+ }
5766
+ const method = args[0];
5767
+ const context = args[1];
5768
+ if (typeof method !== "function" || context?.kind !== "method") {
5769
+ throw new BitfabError("@bitfab.node can only decorate methods");
5770
+ }
5771
+ if (!this.explicitlyEnabled) {
5772
+ return method;
5773
+ }
5774
+ return this.createAutoTraceNode(
5775
+ configuration,
5776
+ method,
5777
+ String(context.name)
5778
+ );
5779
+ };
5780
+ return decorator;
5781
+ }
5782
+ withNode(optionsOrFn, maybeFn, internalFunctionName) {
5783
+ const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
5784
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
5785
+ if (!fn) {
5786
+ throw new BitfabError("bitfab.withNode requires a function");
5787
+ }
5788
+ const configuration = this.resolveNodeConfiguration(options);
5789
+ if (!this.explicitlyEnabled) {
5790
+ return fn;
5791
+ }
5792
+ const functionName = internalFunctionName ?? fn.name;
5793
+ if (functionName === "") {
5794
+ throw new BitfabError(
5795
+ "bitfab.withNode requires a named function so the subtree transform can bind its configuration to the correct call."
5796
+ );
5797
+ }
5798
+ return this.createAutoTraceNode(configuration, fn, functionName);
5799
+ }
5800
+ resolveNodeConfiguration(options) {
5801
+ const capture = options.capture ?? true;
5802
+ if (!capture && options.mockOnReplay === true) {
5803
+ throw new BitfabError(
5804
+ "bitfab.node({ capture: false }) cannot use mockOnReplay: true because an uncaptured node has no recorded output."
5805
+ );
5806
+ }
5807
+ return {
5808
+ capture,
5809
+ type: options.type ?? "custom",
5810
+ ...options.name !== void 0 && { name: options.name },
5811
+ ...options.testRunId !== void 0 && {
5812
+ testRunId: options.testRunId
5813
+ },
5814
+ ...options.mockOnReplay !== void 0 && {
5815
+ mockOnReplay: options.mockOnReplay
5816
+ },
5817
+ ...options.finalize !== void 0 && { finalize: options.finalize }
5818
+ };
5819
+ }
5820
+ createAutoTraceNode(configuration, fn, functionName) {
5821
+ const nodeConfiguration = { ...configuration, functionName };
5822
+ return function(...args) {
5823
+ if (!__bitfabAutoTraceActive()) {
5824
+ return fn.apply(this, args);
5825
+ }
5826
+ return runWithAutoTraceNodeConfiguration(
5827
+ nodeConfiguration,
5828
+ () => fn.apply(this, args)
5829
+ );
5830
+ };
5831
+ }
5684
5832
  createAutoTraceRoot(traceFunctionKey, name, options, fn) {
5685
5833
  const self = this;
5686
5834
  const maxDepth = autoTraceLimit(
@@ -5719,29 +5867,51 @@ var Bitfab = class {
5719
5867
  );
5720
5868
  };
5721
5869
  const autoTraceContext = {
5722
- invoke(definition, inputs, invokeFn, depth) {
5870
+ invoke(definition, inputs, invokeFn, depth, nodeConfiguration) {
5723
5871
  const nameParts = definition.name.split(".");
5724
5872
  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();
5873
+ const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
5874
+ if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || nodeConfiguration === void 0 && definition.wrapper === true && !includeWrappers) {
5875
+ return invokeWithoutNode();
5876
+ }
5877
+ if (nodeConfiguration?.capture === false) {
5878
+ return runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
5727
5879
  }
5728
5880
  if (depth >= maxDepth || spansUsed >= maxSpans) {
5729
5881
  warnTruncated();
5730
- return invokeFn();
5882
+ return invokeWithoutNode();
5731
5883
  }
5732
5884
  spansUsed += 1;
5733
5885
  const childOptions = {
5734
- name: definition.name,
5735
- type: "function",
5886
+ name: nodeConfiguration?.name ?? definition.name,
5887
+ type: nodeConfiguration?.type ?? "function",
5736
5888
  captureWhen: "nested",
5737
5889
  functionId: definition.id,
5738
- captureContent: capturePolicy.has(definition.id),
5739
- autoTraceDefinition: definition
5890
+ captureContent: nodeConfiguration !== void 0 || capturePolicy.has(definition.id),
5891
+ autoTraceDefinition: definition,
5892
+ ...nodeConfiguration?.testRunId !== void 0 && {
5893
+ testRunId: nodeConfiguration.testRunId
5894
+ },
5895
+ ...nodeConfiguration?.mockOnReplay !== void 0 && {
5896
+ mockOnReplay: nodeConfiguration.mockOnReplay
5897
+ },
5898
+ ...nodeConfiguration?.finalize !== void 0 && {
5899
+ finalize: nodeConfiguration.finalize
5900
+ }
5740
5901
  };
5902
+ const invokeWithAutoTraceContext = () => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1);
5903
+ if (definition.async === true) {
5904
+ const tracedAsyncChild = self.withSpan(
5905
+ traceFunctionKey,
5906
+ childOptions,
5907
+ async (..._inputs) => await invokeWithAutoTraceContext()
5908
+ );
5909
+ return tracedAsyncChild(...inputs);
5910
+ }
5741
5911
  const tracedChild = self.withSpan(
5742
5912
  traceFunctionKey,
5743
5913
  childOptions,
5744
- (..._inputs) => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1)
5914
+ (..._inputs) => invokeWithAutoTraceContext()
5745
5915
  );
5746
5916
  return tracedChild(...inputs);
5747
5917
  }
@@ -6311,18 +6481,17 @@ var Bitfab = class {
6311
6481
  newStack = [...currentStack, newContext];
6312
6482
  const inputs = args;
6313
6483
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
6484
+ const replayCtxAtStart = getReplayContext();
6485
+ const testRunId = replayCtxAtStart?.testRunId ?? options.testRunId;
6314
6486
  if (isRootSpan && !activeTraceStates.has(traceId)) {
6315
- const replayCtxAtRoot = getReplayContext();
6316
6487
  const dbSnapshotRef = buildSnapshotRef(self.dbSnapshot, startedAt);
6317
6488
  activeTraceStates.set(traceId, {
6318
6489
  traceId,
6319
6490
  startedAt,
6320
6491
  contexts: [],
6321
- ...replayCtxAtRoot?.testRunId && {
6322
- testRunId: replayCtxAtRoot.testRunId
6323
- },
6324
- ...replayCtxAtRoot?.inputSourceTraceId && {
6325
- inputSourceTraceId: replayCtxAtRoot.inputSourceTraceId
6492
+ ...testRunId !== void 0 && { testRunId },
6493
+ ...replayCtxAtStart?.inputSourceTraceId && {
6494
+ inputSourceTraceId: replayCtxAtStart.inputSourceTraceId
6326
6495
  },
6327
6496
  dbSnapshotRef
6328
6497
  });
@@ -6355,9 +6524,7 @@ var Bitfab = class {
6355
6524
  contexts: newContext.contexts,
6356
6525
  prompt: newContext.prompt,
6357
6526
  endedAt,
6358
- ...replayCtx?.testRunId && {
6359
- testRunId: replayCtx.testRunId
6360
- },
6527
+ ...testRunId !== void 0 && { testRunId },
6361
6528
  ...replayCtx?.inputSourceSpanId && {
6362
6529
  inputSourceSpanId: replayCtx.inputSourceSpanId
6363
6530
  }
@@ -7072,6 +7239,13 @@ var finalizers = {
7072
7239
  // src/index.ts
7073
7240
  init_http();
7074
7241
  init_replay();
7242
+
7243
+ // src/replayRegistry.ts
7244
+ init_errors();
7245
+ init_replay();
7246
+ function defineReplayRegistry(registry) {
7247
+ return registry;
7248
+ }
7075
7249
  // Annotate the CommonJS export names for ESM import in node:
7076
7250
  0 && (module.exports = {
7077
7251
  BITFAB_PROGRESS_PREFIX,
@@ -7090,6 +7264,7 @@ init_replay();
7090
7264
  ReplayError,
7091
7265
  SUPPORTED_PROVIDERS,
7092
7266
  __version__,
7267
+ defineReplayRegistry,
7093
7268
  finalizers,
7094
7269
  flushTraces,
7095
7270
  getCurrentReplayBranch,