@bitfab/sdk 0.52.4 → 0.52.6

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.
Files changed (41) hide show
  1. package/README.md +2 -0
  2. package/dist/autoTrace.cjs +84 -34
  3. package/dist/autoTrace.cjs.map +1 -1
  4. package/dist/autoTrace.d.cts +19 -4
  5. package/dist/autoTrace.d.ts +19 -4
  6. package/dist/autoTrace.js +9 -3
  7. package/dist/{chunk-LQ32JQNZ.js → chunk-3TL4SATS.js} +371 -46
  8. package/dist/chunk-3TL4SATS.js.map +1 -0
  9. package/dist/{chunk-OF5GWNGU.js → chunk-7KIRLN47.js} +3 -2
  10. package/dist/{chunk-OF5GWNGU.js.map → chunk-7KIRLN47.js.map} +1 -1
  11. package/dist/{chunk-P2AZ7RUM.js → chunk-A6KY2IFA.js} +3 -3
  12. package/dist/chunk-A6KY2IFA.js.map +1 -0
  13. package/dist/{chunk-ZUD7OFYB.js → chunk-E5BLYL5X.js} +81 -34
  14. package/dist/chunk-E5BLYL5X.js.map +1 -0
  15. package/dist/{chunk-MM4A6UWJ.js → chunk-RC6XLP6M.js} +2 -2
  16. package/dist/{chunk-MM4A6UWJ.js.map → chunk-RC6XLP6M.js.map} +1 -1
  17. package/dist/{chunk-DP3QEGTV.js → chunk-WYC4QRK3.js} +110 -13
  18. package/dist/chunk-WYC4QRK3.js.map +1 -0
  19. package/dist/{http-WBNDRQIV.js → http-EL26HG5B.js} +2 -2
  20. package/dist/{http-UA54C2J2.js → http-YMBQ4XJO.js} +2 -2
  21. package/dist/index.cjs +561 -104
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +10 -2
  24. package/dist/index.d.ts +10 -2
  25. package/dist/index.js +4 -4
  26. package/dist/node.cjs +561 -104
  27. package/dist/node.cjs.map +1 -1
  28. package/dist/node.d.cts +1 -1
  29. package/dist/node.d.ts +1 -1
  30. package/dist/node.js +4 -4
  31. package/dist/{replay-RUONYMHD.js → replay-DXDWFFJK.js} +3 -3
  32. package/dist/replayCli.js +2 -2
  33. package/dist/seedCli.js +2 -2
  34. package/package.json +1 -1
  35. package/dist/chunk-DP3QEGTV.js.map +0 -1
  36. package/dist/chunk-LQ32JQNZ.js.map +0 -1
  37. package/dist/chunk-P2AZ7RUM.js.map +0 -1
  38. package/dist/chunk-ZUD7OFYB.js.map +0 -1
  39. /package/dist/{http-UA54C2J2.js.map → http-EL26HG5B.js.map} +0 -0
  40. /package/dist/{http-WBNDRQIV.js.map → http-YMBQ4XJO.js.map} +0 -0
  41. /package/dist/{replay-RUONYMHD.js.map → replay-DXDWFFJK.js.map} +0 -0
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.4";
91
+ __version__ = "0.52.6";
92
92
  __packageName__ = "@bitfab/sdk";
93
93
  }
94
94
  });
@@ -1128,7 +1128,7 @@ var init_otel = __esm({
1128
1128
  if (this.onDelivered === void 0) {
1129
1129
  return;
1130
1130
  }
1131
- const refs = spans.map((span) => span.ref).filter((ref) => ref !== void 0);
1131
+ const refs = spans.map((span) => span.ref).filter((ref2) => ref2 !== void 0);
1132
1132
  if (refs.length === 0) {
1133
1133
  return;
1134
1134
  }
@@ -1385,9 +1385,9 @@ function parseRetryAfterMs(header) {
1385
1385
  }
1386
1386
  return Math.max(0, at - Date.now());
1387
1387
  }
1388
- function carrierMeta(operation, payload, ref) {
1388
+ function carrierMeta(operation, payload, ref2) {
1389
1389
  return {
1390
- ref,
1390
+ ref: ref2,
1391
1391
  name: carrierName(operation, payload),
1392
1392
  startTime: payloadTimestamp(payload, "started_at"),
1393
1393
  endTime: payloadTimestamp(payload, "ended_at"),
@@ -1632,22 +1632,22 @@ var init_http = __esm({
1632
1632
  return reports;
1633
1633
  }
1634
1634
  /** Build a carrier's meta and record what it adds to its trace's expected set. */
1635
- recordedMeta(operation, payload, ref) {
1636
- this.recordSubmittedCarrier(ref);
1637
- return carrierMeta(operation, payload, ref);
1635
+ recordedMeta(operation, payload, ref2) {
1636
+ this.recordSubmittedCarrier(ref2);
1637
+ return carrierMeta(operation, payload, ref2);
1638
1638
  }
1639
- recordSubmittedCarrier(ref) {
1640
- if (ref === void 0) {
1639
+ recordSubmittedCarrier(ref2) {
1640
+ if (ref2 === void 0) {
1641
1641
  return;
1642
1642
  }
1643
- const delivery = this.traceDeliveries.get(ref.traceId);
1643
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1644
1644
  if (delivery === void 0) {
1645
1645
  return;
1646
1646
  }
1647
- if (ref.spanId === void 0) {
1647
+ if (ref2.spanId === void 0) {
1648
1648
  delivery.closed = true;
1649
1649
  } else {
1650
- delivery.submittedSpanIds.add(ref.spanId);
1650
+ delivery.submittedSpanIds.add(ref2.spanId);
1651
1651
  }
1652
1652
  }
1653
1653
  /**
@@ -1673,15 +1673,15 @@ var init_http = __esm({
1673
1673
  }
1674
1674
  }
1675
1675
  recordDeliveredCarriers(refs) {
1676
- for (const ref of refs) {
1677
- const delivery = this.traceDeliveries.get(ref.traceId);
1676
+ for (const ref2 of refs) {
1677
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1678
1678
  if (delivery === void 0) {
1679
1679
  continue;
1680
1680
  }
1681
- if (ref.spanId === void 0) {
1681
+ if (ref2.spanId === void 0) {
1682
1682
  delivery.closingAcked = true;
1683
1683
  } else {
1684
- delivery.ackedSpanIds.add(ref.spanId);
1684
+ delivery.ackedSpanIds.add(ref2.spanId);
1685
1685
  }
1686
1686
  }
1687
1687
  }
@@ -1711,9 +1711,9 @@ var init_http = __esm({
1711
1711
  */
1712
1712
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1713
1713
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1714
- const settled = await this.settleDeferredWork(timeoutMs);
1714
+ const settled2 = await this.settleDeferredWork(timeoutMs);
1715
1715
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1716
- return settled && flushed;
1716
+ return settled2 && flushed;
1717
1717
  }
1718
1718
  /**
1719
1719
  * Flush and permanently close this client's tracing transport. Idempotent:
@@ -1726,14 +1726,14 @@ var init_http = __esm({
1726
1726
  }
1727
1727
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1728
1728
  this.closing = (async () => {
1729
- const settled = await this.settleDeferredWork(
1729
+ const settled2 = await this.settleDeferredWork(
1730
1730
  Math.max(0, deadline - Date.now())
1731
1731
  );
1732
1732
  this.closed = true;
1733
1733
  const transport = this.traceTransport;
1734
1734
  this.traceTransport = void 0;
1735
1735
  const shutdownOk = await transport?.shutdown(Math.max(0, deadline - Date.now())) ?? true;
1736
- return settled && shutdownOk;
1736
+ return settled2 && shutdownOk;
1737
1737
  })();
1738
1738
  return this.closing;
1739
1739
  }
@@ -2344,6 +2344,112 @@ var init_randomUuid = __esm({
2344
2344
  }
2345
2345
  });
2346
2346
 
2347
+ // src/gitCommand.ts
2348
+ function isUnrefable(value) {
2349
+ return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
2350
+ }
2351
+ function unrefStream(stream) {
2352
+ if (isUnrefable(stream)) {
2353
+ stream.unref();
2354
+ }
2355
+ }
2356
+ function terminate(child) {
2357
+ if (child.pid && process.platform !== "win32") {
2358
+ try {
2359
+ process.kill(-child.pid, "SIGTERM");
2360
+ return;
2361
+ } catch {
2362
+ child.kill("SIGTERM");
2363
+ return;
2364
+ }
2365
+ }
2366
+ child.kill("SIGTERM");
2367
+ }
2368
+ async function gitRunner(options) {
2369
+ let spawn;
2370
+ try {
2371
+ ;
2372
+ ({ spawn } = await import("child_process"));
2373
+ } catch {
2374
+ return null;
2375
+ }
2376
+ return (dir, args) => new Promise((resolve) => {
2377
+ let child;
2378
+ try {
2379
+ child = spawn("git", args, {
2380
+ cwd: dir,
2381
+ detached: process.platform !== "win32",
2382
+ stdio: ["ignore", "pipe", "pipe"]
2383
+ });
2384
+ } catch {
2385
+ resolve(null);
2386
+ return;
2387
+ }
2388
+ const chunks = [];
2389
+ let size = 0;
2390
+ let overflow = false;
2391
+ let exitCode = null;
2392
+ let done = false;
2393
+ const timers = [];
2394
+ const schedule = (callback, ms) => {
2395
+ const timer = setTimeout(callback, ms);
2396
+ if (!options.keepProcessAlive) {
2397
+ timer.unref();
2398
+ }
2399
+ timers.push(timer);
2400
+ };
2401
+ const finish = () => {
2402
+ if (done) {
2403
+ return;
2404
+ }
2405
+ done = true;
2406
+ for (const timer of timers) {
2407
+ clearTimeout(timer);
2408
+ }
2409
+ child.stdout?.destroy();
2410
+ child.stderr?.destroy();
2411
+ resolve(
2412
+ exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null
2413
+ );
2414
+ };
2415
+ child.stdout?.on("data", (chunk) => {
2416
+ size += chunk.length;
2417
+ if (size > options.maxBuffer) {
2418
+ overflow = true;
2419
+ terminate(child);
2420
+ return;
2421
+ }
2422
+ chunks.push(chunk);
2423
+ });
2424
+ child.stderr?.resume();
2425
+ child.on("error", () => {
2426
+ exitCode = null;
2427
+ finish();
2428
+ });
2429
+ child.on("exit", (code) => {
2430
+ exitCode = code;
2431
+ schedule(finish, EXIT_GRACE_MS);
2432
+ });
2433
+ child.on("close", (code) => {
2434
+ exitCode = code ?? exitCode;
2435
+ finish();
2436
+ });
2437
+ schedule(() => terminate(child), options.timeoutMs);
2438
+ if (!options.keepProcessAlive) {
2439
+ child.unref();
2440
+ unrefStream(child.stdout);
2441
+ unrefStream(child.stderr);
2442
+ }
2443
+ });
2444
+ }
2445
+ var EXIT_GRACE_MS;
2446
+ var init_gitCommand = __esm({
2447
+ "src/gitCommand.ts"() {
2448
+ "use strict";
2449
+ EXIT_GRACE_MS = 500;
2450
+ }
2451
+ });
2452
+
2347
2453
  // src/mockOverride.ts
2348
2454
  function resolveMockValue(value, ctx) {
2349
2455
  return typeof value === "function" ? value(ctx) : value;
@@ -2400,37 +2506,33 @@ async function readCodeChangeFile() {
2400
2506
  }
2401
2507
  }
2402
2508
  async function captureCodeChangeFromGit(cwd, label) {
2403
- let execFile;
2404
2509
  let readFile;
2405
2510
  try {
2406
2511
  ;
2407
- ({ execFile } = await import("child_process"));
2408
2512
  ({ readFile } = await import("fs/promises"));
2409
2513
  } catch {
2410
2514
  return null;
2411
2515
  }
2412
- const git = (dir, args) => new Promise((resolve) => {
2413
- execFile(
2414
- "git",
2415
- args,
2416
- // 30s timeout so a hung git (e.g. a network-touching ref op) can't
2417
- // block the whole replay indefinitely.
2418
- { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 3e4 },
2419
- (err, stdout) => resolve(err ? null : stdout)
2420
- );
2516
+ const git = await gitRunner({
2517
+ timeoutMs: 3e4,
2518
+ maxBuffer: 64 * 1024 * 1024,
2519
+ keepProcessAlive: true
2421
2520
  });
2521
+ if (!git) {
2522
+ return null;
2523
+ }
2422
2524
  try {
2423
2525
  const root = (await git(cwd, ["rev-parse", "--show-toplevel"]))?.trim();
2424
2526
  if (!root) {
2425
2527
  return null;
2426
2528
  }
2427
- const resolved = await resolveBase(git, root);
2428
- if (!resolved) {
2529
+ const resolved2 = await resolveBase(git, root);
2530
+ if (!resolved2) {
2429
2531
  return null;
2430
2532
  }
2431
- const { base, fromTrunk } = resolved;
2432
- const blobBytes = async (ref, path) => {
2433
- const out = await git(root, ["cat-file", "-s", `${ref}:${path}`]);
2533
+ const { base, fromTrunk } = resolved2;
2534
+ const blobBytes = async (ref2, path) => {
2535
+ const out = await git(root, ["cat-file", "-s", `${ref2}:${path}`]);
2434
2536
  const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN;
2435
2537
  return Number.isFinite(n) ? n : 0;
2436
2538
  };
@@ -2522,8 +2624,8 @@ async function resolveBase(git, root) {
2522
2624
  }
2523
2625
  return await refExists(git, root, "HEAD") ? { base: "HEAD", fromTrunk: false } : null;
2524
2626
  }
2525
- async function refExists(git, root, ref) {
2526
- return await git(root, ["rev-parse", "--verify", `${ref}^{object}`]) !== null;
2627
+ async function refExists(git, root, ref2) {
2628
+ return await git(root, ["rev-parse", "--verify", `${ref2}^{object}`]) !== null;
2527
2629
  }
2528
2630
  async function readWorkingFile(readFile, root, path) {
2529
2631
  try {
@@ -2558,6 +2660,7 @@ var MAX_FILES, MAX_FILE_BYTES, MAX_TOTAL_BYTES, TRUNK_CANDIDATES, NUL;
2558
2660
  var init_codeChange = __esm({
2559
2661
  "src/codeChange.ts"() {
2560
2662
  "use strict";
2663
+ init_gitCommand();
2561
2664
  MAX_FILES = 60;
2562
2665
  MAX_FILE_BYTES = 5e5;
2563
2666
  MAX_TOTAL_BYTES = 2e6;
@@ -2762,9 +2865,9 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2762
2865
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2763
2866
  try {
2764
2867
  if (includeDbBranchLease && !lease && !leaseError) {
2765
- let resolved;
2868
+ let resolved2;
2766
2869
  try {
2767
- resolved = await httpClient.resolveDbBranchLease(
2870
+ resolved2 = await httpClient.resolveDbBranchLease(
2768
2871
  testRunId,
2769
2872
  originalTraceId,
2770
2873
  dbBranchSettings,
@@ -2778,10 +2881,10 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2778
2881
  cause
2779
2882
  );
2780
2883
  }
2781
- lease = resolved.lease ?? void 0;
2782
- leaseError = resolved.leaseError ?? void 0;
2783
- dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2784
- dbBranchTimings = resolved.timings ?? dbBranchTimings;
2884
+ lease = resolved2.lease ?? void 0;
2885
+ leaseError = resolved2.leaseError ?? void 0;
2886
+ dbSnapshotRef = resolved2.dbSnapshotRef ?? dbSnapshotRef;
2887
+ dbBranchTimings = resolved2.timings ?? dbBranchTimings;
2785
2888
  }
2786
2889
  if (leaseError) {
2787
2890
  throw new DbBranchReplayError(
@@ -4109,19 +4212,18 @@ init_asyncStorage();
4109
4212
  // src/autoTrace.ts
4110
4213
  init_asyncStorage();
4111
4214
  var autoTraceGlobal = globalThis;
4112
- var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
4215
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV4 ?? {
4113
4216
  storage: null,
4114
4217
  browserScope: void 0,
4115
4218
  capturePolicies: /* @__PURE__ */ new WeakMap(),
4116
4219
  activeRoots: 0
4117
4220
  };
4118
- autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
4221
+ autoTraceGlobal.__bitfabAutoTraceStateV4 = autoTraceState;
4119
4222
  function initializeAutoTraceStorage() {
4120
4223
  autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
4121
4224
  }
4122
- function runWithAutoTraceContext(context, fn, depth = 0) {
4225
+ function runWithAutoTraceScope(scope, fn) {
4123
4226
  initializeAutoTraceStorage();
4124
- const scope = { context, depth };
4125
4227
  if (autoTraceState.storage) {
4126
4228
  return autoTraceState.storage.run(scope, fn);
4127
4229
  }
@@ -4133,41 +4235,65 @@ function runWithAutoTraceContext(context, fn, depth = 0) {
4133
4235
  autoTraceState.browserScope = previous;
4134
4236
  }
4135
4237
  }
4238
+ function currentAutoTraceEntries() {
4239
+ return currentAutoTraceScope()?.entries ?? [];
4240
+ }
4241
+ function replaceEntry(entries, previous, updated) {
4242
+ return entries.map((entry) => entry === previous ? updated : entry);
4243
+ }
4244
+ function runWithAutoTraceEntry(previous, updated, fn) {
4245
+ const result = runWithAutoTraceScope(
4246
+ { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },
4247
+ fn
4248
+ );
4249
+ if (isAutoTraceAsyncGenerator(result)) {
4250
+ return wrapAutoTraceEntryAsyncGenerator(previous, updated, result);
4251
+ }
4252
+ return result;
4253
+ }
4254
+ function wrapAutoTraceEntryAsyncGenerator(previous, updated, source) {
4255
+ const step = (method, value) => runWithAutoTraceScope(
4256
+ { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },
4257
+ () => source[method](value)
4258
+ );
4259
+ const wrapped = {
4260
+ next: (value) => step("next", value),
4261
+ return: (value) => step("return", value),
4262
+ throw: (error) => step("throw", error),
4263
+ [Symbol.asyncIterator]: () => wrapped
4264
+ };
4265
+ return wrapped;
4266
+ }
4267
+ function clearAutoTraceNodeConfiguration(fn) {
4268
+ return runWithAutoTraceScope({ entries: currentAutoTraceEntries() }, fn);
4269
+ }
4136
4270
  function runWithAutoTraceNodeConfiguration(nodeConfiguration, fn) {
4137
4271
  const scope = currentAutoTraceScope();
4138
- if (!scope) {
4272
+ if (!scope || scope.entries.length === 0) {
4139
4273
  return fn();
4140
4274
  }
4141
- const configuredScope = { ...scope, nodeConfiguration };
4142
- let result;
4143
- if (autoTraceState.storage) {
4144
- result = autoTraceState.storage.run(configuredScope, fn);
4145
- } else {
4146
- const previous = autoTraceState.browserScope;
4147
- autoTraceState.browserScope = configuredScope;
4148
- try {
4149
- result = fn();
4150
- } finally {
4151
- autoTraceState.browserScope = previous;
4152
- }
4153
- }
4275
+ const result = runWithAutoTraceScope({ ...scope, nodeConfiguration }, fn);
4154
4276
  if (isAutoTraceAsyncGenerator(result)) {
4155
4277
  return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result);
4156
4278
  }
4157
4279
  return result;
4158
4280
  }
4159
- function runWithAutoTraceRootContext(context, fn) {
4281
+ function runWithAutoTraceRootContext(context, spanStack, fn) {
4160
4282
  autoTraceState.activeRoots += 1;
4283
+ const entries = [
4284
+ ...currentAutoTraceEntries(),
4285
+ { context, depth: 0, spanStack }
4286
+ ];
4161
4287
  let result;
4162
4288
  try {
4163
- result = runWithAutoTraceContext(context, fn);
4289
+ result = runWithAutoTraceScope({ entries }, fn);
4164
4290
  } catch (error) {
4165
4291
  autoTraceState.activeRoots -= 1;
4166
4292
  throw error;
4167
4293
  }
4168
4294
  if (isAutoTraceAsyncGenerator(result)) {
4169
4295
  autoTraceState.activeRoots -= 1;
4170
- return wrapAutoTraceAsyncGenerator(context, result);
4296
+ return wrapAutoTraceAsyncGenerator(context, spanStack, result);
4171
4297
  }
4172
4298
  if (result instanceof Promise) {
4173
4299
  return result.finally(() => {
@@ -4177,6 +4303,15 @@ function runWithAutoTraceRootContext(context, fn) {
4177
4303
  autoTraceState.activeRoots -= 1;
4178
4304
  return result;
4179
4305
  }
4306
+ function invokeThroughAutoTraceEntries(entries, step, fn) {
4307
+ let run = fn;
4308
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
4309
+ const entry = entries[index];
4310
+ const next = run;
4311
+ run = () => step(entry, next);
4312
+ }
4313
+ return run();
4314
+ }
4180
4315
  function isAutoTraceAsyncGenerator(value) {
4181
4316
  if (value === null || typeof value !== "object") {
4182
4317
  return false;
@@ -4184,8 +4319,8 @@ function isAutoTraceAsyncGenerator(value) {
4184
4319
  const candidate = value;
4185
4320
  return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
4186
4321
  }
4187
- function wrapAutoTraceAsyncGenerator(context, source) {
4188
- const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
4322
+ function wrapAutoTraceAsyncGenerator(context, spanStack, source) {
4323
+ const step = (method, value) => runWithAutoTraceRootContext(context, spanStack, () => source[method](value));
4189
4324
  const wrapped = {
4190
4325
  next: (value) => step("next", value),
4191
4326
  return: (value) => step("return", value),
@@ -4211,7 +4346,7 @@ function __bitfabAutoTraceActive() {
4211
4346
  if (autoTraceState.activeRoots === 0) {
4212
4347
  return false;
4213
4348
  }
4214
- return currentAutoTraceScope() !== void 0;
4349
+ return currentAutoTraceEntries().length > 0;
4215
4350
  }
4216
4351
  function currentAutoTraceScope() {
4217
4352
  initializeAutoTraceStorage();
@@ -4564,24 +4699,239 @@ function mixedTracingError(enteredApi, entered, enclosing, traceFunctionKey) {
4564
4699
  `opt-in and opt-out tracing can't be mixed in one call stack: ${enteredApi} (${entered})${subject} was entered inside a ${SURFACE_API[enclosing]} call (${enclosing}). ${MIXED_SURFACE_REMEDY[entered]}`
4565
4700
  );
4566
4701
  }
4567
- function assertSurfacesCompatible(requested, resolved, parentSurface, traceFunctionKey) {
4702
+ function assertSurfacesCompatible(requested, resolved2, parentSurface, traceFunctionKey) {
4568
4703
  if (requested === "inherit" || requested === "neutral") {
4569
4704
  return;
4570
4705
  }
4571
- if (resolved === void 0 || parentSurface === void 0) {
4706
+ if (resolved2 === void 0 || parentSurface === void 0) {
4572
4707
  return;
4573
4708
  }
4574
- if (parentSurface === resolved) {
4709
+ if (parentSurface === resolved2) {
4575
4710
  return;
4576
4711
  }
4577
4712
  throw mixedTracingError(
4578
- SURFACE_API[resolved],
4579
- resolved,
4713
+ SURFACE_API[resolved2],
4714
+ resolved2,
4580
4715
  parentSurface,
4581
4716
  traceFunctionKey
4582
4717
  );
4583
4718
  }
4584
4719
 
4720
+ // src/commitRef.ts
4721
+ init_gitCommand();
4722
+ init_readEnv();
4723
+ var EXPLICIT_SHA_ENV = "BITFAB_COMMIT_SHA";
4724
+ var DISABLE_ENV = "BITFAB_DISABLE_COMMIT_REF";
4725
+ var GIT_TIMEOUT_MS = 2e3;
4726
+ var GIT_MAX_BUFFER = 1024 * 1024;
4727
+ var VERCEL_PROVIDER_HOSTS = {
4728
+ github: "github.com",
4729
+ gitlab: "gitlab.com",
4730
+ bitbucket: "bitbucket.org"
4731
+ };
4732
+ function read(env, name) {
4733
+ if (name === null) {
4734
+ return null;
4735
+ }
4736
+ const value = env(name)?.trim();
4737
+ return value ? value : null;
4738
+ }
4739
+ function remoteFrom(...names) {
4740
+ return (env) => {
4741
+ const parts = names.map((name) => read(env, name));
4742
+ if (parts.some((part) => part === null)) {
4743
+ return null;
4744
+ }
4745
+ return normalizeRemote(parts.join("/"));
4746
+ };
4747
+ }
4748
+ function vercelRemote(env) {
4749
+ const provider = read(env, "VERCEL_GIT_PROVIDER")?.toLowerCase() ?? "";
4750
+ const host = VERCEL_PROVIDER_HOSTS[provider];
4751
+ const owner = read(env, "VERCEL_GIT_REPO_OWNER");
4752
+ const slug = read(env, "VERCEL_GIT_REPO_SLUG");
4753
+ if (!host || !owner || !slug) {
4754
+ return null;
4755
+ }
4756
+ return `${host}/${owner}/${slug}`;
4757
+ }
4758
+ function noRemote() {
4759
+ return null;
4760
+ }
4761
+ var PLATFORM_ENVS = [
4762
+ ["VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF", vercelRemote],
4763
+ [
4764
+ "GITHUB_SHA",
4765
+ "GITHUB_REF_NAME",
4766
+ remoteFrom("GITHUB_SERVER_URL", "GITHUB_REPOSITORY")
4767
+ ],
4768
+ ["RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH", noRemote],
4769
+ ["RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH", noRemote],
4770
+ ["SOURCE_VERSION", null, noRemote],
4771
+ ["CF_PAGES_COMMIT_SHA", "CF_PAGES_BRANCH", noRemote],
4772
+ ["CI_COMMIT_SHA", "CI_COMMIT_REF_NAME", remoteFrom("CI_REPOSITORY_URL")],
4773
+ [
4774
+ "BUILD_SOURCEVERSION",
4775
+ "BUILD_SOURCEBRANCHNAME",
4776
+ remoteFrom("BUILD_REPOSITORY_URI")
4777
+ ],
4778
+ ["CIRCLE_SHA1", "CIRCLE_BRANCH", remoteFrom("CIRCLE_REPOSITORY_URL")]
4779
+ ];
4780
+ var COMMIT_REF_ENV_NAMES = [
4781
+ EXPLICIT_SHA_ENV,
4782
+ DISABLE_ENV,
4783
+ ...PLATFORM_ENVS.flatMap(
4784
+ ([sha, branch]) => branch === null ? [sha] : [sha, branch]
4785
+ ),
4786
+ "GITHUB_SERVER_URL",
4787
+ "GITHUB_REPOSITORY",
4788
+ "CI_REPOSITORY_URL",
4789
+ "BUILD_REPOSITORY_URI",
4790
+ "CIRCLE_REPOSITORY_URL",
4791
+ "VERCEL_GIT_PROVIDER",
4792
+ "VERCEL_GIT_REPO_OWNER",
4793
+ "VERCEL_GIT_REPO_SLUG"
4794
+ ];
4795
+ function normalizeRemote(raw) {
4796
+ const value = raw?.trim();
4797
+ if (!value) {
4798
+ return null;
4799
+ }
4800
+ let host = "";
4801
+ let path = value;
4802
+ if (value.includes("://")) {
4803
+ try {
4804
+ const parsed = new URL(value);
4805
+ host = parsed.hostname;
4806
+ path = parsed.pathname;
4807
+ } catch {
4808
+ return null;
4809
+ }
4810
+ } else {
4811
+ const separator = value.indexOf(":");
4812
+ if (separator !== -1) {
4813
+ const head = value.slice(0, separator);
4814
+ host = head.slice(head.lastIndexOf("@") + 1);
4815
+ path = value.slice(separator + 1);
4816
+ }
4817
+ }
4818
+ path = path.replace(/^\/+|\/+$/g, "");
4819
+ if (path.endsWith(".git")) {
4820
+ path = path.slice(0, -".git".length).replace(/\/+$/, "");
4821
+ }
4822
+ if (!host) {
4823
+ return path || null;
4824
+ }
4825
+ return path ? `${host}/${path}` : host;
4826
+ }
4827
+ function resolveCommitRefFromEnv(env) {
4828
+ const explicit = read(env, EXPLICIT_SHA_ENV);
4829
+ const platform = PLATFORM_ENVS.find(([sha]) => read(env, sha) !== null);
4830
+ if (!platform) {
4831
+ if (explicit === null) {
4832
+ return null;
4833
+ }
4834
+ return {
4835
+ sha: explicit,
4836
+ branch: null,
4837
+ dirty: null,
4838
+ remote: null,
4839
+ rootSha: null
4840
+ };
4841
+ }
4842
+ const [shaEnv, branchEnv, readRemote] = platform;
4843
+ return {
4844
+ sha: explicit ?? read(env, shaEnv),
4845
+ branch: read(env, branchEnv),
4846
+ dirty: null,
4847
+ remote: readRemote(env),
4848
+ rootSha: null
4849
+ };
4850
+ }
4851
+ async function resolveCommitRefFromGit(cwd) {
4852
+ const git = await gitRunner({
4853
+ timeoutMs: GIT_TIMEOUT_MS,
4854
+ maxBuffer: GIT_MAX_BUFFER,
4855
+ keepProcessAlive: false
4856
+ });
4857
+ if (!git) {
4858
+ return null;
4859
+ }
4860
+ const run = async (args) => (await git(cwd, args))?.trim() ?? null;
4861
+ const sha = await run(["rev-parse", "HEAD"]);
4862
+ if (!sha) {
4863
+ return null;
4864
+ }
4865
+ const [branch, status, remote, roots] = await Promise.all([
4866
+ run(["symbolic-ref", "--short", "-q", "HEAD"]),
4867
+ run(["status", "--porcelain"]),
4868
+ run(["remote", "get-url", "origin"]),
4869
+ run(["rev-list", "--max-parents=0", "HEAD"])
4870
+ ]);
4871
+ return {
4872
+ sha,
4873
+ branch: branch || null,
4874
+ dirty: status === null ? null : status.length > 0,
4875
+ remote: normalizeRemote(remote),
4876
+ rootSha: roots ? roots.split(/\s+/).sort()[0] ?? null : null
4877
+ };
4878
+ }
4879
+ function commitRefWire(ref2) {
4880
+ return {
4881
+ sha: ref2.sha,
4882
+ branch: ref2.branch,
4883
+ dirty: ref2.dirty,
4884
+ remote: ref2.remote,
4885
+ root_sha: ref2.rootSha
4886
+ };
4887
+ }
4888
+ var resolved = false;
4889
+ var ref = null;
4890
+ var gitStarted = false;
4891
+ var settled = Promise.resolve();
4892
+ function startCommitRefResolution() {
4893
+ if (resolved || gitStarted) {
4894
+ return;
4895
+ }
4896
+ if (read(readEnv, DISABLE_ENV) !== null) {
4897
+ resolved = true;
4898
+ return;
4899
+ }
4900
+ const fromEnv = resolveCommitRefFromEnv(readEnv);
4901
+ if (fromEnv) {
4902
+ ref = fromEnv;
4903
+ resolved = true;
4904
+ return;
4905
+ }
4906
+ gitStarted = true;
4907
+ if (typeof process === "undefined") {
4908
+ resolved = true;
4909
+ return;
4910
+ }
4911
+ let cwd;
4912
+ try {
4913
+ cwd = process.cwd?.() ?? ".";
4914
+ } catch {
4915
+ resolved = true;
4916
+ return;
4917
+ }
4918
+ settled = resolveCommitRefFromGit(cwd).then(
4919
+ (fromGit) => {
4920
+ if (!resolved) {
4921
+ ref = fromGit;
4922
+ resolved = true;
4923
+ }
4924
+ },
4925
+ () => {
4926
+ resolved = true;
4927
+ }
4928
+ );
4929
+ }
4930
+ function currentCommitRef() {
4931
+ startCommitRefResolution();
4932
+ return ref;
4933
+ }
4934
+
4585
4935
  // src/client.ts
4586
4936
  init_constants();
4587
4937
 
@@ -5074,11 +5424,11 @@ var BitfabLangGraphCallbackHandler = class {
5074
5424
  this.invocations.set(invocation.rootRunId, invocation);
5075
5425
  }
5076
5426
  if (!willHide) {
5077
- let resolved = parentSpan;
5078
- while (resolved?.hidden === true) {
5079
- resolved = resolved.parentId ? this.runToSpan.get(resolved.parentId) : void 0;
5427
+ let resolved2 = parentSpan;
5428
+ while (resolved2?.hidden === true) {
5429
+ resolved2 = resolved2.parentId ? this.runToSpan.get(resolved2.parentId) : void 0;
5080
5430
  }
5081
- effectiveParentId = resolved ? resolved.spanId : invocation.activeContext?.spanId ?? null;
5431
+ effectiveParentId = resolved2 ? resolved2.spanId : invocation.activeContext?.spanId ?? null;
5082
5432
  } else {
5083
5433
  effectiveParentId = parentRunId ?? null;
5084
5434
  }
@@ -6578,6 +6928,7 @@ var Bitfab = class {
6578
6928
  validateDbSnapshotConfig(config.dbSnapshot);
6579
6929
  }
6580
6930
  this.dbSnapshot = config.dbSnapshot;
6931
+ startCommitRefResolution();
6581
6932
  this.httpClient = new HttpClient({
6582
6933
  apiKey: () => this.resolveApiKey(),
6583
6934
  serviceUrl: this.serviceUrl,
@@ -6748,11 +7099,15 @@ var Bitfab = class {
6748
7099
  type: options.type ?? "custom",
6749
7100
  surface: "opt-out"
6750
7101
  };
6751
- const tracedRoot = this.withSpan(
7102
+ const rootName = options.name ?? name;
7103
+ const buildTracedRoot = (spanOptions) => this.withSpan(
6752
7104
  traceFunctionKey,
6753
- rootOptions,
7105
+ spanOptions,
6754
7106
  function(...args) {
6755
- const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
7107
+ const capturePolicy = getAutoTraceCapturePolicy(
7108
+ self,
7109
+ traceFunctionKey
7110
+ );
6756
7111
  self.refreshAutoTraceCapturePolicy(traceFunctionKey);
6757
7112
  let spansUsed = 0;
6758
7113
  let truncated = false;
@@ -6773,19 +7128,54 @@ var Bitfab = class {
6773
7128
  `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
6774
7129
  );
6775
7130
  };
7131
+ const spanStackOf = (entry) => entry.spanStack;
7132
+ const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
7133
+ const runInside = () => runWithAutoTraceEntry(
7134
+ entry,
7135
+ {
7136
+ context: autoTraceContext,
7137
+ depth: entry.depth + 1,
7138
+ spanStack: getSpanStack()
7139
+ },
7140
+ invokeFn
7141
+ );
7142
+ return runWithSpanStack(spanStackOf(entry), () => {
7143
+ if (isAsync) {
7144
+ const tracedAsyncChild = self.withSpan(
7145
+ traceFunctionKey,
7146
+ childOptions,
7147
+ async (..._inputs) => await runInside()
7148
+ );
7149
+ return tracedAsyncChild(...inputs);
7150
+ }
7151
+ const tracedChild = self.withSpan(
7152
+ traceFunctionKey,
7153
+ childOptions,
7154
+ (..._inputs) => runInside()
7155
+ );
7156
+ return tracedChild(...inputs);
7157
+ });
7158
+ };
7159
+ const overBudget = (entry) => {
7160
+ if (entry.depth < maxDepth && spansUsed < maxSpans) {
7161
+ return false;
7162
+ }
7163
+ runWithSpanStack(spanStackOf(entry), warnTruncated);
7164
+ return true;
7165
+ };
6776
7166
  const autoTraceContext = {
6777
- invoke(definition, inputs, invokeFn, depth, nodeConfiguration) {
7167
+ traceFunctionKey,
7168
+ invoke(definition, inputs, invokeFn, entry, nodeConfiguration) {
6778
7169
  const nameParts = definition.name.split(".");
6779
7170
  const simpleName = nameParts[nameParts.length - 1];
6780
- const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
7171
+ const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : clearAutoTraceNodeConfiguration(invokeFn);
6781
7172
  if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || nodeConfiguration === void 0 && definition.wrapper === true && !includeWrappers) {
6782
7173
  return invokeWithoutNode();
6783
7174
  }
6784
7175
  if (nodeConfiguration?.capture === false) {
6785
- return runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
7176
+ return clearAutoTraceNodeConfiguration(invokeFn);
6786
7177
  }
6787
- if (depth >= maxDepth || spansUsed >= maxSpans) {
6788
- warnTruncated();
7178
+ if (overBudget(entry)) {
6789
7179
  return invokeWithoutNode();
6790
7180
  }
6791
7181
  spansUsed += 1;
@@ -6808,34 +7198,81 @@ var Bitfab = class {
6808
7198
  finalize: nodeConfiguration.finalize
6809
7199
  }
6810
7200
  };
6811
- const invokeWithAutoTraceContext = () => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1);
6812
- if (definition.async === true) {
6813
- const tracedAsyncChild = self.withSpan(
6814
- traceFunctionKey,
6815
- childOptions,
6816
- async (..._inputs) => await invokeWithAutoTraceContext()
6817
- );
6818
- return tracedAsyncChild(...inputs);
6819
- }
6820
- const tracedChild = self.withSpan(
6821
- traceFunctionKey,
7201
+ return openChild(
7202
+ entry,
6822
7203
  childOptions,
6823
- (..._inputs) => invokeWithAutoTraceContext()
7204
+ inputs,
7205
+ definition.async === true,
7206
+ invokeFn
6824
7207
  );
6825
- return tracedChild(...inputs);
7208
+ },
7209
+ invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
7210
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
7211
+ return invokeFn();
7212
+ }
7213
+ spansUsed += 1;
7214
+ const childOptions = {
7215
+ name: nestedName,
7216
+ type: "function",
7217
+ captureWhen: "nested",
7218
+ surface: "opt-out",
7219
+ captureContent: true,
7220
+ ...link !== void 0 && { nestedTrace: link }
7221
+ };
7222
+ return openChild(entry, childOptions, inputs, false, invokeFn);
6826
7223
  }
6827
7224
  };
6828
7225
  return runWithAutoTraceRootContext(
6829
7226
  autoTraceContext,
7227
+ getSpanStack(),
6830
7228
  () => fn.apply(this, args)
6831
7229
  );
6832
7230
  }
6833
7231
  );
7232
+ const tracedRoot = buildTracedRoot(rootOptions);
6834
7233
  const autoTraceRoot = function(...args) {
6835
7234
  if (!self.shouldRecord()) {
6836
7235
  return fn.apply(this, args);
6837
7236
  }
6838
- return tracedRoot.apply(this, args);
7237
+ const enclosing = currentAutoTraceEntries();
7238
+ if (enclosing.length === 0) {
7239
+ return tracedRoot.apply(this, args);
7240
+ }
7241
+ const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
7242
+ return invokeThroughAutoTraceEntries(
7243
+ enclosing,
7244
+ (entry, next) => entry.context.invokeNestedRoot(
7245
+ rootName,
7246
+ name,
7247
+ args,
7248
+ next,
7249
+ entry,
7250
+ link
7251
+ ),
7252
+ () => {
7253
+ if (link === void 0) {
7254
+ return fn.apply(this, args);
7255
+ }
7256
+ const innermost = enclosing[enclosing.length - 1];
7257
+ const innermostNow = currentAutoTraceEntries().find(
7258
+ (entry) => entry.context === innermost.context
7259
+ ) ?? innermost;
7260
+ const innermostStack = innermostNow.spanStack;
7261
+ const copy = innermostStack[innermostStack.length - 1];
7262
+ const detachedRoot = buildTracedRoot({
7263
+ ...rootOptions,
7264
+ ...copy !== void 0 && {
7265
+ enclosingTrace: {
7266
+ traceId: copy.traceId,
7267
+ spanId: copy.spanId,
7268
+ traceFunctionKey: innermost.context.traceFunctionKey,
7269
+ link
7270
+ }
7271
+ }
7272
+ });
7273
+ return runWithSpanStack([], () => detachedRoot.apply(this, args));
7274
+ }
7275
+ );
6839
7276
  };
6840
7277
  Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
6841
7278
  value: traceFunctionKey
@@ -7424,6 +7861,10 @@ var Bitfab = class {
7424
7861
  const spanId = randomUuid();
7425
7862
  const parentSpanId = parentContext?.spanId ?? null;
7426
7863
  const isRootSpan = parentSpanId === null;
7864
+ if (options.enclosingTrace !== void 0) {
7865
+ options.enclosingTrace.link.traceId = traceId;
7866
+ options.enclosingTrace.link.rootSpanId = spanId;
7867
+ }
7427
7868
  const requestedSurface = options.surface ?? DEFAULT_SURFACE;
7428
7869
  const surface = resolveSurface(requestedSurface, parentContext?.surface);
7429
7870
  assertSurfacesCompatible(
@@ -7473,7 +7914,9 @@ var Bitfab = class {
7473
7914
  spanType: options.type ?? "custom",
7474
7915
  functionId: options.functionId,
7475
7916
  captureContent: options.captureContent ?? true,
7476
- autoTraceDefinition: options.autoTraceDefinition
7917
+ autoTraceDefinition: options.autoTraceDefinition,
7918
+ nestedTrace: options.nestedTrace,
7919
+ enclosingTrace: options.enclosingTrace
7477
7920
  };
7478
7921
  const sendSpan = async (params) => {
7479
7922
  const replayCtx = getReplayContext();
@@ -7671,15 +8114,15 @@ var Bitfab = class {
7671
8114
  );
7672
8115
  }
7673
8116
  return runWithSpanStack(newStack, async () => {
7674
- const resolved = await resolution;
7675
- if (resolved.matched) {
8117
+ const resolved2 = await resolution;
8118
+ if (resolved2.matched) {
7676
8119
  void sendSpan({
7677
- result: resolved.output,
8120
+ result: resolved2.output,
7678
8121
  mocked: true,
7679
8122
  mockTarget: "output",
7680
8123
  mockSource: "override"
7681
8124
  });
7682
- return resolved.output;
8125
+ return resolved2.output;
7683
8126
  }
7684
8127
  if (shouldMockWithBaseStrategy && !mockSpan) {
7685
8128
  throw new BitfabError(
@@ -7915,6 +8358,10 @@ var Bitfab = class {
7915
8358
  if (params.dbSnapshotRef) {
7916
8359
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7917
8360
  }
8361
+ const commitRef = currentCommitRef();
8362
+ if (commitRef) {
8363
+ rawTrace.commit_ref = commitRefWire(commitRef);
8364
+ }
7918
8365
  if (params.ingestionType) {
7919
8366
  rawTrace.ingestion_type = params.ingestionType;
7920
8367
  }
@@ -7979,6 +8426,16 @@ var Bitfab = class {
7979
8426
  function_line: params.autoTraceDefinition.line,
7980
8427
  function_column: params.autoTraceDefinition.column
7981
8428
  },
8429
+ ...params.nestedTrace?.traceId !== void 0 && {
8430
+ nested_trace_id: params.nestedTrace.traceId,
8431
+ nested_trace_function_key: params.nestedTrace.traceFunctionKey,
8432
+ nested_root_span_id: params.nestedTrace.rootSpanId
8433
+ },
8434
+ ...params.enclosingTrace !== void 0 && {
8435
+ enclosing_trace_id: params.enclosingTrace.traceId,
8436
+ enclosing_trace_function_key: params.enclosingTrace.traceFunctionKey,
8437
+ enclosing_span_id: params.enclosingTrace.spanId
8438
+ },
7982
8439
  ...serializedInputs !== void 0 && {
7983
8440
  input: serializedInputs.json,
7984
8441
  ...serializedInputs.meta !== void 0 && {