@bitfab/sdk 0.29.0 → 0.29.1

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
@@ -387,23 +387,27 @@ function buildMockTree(rootNode) {
387
387
  }
388
388
  return { spans };
389
389
  }
390
- async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, environment, adaptInputs) {
390
+ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, replayedTraceId, environment, adaptInputs) {
391
391
  const lease = environment ? serverItem.dbBranchLease : void 0;
392
392
  let inputs = [];
393
393
  let originalOutput;
394
394
  let result;
395
395
  let error = null;
396
- const replayedTraceId = randomUuid();
397
396
  const pendingPersistence = [];
397
+ const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
398
+ const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
398
399
  try {
399
- const span = await httpClient.getExternalSpan(serverItem.externalSpanId);
400
+ const span = await httpClient.getExternalSpan(originalSpanId);
400
401
  const spanData = span.rawData?.span_data ?? {};
401
402
  inputs = deserializeInputs(spanData);
402
403
  originalOutput = deserializeOutput(spanData);
403
404
  if (adaptInputs) {
404
405
  inputs = adaptInputs(inputs, {
405
- traceId: serverItem.traceId,
406
- sourceSpanId: serverItem.externalSpanId
406
+ originalTraceId,
407
+ originalSpanId,
408
+ // Deprecated aliases for originalTraceId/originalSpanId.
409
+ sourceTraceId: originalTraceId,
410
+ sourceSpanId: originalSpanId
407
411
  });
408
412
  }
409
413
  const hasOverrides = resolvedOverrides.length > 0;
@@ -412,15 +416,14 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
412
416
  let mockTree;
413
417
  if (needTree) {
414
418
  try {
415
- const treeResponse = await httpClient.getSpanTree(
416
- serverItem.externalSpanId,
417
- { includeOutputs }
418
- );
419
+ const treeResponse = await httpClient.getSpanTree(originalSpanId, {
420
+ includeOutputs
421
+ });
419
422
  if (treeResponse.root) {
420
423
  mockTree = buildMockTree(treeResponse.root);
421
424
  } else if (mockStrategy === "all" || hasOverrides) {
422
425
  throw new BitfabError(
423
- `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for source span ${serverItem.externalSpanId}.`
426
+ `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for original span ${originalSpanId}.`
424
427
  );
425
428
  } else {
426
429
  mockTree = void 0;
@@ -451,7 +454,7 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
451
454
  traceId: replayedTraceId,
452
455
  inputSourceSpanId: span.id,
453
456
  inputSourceTraceId: span.externalTraceId,
454
- sourceBitfabTraceId: serverItem.traceId,
457
+ sourceBitfabTraceId: originalTraceId,
455
458
  mockTree,
456
459
  callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
457
460
  mockStrategy,
@@ -481,7 +484,15 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
481
484
  }
482
485
  }
483
486
  return {
484
- traceId: replayedTraceId,
487
+ // Written in by replay() from the complete-replay response once the server
488
+ // has minted this replay trace's row. Null until then: the client-side
489
+ // correlation id (replayedTraceId) is never surfaced as the item's traceId.
490
+ traceId: null,
491
+ originalTraceId,
492
+ originalSpanId,
493
+ // Deprecated aliases for originalTraceId/originalSpanId.
494
+ sourceTraceId: originalTraceId,
495
+ sourceSpanId: originalSpanId,
485
496
  input: inputs,
486
497
  result,
487
498
  originalOutput,
@@ -557,14 +568,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
557
568
  ...normalizeMockOverrides(options?.mockOverride),
558
569
  ...registeredOverrides
559
570
  ];
571
+ const replayedTraceIds = serverItems.map(() => randomUuid());
560
572
  const tasks = serverItems.map(
561
- (serverItem) => () => processItem(
573
+ (serverItem, index) => () => processItem(
562
574
  httpClient,
563
575
  serverItem,
564
576
  fn,
565
577
  testRunId,
566
578
  mockStrategy,
567
579
  resolvedOverrides,
580
+ replayedTraceIds[index],
568
581
  options?.environment,
569
582
  options?.adaptInputs
570
583
  )
@@ -591,11 +604,17 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
591
604
  succeeded,
592
605
  errored,
593
606
  item: {
594
- // Source (historical) trace id, so a UI can identify the trace
595
- // that just settled. The item's own traceId is the new replay
596
- // trace and is assigned later (below), so use the server item.
597
- traceId: serverItems[index]?.traceId ?? null,
598
- replayTraceId: item.traceId,
607
+ // The server replay trace id isn't known until completeReplay
608
+ // runs (below), so it can't be reported mid-run and we never
609
+ // emit the client-side placeholder. originalTraceId (the
610
+ // historical trace) is known now and is what a UI keys on to
611
+ // identify what just settled.
612
+ traceId: null,
613
+ originalTraceId: item.originalTraceId ?? null,
614
+ originalSpanId: item.originalSpanId ?? null,
615
+ // Deprecated aliases for originalTraceId/originalSpanId.
616
+ sourceTraceId: item.originalTraceId ?? null,
617
+ sourceSpanId: item.originalSpanId ?? null,
599
618
  input: item.input,
600
619
  result: item.result,
601
620
  originalOutput: item.originalOutput,
@@ -613,56 +632,58 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
613
632
  const completeResult = await httpClient.completeReplay(testRunId);
614
633
  const serverTraceIds = completeResult.traceIds;
615
634
  const replayTokens = completeResult.tokens;
616
- if (serverTraceIds === void 0) {
617
- try {
618
- console.warn(
619
- "Bitfab: server did not return replay trace IDs; item.traceId will be null (server upgrade required for verdict persistence)"
620
- );
621
- } catch {
622
- }
623
- for (const item of resultItems) {
624
- item.traceId = null;
625
- }
626
- } else {
635
+ if (serverTraceIds !== void 0) {
627
636
  const missing = [];
628
637
  let completedCount = 0;
629
- for (const item of resultItems) {
630
- if (item.traceId) {
631
- const mapped = serverTraceIds[item.traceId];
632
- if (item.error === null) {
633
- completedCount += 1;
634
- if (mapped === void 0) {
635
- missing.push(item.traceId);
636
- }
637
- }
638
- if (mapped !== void 0) {
639
- item.tokens = replayTokens?.[mapped] ?? null;
638
+ for (let index = 0; index < resultItems.length; index += 1) {
639
+ const item = resultItems[index];
640
+ const localId = replayedTraceIds[index];
641
+ const mapped = localId ? serverTraceIds[localId] : void 0;
642
+ item.traceId = mapped ?? null;
643
+ if (item.error === null) {
644
+ completedCount += 1;
645
+ if (mapped === void 0) {
646
+ missing.push(localId ?? item.originalTraceId);
640
647
  }
641
- item.traceId = mapped ?? null;
648
+ }
649
+ if (mapped !== void 0) {
650
+ item.tokens = replayTokens?.[mapped] ?? null;
642
651
  }
643
652
  }
644
- if (missing.length > 0) {
653
+ if (completedCount > 0 && missing.length === completedCount) {
645
654
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
646
- if (missing.length === completedCount) {
647
- throw new BitfabError(
648
- `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.`
649
- );
650
- }
655
+ throw new BitfabError(
656
+ `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.`
657
+ );
658
+ }
659
+ if (missing.length > 0) {
651
660
  try {
652
661
  console.error(
653
- `Bitfab: server has no persisted trace for ${missing.length} of ${completedCount} completed replay item(s) (testRunId ${testRunId}).${serverCount} Their traceId is null and verdicts cannot be persisted for them. Missing: ${missing.join(", ")}`
662
+ `Bitfab: server has no persisted trace for ${missing.length} of ${completedCount} completed replay item(s) (testRunId ${testRunId}). Their replay token usage is unavailable and they cannot be labeled.`
654
663
  );
655
664
  } catch {
656
665
  }
657
666
  }
658
667
  }
659
- const replayResult = {
668
+ const result = {
660
669
  items: resultItems,
661
670
  testRunId,
662
671
  testRunUrl: `${serviceUrl}${testRunUrl}`
663
672
  };
664
- await writeReplayResultFile(replayResult);
665
- return replayResult;
673
+ await writeReplayResultFile(result);
674
+ try {
675
+ options?.onProgress?.({
676
+ type: "complete",
677
+ testRunId,
678
+ completed: total,
679
+ total,
680
+ succeeded,
681
+ errored,
682
+ result
683
+ });
684
+ } catch {
685
+ }
686
+ return result;
666
687
  }
667
688
  async function writeReplayResultFile(result) {
668
689
  const resultPath = typeof process !== "undefined" ? process.env?.BITFAB_REPLAY_RESULT_PATH : void 0;
@@ -725,7 +746,7 @@ __export(index_exports, {
725
746
  module.exports = __toCommonJS(index_exports);
726
747
 
727
748
  // src/version.generated.ts
728
- var __version__ = "0.29.0";
749
+ var __version__ = "0.29.1";
729
750
 
730
751
  // src/constants.ts
731
752
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -4155,7 +4176,7 @@ var Bitfab = class {
4155
4176
  dbSnapshotUsage: {
4156
4177
  neonBranchId: replayCtx.dbBranchLease.neonBranchId,
4157
4178
  snapshotTimestamp: replayCtx.dbBranchLease.snapshotTimestamp,
4158
- sourceTraceId: replayCtx.sourceBitfabTraceId,
4179
+ originalTraceId: replayCtx.sourceBitfabTraceId,
4159
4180
  accessed: replayCtx.dbSnapshotAccessed === true
4160
4181
  }
4161
4182
  }
@@ -4459,8 +4480,11 @@ var Bitfab = class {
4459
4480
  ...params.dbSnapshotUsage.snapshotTimestamp && {
4460
4481
  snapshot_timestamp: params.dbSnapshotUsage.snapshotTimestamp
4461
4482
  },
4462
- ...params.dbSnapshotUsage.sourceTraceId && {
4463
- source_trace_id: params.dbSnapshotUsage.sourceTraceId
4483
+ ...params.dbSnapshotUsage.originalTraceId && {
4484
+ original_trace_id: params.dbSnapshotUsage.originalTraceId,
4485
+ // Deprecated wire alias, kept so this SDK still reports usage
4486
+ // against servers that predate the rename.
4487
+ source_trace_id: params.dbSnapshotUsage.originalTraceId
4464
4488
  },
4465
4489
  accessed: params.dbSnapshotUsage.accessed
4466
4490
  };