bitfab 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
@@ -396,23 +396,27 @@ function buildMockTree(rootNode) {
396
396
  }
397
397
  return { spans };
398
398
  }
399
- async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, environment, adaptInputs) {
399
+ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy, resolvedOverrides, replayedTraceId, environment, adaptInputs) {
400
400
  const lease = environment ? serverItem.dbBranchLease : void 0;
401
401
  let inputs = [];
402
402
  let originalOutput;
403
403
  let result;
404
404
  let error = null;
405
- const replayedTraceId = randomUuid();
406
405
  const pendingPersistence = [];
406
+ const originalTraceId = serverItem.originalTraceId ?? serverItem.sourceTraceId;
407
+ const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
407
408
  try {
408
- const span = await httpClient.getExternalSpan(serverItem.externalSpanId);
409
+ const span = await httpClient.getExternalSpan(originalSpanId);
409
410
  const spanData = span.rawData?.span_data ?? {};
410
411
  inputs = deserializeInputs(spanData);
411
412
  originalOutput = deserializeOutput(spanData);
412
413
  if (adaptInputs) {
413
414
  inputs = adaptInputs(inputs, {
414
- traceId: serverItem.traceId,
415
- sourceSpanId: serverItem.externalSpanId
415
+ originalTraceId,
416
+ originalSpanId,
417
+ // Deprecated aliases for originalTraceId/originalSpanId.
418
+ sourceTraceId: originalTraceId,
419
+ sourceSpanId: originalSpanId
416
420
  });
417
421
  }
418
422
  const hasOverrides = resolvedOverrides.length > 0;
@@ -421,15 +425,14 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
421
425
  let mockTree;
422
426
  if (needTree) {
423
427
  try {
424
- const treeResponse = await httpClient.getSpanTree(
425
- serverItem.externalSpanId,
426
- { includeOutputs }
427
- );
428
+ const treeResponse = await httpClient.getSpanTree(originalSpanId, {
429
+ includeOutputs
430
+ });
428
431
  if (treeResponse.root) {
429
432
  mockTree = buildMockTree(treeResponse.root);
430
433
  } else if (mockStrategy === "all" || hasOverrides) {
431
434
  throw new BitfabError(
432
- `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for source span ${serverItem.externalSpanId}.`
435
+ `Replay mock strategy "${mockStrategy}"${hasOverrides ? " with overrides" : ""} requires a span tree root for original span ${originalSpanId}.`
433
436
  );
434
437
  } else {
435
438
  mockTree = void 0;
@@ -460,7 +463,7 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
460
463
  traceId: replayedTraceId,
461
464
  inputSourceSpanId: span.id,
462
465
  inputSourceTraceId: span.externalTraceId,
463
- sourceBitfabTraceId: serverItem.traceId,
466
+ sourceBitfabTraceId: originalTraceId,
464
467
  mockTree,
465
468
  callCounters: mockTree ? /* @__PURE__ */ new Map() : void 0,
466
469
  mockStrategy,
@@ -490,7 +493,15 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
490
493
  }
491
494
  }
492
495
  return {
493
- traceId: replayedTraceId,
496
+ // Written in by replay() from the complete-replay response once the server
497
+ // has minted this replay trace's row. Null until then: the client-side
498
+ // correlation id (replayedTraceId) is never surfaced as the item's traceId.
499
+ traceId: null,
500
+ originalTraceId,
501
+ originalSpanId,
502
+ // Deprecated aliases for originalTraceId/originalSpanId.
503
+ sourceTraceId: originalTraceId,
504
+ sourceSpanId: originalSpanId,
494
505
  input: inputs,
495
506
  result,
496
507
  originalOutput,
@@ -566,14 +577,16 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
566
577
  ...normalizeMockOverrides(options?.mockOverride),
567
578
  ...registeredOverrides
568
579
  ];
580
+ const replayedTraceIds = serverItems.map(() => randomUuid());
569
581
  const tasks = serverItems.map(
570
- (serverItem) => () => processItem(
582
+ (serverItem, index) => () => processItem(
571
583
  httpClient,
572
584
  serverItem,
573
585
  fn,
574
586
  testRunId,
575
587
  mockStrategy,
576
588
  resolvedOverrides,
589
+ replayedTraceIds[index],
577
590
  options?.environment,
578
591
  options?.adaptInputs
579
592
  )
@@ -600,11 +613,17 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
600
613
  succeeded,
601
614
  errored,
602
615
  item: {
603
- // Source (historical) trace id, so a UI can identify the trace
604
- // that just settled. The item's own traceId is the new replay
605
- // trace and is assigned later (below), so use the server item.
606
- traceId: serverItems[index]?.traceId ?? null,
607
- replayTraceId: item.traceId,
616
+ // The server replay trace id isn't known until completeReplay
617
+ // runs (below), so it can't be reported mid-run and we never
618
+ // emit the client-side placeholder. originalTraceId (the
619
+ // historical trace) is known now and is what a UI keys on to
620
+ // identify what just settled.
621
+ traceId: null,
622
+ originalTraceId: item.originalTraceId ?? null,
623
+ originalSpanId: item.originalSpanId ?? null,
624
+ // Deprecated aliases for originalTraceId/originalSpanId.
625
+ sourceTraceId: item.originalTraceId ?? null,
626
+ sourceSpanId: item.originalSpanId ?? null,
608
627
  input: item.input,
609
628
  result: item.result,
610
629
  originalOutput: item.originalOutput,
@@ -622,56 +641,58 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
622
641
  const completeResult = await httpClient.completeReplay(testRunId);
623
642
  const serverTraceIds = completeResult.traceIds;
624
643
  const replayTokens = completeResult.tokens;
625
- if (serverTraceIds === void 0) {
626
- try {
627
- console.warn(
628
- "Bitfab: server did not return replay trace IDs; item.traceId will be null (server upgrade required for verdict persistence)"
629
- );
630
- } catch {
631
- }
632
- for (const item of resultItems) {
633
- item.traceId = null;
634
- }
635
- } else {
644
+ if (serverTraceIds !== void 0) {
636
645
  const missing = [];
637
646
  let completedCount = 0;
638
- for (const item of resultItems) {
639
- if (item.traceId) {
640
- const mapped = serverTraceIds[item.traceId];
641
- if (item.error === null) {
642
- completedCount += 1;
643
- if (mapped === void 0) {
644
- missing.push(item.traceId);
645
- }
646
- }
647
- if (mapped !== void 0) {
648
- item.tokens = replayTokens?.[mapped] ?? null;
647
+ for (let index = 0; index < resultItems.length; index += 1) {
648
+ const item = resultItems[index];
649
+ const localId = replayedTraceIds[index];
650
+ const mapped = localId ? serverTraceIds[localId] : void 0;
651
+ item.traceId = mapped ?? null;
652
+ if (item.error === null) {
653
+ completedCount += 1;
654
+ if (mapped === void 0) {
655
+ missing.push(localId ?? item.originalTraceId);
649
656
  }
650
- item.traceId = mapped ?? null;
657
+ }
658
+ if (mapped !== void 0) {
659
+ item.tokens = replayTokens?.[mapped] ?? null;
651
660
  }
652
661
  }
653
- if (missing.length > 0) {
662
+ if (completedCount > 0 && missing.length === completedCount) {
654
663
  const serverCount = completeResult.traceCount !== void 0 ? ` The server persisted ${completeResult.traceCount} trace(s) for this run.` : "";
655
- if (missing.length === completedCount) {
656
- throw new BitfabError(
657
- `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.`
658
- );
659
- }
664
+ throw new BitfabError(
665
+ `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.`
666
+ );
667
+ }
668
+ if (missing.length > 0) {
660
669
  try {
661
670
  console.error(
662
- `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(", ")}`
671
+ `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.`
663
672
  );
664
673
  } catch {
665
674
  }
666
675
  }
667
676
  }
668
- const replayResult = {
677
+ const result = {
669
678
  items: resultItems,
670
679
  testRunId,
671
680
  testRunUrl: `${serviceUrl}${testRunUrl}`
672
681
  };
673
- await writeReplayResultFile(replayResult);
674
- return replayResult;
682
+ await writeReplayResultFile(result);
683
+ try {
684
+ options?.onProgress?.({
685
+ type: "complete",
686
+ testRunId,
687
+ completed: total,
688
+ total,
689
+ succeeded,
690
+ errored,
691
+ result
692
+ });
693
+ } catch {
694
+ }
695
+ return result;
675
696
  }
676
697
  async function writeReplayResultFile(result) {
677
698
  const resultPath = typeof process !== "undefined" ? process.env?.BITFAB_REPLAY_RESULT_PATH : void 0;
@@ -734,7 +755,7 @@ __export(index_exports, {
734
755
  module.exports = __toCommonJS(index_exports);
735
756
 
736
757
  // src/version.generated.ts
737
- var __version__ = "0.29.0";
758
+ var __version__ = "0.29.1";
738
759
 
739
760
  // src/constants.ts
740
761
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -4164,7 +4185,7 @@ var Bitfab = class {
4164
4185
  dbSnapshotUsage: {
4165
4186
  neonBranchId: replayCtx.dbBranchLease.neonBranchId,
4166
4187
  snapshotTimestamp: replayCtx.dbBranchLease.snapshotTimestamp,
4167
- sourceTraceId: replayCtx.sourceBitfabTraceId,
4188
+ originalTraceId: replayCtx.sourceBitfabTraceId,
4168
4189
  accessed: replayCtx.dbSnapshotAccessed === true
4169
4190
  }
4170
4191
  }
@@ -4468,8 +4489,11 @@ var Bitfab = class {
4468
4489
  ...params.dbSnapshotUsage.snapshotTimestamp && {
4469
4490
  snapshot_timestamp: params.dbSnapshotUsage.snapshotTimestamp
4470
4491
  },
4471
- ...params.dbSnapshotUsage.sourceTraceId && {
4472
- source_trace_id: params.dbSnapshotUsage.sourceTraceId
4492
+ ...params.dbSnapshotUsage.originalTraceId && {
4493
+ original_trace_id: params.dbSnapshotUsage.originalTraceId,
4494
+ // Deprecated wire alias, kept so this SDK still reports usage
4495
+ // against servers that predate the rename.
4496
+ source_trace_id: params.dbSnapshotUsage.originalTraceId
4473
4497
  },
4474
4498
  accessed: params.dbSnapshotUsage.accessed
4475
4499
  };