@bitfab/sdk 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
@@ -11,16 +11,19 @@ import {
11
11
  getCurrentReplayBranch,
12
12
  getCurrentSpan,
13
13
  getCurrentTrace
14
- } from "./chunk-XZKYSTWH.js";
14
+ } from "./chunk-5NT3VGCB.js";
15
15
  import {
16
16
  BITFAB_PROGRESS_PREFIX,
17
17
  BitfabError,
18
18
  DEFAULT_SERVICE_URL,
19
+ DbBranchReplayError,
19
20
  HttpClient,
21
+ ReplayError,
20
22
  __version__,
21
23
  flushTraces,
22
- reportReplayProgress
23
- } from "./chunk-4IY5SZYR.js";
24
+ reportReplayProgress,
25
+ serializeReplayResult
26
+ } from "./chunk-6AXY24UL.js";
24
27
  export {
25
28
  BITFAB_PROGRESS_PREFIX,
26
29
  Bitfab,
@@ -33,7 +36,9 @@ export {
33
36
  BitfabOpenAITracingProcessor,
34
37
  BitfabVercelAiHandler,
35
38
  DEFAULT_SERVICE_URL,
39
+ DbBranchReplayError,
36
40
  HttpClient,
41
+ ReplayError,
37
42
  SUPPORTED_PROVIDERS,
38
43
  __version__,
39
44
  finalizers,
@@ -41,6 +46,7 @@ export {
41
46
  getCurrentReplayBranch,
42
47
  getCurrentSpan,
43
48
  getCurrentTrace,
44
- reportReplayProgress
49
+ reportReplayProgress,
50
+ serializeReplayResult
45
51
  };
46
52
  //# sourceMappingURL=index.js.map
package/dist/node.cjs CHANGED
@@ -88,7 +88,7 @@ var __version__;
88
88
  var init_version_generated = __esm({
89
89
  "src/version.generated.ts"() {
90
90
  "use strict";
91
- __version__ = "0.36.2";
91
+ __version__ = "0.36.4";
92
92
  }
93
93
  });
94
94
 
@@ -2060,8 +2060,11 @@ var init_codeChange = __esm({
2060
2060
  var replay_exports = {};
2061
2061
  __export(replay_exports, {
2062
2062
  BITFAB_PROGRESS_PREFIX: () => BITFAB_PROGRESS_PREFIX,
2063
+ DbBranchReplayError: () => DbBranchReplayError,
2064
+ ReplayError: () => ReplayError,
2063
2065
  replay: () => replay,
2064
- reportReplayProgress: () => reportReplayProgress
2066
+ reportReplayProgress: () => reportReplayProgress,
2067
+ serializeReplayResult: () => serializeReplayResult
2065
2068
  });
2066
2069
  function dbBranchEnabled(dbBranch) {
2067
2070
  return dbBranch !== void 0 && dbBranch !== false;
@@ -2084,11 +2087,59 @@ function reportReplayProgress(progress) {
2084
2087
  return;
2085
2088
  }
2086
2089
  try {
2087
- stderr.write(`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress)}
2088
- `);
2090
+ stderr.write(
2091
+ `${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress, replayJsonReplacer)}
2092
+ `
2093
+ );
2089
2094
  } catch {
2090
2095
  }
2091
2096
  }
2097
+ function errorMessage(error) {
2098
+ return error instanceof Error ? error.message : String(error);
2099
+ }
2100
+ function replayItemErrorMessage(error) {
2101
+ if (error instanceof DbBranchReplayError) {
2102
+ 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.`;
2103
+ }
2104
+ return errorMessage(error);
2105
+ }
2106
+ function replayJsonReplacer(_key, value) {
2107
+ if (value instanceof Error) {
2108
+ const serialized = {
2109
+ name: value.name,
2110
+ message: value.message,
2111
+ stack: value.stack
2112
+ };
2113
+ if (value instanceof DbBranchReplayError) {
2114
+ serialized.code = value.code;
2115
+ serialized.originalTraceId = value.originalTraceId;
2116
+ if (value.cause !== void 0) {
2117
+ serialized.cause = value.cause;
2118
+ }
2119
+ }
2120
+ return serialized;
2121
+ }
2122
+ return value;
2123
+ }
2124
+ function serializeReplayResult(result) {
2125
+ return JSON.stringify(result, replayJsonReplacer, 2);
2126
+ }
2127
+ async function preserveReplayFailure(operation, items, testRunId, testRunUrl) {
2128
+ try {
2129
+ return await operation();
2130
+ } catch (cause) {
2131
+ if (cause instanceof ReplayError) {
2132
+ throw cause;
2133
+ }
2134
+ throw new ReplayError(
2135
+ errorMessage(cause),
2136
+ items,
2137
+ testRunId,
2138
+ testRunUrl,
2139
+ cause
2140
+ );
2141
+ }
2142
+ }
2092
2143
  function deserializeInputs(spanData) {
2093
2144
  const inputMeta = spanData.input_meta;
2094
2145
  const rawInput = spanData.input;
@@ -2146,22 +2197,36 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2146
2197
  let originalOutput;
2147
2198
  let result;
2148
2199
  let error = null;
2200
+ let traceError = null;
2201
+ let replayError = null;
2149
2202
  const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
2150
2203
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2151
2204
  try {
2152
2205
  if (includeDbBranchLease && !lease && !leaseError) {
2153
- const resolved = await httpClient.resolveDbBranchLease(
2154
- testRunId,
2155
- originalTraceId,
2156
- dbBranchSettings
2157
- );
2206
+ let resolved;
2207
+ try {
2208
+ resolved = await httpClient.resolveDbBranchLease(
2209
+ testRunId,
2210
+ originalTraceId,
2211
+ dbBranchSettings
2212
+ );
2213
+ } catch (cause) {
2214
+ throw new DbBranchReplayError(
2215
+ "lease_request_failed",
2216
+ `Bitfab could not request the database branch: ${errorMessage(cause)}`,
2217
+ originalTraceId,
2218
+ cause
2219
+ );
2220
+ }
2158
2221
  lease = resolved.lease ?? void 0;
2159
2222
  leaseError = resolved.leaseError ?? void 0;
2160
2223
  dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2161
2224
  }
2162
2225
  if (leaseError) {
2163
- throw new BitfabError(
2164
- `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.`
2226
+ throw new DbBranchReplayError(
2227
+ leaseError.code,
2228
+ leaseError.message,
2229
+ originalTraceId
2165
2230
  );
2166
2231
  }
2167
2232
  const span = await httpClient.getExternalSpan(originalSpanId, {
@@ -2218,25 +2283,31 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2218
2283
  }
2219
2284
  return pending;
2220
2285
  } : void 0;
2221
- const maybePromise = runWithReplayContext(
2222
- {
2223
- testRunId,
2224
- traceId: replayedTraceId,
2225
- inputSourceSpanId: span.id,
2226
- inputSourceTraceId: span.externalTraceId,
2227
- sourceBitfabTraceId: originalTraceId,
2228
- mockTree,
2229
- callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2230
- mockStrategy,
2231
- mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2232
- fetchSpanOutput,
2233
- dbBranchLease: lease
2234
- },
2235
- () => fn(...inputs)
2236
- );
2237
- result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
2286
+ try {
2287
+ const maybePromise = runWithReplayContext(
2288
+ {
2289
+ testRunId,
2290
+ traceId: replayedTraceId,
2291
+ inputSourceSpanId: span.id,
2292
+ inputSourceTraceId: span.externalTraceId,
2293
+ sourceBitfabTraceId: originalTraceId,
2294
+ mockTree,
2295
+ callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2296
+ mockStrategy,
2297
+ mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2298
+ fetchSpanOutput,
2299
+ dbBranchLease: lease
2300
+ },
2301
+ () => fn(...inputs)
2302
+ );
2303
+ result = maybePromise instanceof Promise ? await maybePromise : maybePromise;
2304
+ } catch (e) {
2305
+ traceError = e;
2306
+ error = errorMessage(e);
2307
+ }
2238
2308
  } catch (e) {
2239
- error = e instanceof Error ? e.message : String(e);
2309
+ replayError = e;
2310
+ error = replayItemErrorMessage(e);
2240
2311
  } finally {
2241
2312
  if (lease) {
2242
2313
  try {
@@ -2265,6 +2336,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2265
2336
  result,
2266
2337
  originalOutput,
2267
2338
  error,
2339
+ traceError,
2340
+ replayError,
2268
2341
  durationMs: serverItem.durationMs ?? null,
2269
2342
  // Filled in by replay() from the complete-replay response once the
2270
2343
  // replay traces are persisted and their spans aggregated server-side.
@@ -2389,6 +2462,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2389
2462
  );
2390
2463
  const mockStrategy = options?.mock ?? "marked";
2391
2464
  const maxConcurrency = options?.maxConcurrency ?? 10;
2465
+ const fullTestRunUrl = `${serviceUrl}${testRunUrl}`;
2392
2466
  const resolvedOverrides = [
2393
2467
  ...normalizeMockOverrides(options?.mockOverride),
2394
2468
  ...registeredOverrides
@@ -2445,6 +2519,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2445
2519
  result: item.result,
2446
2520
  originalOutput: item.originalOutput,
2447
2521
  error: item.error,
2522
+ traceError: item.traceError,
2523
+ replayError: item.replayError,
2448
2524
  durationMs: item.durationMs,
2449
2525
  tokens: item.tokens,
2450
2526
  model: item.model,
@@ -2455,8 +2531,18 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2455
2531
  }
2456
2532
  } : void 0
2457
2533
  );
2458
- await waitForReplayPersistence(httpClient, testRunId, replayedTraceIds);
2459
- const completeResult = await httpClient.completeReplay(testRunId);
2534
+ await preserveReplayFailure(
2535
+ () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
2536
+ resultItems,
2537
+ testRunId,
2538
+ fullTestRunUrl
2539
+ );
2540
+ const completeResult = await preserveReplayFailure(
2541
+ () => httpClient.completeReplay(testRunId),
2542
+ resultItems,
2543
+ testRunId,
2544
+ fullTestRunUrl
2545
+ );
2460
2546
  const serverTraceIds = completeResult.traceIds;
2461
2547
  const replayTokens = completeResult.tokens;
2462
2548
  if (serverTraceIds !== void 0) {
@@ -2479,9 +2565,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2479
2565
  }
2480
2566
  if (completedCount > 0 && missing.length === completedCount) {
2481
2567
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
2482
- throw new BitfabError(
2568
+ const cause = new BitfabError(
2483
2569
  `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.`
2484
2570
  );
2571
+ throw new ReplayError(
2572
+ cause.message,
2573
+ resultItems,
2574
+ testRunId,
2575
+ fullTestRunUrl,
2576
+ cause
2577
+ );
2485
2578
  }
2486
2579
  if (missing.length > 0) {
2487
2580
  try {
@@ -2495,7 +2588,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2495
2588
  const result = {
2496
2589
  items: resultItems,
2497
2590
  testRunId,
2498
- testRunUrl: `${serviceUrl}${testRunUrl}`
2591
+ testRunUrl: fullTestRunUrl
2499
2592
  };
2500
2593
  await writeReplayResultFile(result);
2501
2594
  try {
@@ -2523,7 +2616,7 @@ async function writeReplayResultFile(result) {
2523
2616
  import("fs/promises")
2524
2617
  ]);
2525
2618
  await mkdir(dirname(resultPath), { recursive: true });
2526
- await writeFile(resultPath, `${JSON.stringify(result, null, 2)}
2619
+ await writeFile(resultPath, `${serializeReplayResult(result)}
2527
2620
  `);
2528
2621
  } catch (err) {
2529
2622
  try {
@@ -2534,7 +2627,7 @@ async function writeReplayResultFile(result) {
2534
2627
  }
2535
2628
  }
2536
2629
  }
2537
- var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX;
2630
+ var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX, ReplayError, DbBranchReplayError;
2538
2631
  var init_replay = __esm({
2539
2632
  "src/replay.ts"() {
2540
2633
  "use strict";
@@ -2549,6 +2642,25 @@ var init_replay = __esm({
2549
2642
  init_unrefTimer();
2550
2643
  REPLAY_PERSISTENCE_TIMEOUT_MS = 3e4;
2551
2644
  BITFAB_PROGRESS_PREFIX = "@@bitfab:progress ";
2645
+ ReplayError = class extends BitfabError {
2646
+ constructor(message, items, testRunId, testRunUrl, cause) {
2647
+ super(message, testRunUrl);
2648
+ this.items = items;
2649
+ this.testRunId = testRunId;
2650
+ this.testRunUrl = testRunUrl;
2651
+ this.cause = cause;
2652
+ this.name = "ReplayError";
2653
+ }
2654
+ };
2655
+ DbBranchReplayError = class extends BitfabError {
2656
+ constructor(code, message, originalTraceId, cause) {
2657
+ super(message);
2658
+ this.code = code;
2659
+ this.originalTraceId = originalTraceId;
2660
+ this.cause = cause;
2661
+ this.name = "DbBranchReplayError";
2662
+ }
2663
+ };
2552
2664
  }
2553
2665
  });
2554
2666
 
@@ -2566,7 +2678,9 @@ __export(node_exports, {
2566
2678
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
2567
2679
  BitfabVercelAiHandler: () => BitfabVercelAiHandler,
2568
2680
  DEFAULT_SERVICE_URL: () => DEFAULT_SERVICE_URL,
2681
+ DbBranchReplayError: () => DbBranchReplayError,
2569
2682
  HttpClient: () => HttpClient,
2683
+ ReplayError: () => ReplayError,
2570
2684
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
2571
2685
  __version__: () => __version__,
2572
2686
  finalizers: () => finalizers,
@@ -2574,7 +2688,8 @@ __export(node_exports, {
2574
2688
  getCurrentReplayBranch: () => getCurrentReplayBranch,
2575
2689
  getCurrentSpan: () => getCurrentSpan,
2576
2690
  getCurrentTrace: () => getCurrentTrace,
2577
- reportReplayProgress: () => reportReplayProgress
2691
+ reportReplayProgress: () => reportReplayProgress,
2692
+ serializeReplayResult: () => serializeReplayResult
2578
2693
  });
2579
2694
  module.exports = __toCommonJS(node_exports);
2580
2695
 
@@ -6166,7 +6281,9 @@ assertAsyncStorageRegistered();
6166
6281
  BitfabOpenAITracingProcessor,
6167
6282
  BitfabVercelAiHandler,
6168
6283
  DEFAULT_SERVICE_URL,
6284
+ DbBranchReplayError,
6169
6285
  HttpClient,
6286
+ ReplayError,
6170
6287
  SUPPORTED_PROVIDERS,
6171
6288
  __version__,
6172
6289
  finalizers,
@@ -6174,6 +6291,7 @@ assertAsyncStorageRegistered();
6174
6291
  getCurrentReplayBranch,
6175
6292
  getCurrentSpan,
6176
6293
  getCurrentTrace,
6177
- reportReplayProgress
6294
+ reportReplayProgress,
6295
+ serializeReplayResult
6178
6296
  });
6179
6297
  //# sourceMappingURL=node.cjs.map