@bitfab/sdk 0.36.2 → 0.36.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/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.36.2";
45
+ __version__ = "0.36.3";
46
46
  }
47
47
  });
48
48
 
@@ -2053,8 +2053,11 @@ var init_codeChange = __esm({
2053
2053
  var replay_exports = {};
2054
2054
  __export(replay_exports, {
2055
2055
  BITFAB_PROGRESS_PREFIX: () => BITFAB_PROGRESS_PREFIX,
2056
+ DbBranchReplayError: () => DbBranchReplayError,
2057
+ ReplayError: () => ReplayError,
2056
2058
  replay: () => replay,
2057
- reportReplayProgress: () => reportReplayProgress
2059
+ reportReplayProgress: () => reportReplayProgress,
2060
+ serializeReplayResult: () => serializeReplayResult
2058
2061
  });
2059
2062
  function dbBranchEnabled(dbBranch) {
2060
2063
  return dbBranch !== void 0 && dbBranch !== false;
@@ -2077,11 +2080,59 @@ function reportReplayProgress(progress) {
2077
2080
  return;
2078
2081
  }
2079
2082
  try {
2080
- stderr.write(`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress)}
2081
- `);
2083
+ stderr.write(
2084
+ `${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress, replayJsonReplacer)}
2085
+ `
2086
+ );
2082
2087
  } catch {
2083
2088
  }
2084
2089
  }
2090
+ function errorMessage(error) {
2091
+ return error instanceof Error ? error.message : String(error);
2092
+ }
2093
+ function replayItemErrorMessage(error) {
2094
+ if (error instanceof DbBranchReplayError) {
2095
+ return `Replay requested a database branch for trace ${error.originalTraceId} but it could not be resolved (${error.code}): ${error.message}. The function was not run, because replaying it against the live database would produce a result that looks valid but did not use the historical data you asked for.`;
2096
+ }
2097
+ return errorMessage(error);
2098
+ }
2099
+ function replayJsonReplacer(_key, value) {
2100
+ if (value instanceof Error) {
2101
+ const serialized = {
2102
+ name: value.name,
2103
+ message: value.message,
2104
+ stack: value.stack
2105
+ };
2106
+ if (value instanceof DbBranchReplayError) {
2107
+ serialized.code = value.code;
2108
+ serialized.originalTraceId = value.originalTraceId;
2109
+ if (value.cause !== void 0) {
2110
+ serialized.cause = value.cause;
2111
+ }
2112
+ }
2113
+ return serialized;
2114
+ }
2115
+ return value;
2116
+ }
2117
+ function serializeReplayResult(result) {
2118
+ return JSON.stringify(result, replayJsonReplacer, 2);
2119
+ }
2120
+ async function preserveReplayFailure(operation, items, testRunId, testRunUrl) {
2121
+ try {
2122
+ return await operation();
2123
+ } catch (cause) {
2124
+ if (cause instanceof ReplayError) {
2125
+ throw cause;
2126
+ }
2127
+ throw new ReplayError(
2128
+ errorMessage(cause),
2129
+ items,
2130
+ testRunId,
2131
+ testRunUrl,
2132
+ cause
2133
+ );
2134
+ }
2135
+ }
2085
2136
  function deserializeInputs(spanData) {
2086
2137
  const inputMeta = spanData.input_meta;
2087
2138
  const rawInput = spanData.input;
@@ -2139,22 +2190,36 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2139
2190
  let originalOutput;
2140
2191
  let result;
2141
2192
  let error = null;
2193
+ let traceError = null;
2194
+ let replayError = null;
2142
2195
  const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
2143
2196
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2144
2197
  try {
2145
2198
  if (includeDbBranchLease && !lease && !leaseError) {
2146
- const resolved = await httpClient.resolveDbBranchLease(
2147
- testRunId,
2148
- originalTraceId,
2149
- dbBranchSettings
2150
- );
2199
+ let resolved;
2200
+ try {
2201
+ resolved = await httpClient.resolveDbBranchLease(
2202
+ testRunId,
2203
+ originalTraceId,
2204
+ dbBranchSettings
2205
+ );
2206
+ } catch (cause) {
2207
+ throw new DbBranchReplayError(
2208
+ "lease_request_failed",
2209
+ `Bitfab could not request the database branch: ${errorMessage(cause)}`,
2210
+ originalTraceId,
2211
+ cause
2212
+ );
2213
+ }
2151
2214
  lease = resolved.lease ?? void 0;
2152
2215
  leaseError = resolved.leaseError ?? void 0;
2153
2216
  dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2154
2217
  }
2155
2218
  if (leaseError) {
2156
- throw new BitfabError(
2157
- `Replay requested a database branch for trace ${originalTraceId} but it could not be resolved (${leaseError.code}): ${leaseError.message}. The function was not run, because replaying it against the live database would produce a result that looks valid but did not use the historical data you asked for.`
2219
+ throw new DbBranchReplayError(
2220
+ leaseError.code,
2221
+ leaseError.message,
2222
+ originalTraceId
2158
2223
  );
2159
2224
  }
2160
2225
  const span = await httpClient.getExternalSpan(originalSpanId, {
@@ -2211,25 +2276,31 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2211
2276
  }
2212
2277
  return pending;
2213
2278
  } : void 0;
2214
- const maybePromise = runWithReplayContext(
2215
- {
2216
- testRunId,
2217
- traceId: replayedTraceId,
2218
- inputSourceSpanId: span.id,
2219
- inputSourceTraceId: span.externalTraceId,
2220
- sourceBitfabTraceId: originalTraceId,
2221
- mockTree,
2222
- callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2223
- mockStrategy,
2224
- mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2225
- fetchSpanOutput,
2226
- dbBranchLease: lease
2227
- },
2228
- () => fn(...inputs)
2229
- );
2230
- result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
2279
+ try {
2280
+ const maybePromise = runWithReplayContext(
2281
+ {
2282
+ testRunId,
2283
+ traceId: replayedTraceId,
2284
+ inputSourceSpanId: span.id,
2285
+ inputSourceTraceId: span.externalTraceId,
2286
+ sourceBitfabTraceId: originalTraceId,
2287
+ mockTree,
2288
+ callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2289
+ mockStrategy,
2290
+ mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2291
+ fetchSpanOutput,
2292
+ dbBranchLease: lease
2293
+ },
2294
+ () => fn(...inputs)
2295
+ );
2296
+ result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
2297
+ } catch (e) {
2298
+ traceError = e;
2299
+ error = errorMessage(e);
2300
+ }
2231
2301
  } catch (e) {
2232
- error = e instanceof Error ? e.message : String(e);
2302
+ replayError = e;
2303
+ error = replayItemErrorMessage(e);
2233
2304
  } finally {
2234
2305
  if (lease) {
2235
2306
  try {
@@ -2258,6 +2329,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2258
2329
  result,
2259
2330
  originalOutput,
2260
2331
  error,
2332
+ traceError,
2333
+ replayError,
2261
2334
  durationMs: serverItem.durationMs ?? null,
2262
2335
  // Filled in by replay() from the complete-replay response once the
2263
2336
  // replay traces are persisted and their spans aggregated server-side.
@@ -2382,6 +2455,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2382
2455
  );
2383
2456
  const mockStrategy = options?.mock ?? "marked";
2384
2457
  const maxConcurrency = options?.maxConcurrency ?? 10;
2458
+ const fullTestRunUrl = `${serviceUrl}${testRunUrl}`;
2385
2459
  const resolvedOverrides = [
2386
2460
  ...normalizeMockOverrides(options?.mockOverride),
2387
2461
  ...registeredOverrides
@@ -2438,6 +2512,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2438
2512
  result: item.result,
2439
2513
  originalOutput: item.originalOutput,
2440
2514
  error: item.error,
2515
+ traceError: item.traceError,
2516
+ replayError: item.replayError,
2441
2517
  durationMs: item.durationMs,
2442
2518
  tokens: item.tokens,
2443
2519
  model: item.model,
@@ -2448,8 +2524,18 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2448
2524
  }
2449
2525
  } : void 0
2450
2526
  );
2451
- await waitForReplayPersistence(httpClient, testRunId, replayedTraceIds);
2452
- const completeResult = await httpClient.completeReplay(testRunId);
2527
+ await preserveReplayFailure(
2528
+ () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
2529
+ resultItems,
2530
+ testRunId,
2531
+ fullTestRunUrl
2532
+ );
2533
+ const completeResult = await preserveReplayFailure(
2534
+ () => httpClient.completeReplay(testRunId),
2535
+ resultItems,
2536
+ testRunId,
2537
+ fullTestRunUrl
2538
+ );
2453
2539
  const serverTraceIds = completeResult.traceIds;
2454
2540
  const replayTokens = completeResult.tokens;
2455
2541
  if (serverTraceIds !== void 0) {
@@ -2472,9 +2558,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2472
2558
  }
2473
2559
  if (completedCount > 0 && missing.length === completedCount) {
2474
2560
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
2475
- throw new BitfabError(
2561
+ const cause = new BitfabError(
2476
2562
  `Replay completed but the server has no persisted trace for any of the ${completedCount} completed item(s) (testRunId ${testRunId}).${serverCount} Trace uploads were awaited, so either the uploads failed (check for "Bitfab: Failed to create" errors above) or the replayed function is not wrapped with withSpan.`
2477
2563
  );
2564
+ throw new ReplayError(
2565
+ cause.message,
2566
+ resultItems,
2567
+ testRunId,
2568
+ fullTestRunUrl,
2569
+ cause
2570
+ );
2478
2571
  }
2479
2572
  if (missing.length > 0) {
2480
2573
  try {
@@ -2488,7 +2581,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2488
2581
  const result = {
2489
2582
  items: resultItems,
2490
2583
  testRunId,
2491
- testRunUrl: `${serviceUrl}${testRunUrl}`
2584
+ testRunUrl: fullTestRunUrl
2492
2585
  };
2493
2586
  await writeReplayResultFile(result);
2494
2587
  try {
@@ -2516,7 +2609,7 @@ async function writeReplayResultFile(result) {
2516
2609
  import("fs/promises")
2517
2610
  ]);
2518
2611
  await mkdir(dirname(resultPath), { recursive: true });
2519
- await writeFile(resultPath, `${JSON.stringify(result, null, 2)}
2612
+ await writeFile(resultPath, `${serializeReplayResult(result)}
2520
2613
  `);
2521
2614
  } catch (err) {
2522
2615
  try {
@@ -2527,7 +2620,7 @@ async function writeReplayResultFile(result) {
2527
2620
  }
2528
2621
  }
2529
2622
  }
2530
- var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX;
2623
+ var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX, ReplayError, DbBranchReplayError;
2531
2624
  var init_replay = __esm({
2532
2625
  "src/replay.ts"() {
2533
2626
  "use strict";
@@ -2542,6 +2635,25 @@ var init_replay = __esm({
2542
2635
  init_unrefTimer();
2543
2636
  REPLAY_PERSISTENCE_TIMEOUT_MS = 3e4;
2544
2637
  BITFAB_PROGRESS_PREFIX = "@@bitfab:progress ";
2638
+ ReplayError = class extends BitfabError {
2639
+ constructor(message, items, testRunId, testRunUrl, cause) {
2640
+ super(message, testRunUrl);
2641
+ this.items = items;
2642
+ this.testRunId = testRunId;
2643
+ this.testRunUrl = testRunUrl;
2644
+ this.cause = cause;
2645
+ this.name = "ReplayError";
2646
+ }
2647
+ };
2648
+ DbBranchReplayError = class extends BitfabError {
2649
+ constructor(code, message, originalTraceId, cause) {
2650
+ super(message);
2651
+ this.code = code;
2652
+ this.originalTraceId = originalTraceId;
2653
+ this.cause = cause;
2654
+ this.name = "DbBranchReplayError";
2655
+ }
2656
+ };
2545
2657
  }
2546
2658
  });
2547
2659
 
@@ -2559,7 +2671,9 @@ __export(index_exports, {
2559
2671
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
2560
2672
  BitfabVercelAiHandler: () => BitfabVercelAiHandler,
2561
2673
  DEFAULT_SERVICE_URL: () => DEFAULT_SERVICE_URL,
2674
+ DbBranchReplayError: () => DbBranchReplayError,
2562
2675
  HttpClient: () => HttpClient,
2676
+ ReplayError: () => ReplayError,
2563
2677
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
2564
2678
  __version__: () => __version__,
2565
2679
  finalizers: () => finalizers,
@@ -2567,7 +2681,8 @@ __export(index_exports, {
2567
2681
  getCurrentReplayBranch: () => getCurrentReplayBranch,
2568
2682
  getCurrentSpan: () => getCurrentSpan,
2569
2683
  getCurrentTrace: () => getCurrentTrace,
2570
- reportReplayProgress: () => reportReplayProgress
2684
+ reportReplayProgress: () => reportReplayProgress,
2685
+ serializeReplayResult: () => serializeReplayResult
2571
2686
  });
2572
2687
  module.exports = __toCommonJS(index_exports);
2573
2688
 
@@ -6148,7 +6263,9 @@ init_replay();
6148
6263
  BitfabOpenAITracingProcessor,
6149
6264
  BitfabVercelAiHandler,
6150
6265
  DEFAULT_SERVICE_URL,
6266
+ DbBranchReplayError,
6151
6267
  HttpClient,
6268
+ ReplayError,
6152
6269
  SUPPORTED_PROVIDERS,
6153
6270
  __version__,
6154
6271
  finalizers,
@@ -6156,6 +6273,7 @@ init_replay();
6156
6273
  getCurrentReplayBranch,
6157
6274
  getCurrentSpan,
6158
6275
  getCurrentTrace,
6159
- reportReplayProgress
6276
+ reportReplayProgress,
6277
+ serializeReplayResult
6160
6278
  });
6161
6279
  //# sourceMappingURL=index.cjs.map