bitfab 0.36.4 → 0.36.6

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__;
97
97
  var init_version_generated = __esm({
98
98
  "src/version.generated.ts"() {
99
99
  "use strict";
100
- __version__ = "0.36.4";
100
+ __version__ = "0.36.6";
101
101
  }
102
102
  });
103
103
 
@@ -2400,12 +2400,13 @@ function sleep(ms) {
2400
2400
  unrefTimer(timer);
2401
2401
  });
2402
2402
  }
2403
- async function mapWithConcurrency2(tasks, maxConcurrency, onSettled) {
2403
+ async function mapWithConcurrency2(tasks, maxConcurrency, onSettled, onStarted) {
2404
2404
  const results = new Array(tasks.length);
2405
2405
  let nextIndex = 0;
2406
2406
  async function worker() {
2407
2407
  while (nextIndex < tasks.length) {
2408
2408
  const index = nextIndex++;
2409
+ onStarted?.(index);
2409
2410
  const result = await tasks[index]();
2410
2411
  results[index] = result;
2411
2412
  onSettled?.(result, index);
@@ -2492,13 +2493,15 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2492
2493
  )
2493
2494
  );
2494
2495
  const total = tasks.length;
2496
+ const onItemFinish = options?.onItemFinish ?? options?.onProgress;
2495
2497
  let completed = 0;
2498
+ let started = 0;
2496
2499
  let succeeded = 0;
2497
2500
  let errored = 0;
2498
2501
  const resultItems = await mapWithConcurrency2(
2499
2502
  tasks,
2500
2503
  maxConcurrency,
2501
- options?.onProgress ? (item) => {
2504
+ (item) => {
2502
2505
  completed += 1;
2503
2506
  if (item.error === null) {
2504
2507
  succeeded += 1;
@@ -2506,18 +2509,17 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2506
2509
  errored += 1;
2507
2510
  }
2508
2511
  try {
2509
- options?.onProgress?.({
2512
+ onItemFinish?.({
2510
2513
  testRunId,
2511
2514
  completed,
2512
2515
  total,
2513
2516
  succeeded,
2514
2517
  errored,
2515
2518
  item: {
2516
- // The server replay trace id isn't known until completeReplay
2517
- // runs (below), so it can't be reported mid-run and we never
2518
- // emit the client-side placeholder. originalTraceId (the
2519
- // historical trace) is known now and is what a UI keys on to
2520
- // identify what just settled.
2519
+ // The server replay trace id isn't known until completeReplay runs
2520
+ // (below), so it can't be reported mid-run and we never emit the
2521
+ // client-side placeholder. originalTraceId (the historical trace)
2522
+ // is known now and is what a UI keys on to identify what settled.
2521
2523
  traceId: null,
2522
2524
  originalTraceId: item.originalTraceId ?? null,
2523
2525
  originalSpanId: item.originalSpanId ?? null,
@@ -2538,6 +2540,30 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2538
2540
  });
2539
2541
  } catch {
2540
2542
  }
2543
+ },
2544
+ options?.onItemStart ? (index) => {
2545
+ started += 1;
2546
+ const serverItem = serverItems[index];
2547
+ const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
2548
+ const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2549
+ try {
2550
+ options.onItemStart?.({
2551
+ type: "started",
2552
+ testRunId,
2553
+ started,
2554
+ completed,
2555
+ total,
2556
+ succeeded,
2557
+ errored,
2558
+ item: {
2559
+ originalTraceId,
2560
+ originalSpanId,
2561
+ sourceTraceId: originalTraceId,
2562
+ sourceSpanId: originalSpanId
2563
+ }
2564
+ });
2565
+ } catch {
2566
+ }
2541
2567
  } : void 0
2542
2568
  );
2543
2569
  await preserveReplayFailure(
@@ -2600,17 +2626,19 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2600
2626
  testRunUrl: fullTestRunUrl
2601
2627
  };
2602
2628
  await writeReplayResultFile(result);
2603
- try {
2604
- options?.onProgress?.({
2605
- type: "complete",
2606
- testRunId,
2607
- completed: total,
2608
- total,
2609
- succeeded,
2610
- errored,
2611
- result
2612
- });
2613
- } catch {
2629
+ if (!options?.onItemFinish) {
2630
+ try {
2631
+ options?.onProgress?.({
2632
+ type: "complete",
2633
+ testRunId,
2634
+ completed: total,
2635
+ total,
2636
+ succeeded,
2637
+ errored,
2638
+ result
2639
+ });
2640
+ } catch {
2641
+ }
2614
2642
  }
2615
2643
  return result;
2616
2644
  }
@@ -5791,7 +5819,7 @@ var Bitfab = class {
5791
5819
  }
5792
5820
  };
5793
5821
  executeWithContext = () => {
5794
- const result = fn(...args);
5822
+ const result = fn.apply(this, args);
5795
5823
  if (result instanceof Promise) {
5796
5824
  return result.then((resolvedResult) => {
5797
5825
  recordSpan(resolvedResult);
@@ -5821,7 +5849,7 @@ var Bitfab = class {
5821
5849
  `withSpan-setup:${traceFunctionKey}`,
5822
5850
  `tracing setup failed for "${traceFunctionKey}"; running it untraced. The function still runs and returns normally; no span is recorded.`
5823
5851
  );
5824
- return fn(...args);
5852
+ return fn.apply(this, args);
5825
5853
  }
5826
5854
  return runWithSpanStack(newStack, executeWithContext);
5827
5855
  };
@@ -5830,6 +5858,40 @@ var Bitfab = class {
5830
5858
  });
5831
5859
  return wrappedFn;
5832
5860
  }
5861
+ /**
5862
+ * Create a standard ECMAScript method decorator that records each invocation
5863
+ * as a span.
5864
+ *
5865
+ * It supports instance, static, and private methods; use
5866
+ * {@link Bitfab.withSpan} for standalone functions, class fields, and
5867
+ * accessors.
5868
+ *
5869
+ * @example
5870
+ * ```typescript
5871
+ * const bitfab = new Bitfab({ apiKey: process.env.BITFAB_API_KEY });
5872
+ *
5873
+ * class OrderService {
5874
+ * @bitfab.span("order-processing", { type: "agent" })
5875
+ * async process(orderId: string) {
5876
+ * return { orderId };
5877
+ * }
5878
+ * }
5879
+ * ```
5880
+ *
5881
+ * @param traceFunctionKey - A string identifier for grouping spans
5882
+ * @param options - Span configuration applied to the decorated method
5883
+ * @returns A standard ECMAScript method decorator
5884
+ */
5885
+ span(traceFunctionKey, options = {}) {
5886
+ return (originalMethod, context) => {
5887
+ if (context.kind !== "method") {
5888
+ throw new BitfabError(
5889
+ `Bitfab span decorators can only decorate methods; ${String(context.name)} is a ${context.kind}`
5890
+ );
5891
+ }
5892
+ return this.withSpan(traceFunctionKey, options, originalMethod);
5893
+ };
5894
+ }
5833
5895
  /**
5834
5896
  * Get a detached handle to a previously-created trace, looked up by the
5835
5897
  * canonical Bitfab trace ID.
@@ -6106,6 +6168,27 @@ var BitfabFunction = class {
6106
6168
  const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
6107
6169
  return this.client.withSpan(this.traceFunctionKey, options, fn);
6108
6170
  }
6171
+ /**
6172
+ * Create a standard ECMAScript method decorator bound to this function key.
6173
+ *
6174
+ * @example
6175
+ * ```typescript
6176
+ * const orders = client.getFunction("order-processing");
6177
+ *
6178
+ * class OrderService {
6179
+ * @orders.span({ type: "agent" })
6180
+ * async process(orderId: string) {
6181
+ * return { orderId };
6182
+ * }
6183
+ * }
6184
+ * ```
6185
+ *
6186
+ * @param options - Span configuration applied to the decorated method
6187
+ * @returns A standard ECMAScript method decorator
6188
+ */
6189
+ span(options = {}) {
6190
+ return this.client.span(this.traceFunctionKey, options);
6191
+ }
6109
6192
  /**
6110
6193
  * Get a Vercel AI SDK language-model middleware bound to this function's key.
6111
6194
  *