@bitfab/sdk 0.36.1 → 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.d.cts CHANGED
@@ -457,8 +457,11 @@ declare class HttpClient {
457
457
  /**
458
458
  * Fetch an external span by ID.
459
459
  * Blocking GET request.
460
+ * The replay view limits rawData to input/output serialization fields.
460
461
  */
461
- getExternalSpan(spanId: string): Promise<ExternalSpanResponse>;
462
+ getExternalSpan(spanId: string, options?: {
463
+ view?: "full" | "replay";
464
+ }): Promise<ExternalSpanResponse>;
462
465
  /**
463
466
  * Fetch the span tree for a root span.
464
467
  * Blocking GET request.
@@ -466,9 +469,11 @@ declare class HttpClient {
466
469
  * Pass `includeOutputs: false` for a payload-free tree (structure +
467
470
  * `externalSpanId` only), so recorded outputs are fetched lazily per mocked
468
471
  * span instead of all up front. Omit it (default eager) for `mock: "all"`.
472
+ * Pass `includeRootOutput: false` when the root was already fetched.
469
473
  */
470
474
  getSpanTree(externalSpanId: string, options?: {
471
475
  includeOutputs?: boolean;
476
+ includeRootOutput?: boolean;
472
477
  }): Promise<SpanTreeResponse>;
473
478
  /**
474
479
  * Read which of a replay run's traces the server has fully persisted.
@@ -1237,9 +1242,9 @@ interface ReplayProgress {
1237
1242
  completed: number;
1238
1243
  /** Total number of items in this replay run. */
1239
1244
  total: number;
1240
- /** 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. */
1241
1246
  succeeded: number;
1242
- /** Of the completed items, how many threw (their `item.error` is set). */
1247
+ /** Of the completed items, how many have `item.error` set. */
1243
1248
  errored: number;
1244
1249
  /**
1245
1250
  * The single item that just settled to produce this event. `traceId` is null
@@ -1267,7 +1272,12 @@ interface ReplayProgress {
1267
1272
  result?: unknown;
1268
1273
  /** The original output from the historical trace. */
1269
1274
  originalOutput?: unknown;
1275
+ /** Backward-compatible message for either error kind. */
1270
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;
1271
1281
  durationMs: number | null;
1272
1282
  tokens?: TokenUsage | null;
1273
1283
  model?: string | null;
@@ -1345,8 +1355,18 @@ interface ReplayItem<T> {
1345
1355
  result: T | undefined;
1346
1356
  /** The original output from the historical trace. */
1347
1357
  originalOutput: unknown;
1348
- /** 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
+ */
1349
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;
1350
1370
  /** Original trace duration in milliseconds, or null if timestamps are missing. */
1351
1371
  durationMs: number | null;
1352
1372
  /**
@@ -1376,6 +1396,37 @@ interface ReplayResult<T> {
1376
1396
  /** Full URL to view the test run in the dashboard. */
1377
1397
  testRunUrl: string;
1378
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;
1379
1430
 
1380
1431
  /**
1381
1432
  * The database branch a single replay item runs against.
@@ -2348,7 +2399,7 @@ declare class BitfabFunction {
2348
2399
  /**
2349
2400
  * SDK version from package.json (injected at build time)
2350
2401
  */
2351
- declare const __version__ = "0.36.1";
2402
+ declare const __version__ = "0.36.3";
2352
2403
 
2353
2404
  /**
2354
2405
  * Constants for the Bitfab SDK.
@@ -2416,4 +2467,4 @@ declare const finalizers: {
2416
2467
  readableStream: typeof readableStream;
2417
2468
  };
2418
2469
 
2419
- 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
@@ -457,8 +457,11 @@ declare class HttpClient {
457
457
  /**
458
458
  * Fetch an external span by ID.
459
459
  * Blocking GET request.
460
+ * The replay view limits rawData to input/output serialization fields.
460
461
  */
461
- getExternalSpan(spanId: string): Promise<ExternalSpanResponse>;
462
+ getExternalSpan(spanId: string, options?: {
463
+ view?: "full" | "replay";
464
+ }): Promise<ExternalSpanResponse>;
462
465
  /**
463
466
  * Fetch the span tree for a root span.
464
467
  * Blocking GET request.
@@ -466,9 +469,11 @@ declare class HttpClient {
466
469
  * Pass `includeOutputs: false` for a payload-free tree (structure +
467
470
  * `externalSpanId` only), so recorded outputs are fetched lazily per mocked
468
471
  * span instead of all up front. Omit it (default eager) for `mock: "all"`.
472
+ * Pass `includeRootOutput: false` when the root was already fetched.
469
473
  */
470
474
  getSpanTree(externalSpanId: string, options?: {
471
475
  includeOutputs?: boolean;
476
+ includeRootOutput?: boolean;
472
477
  }): Promise<SpanTreeResponse>;
473
478
  /**
474
479
  * Read which of a replay run's traces the server has fully persisted.
@@ -1237,9 +1242,9 @@ interface ReplayProgress {
1237
1242
  completed: number;
1238
1243
  /** Total number of items in this replay run. */
1239
1244
  total: number;
1240
- /** 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. */
1241
1246
  succeeded: number;
1242
- /** Of the completed items, how many threw (their `item.error` is set). */
1247
+ /** Of the completed items, how many have `item.error` set. */
1243
1248
  errored: number;
1244
1249
  /**
1245
1250
  * The single item that just settled to produce this event. `traceId` is null
@@ -1267,7 +1272,12 @@ interface ReplayProgress {
1267
1272
  result?: unknown;
1268
1273
  /** The original output from the historical trace. */
1269
1274
  originalOutput?: unknown;
1275
+ /** Backward-compatible message for either error kind. */
1270
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;
1271
1281
  durationMs: number | null;
1272
1282
  tokens?: TokenUsage | null;
1273
1283
  model?: string | null;
@@ -1345,8 +1355,18 @@ interface ReplayItem<T> {
1345
1355
  result: T | undefined;
1346
1356
  /** The original output from the historical trace. */
1347
1357
  originalOutput: unknown;
1348
- /** 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
+ */
1349
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;
1350
1370
  /** Original trace duration in milliseconds, or null if timestamps are missing. */
1351
1371
  durationMs: number | null;
1352
1372
  /**
@@ -1376,6 +1396,37 @@ interface ReplayResult<T> {
1376
1396
  /** Full URL to view the test run in the dashboard. */
1377
1397
  testRunUrl: string;
1378
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;
1379
1430
 
1380
1431
  /**
1381
1432
  * The database branch a single replay item runs against.
@@ -2348,7 +2399,7 @@ declare class BitfabFunction {
2348
2399
  /**
2349
2400
  * SDK version from package.json (injected at build time)
2350
2401
  */
2351
- declare const __version__ = "0.36.1";
2402
+ declare const __version__ = "0.36.3";
2352
2403
 
2353
2404
  /**
2354
2405
  * Constants for the Bitfab SDK.
@@ -2416,4 +2467,4 @@ declare const finalizers: {
2416
2467
  readableStream: typeof readableStream;
2417
2468
  };
2418
2469
 
2419
- 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-HD4DRDRE.js";
14
+ } from "./chunk-4CTDZMG5.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-6ZBZBR5K.js";
24
+ reportReplayProgress,
25
+ serializeReplayResult
26
+ } from "./chunk-M2GISXGV.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.1";
91
+ __version__ = "0.36.3";
92
92
  }
93
93
  });
94
94
 
@@ -1528,9 +1528,11 @@ var init_http = __esm({
1528
1528
  /**
1529
1529
  * Fetch an external span by ID.
1530
1530
  * Blocking GET request.
1531
+ * The replay view limits rawData to input/output serialization fields.
1531
1532
  */
1532
- async getExternalSpan(spanId) {
1533
- const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}`;
1533
+ async getExternalSpan(spanId, options) {
1534
+ const query = options?.view === "replay" ? "?view=replay" : "";
1535
+ const url = `${this.serviceUrl}/api/sdk/externalSpans/${spanId}${query}`;
1534
1536
  const controller = new AbortController();
1535
1537
  const timeoutId = setTimeout(() => controller.abort(), 3e4);
1536
1538
  try {
@@ -1568,9 +1570,18 @@ var init_http = __esm({
1568
1570
  * Pass `includeOutputs: false` for a payload-free tree (structure +
1569
1571
  * `externalSpanId` only), so recorded outputs are fetched lazily per mocked
1570
1572
  * span instead of all up front. Omit it (default eager) for `mock: "all"`.
1573
+ * Pass `includeRootOutput: false` when the root was already fetched.
1571
1574
  */
1572
1575
  async getSpanTree(externalSpanId, options) {
1573
- const query = options?.includeOutputs === false ? "?includeOutputs=false" : "";
1576
+ const searchParams = new URLSearchParams();
1577
+ if (options?.includeOutputs === false) {
1578
+ searchParams.set("includeOutputs", "false");
1579
+ }
1580
+ if (options?.includeRootOutput === false) {
1581
+ searchParams.set("includeRootOutput", "false");
1582
+ }
1583
+ const encodedQuery = searchParams.toString();
1584
+ const query = encodedQuery ? `?${encodedQuery}` : "";
1574
1585
  const url = `${this.serviceUrl}/api/sdk/replay/spanTree/${externalSpanId}${query}`;
1575
1586
  const controller = new AbortController();
1576
1587
  const timeoutId = setTimeout(() => controller.abort(), 3e4);
@@ -2049,8 +2060,11 @@ var init_codeChange = __esm({
2049
2060
  var replay_exports = {};
2050
2061
  __export(replay_exports, {
2051
2062
  BITFAB_PROGRESS_PREFIX: () => BITFAB_PROGRESS_PREFIX,
2063
+ DbBranchReplayError: () => DbBranchReplayError,
2064
+ ReplayError: () => ReplayError,
2052
2065
  replay: () => replay,
2053
- reportReplayProgress: () => reportReplayProgress
2066
+ reportReplayProgress: () => reportReplayProgress,
2067
+ serializeReplayResult: () => serializeReplayResult
2054
2068
  });
2055
2069
  function dbBranchEnabled(dbBranch) {
2056
2070
  return dbBranch !== void 0 && dbBranch !== false;
@@ -2073,11 +2087,59 @@ function reportReplayProgress(progress) {
2073
2087
  return;
2074
2088
  }
2075
2089
  try {
2076
- stderr.write(`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress)}
2077
- `);
2090
+ stderr.write(
2091
+ `${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress, replayJsonReplacer)}
2092
+ `
2093
+ );
2078
2094
  } catch {
2079
2095
  }
2080
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
+ }
2081
2143
  function deserializeInputs(spanData) {
2082
2144
  const inputMeta = spanData.input_meta;
2083
2145
  const rawInput = spanData.input;
@@ -2135,25 +2197,41 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2135
2197
  let originalOutput;
2136
2198
  let result;
2137
2199
  let error = null;
2200
+ let traceError = null;
2201
+ let replayError = null;
2138
2202
  const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
2139
2203
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2140
2204
  try {
2141
2205
  if (includeDbBranchLease && !lease && !leaseError) {
2142
- const resolved = await httpClient.resolveDbBranchLease(
2143
- testRunId,
2144
- originalTraceId,
2145
- dbBranchSettings
2146
- );
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
+ }
2147
2221
  lease = resolved.lease ?? void 0;
2148
2222
  leaseError = resolved.leaseError ?? void 0;
2149
2223
  dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2150
2224
  }
2151
2225
  if (leaseError) {
2152
- throw new BitfabError(
2153
- `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
2154
2230
  );
2155
2231
  }
2156
- const span = await httpClient.getExternalSpan(originalSpanId);
2232
+ const span = await httpClient.getExternalSpan(originalSpanId, {
2233
+ view: "replay"
2234
+ });
2157
2235
  const spanData = span.rawData?.span_data ?? {};
2158
2236
  inputs = deserializeInputs(spanData);
2159
2237
  originalOutput = deserializeOutput(spanData);
@@ -2173,7 +2251,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2173
2251
  if (needTree) {
2174
2252
  try {
2175
2253
  const treeResponse = await httpClient.getSpanTree(originalSpanId, {
2176
- includeOutputs
2254
+ includeOutputs,
2255
+ includeRootOutput: false
2177
2256
  });
2178
2257
  if (treeResponse.root) {
2179
2258
  mockTree = buildMockTree(treeResponse.root);
@@ -2195,7 +2274,7 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2195
2274
  const fetchSpanOutput = mockTree && !includeOutputs ? (externalSpanId) => {
2196
2275
  let pending = outputCache.get(externalSpanId);
2197
2276
  if (!pending) {
2198
- pending = httpClient.getExternalSpan(externalSpanId).then(
2277
+ pending = httpClient.getExternalSpan(externalSpanId, { view: "replay" }).then(
2199
2278
  (s) => deserializeOutput(
2200
2279
  s.rawData?.span_data ?? {}
2201
2280
  )
@@ -2204,25 +2283,31 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2204
2283
  }
2205
2284
  return pending;
2206
2285
  } : void 0;
2207
- const maybePromise = runWithReplayContext(
2208
- {
2209
- testRunId,
2210
- traceId: replayedTraceId,
2211
- inputSourceSpanId: span.id,
2212
- inputSourceTraceId: span.externalTraceId,
2213
- sourceBitfabTraceId: originalTraceId,
2214
- mockTree,
2215
- callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
2216
- mockStrategy,
2217
- mockOverrides: hasOverrides ? resolvedOverrides : void 0,
2218
- fetchSpanOutput,
2219
- dbBranchLease: lease
2220
- },
2221
- () => fn(...inputs)
2222
- );
2223
- 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
+ }
2224
2308
  } catch (e) {
2225
- error = e instanceof Error ? e.message : String(e);
2309
+ replayError = e;
2310
+ error = replayItemErrorMessage(e);
2226
2311
  } finally {
2227
2312
  if (lease) {
2228
2313
  try {
@@ -2251,6 +2336,8 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2251
2336
  result,
2252
2337
  originalOutput,
2253
2338
  error,
2339
+ traceError,
2340
+ replayError,
2254
2341
  durationMs: serverItem.durationMs ?? null,
2255
2342
  // Filled in by replay() from the complete-replay response once the
2256
2343
  // replay traces are persisted and their spans aggregated server-side.
@@ -2375,6 +2462,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2375
2462
  );
2376
2463
  const mockStrategy = options?.mock ?? "marked";
2377
2464
  const maxConcurrency = options?.maxConcurrency ?? 10;
2465
+ const fullTestRunUrl = `${serviceUrl}${testRunUrl}`;
2378
2466
  const resolvedOverrides = [
2379
2467
  ...normalizeMockOverrides(options?.mockOverride),
2380
2468
  ...registeredOverrides
@@ -2431,6 +2519,8 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2431
2519
  result: item.result,
2432
2520
  originalOutput: item.originalOutput,
2433
2521
  error: item.error,
2522
+ traceError: item.traceError,
2523
+ replayError: item.replayError,
2434
2524
  durationMs: item.durationMs,
2435
2525
  tokens: item.tokens,
2436
2526
  model: item.model,
@@ -2441,8 +2531,18 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2441
2531
  }
2442
2532
  } : void 0
2443
2533
  );
2444
- await waitForReplayPersistence(httpClient, testRunId, replayedTraceIds);
2445
- 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
+ );
2446
2546
  const serverTraceIds = completeResult.traceIds;
2447
2547
  const replayTokens = completeResult.tokens;
2448
2548
  if (serverTraceIds !== void 0) {
@@ -2465,9 +2565,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2465
2565
  }
2466
2566
  if (completedCount > 0 && missing.length === completedCount) {
2467
2567
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
2468
- throw new BitfabError(
2568
+ const cause = new BitfabError(
2469
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.`
2470
2570
  );
2571
+ throw new ReplayError(
2572
+ cause.message,
2573
+ resultItems,
2574
+ testRunId,
2575
+ fullTestRunUrl,
2576
+ cause
2577
+ );
2471
2578
  }
2472
2579
  if (missing.length > 0) {
2473
2580
  try {
@@ -2481,7 +2588,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2481
2588
  const result = {
2482
2589
  items: resultItems,
2483
2590
  testRunId,
2484
- testRunUrl: `${serviceUrl}${testRunUrl}`
2591
+ testRunUrl: fullTestRunUrl
2485
2592
  };
2486
2593
  await writeReplayResultFile(result);
2487
2594
  try {
@@ -2509,7 +2616,7 @@ async function writeReplayResultFile(result) {
2509
2616
  import("fs/promises")
2510
2617
  ]);
2511
2618
  await mkdir(dirname(resultPath), { recursive: true });
2512
- await writeFile(resultPath, `${JSON.stringify(result, null, 2)}
2619
+ await writeFile(resultPath, `${serializeReplayResult(result)}
2513
2620
  `);
2514
2621
  } catch (err) {
2515
2622
  try {
@@ -2520,7 +2627,7 @@ async function writeReplayResultFile(result) {
2520
2627
  }
2521
2628
  }
2522
2629
  }
2523
- var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX;
2630
+ var REPLAY_PERSISTENCE_TIMEOUT_MS, BITFAB_PROGRESS_PREFIX, ReplayError, DbBranchReplayError;
2524
2631
  var init_replay = __esm({
2525
2632
  "src/replay.ts"() {
2526
2633
  "use strict";
@@ -2535,6 +2642,25 @@ var init_replay = __esm({
2535
2642
  init_unrefTimer();
2536
2643
  REPLAY_PERSISTENCE_TIMEOUT_MS = 3e4;
2537
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
+ };
2538
2664
  }
2539
2665
  });
2540
2666
 
@@ -2552,7 +2678,9 @@ __export(node_exports, {
2552
2678
  BitfabOpenAITracingProcessor: () => BitfabOpenAITracingProcessor,
2553
2679
  BitfabVercelAiHandler: () => BitfabVercelAiHandler,
2554
2680
  DEFAULT_SERVICE_URL: () => DEFAULT_SERVICE_URL,
2681
+ DbBranchReplayError: () => DbBranchReplayError,
2555
2682
  HttpClient: () => HttpClient,
2683
+ ReplayError: () => ReplayError,
2556
2684
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
2557
2685
  __version__: () => __version__,
2558
2686
  finalizers: () => finalizers,
@@ -2560,7 +2688,8 @@ __export(node_exports, {
2560
2688
  getCurrentReplayBranch: () => getCurrentReplayBranch,
2561
2689
  getCurrentSpan: () => getCurrentSpan,
2562
2690
  getCurrentTrace: () => getCurrentTrace,
2563
- reportReplayProgress: () => reportReplayProgress
2691
+ reportReplayProgress: () => reportReplayProgress,
2692
+ serializeReplayResult: () => serializeReplayResult
2564
2693
  });
2565
2694
  module.exports = __toCommonJS(node_exports);
2566
2695
 
@@ -6152,7 +6281,9 @@ assertAsyncStorageRegistered();
6152
6281
  BitfabOpenAITracingProcessor,
6153
6282
  BitfabVercelAiHandler,
6154
6283
  DEFAULT_SERVICE_URL,
6284
+ DbBranchReplayError,
6155
6285
  HttpClient,
6286
+ ReplayError,
6156
6287
  SUPPORTED_PROVIDERS,
6157
6288
  __version__,
6158
6289
  finalizers,
@@ -6160,6 +6291,7 @@ assertAsyncStorageRegistered();
6160
6291
  getCurrentReplayBranch,
6161
6292
  getCurrentSpan,
6162
6293
  getCurrentTrace,
6163
- reportReplayProgress
6294
+ reportReplayProgress,
6295
+ serializeReplayResult
6164
6296
  });
6165
6297
  //# sourceMappingURL=node.cjs.map