@bitfab/sdk 0.36.9 → 0.36.10

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.
@@ -16,7 +16,7 @@ import {
16
16
  toJsonSafe,
17
17
  toJsonSafeReport,
18
18
  warnOnce
19
- } from "./chunk-MBKY42QC.js";
19
+ } from "./chunk-AAMRJGZJ.js";
20
20
 
21
21
  // src/processorPayload.ts
22
22
  var SERIALIZATION_DEGRADED_STEP = "serialization_degraded";
@@ -3371,7 +3371,7 @@ var Bitfab = class {
3371
3371
  `Function is wrapped with trace function key '${wrappedKey}' but replay was called with '${traceFunctionKey}'. Pass matching keys, or pass the unwrapped function to replay it under the explicit key.`
3372
3372
  );
3373
3373
  }
3374
- const { replay: doReplay } = await import("./replay-MH5QFXET.js");
3374
+ const { replay: doReplay } = await import("./replay-WKWBBIGE.js");
3375
3375
  return doReplay(
3376
3376
  this.httpClient,
3377
3377
  this.serviceUrl,
@@ -3609,4 +3609,4 @@ export {
3609
3609
  BitfabFunction,
3610
3610
  finalizers
3611
3611
  };
3612
- //# sourceMappingURL=chunk-TJAFKZ4X.js.map
3612
+ //# sourceMappingURL=chunk-RSM2TLKG.js.map
package/dist/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.36.9";
45
+ __version__ = "0.36.10";
46
46
  }
47
47
  });
48
48
 
@@ -1435,6 +1435,10 @@ var init_http = __esm({
1435
1435
  ...error instanceof BitfabError && error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {}
1436
1436
  });
1437
1437
  }
1438
+ const serverTraceIds = asPayloadRecord(response?.traceIds);
1439
+ if (serverTraceIds !== void 0) {
1440
+ this.recordServerTraceIds(serverTraceIds);
1441
+ }
1438
1442
  const partialSuccess = asPayloadRecord(response?.partialSuccess);
1439
1443
  const rejected = partialSuccess?.rejectedSpans;
1440
1444
  if (rejected !== void 0 && rejected !== "0" && rejected !== 0) {
@@ -1459,6 +1463,14 @@ var init_http = __esm({
1459
1463
  }
1460
1464
  }
1461
1465
  }
1466
+ /**
1467
+ * The server's assigned `traces.id` for a tracked trace if it has already
1468
+ * been read back off an ingest response, without stopping tracking. Lets a
1469
+ * replay surface the id mid-run for items whose spans already landed.
1470
+ */
1471
+ peekServerTraceId(traceId) {
1472
+ return this.traceDeliveries.get(traceId)?.serverTraceId;
1473
+ }
1462
1474
  /** Whether any tracked trace has had its closing carrier submitted. */
1463
1475
  hasClosedDeliveries(traceIds) {
1464
1476
  return traceIds.some((traceId) => this.traceDeliveries.get(traceId)?.closed);
@@ -1485,7 +1497,8 @@ var init_http = __esm({
1485
1497
  closed: delivery.closed,
1486
1498
  delivered: delivery.closingAcked && [...delivery.submittedSpanIds].every(
1487
1499
  (spanId) => delivery.ackedSpanIds.has(spanId)
1488
- )
1500
+ ),
1501
+ serverTraceId: delivery.serverTraceId
1489
1502
  };
1490
1503
  }
1491
1504
  return reports;
@@ -1514,6 +1527,23 @@ var init_http = __esm({
1514
1527
  * delivered ref is proof its row exists: the same fact the replay status
1515
1528
  * endpoint would report, already in hand.
1516
1529
  */
1530
+ /**
1531
+ * Record the server's assigned `traces.id` for each tracked source trace,
1532
+ * read back from the OTLP ingest response. Keyed by source trace id, the same
1533
+ * key the delivery ledger uses. Untracked ids are ignored.
1534
+ */
1535
+ recordServerTraceIds(map) {
1536
+ for (const [sourceTraceId, serverTraceId] of Object.entries(map)) {
1537
+ if (typeof serverTraceId !== "string") {
1538
+ continue;
1539
+ }
1540
+ const delivery = this.traceDeliveries.get(sourceTraceId);
1541
+ if (delivery === void 0) {
1542
+ continue;
1543
+ }
1544
+ delivery.serverTraceId = serverTraceId;
1545
+ }
1546
+ }
1517
1547
  recordDeliveredCarriers(refs) {
1518
1548
  for (const ref of refs) {
1519
1549
  const delivery = this.traceDeliveries.get(ref.traceId);
@@ -2651,13 +2681,17 @@ async function waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)
2651
2681
  }
2652
2682
  if (!httpClient.hasClosedDeliveries(replayedTraceIds)) {
2653
2683
  httpClient.takeTraceDeliveries(replayedTraceIds);
2654
- return;
2684
+ return {};
2655
2685
  }
2656
2686
  const flushed = await flushTraces(REPLAY_PERSISTENCE_TIMEOUT_MS);
2657
2687
  const deliveries = httpClient.takeTraceDeliveries(replayedTraceIds);
2658
2688
  const expectedSpanCounts = {};
2689
+ const readBackTraceIds = {};
2659
2690
  let allDelivered = true;
2660
2691
  for (const [traceId, delivery] of Object.entries(deliveries)) {
2692
+ if (delivery.serverTraceId !== void 0) {
2693
+ readBackTraceIds[traceId] = delivery.serverTraceId;
2694
+ }
2661
2695
  if (!delivery.closed) {
2662
2696
  continue;
2663
2697
  }
@@ -2665,7 +2699,7 @@ async function waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)
2665
2699
  allDelivered = allDelivered && delivery.delivered;
2666
2700
  }
2667
2701
  if (allDelivered) {
2668
- return;
2702
+ return readBackTraceIds;
2669
2703
  }
2670
2704
  const deadline = Date.now() + REPLAY_PERSISTENCE_TIMEOUT_MS;
2671
2705
  let missing = Object.keys(expectedSpanCounts).length;
@@ -2679,7 +2713,7 @@ async function waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)
2679
2713
  (traceId) => ready[traceId] === void 0
2680
2714
  ).length;
2681
2715
  if (missing === 0) {
2682
- return;
2716
+ return readBackTraceIds;
2683
2717
  }
2684
2718
  if (Date.now() >= deadline) {
2685
2719
  break;
@@ -2707,7 +2741,7 @@ async function mapWithConcurrency2(tasks, maxConcurrency, onSettled, onStarted)
2707
2741
  onStarted?.(index);
2708
2742
  const result = await tasks[index]();
2709
2743
  results[index] = result;
2710
- onSettled?.(result, index);
2744
+ await onSettled?.(result, index);
2711
2745
  }
2712
2746
  }
2713
2747
  const workers = Array.from(
@@ -2797,10 +2831,36 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2797
2831
  let started = 0;
2798
2832
  let succeeded = 0;
2799
2833
  let errored = 0;
2834
+ let flushInFlight = null;
2835
+ let flushPending = false;
2836
+ const flushFinishedItemTrace = () => {
2837
+ flushPending = true;
2838
+ if (!flushInFlight) {
2839
+ flushInFlight = (async () => {
2840
+ try {
2841
+ while (flushPending) {
2842
+ flushPending = false;
2843
+ await httpClient.settleDeferredWork(REPLAY_PERSISTENCE_TIMEOUT_MS);
2844
+ await flushTraces(REPLAY_PERSISTENCE_TIMEOUT_MS);
2845
+ }
2846
+ } finally {
2847
+ flushInFlight = null;
2848
+ }
2849
+ })();
2850
+ }
2851
+ return flushInFlight;
2852
+ };
2800
2853
  const resultItems = await mapWithConcurrency2(
2801
2854
  tasks,
2802
2855
  maxConcurrency,
2803
- (item) => {
2856
+ async (item, index) => {
2857
+ let serverTraceId = null;
2858
+ try {
2859
+ await flushFinishedItemTrace();
2860
+ serverTraceId = httpClient.peekServerTraceId(replayedTraceIds[index]) ?? null;
2861
+ } catch {
2862
+ }
2863
+ item.traceId = serverTraceId;
2804
2864
  completed += 1;
2805
2865
  if (item.error === null) {
2806
2866
  succeeded += 1;
@@ -2815,11 +2875,12 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2815
2875
  succeeded,
2816
2876
  errored,
2817
2877
  item: {
2818
- // The server replay trace id isn't known until completeReplay runs
2819
- // (below), so it can't be reported mid-run and we never emit the
2820
- // client-side placeholder. originalTraceId (the historical trace)
2821
- // is known now and is what a UI keys on to identify what settled.
2822
- traceId: null,
2878
+ // The server's assigned traces.id, read back off the ingest
2879
+ // response and surfaced as this item finishes. Null only if the
2880
+ // per-item flush could not confirm delivery in time; the end-of-run
2881
+ // barrier then fills the returned ReplayItem. The client-side
2882
+ // placeholder is never surfaced.
2883
+ traceId: serverTraceId,
2823
2884
  originalTraceId: item.originalTraceId ?? null,
2824
2885
  originalSpanId: item.originalSpanId ?? null,
2825
2886
  // Deprecated aliases for originalTraceId/originalSpanId.
@@ -2865,12 +2926,19 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2865
2926
  }
2866
2927
  } : void 0
2867
2928
  );
2868
- await preserveReplayFailure(
2929
+ const deliveredTraceIds = await preserveReplayFailure(
2869
2930
  () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
2870
2931
  resultItems,
2871
2932
  testRunId,
2872
2933
  fullTestRunUrl
2873
2934
  );
2935
+ for (let index = 0; index < resultItems.length; index += 1) {
2936
+ const localId = replayedTraceIds[index];
2937
+ const readBack = localId ? deliveredTraceIds[localId] : void 0;
2938
+ if (readBack !== void 0) {
2939
+ resultItems[index].traceId = readBack;
2940
+ }
2941
+ }
2874
2942
  const completeResult = await preserveReplayFailure(
2875
2943
  () => httpClient.completeReplay(testRunId),
2876
2944
  resultItems,
@@ -2886,7 +2954,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2886
2954
  const item = resultItems[index];
2887
2955
  const localId = replayedTraceIds[index];
2888
2956
  const mapped = localId ? serverTraceIds[localId] : void 0;
2889
- item.traceId = mapped ?? null;
2957
+ item.traceId = item.traceId ?? mapped ?? null;
2890
2958
  if (item.error === null) {
2891
2959
  completedCount += 1;
2892
2960
  if (mapped === void 0) {