bitfab 0.36.2 → 0.36.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.d.cts CHANGED
@@ -1242,9 +1242,9 @@ interface ReplayProgress {
1242
1242
  completed: number;
1243
1243
  /** Total number of items in this replay run. */
1244
1244
  total: number;
1245
- /** Of the completed items, how many ran the function without throwing. */
1245
+ /** Of the completed items, how many finished without a code or replay error. */
1246
1246
  succeeded: number;
1247
- /** Of the completed items, how many threw (their `item.error` is set). */
1247
+ /** Of the completed items, how many have `item.error` set. */
1248
1248
  errored: number;
1249
1249
  /**
1250
1250
  * The single item that just settled to produce this event. `traceId` is null
@@ -1272,7 +1272,12 @@ interface ReplayProgress {
1272
1272
  result?: unknown;
1273
1273
  /** The original output from the historical trace. */
1274
1274
  originalOutput?: unknown;
1275
+ /** Backward-compatible message for either error kind. */
1275
1276
  error: string | null;
1277
+ /** The actual value thrown by the replayed customer function. */
1278
+ traceError: unknown | null;
1279
+ /** The actual value thrown while Bitfab prepared this replay item. */
1280
+ replayError: unknown | null;
1276
1281
  durationMs: number | null;
1277
1282
  tokens?: TokenUsage | null;
1278
1283
  model?: string | null;
@@ -1350,8 +1355,18 @@ interface ReplayItem<T> {
1350
1355
  result: T | undefined;
1351
1356
  /** The original output from the historical trace. */
1352
1357
  originalOutput: unknown;
1353
- /** Error message if the function threw, or null on success. */
1358
+ /**
1359
+ * Backward-compatible message for either error kind. Prefer `traceError` and
1360
+ * `replayError` when callers need the original exception and its source.
1361
+ */
1354
1362
  error: string | null;
1363
+ /** The actual value thrown by the replayed customer function. */
1364
+ traceError: unknown | null;
1365
+ /**
1366
+ * The actual value thrown by replay setup before the customer function ran,
1367
+ * such as database warmup, input hydration, or mock preparation.
1368
+ */
1369
+ replayError: unknown | null;
1355
1370
  /** Original trace duration in milliseconds, or null if timestamps are missing. */
1356
1371
  durationMs: number | null;
1357
1372
  /**
@@ -1381,6 +1396,37 @@ interface ReplayResult<T> {
1381
1396
  /** Full URL to view the test run in the dashboard. */
1382
1397
  testRunUrl: string;
1383
1398
  }
1399
+ /**
1400
+ * Whole-run replay failure that preserves every item collected before the run
1401
+ * failed. The original whole-run exception is available as `cause`.
1402
+ */
1403
+ declare class ReplayError<T = unknown> extends BitfabError {
1404
+ readonly items: ReplayItem<T>[];
1405
+ readonly testRunId: string;
1406
+ readonly testRunUrl: string;
1407
+ readonly cause: unknown;
1408
+ constructor(message: string, items: ReplayItem<T>[], testRunId: string, testRunUrl: string, cause: unknown);
1409
+ }
1410
+ /**
1411
+ * A database branch requested for one replay item could not be resolved.
1412
+ *
1413
+ * The server's resolver code and message are retained as structured fields so
1414
+ * callers can handle failures such as `branch_create_failed` and
1415
+ * `snapshot_from_replaced_origin` without parsing the compatible `item.error`
1416
+ * string.
1417
+ */
1418
+ declare class DbBranchReplayError extends BitfabError {
1419
+ readonly code: string;
1420
+ readonly originalTraceId: string;
1421
+ readonly cause?: unknown | undefined;
1422
+ constructor(code: string, message: string, originalTraceId: string, cause?: unknown | undefined);
1423
+ }
1424
+ /**
1425
+ * Serialize a replay result as JSON while retaining structured trace and replay
1426
+ * errors. Use this for direct-run stdout instead of raw `JSON.stringify`, which
1427
+ * drops the useful fields on JavaScript `Error` objects.
1428
+ */
1429
+ declare function serializeReplayResult<T>(result: ReplayResult<T>): string;
1384
1430
 
1385
1431
  /**
1386
1432
  * The database branch a single replay item runs against.
@@ -2353,7 +2399,7 @@ declare class BitfabFunction {
2353
2399
  /**
2354
2400
  * SDK version from package.json (injected at build time)
2355
2401
  */
2356
- declare const __version__ = "0.36.2";
2402
+ declare const __version__ = "0.36.4";
2357
2403
 
2358
2404
  /**
2359
2405
  * Constants for the Bitfab SDK.
@@ -2421,4 +2467,4 @@ declare const finalizers: {
2421
2467
  readableStream: typeof readableStream;
2422
2468
  };
2423
2469
 
2424
- export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CaptureWhen, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbBranchOptions, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, HttpClient, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayBranch, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentReplayBranch, getCurrentSpan, getCurrentTrace, reportReplayProgress };
2470
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CaptureWhen, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbBranchOptions, DbBranchReplayError, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, HttpClient, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayBranch, ReplayError, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentReplayBranch, getCurrentSpan, getCurrentTrace, reportReplayProgress, serializeReplayResult };
package/dist/index.d.ts CHANGED
@@ -1242,9 +1242,9 @@ interface ReplayProgress {
1242
1242
  completed: number;
1243
1243
  /** Total number of items in this replay run. */
1244
1244
  total: number;
1245
- /** Of the completed items, how many ran the function without throwing. */
1245
+ /** Of the completed items, how many finished without a code or replay error. */
1246
1246
  succeeded: number;
1247
- /** Of the completed items, how many threw (their `item.error` is set). */
1247
+ /** Of the completed items, how many have `item.error` set. */
1248
1248
  errored: number;
1249
1249
  /**
1250
1250
  * The single item that just settled to produce this event. `traceId` is null
@@ -1272,7 +1272,12 @@ interface ReplayProgress {
1272
1272
  result?: unknown;
1273
1273
  /** The original output from the historical trace. */
1274
1274
  originalOutput?: unknown;
1275
+ /** Backward-compatible message for either error kind. */
1275
1276
  error: string | null;
1277
+ /** The actual value thrown by the replayed customer function. */
1278
+ traceError: unknown | null;
1279
+ /** The actual value thrown while Bitfab prepared this replay item. */
1280
+ replayError: unknown | null;
1276
1281
  durationMs: number | null;
1277
1282
  tokens?: TokenUsage | null;
1278
1283
  model?: string | null;
@@ -1350,8 +1355,18 @@ interface ReplayItem<T> {
1350
1355
  result: T | undefined;
1351
1356
  /** The original output from the historical trace. */
1352
1357
  originalOutput: unknown;
1353
- /** Error message if the function threw, or null on success. */
1358
+ /**
1359
+ * Backward-compatible message for either error kind. Prefer `traceError` and
1360
+ * `replayError` when callers need the original exception and its source.
1361
+ */
1354
1362
  error: string | null;
1363
+ /** The actual value thrown by the replayed customer function. */
1364
+ traceError: unknown | null;
1365
+ /**
1366
+ * The actual value thrown by replay setup before the customer function ran,
1367
+ * such as database warmup, input hydration, or mock preparation.
1368
+ */
1369
+ replayError: unknown | null;
1355
1370
  /** Original trace duration in milliseconds, or null if timestamps are missing. */
1356
1371
  durationMs: number | null;
1357
1372
  /**
@@ -1381,6 +1396,37 @@ interface ReplayResult<T> {
1381
1396
  /** Full URL to view the test run in the dashboard. */
1382
1397
  testRunUrl: string;
1383
1398
  }
1399
+ /**
1400
+ * Whole-run replay failure that preserves every item collected before the run
1401
+ * failed. The original whole-run exception is available as `cause`.
1402
+ */
1403
+ declare class ReplayError<T = unknown> extends BitfabError {
1404
+ readonly items: ReplayItem<T>[];
1405
+ readonly testRunId: string;
1406
+ readonly testRunUrl: string;
1407
+ readonly cause: unknown;
1408
+ constructor(message: string, items: ReplayItem<T>[], testRunId: string, testRunUrl: string, cause: unknown);
1409
+ }
1410
+ /**
1411
+ * A database branch requested for one replay item could not be resolved.
1412
+ *
1413
+ * The server's resolver code and message are retained as structured fields so
1414
+ * callers can handle failures such as `branch_create_failed` and
1415
+ * `snapshot_from_replaced_origin` without parsing the compatible `item.error`
1416
+ * string.
1417
+ */
1418
+ declare class DbBranchReplayError extends BitfabError {
1419
+ readonly code: string;
1420
+ readonly originalTraceId: string;
1421
+ readonly cause?: unknown | undefined;
1422
+ constructor(code: string, message: string, originalTraceId: string, cause?: unknown | undefined);
1423
+ }
1424
+ /**
1425
+ * Serialize a replay result as JSON while retaining structured trace and replay
1426
+ * errors. Use this for direct-run stdout instead of raw `JSON.stringify`, which
1427
+ * drops the useful fields on JavaScript `Error` objects.
1428
+ */
1429
+ declare function serializeReplayResult<T>(result: ReplayResult<T>): string;
1384
1430
 
1385
1431
  /**
1386
1432
  * The database branch a single replay item runs against.
@@ -2353,7 +2399,7 @@ declare class BitfabFunction {
2353
2399
  /**
2354
2400
  * SDK version from package.json (injected at build time)
2355
2401
  */
2356
- declare const __version__ = "0.36.2";
2402
+ declare const __version__ = "0.36.4";
2357
2403
 
2358
2404
  /**
2359
2405
  * Constants for the Bitfab SDK.
@@ -2421,4 +2467,4 @@ declare const finalizers: {
2421
2467
  readableStream: typeof readableStream;
2422
2468
  };
2423
2469
 
2424
- export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CaptureWhen, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbBranchOptions, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, HttpClient, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayBranch, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentReplayBranch, getCurrentSpan, getCurrentTrace, reportReplayProgress };
2470
+ export { type ActiveSpanContext, type AdaptContext, type AdaptInputsFn, type AllowedEnvVars, BITFAB_PROGRESS_PREFIX, type BamlExecutionResult, Bitfab, BitfabClaudeAgentHandler, type BitfabConfig, BitfabError, BitfabFunction, BitfabLangGraphCallbackHandler as BitfabLangChainCallbackHandler, BitfabLangGraphCallbackHandler, type BitfabLanguageModelMiddleware, BitfabOpenAIAgentHandler, BitfabOpenAITracingProcessor, BitfabVercelAiHandler, type CaptureWhen, type CapturedSpan, type CodeChangeFile, type CurrentSpan, type CurrentTrace, DEFAULT_SERVICE_URL, type DbBranchOptions, DbBranchReplayError, type DbSnapshotConfig, type DbSnapshotProvider, type DbSnapshotRef, type DetachedTrace, HttpClient, type MockOverride, type MockOverrideCtx, type MockStrategy, type MockValue, type NodeMatcher, type ProviderDefinition, ReplayBranch, ReplayError, type ReplayItem, type ReplayOptions, type ReplayProgress, type ReplayResult, SUPPORTED_PROVIDERS, type SpanLookup, type SpanNodeMeta, type SpanOccurrence, type SpanOptions, type SpanType, type TokenUsage, type TraceResponse, type TracingProcessor, type VercelCallParams, type VercelGenerateResult, type VercelStreamResult, type WrapBAMLOptions, type WrappedBamlFn, __version__, finalizers, flushTraces, getCurrentReplayBranch, getCurrentSpan, getCurrentTrace, reportReplayProgress, serializeReplayResult };
package/dist/index.js CHANGED
@@ -20,16 +20,19 @@ import {
20
20
  getCurrentReplayBranch,
21
21
  getCurrentSpan,
22
22
  getCurrentTrace
23
- } from "./chunk-XZKYSTWH.js";
23
+ } from "./chunk-5NT3VGCB.js";
24
24
  import {
25
25
  BITFAB_PROGRESS_PREFIX,
26
26
  BitfabError,
27
27
  DEFAULT_SERVICE_URL,
28
+ DbBranchReplayError,
28
29
  HttpClient,
30
+ ReplayError,
29
31
  __version__,
30
32
  flushTraces,
31
- reportReplayProgress
32
- } from "./chunk-4IY5SZYR.js";
33
+ reportReplayProgress,
34
+ serializeReplayResult
35
+ } from "./chunk-6AXY24UL.js";
33
36
  export {
34
37
  BITFAB_PROGRESS_PREFIX,
35
38
  Bitfab,
@@ -42,7 +45,9 @@ export {
42
45
  BitfabOpenAITracingProcessor,
43
46
  BitfabVercelAiHandler,
44
47
  DEFAULT_SERVICE_URL,
48
+ DbBranchReplayError,
45
49
  HttpClient,
50
+ ReplayError,
46
51
  SUPPORTED_PROVIDERS,
47
52
  __version__,
48
53
  finalizers,
@@ -50,6 +55,7 @@ export {
50
55
  getCurrentReplayBranch,
51
56
  getCurrentSpan,
52
57
  getCurrentTrace,
53
- reportReplayProgress
58
+ reportReplayProgress,
59
+ serializeReplayResult
54
60
  };
55
61
  //# sourceMappingURL=index.js.map
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.2";
100
+ __version__ = "0.36.4";
101
101
  }
102
102
  });
103
103
 
@@ -2069,8 +2069,11 @@ var init_codeChange = __esm({
2069
2069
  var replay_exports = {};
2070
2070
  __export(replay_exports, {
2071
2071
  BITFAB_PROGRESS_PREFIX: () => BITFAB_PROGRESS_PREFIX,
2072
+ DbBranchReplayError: () => DbBranchReplayError,
2073
+ ReplayError: () => ReplayError,
2072
2074
  replay: () => replay,
2073
- reportReplayProgress: () => reportReplayProgress
2075
+ reportReplayProgress: () => reportReplayProgress,
2076
+ serializeReplayResult: () => serializeReplayResult
2074
2077
  });
2075
2078
  function dbBranchEnabled(dbBranch) {
2076
2079
  return dbBranch !== void 0 && dbBranch !== false;
@@ -2093,11 +2096,59 @@ function reportReplayProgress(progress) {
2093
2096
  return;
2094
2097
  }
2095
2098
  try {
2096
- stderr.write(`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress)}
2097
- `);
2099
+ stderr.write(
2100
+ `${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress, replayJsonReplacer)}
2101
+ `
2102
+ );
2098
2103
  } catch {
2099
2104
  }
2100
2105
  }
2106
+ function errorMessage(error) {
2107
+ return error instanceof Error ? error.message : String(error);
2108
+ }
2109
+ function replayItemErrorMessage(error) {
2110
+ if (error instanceof DbBranchReplayError) {
2111
+ 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.`;
2112
+ }
2113
+ return errorMessage(error);
2114
+ }
2115
+ function replayJsonReplacer(_key, value) {
2116
+ if (value instanceof Error) {
2117
+ const serialized = {
2118
+ name: value.name,
2119
+ message: value.message,
2120
+ stack: value.stack
2121
+ };
2122
+ if (value instanceof DbBranchReplayError) {
2123
+ serialized.code = value.code;
2124
+ serialized.originalTraceId = value.originalTraceId;
2125
+ if (value.cause !== void 0) {
2126
+ serialized.cause = value.cause;
2127
+ }
2128
+ }
2129
+ return serialized;
2130
+ }
2131
+ return value;
2132
+ }
2133
+ function serializeReplayResult(result) {
2134
+ return JSON.stringify(result, replayJsonReplacer, 2);
2135
+ }
2136
+ async function preserveReplayFailure(operation, items, testRunId, testRunUrl) {
2137
+ try {
2138
+ return await operation();
2139
+ } catch (cause) {
2140
+ if (cause instanceof ReplayError) {
2141
+ throw cause;
2142
+ }
2143
+ throw new ReplayError(
2144
+ errorMessage(cause),
2145
+ items,
2146
+ testRunId,
2147
+ testRunUrl,
2148
+ cause
2149
+ );
2150
+ }
2151
+ }
2101
2152
  function deserializeInputs(spanData) {
2102
2153
  const inputMeta = spanData.input_meta;
2103
2154
  const rawInput = spanData.input;
@@ -2155,22 +2206,36 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2155
2206
  let originalOutput;
2156
2207
  let result;
2157
2208
  let error = null;
2209
+ let traceError = null;
2210
+ let replayError = null;
2158
2211
  const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
2159
2212
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2160
2213
  try {
2161
2214
  if (includeDbBranchLease && !lease && !leaseError) {
2162
- const resolved = await httpClient.resolveDbBranchLease(
2163
- testRunId,
2164
- originalTraceId,
2165
- dbBranchSettings
2166
- );
2215
+ let resolved;
2216
+ try {
2217
+ resolved = await httpClient.resolveDbBranchLease(
2218
+ testRunId,
2219
+ originalTraceId,
2220
+ dbBranchSettings
2221
+ );
2222
+ } catch (cause) {
2223
+ throw new DbBranchReplayError(
2224
+ "lease_request_failed",
2225
+ `Bitfab could not request the database branch: ${errorMessage(cause)}`,
2226
+ originalTraceId,
2227
+ cause
2228
+ );
2229
+ }
2167
2230
  lease = resolved.lease ?? void 0;
2168
2231
  leaseError = resolved.leaseError ?? void 0;
2169
2232
  dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2170
2233
  }
2171
2234
  if (leaseError) {
2172
- throw new BitfabError(
2173
- `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.`
2235
+ throw new DbBranchReplayError(
2236
+ leaseError.code,
2237
+ leaseError.message,
2238
+ originalTraceId
2174
2239
  );
2175
2240
  }
2176
2241
  const span = await httpClient.getExternalSpan(originalSpanId, {
@@ -2227,25 +2292,31 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2227
2292
  }
2228
2293
  return pending;
2229
2294
  } : void 0;
2230
- const maybePromise = runWithReplayContext(
2231
- {
2232
- testRunId,
2233
- traceId: replayedTraceId,
2234
- inputSourceSpanId: span.id,
2235
- inputSourceTraceId: span.externalTraceId,
2236
- sourceBitfabTraceId: originalTraceId,
2237
- mockTree,
2238
- callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2239
- mockStrategy,
2240
- mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2241
- fetchSpanOutput,
2242
- dbBranchLease: lease
2243
- },
2244
- () => fn(...inputs)
2245
- );
2246
- result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
2295
+ try {
2296
+ const maybePromise = runWithReplayContext(
2297
+ {
2298
+ testRunId,
2299
+ traceId: replayedTraceId,
2300
+ inputSourceSpanId: span.id,
2301
+ inputSourceTraceId: span.externalTraceId,
2302
+ sourceBitfabTraceId: originalTraceId,
2303
+ mockTree,
2304
+ callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2305
+ mockStrategy,
2306
+ mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2307
+ fetchSpanOutput,
2308
+ dbBranchLease: lease
2309
+ },
2310
+ () => fn(...inputs)
2311
+ );
2312
+ result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
2313
+ } catch (e) {
2314
+ traceError = e;
2315
+ error = errorMessage(e);
2316
+ }
2247
2317
  } catch (e) {
2248
- error = e instanceof Error ? e.message : String(e);
2318
+ replayError = e;
2319
+ error = replayItemErrorMessage(e);
2249
2320
  } finally {
2250
2321
  if (lease) {
2251
2322
  try {
@@ -2274,6 +2345,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2274
2345
  result,
2275
2346
  originalOutput,
2276
2347
  error,
2348
+ traceError,
2349
+ replayError,
2277
2350
  durationMs: serverItem.durationMs ?? null,
2278
2351
  // Filled in by replay() from the complete-replay response once the
2279
2352
  // replay traces are persisted and their spans aggregated server-side.
@@ -2398,6 +2471,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2398
2471
  );
2399
2472
  const mockStrategy = options?.mock ?? "marked";
2400
2473
  const maxConcurrency = options?.maxConcurrency ?? 10;
2474
+ const fullTestRunUrl = `${serviceUrl}${testRunUrl}`;
2401
2475
  const resolvedOverrides = [
2402
2476
  ...normalizeMockOverrides(options?.mockOverride),
2403
2477
  ...registeredOverrides
@@ -2454,6 +2528,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2454
2528
  result: item.result,
2455
2529
  originalOutput: item.originalOutput,
2456
2530
  error: item.error,
2531
+ traceError: item.traceError,
2532
+ replayError: item.replayError,
2457
2533
  durationMs: item.durationMs,
2458
2534
  tokens: item.tokens,
2459
2535
  model: item.model,
@@ -2464,8 +2540,18 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2464
2540
  }
2465
2541
  } : void 0
2466
2542
  );
2467
- await waitForReplayPersistence(httpClient, testRunId, replayedTraceIds);
2468
- const completeResult = await httpClient.completeReplay(testRunId);
2543
+ await preserveReplayFailure(
2544
+ () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
2545
+ resultItems,
2546
+ testRunId,
2547
+ fullTestRunUrl
2548
+ );
2549
+ const completeResult = await preserveReplayFailure(
2550
+ () => httpClient.completeReplay(testRunId),
2551
+ resultItems,
2552
+ testRunId,
2553
+ fullTestRunUrl
2554
+ );
2469
2555
  const serverTraceIds = completeResult.traceIds;
2470
2556
  const replayTokens = completeResult.tokens;
2471
2557
  if (serverTraceIds !== void 0) {
@@ -2488,9 +2574,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2488
2574
  }
2489
2575
  if (completedCount > 0 && missing.length === completedCount) {
2490
2576
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
2491
- throw new BitfabError(
2577
+ const cause = new BitfabError(
2492
2578
  `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.`
2493
2579
  );
2580
+ throw new ReplayError(
2581
+ cause.message,
2582
+ resultItems,
2583
+ testRunId,
2584
+ fullTestRunUrl,
2585
+ cause
2586
+ );
2494
2587
  }
2495
2588
  if (missing.length > 0) {
2496
2589
  try {
@@ -2504,7 +2597,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2504
2597
  const result = {
2505
2598
  items: resultItems,
2506
2599
  testRunId,
2507
- testRunUrl: `${serviceUrl}${testRunUrl}`
2600
+ testRunUrl: fullTestRunUrl
2508
2601
  };
2509
2602
  await writeReplayResultFile(result);
2510
2603
  try {
@@ -2532,7 +2625,7 @@ async function writeReplayResultFile(result) {
2532
2625
  import("fs/promises")
2533
2626
  ]);
2534
2627
  await mkdir(dirname(resultPath), { recursive: true });
2535
- await writeFile(resultPath, `${JSON.stringify(result, null, 2)}
2628
+ await writeFile(resultPath, `${serializeReplayResult(result)}
2536
2629
  `);
2537
2630
  } catch (err) {
2538
2631
  try {
@@ -2543,7 +2636,7 @@ async function writeReplayResultFile(result) {
2543
2636
  }
2544
2637
  }
2545
2638
  }
2546
- var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX;
2639
+ var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX, ReplayError, DbBranchReplayError;
2547
2640
  var init_replay = __esm({
2548
2641
  "src/replay.ts"() {
2549
2642
  "use strict";
@@ -2558,6 +2651,25 @@ var init_replay = __esm({
2558
2651
  init_unrefTimer();
2559
2652
  REPLAY_PERSISTENCE_TIMEOUT_MS = 3e4;
2560
2653
  BITFAB_PROGRESS_PREFIX = "@@bitfab:progress ";
2654
+ ReplayError = class extends BitfabError {
2655
+ constructor(message, items, testRunId, testRunUrl, cause) {
2656
+ super(message, testRunUrl);
2657
+ this.items = items;
2658
+ this.testRunId = testRunId;
2659
+ this.testRunUrl = testRunUrl;
2660
+ this.cause = cause;
2661
+ this.name = "ReplayError";
2662
+ }
2663
+ };
2664
+ DbBranchReplayError = class extends BitfabError {
2665
+ constructor(code, message, originalTraceId, cause) {
2666
+ super(message);
2667
+ this.code = code;
2668
+ this.originalTraceId = originalTraceId;
2669
+ this.cause = cause;
2670
+ this.name = "DbBranchReplayError";
2671
+ }
2672
+ };
2561
2673
  }
2562
2674
  });
2563
2675
 
@@ -2575,7 +2687,9 @@ __export(node_exports, {
2575
2687
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
2576
2688
  BitfabVercelAiHandler: () => BitfabVercelAiHandler,
2577
2689
  DEFAULT_SERVICE_URL: () => DEFAULT_SERVICE_URL,
2690
+ DbBranchReplayError: () => DbBranchReplayError,
2578
2691
  HttpClient: () => HttpClient,
2692
+ ReplayError: () => ReplayError,
2579
2693
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
2580
2694
  __version__: () => __version__,
2581
2695
  finalizers: () => finalizers,
@@ -2583,7 +2697,8 @@ __export(node_exports, {
2583
2697
  getCurrentReplayBranch: () => getCurrentReplayBranch,
2584
2698
  getCurrentSpan: () => getCurrentSpan,
2585
2699
  getCurrentTrace: () => getCurrentTrace,
2586
- reportReplayProgress: () => reportReplayProgress
2700
+ reportReplayProgress: () => reportReplayProgress,
2701
+ serializeReplayResult: () => serializeReplayResult
2587
2702
  });
2588
2703
  module.exports = __toCommonJS(node_exports);
2589
2704
 
@@ -6175,7 +6290,9 @@ assertAsyncStorageRegistered();
6175
6290
  BitfabOpenAITracingProcessor,
6176
6291
  BitfabVercelAiHandler,
6177
6292
  DEFAULT_SERVICE_URL,
6293
+ DbBranchReplayError,
6178
6294
  HttpClient,
6295
+ ReplayError,
6179
6296
  SUPPORTED_PROVIDERS,
6180
6297
  __version__,
6181
6298
  finalizers,
@@ -6183,6 +6300,7 @@ assertAsyncStorageRegistered();
6183
6300
  getCurrentReplayBranch,
6184
6301
  getCurrentSpan,
6185
6302
  getCurrentTrace,
6186
- reportReplayProgress
6303
+ reportReplayProgress,
6304
+ serializeReplayResult
6187
6305
  });
6188
6306
  //# sourceMappingURL=node.cjs.map