@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/index.cjs CHANGED
@@ -42,7 +42,7 @@ var __version__, __packageName__;
42
42
  var init_version_generated = __esm({
43
43
  "src/version.generated.ts"() {
44
44
  "use strict";
45
- __version__ = "0.52.4";
45
+ __version__ = "0.52.6";
46
46
  __packageName__ = "@bitfab/sdk";
47
47
  }
48
48
  });
@@ -1121,7 +1121,7 @@ var init_otel = __esm({
1121
1121
  if (this.onDelivered === void 0) {
1122
1122
  return;
1123
1123
  }
1124
- const refs = spans.map((span) => span.ref).filter((ref) => ref !== void 0);
1124
+ const refs = spans.map((span) => span.ref).filter((ref2) => ref2 !== void 0);
1125
1125
  if (refs.length === 0) {
1126
1126
  return;
1127
1127
  }
@@ -1378,9 +1378,9 @@ function parseRetryAfterMs(header) {
1378
1378
  }
1379
1379
  return Math.max(0, at - Date.now());
1380
1380
  }
1381
- function carrierMeta(operation, payload, ref) {
1381
+ function carrierMeta(operation, payload, ref2) {
1382
1382
  return {
1383
- ref,
1383
+ ref: ref2,
1384
1384
  name: carrierName(operation, payload),
1385
1385
  startTime: payloadTimestamp(payload, "started_at"),
1386
1386
  endTime: payloadTimestamp(payload, "ended_at"),
@@ -1625,22 +1625,22 @@ var init_http = __esm({
1625
1625
  return reports;
1626
1626
  }
1627
1627
  /** Build a carrier's meta and record what it adds to its trace's expected set. */
1628
- recordedMeta(operation, payload, ref) {
1629
- this.recordSubmittedCarrier(ref);
1630
- return carrierMeta(operation, payload, ref);
1628
+ recordedMeta(operation, payload, ref2) {
1629
+ this.recordSubmittedCarrier(ref2);
1630
+ return carrierMeta(operation, payload, ref2);
1631
1631
  }
1632
- recordSubmittedCarrier(ref) {
1633
- if (ref === void 0) {
1632
+ recordSubmittedCarrier(ref2) {
1633
+ if (ref2 === void 0) {
1634
1634
  return;
1635
1635
  }
1636
- const delivery = this.traceDeliveries.get(ref.traceId);
1636
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1637
1637
  if (delivery === void 0) {
1638
1638
  return;
1639
1639
  }
1640
- if (ref.spanId === void 0) {
1640
+ if (ref2.spanId === void 0) {
1641
1641
  delivery.closed = true;
1642
1642
  } else {
1643
- delivery.submittedSpanIds.add(ref.spanId);
1643
+ delivery.submittedSpanIds.add(ref2.spanId);
1644
1644
  }
1645
1645
  }
1646
1646
  /**
@@ -1666,15 +1666,15 @@ var init_http = __esm({
1666
1666
  }
1667
1667
  }
1668
1668
  recordDeliveredCarriers(refs) {
1669
- for (const ref of refs) {
1670
- const delivery = this.traceDeliveries.get(ref.traceId);
1669
+ for (const ref2 of refs) {
1670
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1671
1671
  if (delivery === void 0) {
1672
1672
  continue;
1673
1673
  }
1674
- if (ref.spanId === void 0) {
1674
+ if (ref2.spanId === void 0) {
1675
1675
  delivery.closingAcked = true;
1676
1676
  } else {
1677
- delivery.ackedSpanIds.add(ref.spanId);
1677
+ delivery.ackedSpanIds.add(ref2.spanId);
1678
1678
  }
1679
1679
  }
1680
1680
  }
@@ -1704,9 +1704,9 @@ var init_http = __esm({
1704
1704
  */
1705
1705
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1706
1706
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1707
- const settled = await this.settleDeferredWork(timeoutMs);
1707
+ const settled2 = await this.settleDeferredWork(timeoutMs);
1708
1708
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1709
- return settled && flushed;
1709
+ return settled2 && flushed;
1710
1710
  }
1711
1711
  /**
1712
1712
  * Flush and permanently close this client's tracing transport. Idempotent:
@@ -1719,14 +1719,14 @@ var init_http = __esm({
1719
1719
  }
1720
1720
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1721
1721
  this.closing = (async () => {
1722
- const settled = await this.settleDeferredWork(
1722
+ const settled2 = await this.settleDeferredWork(
1723
1723
  Math.max(0, deadline - Date.now())
1724
1724
  );
1725
1725
  this.closed = true;
1726
1726
  const transport = this.traceTransport;
1727
1727
  this.traceTransport = void 0;
1728
1728
  const shutdownOk = await transport?.shutdown(Math.max(0, deadline - Date.now())) ?? true;
1729
- return settled && shutdownOk;
1729
+ return settled2 && shutdownOk;
1730
1730
  })();
1731
1731
  return this.closing;
1732
1732
  }
@@ -2337,6 +2337,112 @@ var init_randomUuid = __esm({
2337
2337
  }
2338
2338
  });
2339
2339
 
2340
+ // src/gitCommand.ts
2341
+ function isUnrefable(value) {
2342
+ return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
2343
+ }
2344
+ function unrefStream(stream) {
2345
+ if (isUnrefable(stream)) {
2346
+ stream.unref();
2347
+ }
2348
+ }
2349
+ function terminate(child) {
2350
+ if (child.pid && process.platform !== "win32") {
2351
+ try {
2352
+ process.kill(-child.pid, "SIGTERM");
2353
+ return;
2354
+ } catch {
2355
+ child.kill("SIGTERM");
2356
+ return;
2357
+ }
2358
+ }
2359
+ child.kill("SIGTERM");
2360
+ }
2361
+ async function gitRunner(options) {
2362
+ let spawn;
2363
+ try {
2364
+ ;
2365
+ ({ spawn } = await import("child_process"));
2366
+ } catch {
2367
+ return null;
2368
+ }
2369
+ return (dir, args) => new Promise((resolve) => {
2370
+ let child;
2371
+ try {
2372
+ child = spawn("git", args, {
2373
+ cwd: dir,
2374
+ detached: process.platform !== "win32",
2375
+ stdio: ["ignore", "pipe", "pipe"]
2376
+ });
2377
+ } catch {
2378
+ resolve(null);
2379
+ return;
2380
+ }
2381
+ const chunks = [];
2382
+ let size = 0;
2383
+ let overflow = false;
2384
+ let exitCode = null;
2385
+ let done = false;
2386
+ const timers = [];
2387
+ const schedule = (callback, ms) => {
2388
+ const timer = setTimeout(callback, ms);
2389
+ if (!options.keepProcessAlive) {
2390
+ timer.unref();
2391
+ }
2392
+ timers.push(timer);
2393
+ };
2394
+ const finish = () => {
2395
+ if (done) {
2396
+ return;
2397
+ }
2398
+ done = true;
2399
+ for (const timer of timers) {
2400
+ clearTimeout(timer);
2401
+ }
2402
+ child.stdout?.destroy();
2403
+ child.stderr?.destroy();
2404
+ resolve(
2405
+ exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null
2406
+ );
2407
+ };
2408
+ child.stdout?.on("data", (chunk) => {
2409
+ size += chunk.length;
2410
+ if (size > options.maxBuffer) {
2411
+ overflow = true;
2412
+ terminate(child);
2413
+ return;
2414
+ }
2415
+ chunks.push(chunk);
2416
+ });
2417
+ child.stderr?.resume();
2418
+ child.on("error", () => {
2419
+ exitCode = null;
2420
+ finish();
2421
+ });
2422
+ child.on("exit", (code) => {
2423
+ exitCode = code;
2424
+ schedule(finish, EXIT_GRACE_MS);
2425
+ });
2426
+ child.on("close", (code) => {
2427
+ exitCode = code ?? exitCode;
2428
+ finish();
2429
+ });
2430
+ schedule(() => terminate(child), options.timeoutMs);
2431
+ if (!options.keepProcessAlive) {
2432
+ child.unref();
2433
+ unrefStream(child.stdout);
2434
+ unrefStream(child.stderr);
2435
+ }
2436
+ });
2437
+ }
2438
+ var EXIT_GRACE_MS;
2439
+ var init_gitCommand = __esm({
2440
+ "src/gitCommand.ts"() {
2441
+ "use strict";
2442
+ EXIT_GRACE_MS = 500;
2443
+ }
2444
+ });
2445
+
2340
2446
  // src/mockOverride.ts
2341
2447
  function resolveMockValue(value, ctx) {
2342
2448
  return typeof value === "function" ? value(ctx) : value;
@@ -2393,37 +2499,33 @@ async function readCodeChangeFile() {
2393
2499
  }
2394
2500
  }
2395
2501
  async function captureCodeChangeFromGit(cwd, label) {
2396
- let execFile;
2397
2502
  let readFile;
2398
2503
  try {
2399
2504
  ;
2400
- ({ execFile } = await import("child_process"));
2401
2505
  ({ readFile } = await import("fs/promises"));
2402
2506
  } catch {
2403
2507
  return null;
2404
2508
  }
2405
- const git = (dir, args) => new Promise((resolve) => {
2406
- execFile(
2407
- "git",
2408
- args,
2409
- // 30s timeout so a hung git (e.g. a network-touching ref op) can't
2410
- // block the whole replay indefinitely.
2411
- { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 3e4 },
2412
- (err, stdout) => resolve(err ? null : stdout)
2413
- );
2509
+ const git = await gitRunner({
2510
+ timeoutMs: 3e4,
2511
+ maxBuffer: 64 * 1024 * 1024,
2512
+ keepProcessAlive: true
2414
2513
  });
2514
+ if (!git) {
2515
+ return null;
2516
+ }
2415
2517
  try {
2416
2518
  const root = (await git(cwd, ["rev-parse", "--show-toplevel"]))?.trim();
2417
2519
  if (!root) {
2418
2520
  return null;
2419
2521
  }
2420
- const resolved = await resolveBase(git, root);
2421
- if (!resolved) {
2522
+ const resolved2 = await resolveBase(git, root);
2523
+ if (!resolved2) {
2422
2524
  return null;
2423
2525
  }
2424
- const { base, fromTrunk } = resolved;
2425
- const blobBytes = async (ref, path) => {
2426
- const out = await git(root, ["cat-file", "-s", `${ref}:${path}`]);
2526
+ const { base, fromTrunk } = resolved2;
2527
+ const blobBytes = async (ref2, path) => {
2528
+ const out = await git(root, ["cat-file", "-s", `${ref2}:${path}`]);
2427
2529
  const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN;
2428
2530
  return Number.isFinite(n) ? n : 0;
2429
2531
  };
@@ -2515,8 +2617,8 @@ async function resolveBase(git, root) {
2515
2617
  }
2516
2618
  return await refExists(git, root, "HEAD") ? { base: "HEAD", fromTrunk: false } : null;
2517
2619
  }
2518
- async function refExists(git, root, ref) {
2519
- return await git(root, ["rev-parse", "--verify", `${ref}^{object}`]) !== null;
2620
+ async function refExists(git, root, ref2) {
2621
+ return await git(root, ["rev-parse", "--verify", `${ref2}^{object}`]) !== null;
2520
2622
  }
2521
2623
  async function readWorkingFile(readFile, root, path) {
2522
2624
  try {
@@ -2551,6 +2653,7 @@ var MAX_FILES, MAX_FILE_BYTES, MAX_TOTAL_BYTES, TRUNK_CANDIDATES, NUL;
2551
2653
  var init_codeChange = __esm({
2552
2654
  "src/codeChange.ts"() {
2553
2655
  "use strict";
2656
+ init_gitCommand();
2554
2657
  MAX_FILES = 60;
2555
2658
  MAX_FILE_BYTES = 5e5;
2556
2659
  MAX_TOTAL_BYTES = 2e6;
@@ -2755,9 +2858,9 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2755
2858
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2756
2859
  try {
2757
2860
  if (includeDbBranchLease && !lease && !leaseError) {
2758
- let resolved;
2861
+ let resolved2;
2759
2862
  try {
2760
- resolved = await httpClient.resolveDbBranchLease(
2863
+ resolved2 = await httpClient.resolveDbBranchLease(
2761
2864
  testRunId,
2762
2865
  originalTraceId,
2763
2866
  dbBranchSettings,
@@ -2771,10 +2874,10 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2771
2874
  cause
2772
2875
  );
2773
2876
  }
2774
- lease = resolved.lease ?? void 0;
2775
- leaseError = resolved.leaseError ?? void 0;
2776
- dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2777
- dbBranchTimings = resolved.timings ?? dbBranchTimings;
2877
+ lease = resolved2.lease ?? void 0;
2878
+ leaseError = resolved2.leaseError ?? void 0;
2879
+ dbSnapshotRef = resolved2.dbSnapshotRef ?? dbSnapshotRef;
2880
+ dbBranchTimings = resolved2.timings ?? dbBranchTimings;
2778
2881
  }
2779
2882
  if (leaseError) {
2780
2883
  throw new DbBranchReplayError(
@@ -4095,19 +4198,18 @@ init_asyncStorage();
4095
4198
  // src/autoTrace.ts
4096
4199
  init_asyncStorage();
4097
4200
  var autoTraceGlobal = globalThis;
4098
- var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
4201
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV4 ?? {
4099
4202
  storage: null,
4100
4203
  browserScope: void 0,
4101
4204
  capturePolicies: /* @__PURE__ */ new WeakMap(),
4102
4205
  activeRoots: 0
4103
4206
  };
4104
- autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
4207
+ autoTraceGlobal.__bitfabAutoTraceStateV4 = autoTraceState;
4105
4208
  function initializeAutoTraceStorage() {
4106
4209
  autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
4107
4210
  }
4108
- function runWithAutoTraceContext(context, fn, depth = 0) {
4211
+ function runWithAutoTraceScope(scope, fn) {
4109
4212
  initializeAutoTraceStorage();
4110
- const scope = { context, depth };
4111
4213
  if (autoTraceState.storage) {
4112
4214
  return autoTraceState.storage.run(scope, fn);
4113
4215
  }
@@ -4119,41 +4221,65 @@ function runWithAutoTraceContext(context, fn, depth = 0) {
4119
4221
  autoTraceState.browserScope = previous;
4120
4222
  }
4121
4223
  }
4224
+ function currentAutoTraceEntries() {
4225
+ return currentAutoTraceScope()?.entries ?? [];
4226
+ }
4227
+ function replaceEntry(entries, previous, updated) {
4228
+ return entries.map((entry) => entry === previous ? updated : entry);
4229
+ }
4230
+ function runWithAutoTraceEntry(previous, updated, fn) {
4231
+ const result = runWithAutoTraceScope(
4232
+ { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },
4233
+ fn
4234
+ );
4235
+ if (isAutoTraceAsyncGenerator(result)) {
4236
+ return wrapAutoTraceEntryAsyncGenerator(previous, updated, result);
4237
+ }
4238
+ return result;
4239
+ }
4240
+ function wrapAutoTraceEntryAsyncGenerator(previous, updated, source) {
4241
+ const step = (method, value) => runWithAutoTraceScope(
4242
+ { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },
4243
+ () => source[method](value)
4244
+ );
4245
+ const wrapped = {
4246
+ next: (value) => step("next", value),
4247
+ return: (value) => step("return", value),
4248
+ throw: (error) => step("throw", error),
4249
+ [Symbol.asyncIterator]: () => wrapped
4250
+ };
4251
+ return wrapped;
4252
+ }
4253
+ function clearAutoTraceNodeConfiguration(fn) {
4254
+ return runWithAutoTraceScope({ entries: currentAutoTraceEntries() }, fn);
4255
+ }
4122
4256
  function runWithAutoTraceNodeConfiguration(nodeConfiguration, fn) {
4123
4257
  const scope = currentAutoTraceScope();
4124
- if (!scope) {
4258
+ if (!scope || scope.entries.length === 0) {
4125
4259
  return fn();
4126
4260
  }
4127
- const configuredScope = { ...scope, nodeConfiguration };
4128
- let result;
4129
- if (autoTraceState.storage) {
4130
- result = autoTraceState.storage.run(configuredScope, fn);
4131
- } else {
4132
- const previous = autoTraceState.browserScope;
4133
- autoTraceState.browserScope = configuredScope;
4134
- try {
4135
- result = fn();
4136
- } finally {
4137
- autoTraceState.browserScope = previous;
4138
- }
4139
- }
4261
+ const result = runWithAutoTraceScope({ ...scope, nodeConfiguration }, fn);
4140
4262
  if (isAutoTraceAsyncGenerator(result)) {
4141
4263
  return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result);
4142
4264
  }
4143
4265
  return result;
4144
4266
  }
4145
- function runWithAutoTraceRootContext(context, fn) {
4267
+ function runWithAutoTraceRootContext(context, spanStack, fn) {
4146
4268
  autoTraceState.activeRoots += 1;
4269
+ const entries = [
4270
+ ...currentAutoTraceEntries(),
4271
+ { context, depth: 0, spanStack }
4272
+ ];
4147
4273
  let result;
4148
4274
  try {
4149
- result = runWithAutoTraceContext(context, fn);
4275
+ result = runWithAutoTraceScope({ entries }, fn);
4150
4276
  } catch (error) {
4151
4277
  autoTraceState.activeRoots -= 1;
4152
4278
  throw error;
4153
4279
  }
4154
4280
  if (isAutoTraceAsyncGenerator(result)) {
4155
4281
  autoTraceState.activeRoots -= 1;
4156
- return wrapAutoTraceAsyncGenerator(context, result);
4282
+ return wrapAutoTraceAsyncGenerator(context, spanStack, result);
4157
4283
  }
4158
4284
  if (result instanceof Promise) {
4159
4285
  return result.finally(() => {
@@ -4163,6 +4289,15 @@ function runWithAutoTraceRootContext(context, fn) {
4163
4289
  autoTraceState.activeRoots -= 1;
4164
4290
  return result;
4165
4291
  }
4292
+ function invokeThroughAutoTraceEntries(entries, step, fn) {
4293
+ let run = fn;
4294
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
4295
+ const entry = entries[index];
4296
+ const next = run;
4297
+ run = () => step(entry, next);
4298
+ }
4299
+ return run();
4300
+ }
4166
4301
  function isAutoTraceAsyncGenerator(value) {
4167
4302
  if (value === null || typeof value !== "object") {
4168
4303
  return false;
@@ -4170,8 +4305,8 @@ function isAutoTraceAsyncGenerator(value) {
4170
4305
  const candidate = value;
4171
4306
  return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
4172
4307
  }
4173
- function wrapAutoTraceAsyncGenerator(context, source) {
4174
- const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
4308
+ function wrapAutoTraceAsyncGenerator(context, spanStack, source) {
4309
+ const step = (method, value) => runWithAutoTraceRootContext(context, spanStack, () => source[method](value));
4175
4310
  const wrapped = {
4176
4311
  next: (value) => step("next", value),
4177
4312
  return: (value) => step("return", value),
@@ -4197,7 +4332,7 @@ function __bitfabAutoTraceActive() {
4197
4332
  if (autoTraceState.activeRoots === 0) {
4198
4333
  return false;
4199
4334
  }
4200
- return currentAutoTraceScope() !== void 0;
4335
+ return currentAutoTraceEntries().length > 0;
4201
4336
  }
4202
4337
  function currentAutoTraceScope() {
4203
4338
  initializeAutoTraceStorage();
@@ -4550,24 +4685,239 @@ function mixedTracingError(enteredApi, entered, enclosing, traceFunctionKey) {
4550
4685
  `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]}`
4551
4686
  );
4552
4687
  }
4553
- function assertSurfacesCompatible(requested, resolved, parentSurface, traceFunctionKey) {
4688
+ function assertSurfacesCompatible(requested, resolved2, parentSurface, traceFunctionKey) {
4554
4689
  if (requested === "inherit" || requested === "neutral") {
4555
4690
  return;
4556
4691
  }
4557
- if (resolved === void 0 || parentSurface === void 0) {
4692
+ if (resolved2 === void 0 || parentSurface === void 0) {
4558
4693
  return;
4559
4694
  }
4560
- if (parentSurface === resolved) {
4695
+ if (parentSurface === resolved2) {
4561
4696
  return;
4562
4697
  }
4563
4698
  throw mixedTracingError(
4564
- SURFACE_API[resolved],
4565
- resolved,
4699
+ SURFACE_API[resolved2],
4700
+ resolved2,
4566
4701
  parentSurface,
4567
4702
  traceFunctionKey
4568
4703
  );
4569
4704
  }
4570
4705
 
4706
+ // src/commitRef.ts
4707
+ init_gitCommand();
4708
+ init_readEnv();
4709
+ var EXPLICIT_SHA_ENV = "BITFAB_COMMIT_SHA";
4710
+ var DISABLE_ENV = "BITFAB_DISABLE_COMMIT_REF";
4711
+ var GIT_TIMEOUT_MS = 2e3;
4712
+ var GIT_MAX_BUFFER = 1024 * 1024;
4713
+ var VERCEL_PROVIDER_HOSTS = {
4714
+ github: "github.com",
4715
+ gitlab: "gitlab.com",
4716
+ bitbucket: "bitbucket.org"
4717
+ };
4718
+ function read(env, name) {
4719
+ if (name === null) {
4720
+ return null;
4721
+ }
4722
+ const value = env(name)?.trim();
4723
+ return value ? value : null;
4724
+ }
4725
+ function remoteFrom(...names) {
4726
+ return (env) => {
4727
+ const parts = names.map((name) => read(env, name));
4728
+ if (parts.some((part) => part === null)) {
4729
+ return null;
4730
+ }
4731
+ return normalizeRemote(parts.join("/"));
4732
+ };
4733
+ }
4734
+ function vercelRemote(env) {
4735
+ const provider = read(env, "VERCEL_GIT_PROVIDER")?.toLowerCase() ?? "";
4736
+ const host = VERCEL_PROVIDER_HOSTS[provider];
4737
+ const owner = read(env, "VERCEL_GIT_REPO_OWNER");
4738
+ const slug = read(env, "VERCEL_GIT_REPO_SLUG");
4739
+ if (!host || !owner || !slug) {
4740
+ return null;
4741
+ }
4742
+ return `${host}/${owner}/${slug}`;
4743
+ }
4744
+ function noRemote() {
4745
+ return null;
4746
+ }
4747
+ var PLATFORM_ENVS = [
4748
+ ["VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF", vercelRemote],
4749
+ [
4750
+ "GITHUB_SHA",
4751
+ "GITHUB_REF_NAME",
4752
+ remoteFrom("GITHUB_SERVER_URL", "GITHUB_REPOSITORY")
4753
+ ],
4754
+ ["RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH", noRemote],
4755
+ ["RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH", noRemote],
4756
+ ["SOURCE_VERSION", null, noRemote],
4757
+ ["CF_PAGES_COMMIT_SHA", "CF_PAGES_BRANCH", noRemote],
4758
+ ["CI_COMMIT_SHA", "CI_COMMIT_REF_NAME", remoteFrom("CI_REPOSITORY_URL")],
4759
+ [
4760
+ "BUILD_SOURCEVERSION",
4761
+ "BUILD_SOURCEBRANCHNAME",
4762
+ remoteFrom("BUILD_REPOSITORY_URI")
4763
+ ],
4764
+ ["CIRCLE_SHA1", "CIRCLE_BRANCH", remoteFrom("CIRCLE_REPOSITORY_URL")]
4765
+ ];
4766
+ var COMMIT_REF_ENV_NAMES = [
4767
+ EXPLICIT_SHA_ENV,
4768
+ DISABLE_ENV,
4769
+ ...PLATFORM_ENVS.flatMap(
4770
+ ([sha, branch]) => branch === null ? [sha] : [sha, branch]
4771
+ ),
4772
+ "GITHUB_SERVER_URL",
4773
+ "GITHUB_REPOSITORY",
4774
+ "CI_REPOSITORY_URL",
4775
+ "BUILD_REPOSITORY_URI",
4776
+ "CIRCLE_REPOSITORY_URL",
4777
+ "VERCEL_GIT_PROVIDER",
4778
+ "VERCEL_GIT_REPO_OWNER",
4779
+ "VERCEL_GIT_REPO_SLUG"
4780
+ ];
4781
+ function normalizeRemote(raw) {
4782
+ const value = raw?.trim();
4783
+ if (!value) {
4784
+ return null;
4785
+ }
4786
+ let host = "";
4787
+ let path = value;
4788
+ if (value.includes("://")) {
4789
+ try {
4790
+ const parsed = new URL(value);
4791
+ host = parsed.hostname;
4792
+ path = parsed.pathname;
4793
+ } catch {
4794
+ return null;
4795
+ }
4796
+ } else {
4797
+ const separator = value.indexOf(":");
4798
+ if (separator !== -1) {
4799
+ const head = value.slice(0, separator);
4800
+ host = head.slice(head.lastIndexOf("@") + 1);
4801
+ path = value.slice(separator + 1);
4802
+ }
4803
+ }
4804
+ path = path.replace(/^\/+|\/+$/g, "");
4805
+ if (path.endsWith(".git")) {
4806
+ path = path.slice(0, -".git".length).replace(/\/+$/, "");
4807
+ }
4808
+ if (!host) {
4809
+ return path || null;
4810
+ }
4811
+ return path ? `${host}/${path}` : host;
4812
+ }
4813
+ function resolveCommitRefFromEnv(env) {
4814
+ const explicit = read(env, EXPLICIT_SHA_ENV);
4815
+ const platform = PLATFORM_ENVS.find(([sha]) => read(env, sha) !== null);
4816
+ if (!platform) {
4817
+ if (explicit === null) {
4818
+ return null;
4819
+ }
4820
+ return {
4821
+ sha: explicit,
4822
+ branch: null,
4823
+ dirty: null,
4824
+ remote: null,
4825
+ rootSha: null
4826
+ };
4827
+ }
4828
+ const [shaEnv, branchEnv, readRemote] = platform;
4829
+ return {
4830
+ sha: explicit ?? read(env, shaEnv),
4831
+ branch: read(env, branchEnv),
4832
+ dirty: null,
4833
+ remote: readRemote(env),
4834
+ rootSha: null
4835
+ };
4836
+ }
4837
+ async function resolveCommitRefFromGit(cwd) {
4838
+ const git = await gitRunner({
4839
+ timeoutMs: GIT_TIMEOUT_MS,
4840
+ maxBuffer: GIT_MAX_BUFFER,
4841
+ keepProcessAlive: false
4842
+ });
4843
+ if (!git) {
4844
+ return null;
4845
+ }
4846
+ const run = async (args) => (await git(cwd, args))?.trim() ?? null;
4847
+ const sha = await run(["rev-parse", "HEAD"]);
4848
+ if (!sha) {
4849
+ return null;
4850
+ }
4851
+ const [branch, status, remote, roots] = await Promise.all([
4852
+ run(["symbolic-ref", "--short", "-q", "HEAD"]),
4853
+ run(["status", "--porcelain"]),
4854
+ run(["remote", "get-url", "origin"]),
4855
+ run(["rev-list", "--max-parents=0", "HEAD"])
4856
+ ]);
4857
+ return {
4858
+ sha,
4859
+ branch: branch || null,
4860
+ dirty: status === null ? null : status.length > 0,
4861
+ remote: normalizeRemote(remote),
4862
+ rootSha: roots ? roots.split(/\s+/).sort()[0] ?? null : null
4863
+ };
4864
+ }
4865
+ function commitRefWire(ref2) {
4866
+ return {
4867
+ sha: ref2.sha,
4868
+ branch: ref2.branch,
4869
+ dirty: ref2.dirty,
4870
+ remote: ref2.remote,
4871
+ root_sha: ref2.rootSha
4872
+ };
4873
+ }
4874
+ var resolved = false;
4875
+ var ref = null;
4876
+ var gitStarted = false;
4877
+ var settled = Promise.resolve();
4878
+ function startCommitRefResolution() {
4879
+ if (resolved || gitStarted) {
4880
+ return;
4881
+ }
4882
+ if (read(readEnv, DISABLE_ENV) !== null) {
4883
+ resolved = true;
4884
+ return;
4885
+ }
4886
+ const fromEnv = resolveCommitRefFromEnv(readEnv);
4887
+ if (fromEnv) {
4888
+ ref = fromEnv;
4889
+ resolved = true;
4890
+ return;
4891
+ }
4892
+ gitStarted = true;
4893
+ if (typeof process === "undefined") {
4894
+ resolved = true;
4895
+ return;
4896
+ }
4897
+ let cwd;
4898
+ try {
4899
+ cwd = process.cwd?.() ?? ".";
4900
+ } catch {
4901
+ resolved = true;
4902
+ return;
4903
+ }
4904
+ settled = resolveCommitRefFromGit(cwd).then(
4905
+ (fromGit) => {
4906
+ if (!resolved) {
4907
+ ref = fromGit;
4908
+ resolved = true;
4909
+ }
4910
+ },
4911
+ () => {
4912
+ resolved = true;
4913
+ }
4914
+ );
4915
+ }
4916
+ function currentCommitRef() {
4917
+ startCommitRefResolution();
4918
+ return ref;
4919
+ }
4920
+
4571
4921
  // src/client.ts
4572
4922
  init_constants();
4573
4923
 
@@ -5060,11 +5410,11 @@ var BitfabLangGraphCallbackHandler = class {
5060
5410
  this.invocations.set(invocation.rootRunId, invocation);
5061
5411
  }
5062
5412
  if (!willHide) {
5063
- let resolved = parentSpan;
5064
- while (resolved?.hidden === true) {
5065
- resolved = resolved.parentId ? this.runToSpan.get(resolved.parentId) : void 0;
5413
+ let resolved2 = parentSpan;
5414
+ while (resolved2?.hidden === true) {
5415
+ resolved2 = resolved2.parentId ? this.runToSpan.get(resolved2.parentId) : void 0;
5066
5416
  }
5067
- effectiveParentId = resolved ? resolved.spanId : invocation.activeContext?.spanId ?? null;
5417
+ effectiveParentId = resolved2 ? resolved2.spanId : invocation.activeContext?.spanId ?? null;
5068
5418
  } else {
5069
5419
  effectiveParentId = parentRunId ?? null;
5070
5420
  }
@@ -6564,6 +6914,7 @@ var Bitfab = class {
6564
6914
  validateDbSnapshotConfig(config.dbSnapshot);
6565
6915
  }
6566
6916
  this.dbSnapshot = config.dbSnapshot;
6917
+ startCommitRefResolution();
6567
6918
  this.httpClient = new HttpClient({
6568
6919
  apiKey: () => this.resolveApiKey(),
6569
6920
  serviceUrl: this.serviceUrl,
@@ -6734,11 +7085,15 @@ var Bitfab = class {
6734
7085
  type: options.type ?? "custom",
6735
7086
  surface: "opt-out"
6736
7087
  };
6737
- const tracedRoot = this.withSpan(
7088
+ const rootName = options.name ?? name;
7089
+ const buildTracedRoot = (spanOptions) => this.withSpan(
6738
7090
  traceFunctionKey,
6739
- rootOptions,
7091
+ spanOptions,
6740
7092
  function(...args) {
6741
- const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
7093
+ const capturePolicy = getAutoTraceCapturePolicy(
7094
+ self,
7095
+ traceFunctionKey
7096
+ );
6742
7097
  self.refreshAutoTraceCapturePolicy(traceFunctionKey);
6743
7098
  let spansUsed = 0;
6744
7099
  let truncated = false;
@@ -6759,19 +7114,54 @@ var Bitfab = class {
6759
7114
  `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
6760
7115
  );
6761
7116
  };
7117
+ const spanStackOf = (entry) => entry.spanStack;
7118
+ const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
7119
+ const runInside = () => runWithAutoTraceEntry(
7120
+ entry,
7121
+ {
7122
+ context: autoTraceContext,
7123
+ depth: entry.depth + 1,
7124
+ spanStack: getSpanStack()
7125
+ },
7126
+ invokeFn
7127
+ );
7128
+ return runWithSpanStack(spanStackOf(entry), () => {
7129
+ if (isAsync) {
7130
+ const tracedAsyncChild = self.withSpan(
7131
+ traceFunctionKey,
7132
+ childOptions,
7133
+ async (..._inputs) => await runInside()
7134
+ );
7135
+ return tracedAsyncChild(...inputs);
7136
+ }
7137
+ const tracedChild = self.withSpan(
7138
+ traceFunctionKey,
7139
+ childOptions,
7140
+ (..._inputs) => runInside()
7141
+ );
7142
+ return tracedChild(...inputs);
7143
+ });
7144
+ };
7145
+ const overBudget = (entry) => {
7146
+ if (entry.depth < maxDepth && spansUsed < maxSpans) {
7147
+ return false;
7148
+ }
7149
+ runWithSpanStack(spanStackOf(entry), warnTruncated);
7150
+ return true;
7151
+ };
6762
7152
  const autoTraceContext = {
6763
- invoke(definition, inputs, invokeFn, depth, nodeConfiguration) {
7153
+ traceFunctionKey,
7154
+ invoke(definition, inputs, invokeFn, entry, nodeConfiguration) {
6764
7155
  const nameParts = definition.name.split(".");
6765
7156
  const simpleName = nameParts[nameParts.length - 1];
6766
- const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
7157
+ const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : clearAutoTraceNodeConfiguration(invokeFn);
6767
7158
  if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || nodeConfiguration === void 0 && definition.wrapper === true && !includeWrappers) {
6768
7159
  return invokeWithoutNode();
6769
7160
  }
6770
7161
  if (nodeConfiguration?.capture === false) {
6771
- return runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
7162
+ return clearAutoTraceNodeConfiguration(invokeFn);
6772
7163
  }
6773
- if (depth >= maxDepth || spansUsed >= maxSpans) {
6774
- warnTruncated();
7164
+ if (overBudget(entry)) {
6775
7165
  return invokeWithoutNode();
6776
7166
  }
6777
7167
  spansUsed += 1;
@@ -6794,34 +7184,81 @@ var Bitfab = class {
6794
7184
  finalize: nodeConfiguration.finalize
6795
7185
  }
6796
7186
  };
6797
- const invokeWithAutoTraceContext = () => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1);
6798
- if (definition.async === true) {
6799
- const tracedAsyncChild = self.withSpan(
6800
- traceFunctionKey,
6801
- childOptions,
6802
- async (..._inputs) => await invokeWithAutoTraceContext()
6803
- );
6804
- return tracedAsyncChild(...inputs);
6805
- }
6806
- const tracedChild = self.withSpan(
6807
- traceFunctionKey,
7187
+ return openChild(
7188
+ entry,
6808
7189
  childOptions,
6809
- (..._inputs) => invokeWithAutoTraceContext()
7190
+ inputs,
7191
+ definition.async === true,
7192
+ invokeFn
6810
7193
  );
6811
- return tracedChild(...inputs);
7194
+ },
7195
+ invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
7196
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
7197
+ return invokeFn();
7198
+ }
7199
+ spansUsed += 1;
7200
+ const childOptions = {
7201
+ name: nestedName,
7202
+ type: "function",
7203
+ captureWhen: "nested",
7204
+ surface: "opt-out",
7205
+ captureContent: true,
7206
+ ...link !== void 0 && { nestedTrace: link }
7207
+ };
7208
+ return openChild(entry, childOptions, inputs, false, invokeFn);
6812
7209
  }
6813
7210
  };
6814
7211
  return runWithAutoTraceRootContext(
6815
7212
  autoTraceContext,
7213
+ getSpanStack(),
6816
7214
  () => fn.apply(this, args)
6817
7215
  );
6818
7216
  }
6819
7217
  );
7218
+ const tracedRoot = buildTracedRoot(rootOptions);
6820
7219
  const autoTraceRoot = function(...args) {
6821
7220
  if (!self.shouldRecord()) {
6822
7221
  return fn.apply(this, args);
6823
7222
  }
6824
- return tracedRoot.apply(this, args);
7223
+ const enclosing = currentAutoTraceEntries();
7224
+ if (enclosing.length === 0) {
7225
+ return tracedRoot.apply(this, args);
7226
+ }
7227
+ const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
7228
+ return invokeThroughAutoTraceEntries(
7229
+ enclosing,
7230
+ (entry, next) => entry.context.invokeNestedRoot(
7231
+ rootName,
7232
+ name,
7233
+ args,
7234
+ next,
7235
+ entry,
7236
+ link
7237
+ ),
7238
+ () => {
7239
+ if (link === void 0) {
7240
+ return fn.apply(this, args);
7241
+ }
7242
+ const innermost = enclosing[enclosing.length - 1];
7243
+ const innermostNow = currentAutoTraceEntries().find(
7244
+ (entry) => entry.context === innermost.context
7245
+ ) ?? innermost;
7246
+ const innermostStack = innermostNow.spanStack;
7247
+ const copy = innermostStack[innermostStack.length - 1];
7248
+ const detachedRoot = buildTracedRoot({
7249
+ ...rootOptions,
7250
+ ...copy !== void 0 && {
7251
+ enclosingTrace: {
7252
+ traceId: copy.traceId,
7253
+ spanId: copy.spanId,
7254
+ traceFunctionKey: innermost.context.traceFunctionKey,
7255
+ link
7256
+ }
7257
+ }
7258
+ });
7259
+ return runWithSpanStack([], () => detachedRoot.apply(this, args));
7260
+ }
7261
+ );
6825
7262
  };
6826
7263
  Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
6827
7264
  value: traceFunctionKey
@@ -7410,6 +7847,10 @@ var Bitfab = class {
7410
7847
  const spanId = randomUuid();
7411
7848
  const parentSpanId = parentContext?.spanId ?? null;
7412
7849
  const isRootSpan = parentSpanId === null;
7850
+ if (options.enclosingTrace !== void 0) {
7851
+ options.enclosingTrace.link.traceId = traceId;
7852
+ options.enclosingTrace.link.rootSpanId = spanId;
7853
+ }
7413
7854
  const requestedSurface = options.surface ?? DEFAULT_SURFACE;
7414
7855
  const surface = resolveSurface(requestedSurface, parentContext?.surface);
7415
7856
  assertSurfacesCompatible(
@@ -7459,7 +7900,9 @@ var Bitfab = class {
7459
7900
  spanType: options.type ?? "custom",
7460
7901
  functionId: options.functionId,
7461
7902
  captureContent: options.captureContent ?? true,
7462
- autoTraceDefinition: options.autoTraceDefinition
7903
+ autoTraceDefinition: options.autoTraceDefinition,
7904
+ nestedTrace: options.nestedTrace,
7905
+ enclosingTrace: options.enclosingTrace
7463
7906
  };
7464
7907
  const sendSpan = async (params) => {
7465
7908
  const replayCtx = getReplayContext();
@@ -7657,15 +8100,15 @@ var Bitfab = class {
7657
8100
  );
7658
8101
  }
7659
8102
  return runWithSpanStack(newStack, async () => {
7660
- const resolved = await resolution;
7661
- if (resolved.matched) {
8103
+ const resolved2 = await resolution;
8104
+ if (resolved2.matched) {
7662
8105
  void sendSpan({
7663
- result: resolved.output,
8106
+ result: resolved2.output,
7664
8107
  mocked: true,
7665
8108
  mockTarget: "output",
7666
8109
  mockSource: "override"
7667
8110
  });
7668
- return resolved.output;
8111
+ return resolved2.output;
7669
8112
  }
7670
8113
  if (shouldMockWithBaseStrategy && !mockSpan) {
7671
8114
  throw new BitfabError(
@@ -7901,6 +8344,10 @@ var Bitfab = class {
7901
8344
  if (params.dbSnapshotRef) {
7902
8345
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7903
8346
  }
8347
+ const commitRef = currentCommitRef();
8348
+ if (commitRef) {
8349
+ rawTrace.commit_ref = commitRefWire(commitRef);
8350
+ }
7904
8351
  if (params.ingestionType) {
7905
8352
  rawTrace.ingestion_type = params.ingestionType;
7906
8353
  }
@@ -7965,6 +8412,16 @@ var Bitfab = class {
7965
8412
  function_line: params.autoTraceDefinition.line,
7966
8413
  function_column: params.autoTraceDefinition.column
7967
8414
  },
8415
+ ...params.nestedTrace?.traceId !== void 0 && {
8416
+ nested_trace_id: params.nestedTrace.traceId,
8417
+ nested_trace_function_key: params.nestedTrace.traceFunctionKey,
8418
+ nested_root_span_id: params.nestedTrace.rootSpanId
8419
+ },
8420
+ ...params.enclosingTrace !== void 0 && {
8421
+ enclosing_trace_id: params.enclosingTrace.traceId,
8422
+ enclosing_trace_function_key: params.enclosingTrace.traceFunctionKey,
8423
+ enclosing_span_id: params.enclosingTrace.spanId
8424
+ },
7968
8425
  ...serializedInputs !== void 0 && {
7969
8426
  input: serializedInputs.json,
7970
8427
  ...serializedInputs.meta !== void 0 && {