bitfab 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
@@ -51,7 +51,7 @@ var __version__;
51
51
  var init_version_generated = __esm({
52
52
  "src/version.generated.ts"() {
53
53
  "use strict";
54
- __version__ = "0.36.9";
54
+ __version__ = "0.36.10";
55
55
  }
56
56
  });
57
57
 
@@ -1444,6 +1444,10 @@ var init_http = __esm({
1444
1444
  ...error instanceof BitfabError && error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {}
1445
1445
  });
1446
1446
  }
1447
+ const serverTraceIds = asPayloadRecord(response?.traceIds);
1448
+ if (serverTraceIds !== void 0) {
1449
+ this.recordServerTraceIds(serverTraceIds);
1450
+ }
1447
1451
  const partialSuccess = asPayloadRecord(response?.partialSuccess);
1448
1452
  const rejected = partialSuccess?.rejectedSpans;
1449
1453
  if (rejected !== void 0 && rejected !== "0" && rejected !== 0) {
@@ -1468,6 +1472,14 @@ var init_http = __esm({
1468
1472
  }
1469
1473
  }
1470
1474
  }
1475
+ /**
1476
+ * The server's assigned `traces.id` for a tracked trace if it has already
1477
+ * been read back off an ingest response, without stopping tracking. Lets a
1478
+ * replay surface the id mid-run for items whose spans already landed.
1479
+ */
1480
+ peekServerTraceId(traceId) {
1481
+ return this.traceDeliveries.get(traceId)?.serverTraceId;
1482
+ }
1471
1483
  /** Whether any tracked trace has had its closing carrier submitted. */
1472
1484
  hasClosedDeliveries(traceIds) {
1473
1485
  return traceIds.some((traceId) => this.traceDeliveries.get(traceId)?.closed);
@@ -1494,7 +1506,8 @@ var init_http = __esm({
1494
1506
  closed: delivery.closed,
1495
1507
  delivered: delivery.closingAcked && [...delivery.submittedSpanIds].every(
1496
1508
  (spanId) => delivery.ackedSpanIds.has(spanId)
1497
- )
1509
+ ),
1510
+ serverTraceId: delivery.serverTraceId
1498
1511
  };
1499
1512
  }
1500
1513
  return reports;
@@ -1523,6 +1536,23 @@ var init_http = __esm({
1523
1536
  * delivered ref is proof its row exists: the same fact the replay status
1524
1537
  * endpoint would report, already in hand.
1525
1538
  */
1539
+ /**
1540
+ * Record the server's assigned `traces.id` for each tracked source trace,
1541
+ * read back from the OTLP ingest response. Keyed by source trace id, the same
1542
+ * key the delivery ledger uses. Untracked ids are ignored.
1543
+ */
1544
+ recordServerTraceIds(map) {
1545
+ for (const [sourceTraceId, serverTraceId] of Object.entries(map)) {
1546
+ if (typeof serverTraceId !== "string") {
1547
+ continue;
1548
+ }
1549
+ const delivery = this.traceDeliveries.get(sourceTraceId);
1550
+ if (delivery === void 0) {
1551
+ continue;
1552
+ }
1553
+ delivery.serverTraceId = serverTraceId;
1554
+ }
1555
+ }
1526
1556
  recordDeliveredCarriers(refs) {
1527
1557
  for (const ref of refs) {
1528
1558
  const delivery = this.traceDeliveries.get(ref.traceId);
@@ -2660,13 +2690,17 @@ async function waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)
2660
2690
  }
2661
2691
  if (!httpClient.hasClosedDeliveries(replayedTraceIds)) {
2662
2692
  httpClient.takeTraceDeliveries(replayedTraceIds);
2663
- return;
2693
+ return {};
2664
2694
  }
2665
2695
  const flushed = await flushTraces(REPLAY_PERSISTENCE_TIMEOUT_MS);
2666
2696
  const deliveries = httpClient.takeTraceDeliveries(replayedTraceIds);
2667
2697
  const expectedSpanCounts = {};
2698
+ const readBackTraceIds = {};
2668
2699
  let allDelivered = true;
2669
2700
  for (const [traceId, delivery] of Object.entries(deliveries)) {
2701
+ if (delivery.serverTraceId !== void 0) {
2702
+ readBackTraceIds[traceId] = delivery.serverTraceId;
2703
+ }
2670
2704
  if (!delivery.closed) {
2671
2705
  continue;
2672
2706
  }
@@ -2674,7 +2708,7 @@ async function waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)
2674
2708
  allDelivered = allDelivered && delivery.delivered;
2675
2709
  }
2676
2710
  if (allDelivered) {
2677
- return;
2711
+ return readBackTraceIds;
2678
2712
  }
2679
2713
  const deadline = Date.now() + REPLAY_PERSISTENCE_TIMEOUT_MS;
2680
2714
  let missing = Object.keys(expectedSpanCounts).length;
@@ -2688,7 +2722,7 @@ async function waitForReplayPersistence(httpClient, testRunId, replayedTraceIds)
2688
2722
  (traceId) => ready[traceId] === void 0
2689
2723
  ).length;
2690
2724
  if (missing === 0) {
2691
- return;
2725
+ return readBackTraceIds;
2692
2726
  }
2693
2727
  if (Date.now() >= deadline) {
2694
2728
  break;
@@ -2716,7 +2750,7 @@ async function mapWithConcurrency2(tasks, maxConcurrency, onSettled, onStarted)
2716
2750
  onStarted?.(index);
2717
2751
  const result = await tasks[index]();
2718
2752
  results[index] = result;
2719
- onSettled?.(result, index);
2753
+ await onSettled?.(result, index);
2720
2754
  }
2721
2755
  }
2722
2756
  const workers = Array.from(
@@ -2806,10 +2840,36 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2806
2840
  let started = 0;
2807
2841
  let succeeded = 0;
2808
2842
  let errored = 0;
2843
+ let flushInFlight = null;
2844
+ let flushPending = false;
2845
+ const flushFinishedItemTrace = () => {
2846
+ flushPending = true;
2847
+ if (!flushInFlight) {
2848
+ flushInFlight = (async () => {
2849
+ try {
2850
+ while (flushPending) {
2851
+ flushPending = false;
2852
+ await httpClient.settleDeferredWork(REPLAY_PERSISTENCE_TIMEOUT_MS);
2853
+ await flushTraces(REPLAY_PERSISTENCE_TIMEOUT_MS);
2854
+ }
2855
+ } finally {
2856
+ flushInFlight = null;
2857
+ }
2858
+ })();
2859
+ }
2860
+ return flushInFlight;
2861
+ };
2809
2862
  const resultItems = await mapWithConcurrency2(
2810
2863
  tasks,
2811
2864
  maxConcurrency,
2812
- (item) => {
2865
+ async (item, index) => {
2866
+ let serverTraceId = null;
2867
+ try {
2868
+ await flushFinishedItemTrace();
2869
+ serverTraceId = httpClient.peekServerTraceId(replayedTraceIds[index]) ?? null;
2870
+ } catch {
2871
+ }
2872
+ item.traceId = serverTraceId;
2813
2873
  completed += 1;
2814
2874
  if (item.error === null) {
2815
2875
  succeeded += 1;
@@ -2824,11 +2884,12 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2824
2884
  succeeded,
2825
2885
  errored,
2826
2886
  item: {
2827
- // The server replay trace id isn't known until completeReplay runs
2828
- // (below), so it can't be reported mid-run and we never emit the
2829
- // client-side placeholder. originalTraceId (the historical trace)
2830
- // is known now and is what a UI keys on to identify what settled.
2831
- traceId: null,
2887
+ // The server's assigned traces.id, read back off the ingest
2888
+ // response and surfaced as this item finishes. Null only if the
2889
+ // per-item flush could not confirm delivery in time; the end-of-run
2890
+ // barrier then fills the returned ReplayItem. The client-side
2891
+ // placeholder is never surfaced.
2892
+ traceId: serverTraceId,
2832
2893
  originalTraceId: item.originalTraceId ?? null,
2833
2894
  originalSpanId: item.originalSpanId ?? null,
2834
2895
  // Deprecated aliases for originalTraceId/originalSpanId.
@@ -2874,12 +2935,19 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2874
2935
  }
2875
2936
  } : void 0
2876
2937
  );
2877
- await preserveReplayFailure(
2938
+ const deliveredTraceIds = await preserveReplayFailure(
2878
2939
  () => waitForReplayPersistence(httpClient, testRunId, replayedTraceIds),
2879
2940
  resultItems,
2880
2941
  testRunId,
2881
2942
  fullTestRunUrl
2882
2943
  );
2944
+ for (let index = 0; index < resultItems.length; index += 1) {
2945
+ const localId = replayedTraceIds[index];
2946
+ const readBack = localId ? deliveredTraceIds[localId] : void 0;
2947
+ if (readBack !== void 0) {
2948
+ resultItems[index].traceId = readBack;
2949
+ }
2950
+ }
2883
2951
  const completeResult = await preserveReplayFailure(
2884
2952
  () => httpClient.completeReplay(testRunId),
2885
2953
  resultItems,
@@ -2895,7 +2963,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2895
2963
  const item = resultItems[index];
2896
2964
  const localId = replayedTraceIds[index];
2897
2965
  const mapped = localId ? serverTraceIds[localId] : void 0;
2898
- item.traceId = mapped ?? null;
2966
+ item.traceId = item.traceId ?? mapped ?? null;
2899
2967
  if (item.error === null) {
2900
2968
  completedCount += 1;
2901
2969
  if (mapped === void 0) {