@bitfab/sdk 0.52.0 → 0.52.2

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
@@ -536,7 +536,7 @@ declare class HttpClient {
536
536
  * {@link HttpClient.sendExternalSpan}; replay confirms persistence with the
537
537
  * server-authoritative barrier in `replay.ts`, not by awaiting this call.
538
538
  */
539
- sendExternalTrace(payload: Record<string, unknown>): void;
539
+ sendExternalTrace(rawPayload: Record<string, unknown>): void;
540
540
  /**
541
541
  * Partial update of an existing trace identified by its Bitfab trace ID.
542
542
  * Used by the detached `client.getTrace(id)` handle.
@@ -1656,12 +1656,16 @@ interface ReplayOptions {
1656
1656
  * Maximum number of traces to replay (1-5,000, default 5). Ignored when
1657
1657
  * `traceIds` is passed (with a warning), or when `datasetId` / `datasetIds`
1658
1658
  * is passed, because either source already determines how many traces replay.
1659
+ * To replay part of a dataset selection, name the members to run in
1660
+ * `traceIds` rather than bounding it here.
1659
1661
  */
1660
1662
  limit?: number;
1661
1663
  attempts?: number;
1662
1664
  /**
1663
- * Optional list of specific trace IDs to replay (max 100). Mutually exclusive
1664
- * with `datasetId` and `datasetIds`.
1665
+ * Optional list of specific trace IDs to replay (max 100). Passed alongside
1666
+ * `datasetId` or `datasetIds` it pins which members of that selection replay,
1667
+ * and the server rejects any ID none of those datasets contains. On its own
1668
+ * it selects by ID with no dataset attribution.
1665
1669
  */
1666
1670
  traceIds?: string[];
1667
1671
  /** Optional display name for the resulting experiment/test run. */
@@ -1719,8 +1723,9 @@ interface ReplayOptions {
1719
1723
  /** Group ID to associate this replay with an experiment group for live streaming in Studio. */
1720
1724
  experimentGroupId?: string;
1721
1725
  /**
1722
- * Dataset this replay runs against. Mutually exclusive with `traceIds` and
1723
- * with `datasetIds`. When set, the resulting experiment is
1726
+ * Dataset this replay runs against. Mutually exclusive with `datasetIds`.
1727
+ * Alone it replays the dataset's full membership, and with `traceIds` it
1728
+ * replays only those members. When set, the resulting experiment is
1724
1729
  * durably attributed to the dataset (stored on the test run), so it appears
1725
1730
  * under the dataset's experiments even if the trace lineage can't be
1726
1731
  * reconstructed. Validated server-side against the org.
@@ -3288,7 +3293,7 @@ declare class BitfabFunction {
3288
3293
  /**
3289
3294
  * SDK version from package.json (injected at build time)
3290
3295
  */
3291
- declare const __version__ = "0.52.0";
3296
+ declare const __version__ = "0.52.2";
3292
3297
 
3293
3298
  /**
3294
3299
  * Constants for the Bitfab SDK.
package/dist/index.d.ts CHANGED
@@ -536,7 +536,7 @@ declare class HttpClient {
536
536
  * {@link HttpClient.sendExternalSpan}; replay confirms persistence with the
537
537
  * server-authoritative barrier in `replay.ts`, not by awaiting this call.
538
538
  */
539
- sendExternalTrace(payload: Record<string, unknown>): void;
539
+ sendExternalTrace(rawPayload: Record<string, unknown>): void;
540
540
  /**
541
541
  * Partial update of an existing trace identified by its Bitfab trace ID.
542
542
  * Used by the detached `client.getTrace(id)` handle.
@@ -1656,12 +1656,16 @@ interface ReplayOptions {
1656
1656
  * Maximum number of traces to replay (1-5,000, default 5). Ignored when
1657
1657
  * `traceIds` is passed (with a warning), or when `datasetId` / `datasetIds`
1658
1658
  * is passed, because either source already determines how many traces replay.
1659
+ * To replay part of a dataset selection, name the members to run in
1660
+ * `traceIds` rather than bounding it here.
1659
1661
  */
1660
1662
  limit?: number;
1661
1663
  attempts?: number;
1662
1664
  /**
1663
- * Optional list of specific trace IDs to replay (max 100). Mutually exclusive
1664
- * with `datasetId` and `datasetIds`.
1665
+ * Optional list of specific trace IDs to replay (max 100). Passed alongside
1666
+ * `datasetId` or `datasetIds` it pins which members of that selection replay,
1667
+ * and the server rejects any ID none of those datasets contains. On its own
1668
+ * it selects by ID with no dataset attribution.
1665
1669
  */
1666
1670
  traceIds?: string[];
1667
1671
  /** Optional display name for the resulting experiment/test run. */
@@ -1719,8 +1723,9 @@ interface ReplayOptions {
1719
1723
  /** Group ID to associate this replay with an experiment group for live streaming in Studio. */
1720
1724
  experimentGroupId?: string;
1721
1725
  /**
1722
- * Dataset this replay runs against. Mutually exclusive with `traceIds` and
1723
- * with `datasetIds`. When set, the resulting experiment is
1726
+ * Dataset this replay runs against. Mutually exclusive with `datasetIds`.
1727
+ * Alone it replays the dataset's full membership, and with `traceIds` it
1728
+ * replays only those members. When set, the resulting experiment is
1724
1729
  * durably attributed to the dataset (stored on the test run), so it appears
1725
1730
  * under the dataset's experiments even if the trace lineage can't be
1726
1731
  * reconstructed. Validated server-side against the org.
@@ -3288,7 +3293,7 @@ declare class BitfabFunction {
3288
3293
  /**
3289
3294
  * SDK version from package.json (injected at build time)
3290
3295
  */
3291
- declare const __version__ = "0.52.0";
3296
+ declare const __version__ = "0.52.2";
3292
3297
 
3293
3298
  /**
3294
3299
  * Constants for the Bitfab SDK.
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  getCurrentSpan,
19
19
  getCurrentTrace,
20
20
  seedFromRegistry
21
- } from "./chunk-VEDTNQQE.js";
21
+ } from "./chunk-XLSKI7UA.js";
22
22
  import "./chunk-ZUD7OFYB.js";
23
23
  import {
24
24
  BITFAB_PROGRESS_PREFIX,
@@ -27,7 +27,7 @@ import {
27
27
  ReplayError,
28
28
  reportReplayProgress,
29
29
  serializeReplayResult
30
- } from "./chunk-SJ65MW4K.js";
30
+ } from "./chunk-XXKM4EL2.js";
31
31
  import {
32
32
  BitfabError,
33
33
  DEFAULT_SERVICE_URL,
@@ -35,7 +35,7 @@ import {
35
35
  MixedTracingError,
36
36
  __version__,
37
37
  flushTraces
38
- } from "./chunk-4EOEBN3M.js";
38
+ } from "./chunk-QWAWERYM.js";
39
39
  import "./chunk-H6LZRFMN.js";
40
40
  export {
41
41
  BITFAB_PROGRESS_PREFIX,
package/dist/node.cjs CHANGED
@@ -88,7 +88,7 @@ var __version__, __packageName__;
88
88
  var init_version_generated = __esm({
89
89
  "src/version.generated.ts"() {
90
90
  "use strict";
91
- __version__ = "0.52.0";
91
+ __version__ = "0.52.2";
92
92
  __packageName__ = "@bitfab/sdk";
93
93
  }
94
94
  });
@@ -541,6 +541,69 @@ var init_serializePayload = __esm({
541
541
  }
542
542
  });
543
543
 
544
+ // src/traceMetadata.ts
545
+ function recordCallerTraceMetadata(traceId, metadata) {
546
+ if (typeof traceId !== "string" || traceId === "") {
547
+ return;
548
+ }
549
+ if (typeof metadata !== "object" || metadata === null) {
550
+ return;
551
+ }
552
+ if (Object.keys(metadata).length === 0) {
553
+ return;
554
+ }
555
+ callerMetadata.set(traceId, { ...callerMetadata.get(traceId), ...metadata });
556
+ }
557
+ function callerTraceMetadata(traceId) {
558
+ const recorded = callerMetadata.get(traceId);
559
+ return recorded ? { ...recorded } : void 0;
560
+ }
561
+ function forgetTraceMetadata(traceId) {
562
+ callerMetadata.delete(traceId);
563
+ derivedMetadata.delete(traceId);
564
+ }
565
+ function mergeCallerMetadataIntoTracePayload(payload) {
566
+ const externalTrace = payload.externalTrace;
567
+ if (typeof externalTrace !== "object" || externalTrace === null) {
568
+ return payload;
569
+ }
570
+ const external = externalTrace;
571
+ const traceId = typeof payload.id === "string" && payload.id !== "" ? payload.id : external.id;
572
+ if (typeof traceId !== "string" || traceId === "") {
573
+ return payload;
574
+ }
575
+ const caller = callerMetadata.get(traceId);
576
+ if (!caller) {
577
+ return payload;
578
+ }
579
+ const derived = derivedMetadata.get(traceId) ?? {};
580
+ const exported = external.metadata;
581
+ if (typeof exported === "object" && exported !== null) {
582
+ Object.assign(derived, exported);
583
+ }
584
+ derivedMetadata.set(traceId, derived);
585
+ const shadowed = Object.keys(derived).filter((key) => key in caller && caller[key] !== derived[key]).sort();
586
+ if (shadowed.length > 0) {
587
+ warnOnce(
588
+ `trace-metadata-shadowed:${shadowed.join(",")}`,
589
+ `trace metadata key(s) ${shadowed.join(", ")} were set both by the caller and by an integration's own trace export; the caller's value is the one kept on the trace.`
590
+ );
591
+ }
592
+ return {
593
+ ...payload,
594
+ externalTrace: { ...external, metadata: { ...derived, ...caller } }
595
+ };
596
+ }
597
+ var callerMetadata, derivedMetadata;
598
+ var init_traceMetadata = __esm({
599
+ "src/traceMetadata.ts"() {
600
+ "use strict";
601
+ init_warnOnce();
602
+ callerMetadata = /* @__PURE__ */ new Map();
603
+ derivedMetadata = /* @__PURE__ */ new Map();
604
+ }
605
+ });
606
+
544
607
  // src/transportTypes.ts
545
608
  var DeliveryError;
546
609
  var init_transportTypes = __esm({
@@ -1359,6 +1422,7 @@ var init_http = __esm({
1359
1422
  init_errors();
1360
1423
  init_replayContext();
1361
1424
  init_serializePayload();
1425
+ init_traceMetadata();
1362
1426
  init_transport();
1363
1427
  init_transportTypes();
1364
1428
  init_unrefTimer();
@@ -1822,7 +1886,8 @@ var init_http = __esm({
1822
1886
  * {@link HttpClient.sendExternalSpan}; replay confirms persistence with the
1823
1887
  * server-authoritative barrier in `replay.ts`, not by awaiting this call.
1824
1888
  */
1825
- sendExternalTrace(payload) {
1889
+ sendExternalTrace(rawPayload) {
1890
+ const payload = mergeCallerMetadataIntoTracePayload(rawPayload);
1826
1891
  this.getTraceTransport()?.submit(
1827
1892
  "external_trace",
1828
1893
  {
@@ -2935,11 +3000,6 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
2935
3000
  }
2936
3001
  }
2937
3002
  const datasetIds = resolveDatasetIds(options);
2938
- if (options?.traceIds !== void 0 && datasetIds !== void 0) {
2939
- throw new BitfabError(
2940
- "traceIds and datasetIds select different replay sources and cannot be used together."
2941
- );
2942
- }
2943
3003
  if (options?.limit !== void 0 && options?.traceIds !== void 0) {
2944
3004
  try {
2945
3005
  console.warn(
@@ -5714,6 +5774,7 @@ function runWithSeedContext(ctx, fn) {
5714
5774
 
5715
5775
  // src/client.ts
5716
5776
  init_serialize();
5777
+ init_traceMetadata();
5717
5778
 
5718
5779
  // src/tracing.ts
5719
5780
  init_constants();
@@ -6394,8 +6455,7 @@ function getCurrentTrace() {
6394
6455
  if (typeof metadata !== "object" || metadata === null) {
6395
6456
  return;
6396
6457
  }
6397
- const traceState = getOrCreateTraceState();
6398
- traceState.metadata = { ...traceState.metadata, ...metadata };
6458
+ recordCallerTraceMetadata(traceId, metadata);
6399
6459
  } catch {
6400
6460
  }
6401
6461
  },
@@ -7388,7 +7448,7 @@ var Bitfab = class {
7388
7448
  endedAt,
7389
7449
  sessionId: traceState?.sessionId,
7390
7450
  name: traceState?.name,
7391
- metadata: traceState?.metadata,
7451
+ metadata: callerTraceMetadata(traceId),
7392
7452
  contexts: traceState?.contexts ?? [],
7393
7453
  testRunId: traceState?.testRunId,
7394
7454
  inputSourceTraceId: traceState?.inputSourceTraceId,
@@ -7412,6 +7472,7 @@ var Bitfab = class {
7412
7472
  }
7413
7473
  });
7414
7474
  activeTraceStates.delete(traceId);
7475
+ forgetTraceMetadata(traceId);
7415
7476
  }
7416
7477
  } catch {
7417
7478
  }
@@ -7604,6 +7665,7 @@ var Bitfab = class {
7604
7665
  } catch (setupError) {
7605
7666
  if (registeredTraceId) {
7606
7667
  activeTraceStates.delete(registeredTraceId);
7668
+ forgetTraceMetadata(registeredTraceId);
7607
7669
  }
7608
7670
  if (setupError instanceof MixedTracingError) {
7609
7671
  throw setupError;
@@ -7964,14 +8026,16 @@ var Bitfab = class {
7964
8026
  }
7965
8027
  const traceId = randomUuid();
7966
8028
  const startedAt = nowIsoTimestamp();
8029
+ if (options.metadata !== void 0) {
8030
+ recordCallerTraceMetadata(traceId, options.metadata);
8031
+ }
7967
8032
  activeTraceStates.set(traceId, {
7968
8033
  traceId,
7969
8034
  startedAt,
7970
8035
  contexts: [],
7971
8036
  ingestionType: "seeded",
7972
8037
  ...options.sessionId !== void 0 && { sessionId: options.sessionId },
7973
- ...options.name !== void 0 && { name: options.name },
7974
- ...options.metadata !== void 0 && { metadata: options.metadata }
8038
+ ...options.name !== void 0 && { name: options.name }
7975
8039
  });
7976
8040
  try {
7977
8041
  this.sendWrapperSpan({
@@ -7994,12 +8058,13 @@ var Bitfab = class {
7994
8058
  endedAt: startedAt,
7995
8059
  sessionId: options.sessionId,
7996
8060
  name: options.name,
7997
- metadata: options.metadata,
8061
+ metadata: callerTraceMetadata(traceId),
7998
8062
  contexts: [],
7999
8063
  ingestionType: "seeded"
8000
8064
  });
8001
8065
  } finally {
8002
8066
  activeTraceStates.delete(traceId);
8067
+ forgetTraceMetadata(traceId);
8003
8068
  }
8004
8069
  return traceId;
8005
8070
  }
@@ -8024,14 +8089,16 @@ var Bitfab = class {
8024
8089
  }
8025
8090
  await seedContextReady;
8026
8091
  const traceId = randomUuid();
8092
+ if (options?.metadata !== void 0) {
8093
+ recordCallerTraceMetadata(traceId, options.metadata);
8094
+ }
8027
8095
  activeTraceStates.set(traceId, {
8028
8096
  traceId,
8029
8097
  startedAt: nowIsoTimestamp(),
8030
8098
  contexts: [],
8031
8099
  ingestionType: "seeded",
8032
8100
  ...options?.sessionId !== void 0 && { sessionId: options.sessionId },
8033
- ...options?.name !== void 0 && { name: options.name },
8034
- ...options?.metadata !== void 0 && { metadata: options.metadata }
8101
+ ...options?.name !== void 0 && { name: options.name }
8035
8102
  });
8036
8103
  const args = options?.args ?? [];
8037
8104
  let unrecorded = true;
@@ -8043,6 +8110,7 @@ var Bitfab = class {
8043
8110
  await flushTraces2(3e4);
8044
8111
  } finally {
8045
8112
  unrecorded = activeTraceStates.delete(traceId);
8113
+ forgetTraceMetadata(traceId);
8046
8114
  }
8047
8115
  }
8048
8116
  if (unrecorded) {