bitfab 0.26.1 → 0.27.0

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
@@ -73,35 +73,6 @@ var init_warnOnce = __esm({
73
73
  }
74
74
  });
75
75
 
76
- // src/randomUuid.ts
77
- function randomUuid() {
78
- const globalCrypto = globalThis.crypto;
79
- if (typeof globalCrypto?.randomUUID === "function") {
80
- try {
81
- return globalCrypto.randomUUID();
82
- } catch {
83
- }
84
- }
85
- warnOnce(
86
- "crypto-unavailable",
87
- "global crypto.randomUUID is unavailable; using a non-cryptographic fallback for trace/span ids. Tracing works normally (ids are correlation-only, not security-sensitive)."
88
- );
89
- return fallbackUuidV4();
90
- }
91
- function fallbackUuidV4() {
92
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
93
- const rand = Math.random() * 16 | 0;
94
- const value = char === "x" ? rand : rand & 3 | 8;
95
- return value.toString(16);
96
- });
97
- }
98
- var init_randomUuid = __esm({
99
- "src/randomUuid.ts"() {
100
- "use strict";
101
- init_warnOnce();
102
- }
103
- });
104
-
105
76
  // src/serialize.ts
106
77
  function describeValue(value) {
107
78
  try {
@@ -157,7 +128,11 @@ function deserializeValue(serialized) {
157
128
  });
158
129
  }
159
130
  function toJsonSafe(value) {
160
- const safe = toJsonSafeInner(value, 0, /* @__PURE__ */ new WeakSet());
131
+ return toJsonSafeReport(value).safe;
132
+ }
133
+ function toJsonSafeReport(value) {
134
+ const dropped = [];
135
+ const safe = toJsonSafeInner(value, 0, /* @__PURE__ */ new WeakSet(), dropped);
161
136
  try {
162
137
  const size = JSON.stringify(safe)?.length ?? 0;
163
138
  if (size > MAX_FRAMEWORK_SERIALIZED_BYTES) {
@@ -165,13 +140,16 @@ function toJsonSafe(value) {
165
140
  "toJsonSafe:too_large",
166
141
  `a framework payload exceeded ${MAX_FRAMEWORK_SERIALIZED_BYTES} bytes and was replaced with a placeholder so the span still ships. The captured state for this span is incomplete.`
167
142
  );
168
- return `<unserializable: too_large_${size}_bytes>`;
143
+ return {
144
+ safe: `<unserializable: too_large_${size}_bytes>`,
145
+ dropped: [...dropped, `too_large_${size}_bytes`]
146
+ };
169
147
  }
170
148
  } catch {
171
149
  }
172
- return safe;
150
+ return { safe, dropped };
173
151
  }
174
- function toJsonSafeInner(value, depth, seen) {
152
+ function toJsonSafeInner(value, depth, seen, dropped) {
175
153
  if (value === null || value === void 0) {
176
154
  return value;
177
155
  }
@@ -180,30 +158,40 @@ function toJsonSafeInner(value, depth, seen) {
180
158
  }
181
159
  const className = value?.constructor?.name ?? typeof value;
182
160
  if (depth > MAX_SAFE_DEPTH) {
161
+ dropped.push(className);
183
162
  return `<${className}>`;
184
163
  }
185
164
  if (typeof value !== "object") {
165
+ if (typeof value === "function" || typeof value === "symbol") {
166
+ dropped.push(className);
167
+ }
186
168
  try {
187
169
  return String(value);
188
170
  } catch {
171
+ dropped.push(className);
189
172
  return `<${className}>`;
190
173
  }
191
174
  }
192
175
  if (seen.has(value)) {
176
+ dropped.push(className);
193
177
  return `<cycle ${className}>`;
194
178
  }
195
179
  seen.add(value);
196
180
  let result;
197
181
  if (Array.isArray(value)) {
198
- result = value.map((item) => toJsonSafeInner(item, depth + 1, seen));
182
+ result = value.map(
183
+ (item) => toJsonSafeInner(item, depth + 1, seen, dropped)
184
+ );
199
185
  } else if (typeof value.toJSON === "function") {
200
186
  try {
201
187
  result = toJsonSafeInner(
202
188
  value.toJSON(),
203
189
  depth + 1,
204
- seen
190
+ seen,
191
+ dropped
205
192
  );
206
193
  } catch {
194
+ dropped.push(className);
207
195
  result = `<${className}>`;
208
196
  }
209
197
  } else {
@@ -211,11 +199,12 @@ function toJsonSafeInner(value, depth, seen) {
211
199
  const obj = {};
212
200
  for (const [k, v] of Object.entries(value)) {
213
201
  if (!k.startsWith("_")) {
214
- obj[k] = toJsonSafeInner(v, depth + 1, seen);
202
+ obj[k] = toJsonSafeInner(v, depth + 1, seen, dropped);
215
203
  }
216
204
  }
217
205
  result = obj;
218
206
  } catch {
207
+ dropped.push(className);
219
208
  result = `<${className}>`;
220
209
  }
221
210
  }
@@ -234,6 +223,35 @@ var init_serialize = __esm({
234
223
  }
235
224
  });
236
225
 
226
+ // src/randomUuid.ts
227
+ function randomUuid() {
228
+ const globalCrypto = globalThis.crypto;
229
+ if (typeof globalCrypto?.randomUUID === "function") {
230
+ try {
231
+ return globalCrypto.randomUUID();
232
+ } catch {
233
+ }
234
+ }
235
+ warnOnce(
236
+ "crypto-unavailable",
237
+ "global crypto.randomUUID is unavailable; using a non-cryptographic fallback for trace/span ids. Tracing works normally (ids are correlation-only, not security-sensitive)."
238
+ );
239
+ return fallbackUuidV4();
240
+ }
241
+ function fallbackUuidV4() {
242
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
243
+ const rand = Math.random() * 16 | 0;
244
+ const value = char === "x" ? rand : rand & 3 | 8;
245
+ return value.toString(16);
246
+ });
247
+ }
248
+ var init_randomUuid = __esm({
249
+ "src/randomUuid.ts"() {
250
+ "use strict";
251
+ init_warnOnce();
252
+ }
253
+ });
254
+
237
255
  // src/asyncStorage.ts
238
256
  function registerAsyncLocalStorageClass(cls) {
239
257
  if (!AsyncLocalStorageClass) {
@@ -298,8 +316,21 @@ var init_replayContext = __esm({
298
316
  // src/replay.ts
299
317
  var replay_exports = {};
300
318
  __export(replay_exports, {
301
- replay: () => replay
319
+ BITFAB_PROGRESS_PREFIX: () => BITFAB_PROGRESS_PREFIX,
320
+ replay: () => replay,
321
+ reportReplayProgress: () => reportReplayProgress
302
322
  });
323
+ function reportReplayProgress(progress) {
324
+ const stderr = typeof process !== "undefined" ? process.stderr : void 0;
325
+ if (!stderr) {
326
+ return;
327
+ }
328
+ try {
329
+ stderr.write(`${BITFAB_PROGRESS_PREFIX}${JSON.stringify(progress)}
330
+ `);
331
+ } catch {
332
+ }
333
+ }
303
334
  function deserializeInputs(spanData) {
304
335
  const inputMeta = spanData.input_meta;
305
336
  const rawInput = spanData.input;
@@ -497,7 +528,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
497
528
  const resultItems = await mapWithConcurrency(
498
529
  tasks,
499
530
  maxConcurrency,
500
- options?.onProgress ? (item) => {
531
+ options?.onProgress ? (item, index) => {
501
532
  completed += 1;
502
533
  if (item.error === null) {
503
534
  succeeded += 1;
@@ -505,7 +536,20 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
505
536
  errored += 1;
506
537
  }
507
538
  try {
508
- options?.onProgress?.({ completed, total, succeeded, errored });
539
+ options?.onProgress?.({
540
+ completed,
541
+ total,
542
+ succeeded,
543
+ errored,
544
+ item: {
545
+ // Source (historical) trace id, so a UI can identify the trace
546
+ // that just settled. The item's own traceId is the new replay
547
+ // trace and is assigned later (below), so use the server item.
548
+ traceId: serverItems[index]?.traceId ?? null,
549
+ error: item.error,
550
+ durationMs: item.durationMs
551
+ }
552
+ });
509
553
  } catch {
510
554
  }
511
555
  } : void 0
@@ -562,6 +606,7 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options) {
562
606
  testRunUrl: `${serviceUrl}${testRunUrl}`
563
607
  };
564
608
  }
609
+ var BITFAB_PROGRESS_PREFIX;
565
610
  var init_replay = __esm({
566
611
  "src/replay.ts"() {
567
612
  "use strict";
@@ -569,12 +614,14 @@ var init_replay = __esm({
569
614
  init_randomUuid();
570
615
  init_replayContext();
571
616
  init_serialize();
617
+ BITFAB_PROGRESS_PREFIX = "@@bitfab:progress ";
572
618
  }
573
619
  });
574
620
 
575
621
  // src/index.ts
576
622
  var index_exports = {};
577
623
  __export(index_exports, {
624
+ BITFAB_PROGRESS_PREFIX: () => BITFAB_PROGRESS_PREFIX,
578
625
  Bitfab: () => Bitfab,
579
626
  BitfabClaudeAgentHandler: () => BitfabClaudeAgentHandler,
580
627
  BitfabError: () => BitfabError,
@@ -591,12 +638,13 @@ __export(index_exports, {
591
638
  finalizers: () => finalizers,
592
639
  flushTraces: () => flushTraces,
593
640
  getCurrentSpan: () => getCurrentSpan,
594
- getCurrentTrace: () => getCurrentTrace
641
+ getCurrentTrace: () => getCurrentTrace,
642
+ reportReplayProgress: () => reportReplayProgress
595
643
  });
596
644
  module.exports = __toCommonJS(index_exports);
597
645
 
598
646
  // src/version.generated.ts
599
- var __version__ = "0.26.1";
647
+ var __version__ = "0.27.0";
600
648
 
601
649
  // src/constants.ts
602
650
  var DEFAULT_SERVICE_URL = "https://bitfab.ai";
@@ -1038,6 +1086,62 @@ var HttpClient = class {
1038
1086
  }
1039
1087
  };
1040
1088
 
1089
+ // src/processorPayload.ts
1090
+ init_serialize();
1091
+ init_warnOnce();
1092
+ var SERIALIZATION_DEGRADED_STEP = "serialization_degraded";
1093
+ function degradedError(dropped) {
1094
+ const names = [...new Set(dropped)].sort().join(", ");
1095
+ return {
1096
+ source: "sdk",
1097
+ step: SERIALIZATION_DEGRADED_STEP,
1098
+ error: `non-replayable: could not faithfully capture ${names}`
1099
+ };
1100
+ }
1101
+ var ENVELOPE_FIELDS = [
1102
+ "type",
1103
+ "source",
1104
+ "traceFunctionKey",
1105
+ "sourceTraceId",
1106
+ "completed"
1107
+ ];
1108
+ function rebuildEnvelope(payload, bodyKey, placeholder) {
1109
+ const rebuilt = {};
1110
+ for (const k of ENVELOPE_FIELDS) {
1111
+ if (k in payload) {
1112
+ rebuilt[k] = payload[k];
1113
+ }
1114
+ }
1115
+ rebuilt[bodyKey] = { serialized: placeholder };
1116
+ return rebuilt;
1117
+ }
1118
+ function finalizeSpanPayload(payload, extraDropped) {
1119
+ const { safe, dropped } = toJsonSafeReport(payload);
1120
+ const allDropped = [...extraDropped ?? [], ...dropped];
1121
+ const collapsed = safe === null || typeof safe !== "object" || Array.isArray(safe);
1122
+ const result = collapsed ? rebuildEnvelope(payload, "rawSpan", safe) : safe;
1123
+ if (allDropped.length > 0) {
1124
+ const existing = result.errors;
1125
+ const errors = Array.isArray(existing) ? existing : [];
1126
+ errors.push(degradedError(allDropped));
1127
+ result.errors = errors;
1128
+ }
1129
+ return result;
1130
+ }
1131
+ function finalizeTracePayload(payload) {
1132
+ const { safe, dropped } = toJsonSafeReport(payload);
1133
+ const collapsed = safe === null || typeof safe !== "object" || Array.isArray(safe);
1134
+ const result = collapsed ? rebuildEnvelope(payload, "externalTrace", safe) : safe;
1135
+ if (dropped.length > 0 || collapsed) {
1136
+ const names = dropped.length > 0 ? [...new Set(dropped)].sort().join(", ") : "trace";
1137
+ warnOnce(
1138
+ `finalizeTrace:${names.replace(/\d+/g, "N")}`,
1139
+ `a trace held non-serializable value(s) (${names}); they were captured as placeholders, so the trace may not be replayable.`
1140
+ );
1141
+ }
1142
+ return result;
1143
+ }
1144
+
1041
1145
  // src/claudeAgentSdk.ts
1042
1146
  init_randomUuid();
1043
1147
  init_serialize();
@@ -1167,6 +1271,7 @@ var BitfabClaudeAgentHandler = class {
1167
1271
  // ── span helpers ─────────────────────────────────────────────
1168
1272
  startSpan(spanId, name, spanType, inputData, parentId) {
1169
1273
  const traceId = this.ensureTrace();
1274
+ const { safe: safeInput, dropped: inputDropped } = toJsonSafeReport(inputData);
1170
1275
  const spanInfo = {
1171
1276
  spanId,
1172
1277
  traceId,
@@ -1174,9 +1279,12 @@ var BitfabClaudeAgentHandler = class {
1174
1279
  startedAt: nowIso(),
1175
1280
  name,
1176
1281
  type: spanType,
1177
- input: safeSerialize(inputData),
1282
+ input: safeInput,
1178
1283
  contexts: []
1179
1284
  };
1285
+ if (inputDropped.length > 0) {
1286
+ spanInfo.dropped = [...inputDropped];
1287
+ }
1180
1288
  this.runToSpan.set(spanId, spanInfo);
1181
1289
  return spanInfo;
1182
1290
  }
@@ -1187,7 +1295,11 @@ var BitfabClaudeAgentHandler = class {
1187
1295
  }
1188
1296
  this.runToSpan.delete(spanId);
1189
1297
  spanInfo.endedAt = nowIso();
1190
- spanInfo.output = safeSerialize(output);
1298
+ const { safe: safeOutput, dropped: outputDropped } = toJsonSafeReport(output);
1299
+ spanInfo.output = safeOutput;
1300
+ if (outputDropped.length > 0) {
1301
+ spanInfo.dropped = [...spanInfo.dropped ?? [], ...outputDropped];
1302
+ }
1191
1303
  if (error !== void 0) {
1192
1304
  spanInfo.error = error;
1193
1305
  }
@@ -1230,8 +1342,9 @@ var BitfabClaudeAgentHandler = class {
1230
1342
  sourceTraceId: spanInfo.traceId,
1231
1343
  rawSpan
1232
1344
  };
1345
+ const finalized = finalizeSpanPayload(payload, spanInfo.dropped);
1233
1346
  try {
1234
- this.httpClient.sendExternalSpan(payload);
1347
+ this.httpClient.sendExternalSpan(finalized);
1235
1348
  } catch {
1236
1349
  }
1237
1350
  }
@@ -1258,8 +1371,9 @@ var BitfabClaudeAgentHandler = class {
1258
1371
  externalTrace,
1259
1372
  completed
1260
1373
  };
1374
+ const finalized = finalizeTracePayload(traceData);
1261
1375
  try {
1262
- this.httpClient.sendExternalTrace(traceData);
1376
+ this.httpClient.sendExternalTrace(finalized);
1263
1377
  } catch {
1264
1378
  }
1265
1379
  }
@@ -1897,7 +2011,6 @@ var LANGGRAPH_METADATA_KEYS = [
1897
2011
  function nowIso2() {
1898
2012
  return (/* @__PURE__ */ new Date()).toISOString();
1899
2013
  }
1900
- var safeSerialize2 = toJsonSafe;
1901
2014
  function convertMessage(message) {
1902
2015
  if (typeof message !== "object" || message === null) {
1903
2016
  return { role: "unknown", content: String(message) };
@@ -2142,6 +2255,7 @@ var BitfabLangGraphCallbackHandler = class {
2142
2255
  }
2143
2256
  const lgMetadata = extractLangGraphMetadata(metadata);
2144
2257
  const contexts = Object.keys(lgMetadata).length > 0 ? [lgMetadata] : [];
2258
+ const { safe: safeInput, dropped: inputDropped } = toJsonSafeReport(inputData);
2145
2259
  const spanInfo = {
2146
2260
  spanId: runId,
2147
2261
  traceId: invocation.traceId,
@@ -2150,9 +2264,12 @@ var BitfabLangGraphCallbackHandler = class {
2150
2264
  startedAt: nowIso2(),
2151
2265
  name,
2152
2266
  type: spanType,
2153
- input: safeSerialize2(inputData),
2267
+ input: safeInput,
2154
2268
  contexts
2155
2269
  };
2270
+ if (inputDropped.length > 0) {
2271
+ spanInfo.dropped = [...inputDropped];
2272
+ }
2156
2273
  if (willHide) {
2157
2274
  spanInfo.hidden = true;
2158
2275
  }
@@ -2166,7 +2283,11 @@ var BitfabLangGraphCallbackHandler = class {
2166
2283
  }
2167
2284
  this.runToSpan.delete(runId);
2168
2285
  spanInfo.endedAt = nowIso2();
2169
- spanInfo.output = safeSerialize2(output);
2286
+ const { safe: safeOutput, dropped: outputDropped } = toJsonSafeReport(output);
2287
+ spanInfo.output = safeOutput;
2288
+ if (outputDropped.length > 0) {
2289
+ spanInfo.dropped = [...spanInfo.dropped ?? [], ...outputDropped];
2290
+ }
2170
2291
  if (error !== void 0) {
2171
2292
  spanInfo.error = error;
2172
2293
  }
@@ -2217,8 +2338,9 @@ var BitfabLangGraphCallbackHandler = class {
2217
2338
  sourceTraceId: spanInfo.traceId,
2218
2339
  rawSpan
2219
2340
  };
2341
+ const finalized = finalizeSpanPayload(payload, spanInfo.dropped);
2220
2342
  try {
2221
- this.httpClient.sendExternalSpan(payload);
2343
+ this.httpClient.sendExternalSpan(finalized);
2222
2344
  } catch {
2223
2345
  }
2224
2346
  }
@@ -2236,8 +2358,9 @@ var BitfabLangGraphCallbackHandler = class {
2236
2358
  },
2237
2359
  completed
2238
2360
  };
2361
+ const finalized = finalizeTracePayload(traceData);
2239
2362
  try {
2240
- this.httpClient.sendExternalTrace(traceData);
2363
+ this.httpClient.sendExternalTrace(finalized);
2241
2364
  } catch {
2242
2365
  }
2243
2366
  }
@@ -2752,7 +2875,7 @@ var BitfabOpenAITracingProcessor = class {
2752
2875
  if (errors.length > 0) {
2753
2876
  payload.errors = errors;
2754
2877
  }
2755
- return payload;
2878
+ return finalizeSpanPayload(payload);
2756
2879
  }
2757
2880
  /**
2758
2881
  * Send span to Bitfab API (fire-and-forget).
@@ -4262,8 +4385,12 @@ var finalizers = {
4262
4385
  aiSdk,
4263
4386
  readableStream
4264
4387
  };
4388
+
4389
+ // src/index.ts
4390
+ init_replay();
4265
4391
  // Annotate the CommonJS export names for ESM import in node:
4266
4392
  0 && (module.exports = {
4393
+ BITFAB_PROGRESS_PREFIX,
4267
4394
  Bitfab,
4268
4395
  BitfabClaudeAgentHandler,
4269
4396
  BitfabError,
@@ -4280,6 +4407,7 @@ var finalizers = {
4280
4407
  finalizers,
4281
4408
  flushTraces,
4282
4409
  getCurrentSpan,
4283
- getCurrentTrace
4410
+ getCurrentTrace,
4411
+ reportReplayProgress
4284
4412
  });
4285
4413
  //# sourceMappingURL=index.cjs.map