bitfab 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-HKTODDFP.js → chunk-5KVK733P.js} +3 -3
  8. package/dist/chunk-5KVK733P.js.map +1 -0
  9. package/dist/{chunk-U2D7ACC4.js → chunk-DRTHTSHO.js} +110 -13
  10. package/dist/chunk-DRTHTSHO.js.map +1 -0
  11. package/dist/{chunk-ZUD7OFYB.js → chunk-E5BLYL5X.js} +81 -34
  12. package/dist/chunk-E5BLYL5X.js.map +1 -0
  13. package/dist/{chunk-IG3CPSRQ.js → chunk-GJKU7VWG.js} +2 -2
  14. package/dist/{chunk-IG3CPSRQ.js.map → chunk-GJKU7VWG.js.map} +1 -1
  15. package/dist/{chunk-34B7PVAM.js → chunk-NXC6NYIY.js} +3 -2
  16. package/dist/{chunk-34B7PVAM.js.map → chunk-NXC6NYIY.js.map} +1 -1
  17. package/dist/{chunk-AUROMI67.js → chunk-P26KVTI5.js} +371 -46
  18. package/dist/chunk-P26KVTI5.js.map +1 -0
  19. package/dist/{http-F3AXLOJT.js → http-ER2NMEKI.js} +2 -2
  20. package/dist/{http-RFNQ7LSU.js → http-MGES3ZVX.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-ZOTYMBMD.js → replay-5XES2LBL.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-AUROMI67.js.map +0 -1
  36. package/dist/chunk-HKTODDFP.js.map +0 -1
  37. package/dist/chunk-U2D7ACC4.js.map +0 -1
  38. package/dist/chunk-ZUD7OFYB.js.map +0 -1
  39. /package/dist/{http-F3AXLOJT.js.map → http-ER2NMEKI.js.map} +0 -0
  40. /package/dist/{http-RFNQ7LSU.js.map → http-MGES3ZVX.js.map} +0 -0
  41. /package/dist/{replay-ZOTYMBMD.js.map → replay-5XES2LBL.js.map} +0 -0
package/dist/node.cjs CHANGED
@@ -97,7 +97,7 @@ var __version__, __packageName__;
97
97
  var init_version_generated = __esm({
98
98
  "src/version.generated.ts"() {
99
99
  "use strict";
100
- __version__ = "0.52.4";
100
+ __version__ = "0.52.6";
101
101
  __packageName__ = "bitfab";
102
102
  }
103
103
  });
@@ -1137,7 +1137,7 @@ var init_otel = __esm({
1137
1137
  if (this.onDelivered === void 0) {
1138
1138
  return;
1139
1139
  }
1140
- const refs = spans.map((span) => span.ref).filter((ref) => ref !== void 0);
1140
+ const refs = spans.map((span) => span.ref).filter((ref2) => ref2 !== void 0);
1141
1141
  if (refs.length === 0) {
1142
1142
  return;
1143
1143
  }
@@ -1394,9 +1394,9 @@ function parseRetryAfterMs(header) {
1394
1394
  }
1395
1395
  return Math.max(0, at - Date.now());
1396
1396
  }
1397
- function carrierMeta(operation, payload, ref) {
1397
+ function carrierMeta(operation, payload, ref2) {
1398
1398
  return {
1399
- ref,
1399
+ ref: ref2,
1400
1400
  name: carrierName(operation, payload),
1401
1401
  startTime: payloadTimestamp(payload, "started_at"),
1402
1402
  endTime: payloadTimestamp(payload, "ended_at"),
@@ -1641,22 +1641,22 @@ var init_http = __esm({
1641
1641
  return reports;
1642
1642
  }
1643
1643
  /** Build a carrier's meta and record what it adds to its trace's expected set. */
1644
- recordedMeta(operation, payload, ref) {
1645
- this.recordSubmittedCarrier(ref);
1646
- return carrierMeta(operation, payload, ref);
1644
+ recordedMeta(operation, payload, ref2) {
1645
+ this.recordSubmittedCarrier(ref2);
1646
+ return carrierMeta(operation, payload, ref2);
1647
1647
  }
1648
- recordSubmittedCarrier(ref) {
1649
- if (ref === void 0) {
1648
+ recordSubmittedCarrier(ref2) {
1649
+ if (ref2 === void 0) {
1650
1650
  return;
1651
1651
  }
1652
- const delivery = this.traceDeliveries.get(ref.traceId);
1652
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1653
1653
  if (delivery === void 0) {
1654
1654
  return;
1655
1655
  }
1656
- if (ref.spanId === void 0) {
1656
+ if (ref2.spanId === void 0) {
1657
1657
  delivery.closed = true;
1658
1658
  } else {
1659
- delivery.submittedSpanIds.add(ref.spanId);
1659
+ delivery.submittedSpanIds.add(ref2.spanId);
1660
1660
  }
1661
1661
  }
1662
1662
  /**
@@ -1682,15 +1682,15 @@ var init_http = __esm({
1682
1682
  }
1683
1683
  }
1684
1684
  recordDeliveredCarriers(refs) {
1685
- for (const ref of refs) {
1686
- const delivery = this.traceDeliveries.get(ref.traceId);
1685
+ for (const ref2 of refs) {
1686
+ const delivery = this.traceDeliveries.get(ref2.traceId);
1687
1687
  if (delivery === void 0) {
1688
1688
  continue;
1689
1689
  }
1690
- if (ref.spanId === void 0) {
1690
+ if (ref2.spanId === void 0) {
1691
1691
  delivery.closingAcked = true;
1692
1692
  } else {
1693
- delivery.ackedSpanIds.add(ref.spanId);
1693
+ delivery.ackedSpanIds.add(ref2.spanId);
1694
1694
  }
1695
1695
  }
1696
1696
  }
@@ -1720,9 +1720,9 @@ var init_http = __esm({
1720
1720
  */
1721
1721
  async waitForPendingRequests(timeoutMs = DEFAULT_LIFECYCLE_TIMEOUT_MS2) {
1722
1722
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1723
- const settled = await this.settleDeferredWork(timeoutMs);
1723
+ const settled2 = await this.settleDeferredWork(timeoutMs);
1724
1724
  const flushed = await this.traceTransport?.flush(Math.max(0, deadline - Date.now())) ?? true;
1725
- return settled && flushed;
1725
+ return settled2 && flushed;
1726
1726
  }
1727
1727
  /**
1728
1728
  * Flush and permanently close this client's tracing transport. Idempotent:
@@ -1735,14 +1735,14 @@ var init_http = __esm({
1735
1735
  }
1736
1736
  const deadline = Date.now() + Math.max(timeoutMs, 0);
1737
1737
  this.closing = (async () => {
1738
- const settled = await this.settleDeferredWork(
1738
+ const settled2 = await this.settleDeferredWork(
1739
1739
  Math.max(0, deadline - Date.now())
1740
1740
  );
1741
1741
  this.closed = true;
1742
1742
  const transport = this.traceTransport;
1743
1743
  this.traceTransport = void 0;
1744
1744
  const shutdownOk = await transport?.shutdown(Math.max(0, deadline - Date.now())) ?? true;
1745
- return settled && shutdownOk;
1745
+ return settled2 && shutdownOk;
1746
1746
  })();
1747
1747
  return this.closing;
1748
1748
  }
@@ -2353,6 +2353,112 @@ var init_randomUuid = __esm({
2353
2353
  }
2354
2354
  });
2355
2355
 
2356
+ // src/gitCommand.ts
2357
+ function isUnrefable(value) {
2358
+ return typeof value === "object" && value !== null && "unref" in value && typeof value.unref === "function";
2359
+ }
2360
+ function unrefStream(stream) {
2361
+ if (isUnrefable(stream)) {
2362
+ stream.unref();
2363
+ }
2364
+ }
2365
+ function terminate(child) {
2366
+ if (child.pid && process.platform !== "win32") {
2367
+ try {
2368
+ process.kill(-child.pid, "SIGTERM");
2369
+ return;
2370
+ } catch {
2371
+ child.kill("SIGTERM");
2372
+ return;
2373
+ }
2374
+ }
2375
+ child.kill("SIGTERM");
2376
+ }
2377
+ async function gitRunner(options) {
2378
+ let spawn;
2379
+ try {
2380
+ ;
2381
+ ({ spawn } = await import("child_process"));
2382
+ } catch {
2383
+ return null;
2384
+ }
2385
+ return (dir, args) => new Promise((resolve) => {
2386
+ let child;
2387
+ try {
2388
+ child = spawn("git", args, {
2389
+ cwd: dir,
2390
+ detached: process.platform !== "win32",
2391
+ stdio: ["ignore", "pipe", "pipe"]
2392
+ });
2393
+ } catch {
2394
+ resolve(null);
2395
+ return;
2396
+ }
2397
+ const chunks = [];
2398
+ let size = 0;
2399
+ let overflow = false;
2400
+ let exitCode = null;
2401
+ let done = false;
2402
+ const timers = [];
2403
+ const schedule = (callback, ms) => {
2404
+ const timer = setTimeout(callback, ms);
2405
+ if (!options.keepProcessAlive) {
2406
+ timer.unref();
2407
+ }
2408
+ timers.push(timer);
2409
+ };
2410
+ const finish = () => {
2411
+ if (done) {
2412
+ return;
2413
+ }
2414
+ done = true;
2415
+ for (const timer of timers) {
2416
+ clearTimeout(timer);
2417
+ }
2418
+ child.stdout?.destroy();
2419
+ child.stderr?.destroy();
2420
+ resolve(
2421
+ exitCode === 0 && !overflow ? Buffer.concat(chunks).toString("utf8") : null
2422
+ );
2423
+ };
2424
+ child.stdout?.on("data", (chunk) => {
2425
+ size += chunk.length;
2426
+ if (size > options.maxBuffer) {
2427
+ overflow = true;
2428
+ terminate(child);
2429
+ return;
2430
+ }
2431
+ chunks.push(chunk);
2432
+ });
2433
+ child.stderr?.resume();
2434
+ child.on("error", () => {
2435
+ exitCode = null;
2436
+ finish();
2437
+ });
2438
+ child.on("exit", (code) => {
2439
+ exitCode = code;
2440
+ schedule(finish, EXIT_GRACE_MS);
2441
+ });
2442
+ child.on("close", (code) => {
2443
+ exitCode = code ?? exitCode;
2444
+ finish();
2445
+ });
2446
+ schedule(() => terminate(child), options.timeoutMs);
2447
+ if (!options.keepProcessAlive) {
2448
+ child.unref();
2449
+ unrefStream(child.stdout);
2450
+ unrefStream(child.stderr);
2451
+ }
2452
+ });
2453
+ }
2454
+ var EXIT_GRACE_MS;
2455
+ var init_gitCommand = __esm({
2456
+ "src/gitCommand.ts"() {
2457
+ "use strict";
2458
+ EXIT_GRACE_MS = 500;
2459
+ }
2460
+ });
2461
+
2356
2462
  // src/mockOverride.ts
2357
2463
  function resolveMockValue(value, ctx) {
2358
2464
  return typeof value === "function" ? value(ctx) : value;
@@ -2409,37 +2515,33 @@ async function readCodeChangeFile() {
2409
2515
  }
2410
2516
  }
2411
2517
  async function captureCodeChangeFromGit(cwd, label) {
2412
- let execFile;
2413
2518
  let readFile;
2414
2519
  try {
2415
2520
  ;
2416
- ({ execFile } = await import("child_process"));
2417
2521
  ({ readFile } = await import("fs/promises"));
2418
2522
  } catch {
2419
2523
  return null;
2420
2524
  }
2421
- const git = (dir, args) => new Promise((resolve) => {
2422
- execFile(
2423
- "git",
2424
- args,
2425
- // 30s timeout so a hung git (e.g. a network-touching ref op) can't
2426
- // block the whole replay indefinitely.
2427
- { cwd: dir, maxBuffer: 64 * 1024 * 1024, timeout: 3e4 },
2428
- (err, stdout) => resolve(err ? null : stdout)
2429
- );
2525
+ const git = await gitRunner({
2526
+ timeoutMs: 3e4,
2527
+ maxBuffer: 64 * 1024 * 1024,
2528
+ keepProcessAlive: true
2430
2529
  });
2530
+ if (!git) {
2531
+ return null;
2532
+ }
2431
2533
  try {
2432
2534
  const root = (await git(cwd, ["rev-parse", "--show-toplevel"]))?.trim();
2433
2535
  if (!root) {
2434
2536
  return null;
2435
2537
  }
2436
- const resolved = await resolveBase(git, root);
2437
- if (!resolved) {
2538
+ const resolved2 = await resolveBase(git, root);
2539
+ if (!resolved2) {
2438
2540
  return null;
2439
2541
  }
2440
- const { base, fromTrunk } = resolved;
2441
- const blobBytes = async (ref, path) => {
2442
- const out = await git(root, ["cat-file", "-s", `${ref}:${path}`]);
2542
+ const { base, fromTrunk } = resolved2;
2543
+ const blobBytes = async (ref2, path) => {
2544
+ const out = await git(root, ["cat-file", "-s", `${ref2}:${path}`]);
2443
2545
  const n = out ? Number.parseInt(out.trim(), 10) : Number.NaN;
2444
2546
  return Number.isFinite(n) ? n : 0;
2445
2547
  };
@@ -2531,8 +2633,8 @@ async function resolveBase(git, root) {
2531
2633
  }
2532
2634
  return await refExists(git, root, "HEAD") ? { base: "HEAD", fromTrunk: false } : null;
2533
2635
  }
2534
- async function refExists(git, root, ref) {
2535
- return await git(root, ["rev-parse", "--verify", `${ref}^{object}`]) !== null;
2636
+ async function refExists(git, root, ref2) {
2637
+ return await git(root, ["rev-parse", "--verify", `${ref2}^{object}`]) !== null;
2536
2638
  }
2537
2639
  async function readWorkingFile(readFile, root, path) {
2538
2640
  try {
@@ -2567,6 +2669,7 @@ var MAX_FILES, MAX_FILE_BYTES, MAX_TOTAL_BYTES, TRUNK_CANDIDATES, NUL;
2567
2669
  var init_codeChange = __esm({
2568
2670
  "src/codeChange.ts"() {
2569
2671
  "use strict";
2672
+ init_gitCommand();
2570
2673
  MAX_FILES = 60;
2571
2674
  MAX_FILE_BYTES = 5e5;
2572
2675
  MAX_TOTAL_BYTES = 2e6;
@@ -2771,9 +2874,9 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2771
2874
  const originalSpanId = serverItem.originalSpanId ?? serverItem.sourceSpanId;
2772
2875
  try {
2773
2876
  if (includeDbBranchLease && !lease && !leaseError) {
2774
- let resolved;
2877
+ let resolved2;
2775
2878
  try {
2776
- resolved = await httpClient.resolveDbBranchLease(
2879
+ resolved2 = await httpClient.resolveDbBranchLease(
2777
2880
  testRunId,
2778
2881
  originalTraceId,
2779
2882
  dbBranchSettings,
@@ -2787,10 +2890,10 @@ async function processItem(httpClient, serverItem, fn, testRunId, mockStrategy,
2787
2890
  cause
2788
2891
  );
2789
2892
  }
2790
- lease = resolved.lease ?? void 0;
2791
- leaseError = resolved.leaseError ?? void 0;
2792
- dbSnapshotRef = resolved.dbSnapshotRef ?? dbSnapshotRef;
2793
- dbBranchTimings = resolved.timings ?? dbBranchTimings;
2893
+ lease = resolved2.lease ?? void 0;
2894
+ leaseError = resolved2.leaseError ?? void 0;
2895
+ dbSnapshotRef = resolved2.dbSnapshotRef ?? dbSnapshotRef;
2896
+ dbBranchTimings = resolved2.timings ?? dbBranchTimings;
2794
2897
  }
2795
2898
  if (leaseError) {
2796
2899
  throw new DbBranchReplayError(
@@ -4118,19 +4221,18 @@ init_asyncStorage();
4118
4221
  // src/autoTrace.ts
4119
4222
  init_asyncStorage();
4120
4223
  var autoTraceGlobal = globalThis;
4121
- var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV3 ?? {
4224
+ var autoTraceState = autoTraceGlobal.__bitfabAutoTraceStateV4 ?? {
4122
4225
  storage: null,
4123
4226
  browserScope: void 0,
4124
4227
  capturePolicies: /* @__PURE__ */ new WeakMap(),
4125
4228
  activeRoots: 0
4126
4229
  };
4127
- autoTraceGlobal.__bitfabAutoTraceStateV3 = autoTraceState;
4230
+ autoTraceGlobal.__bitfabAutoTraceStateV4 = autoTraceState;
4128
4231
  function initializeAutoTraceStorage() {
4129
4232
  autoTraceState.storage ?? (autoTraceState.storage = createAsyncLocalStorage());
4130
4233
  }
4131
- function runWithAutoTraceContext(context, fn, depth = 0) {
4234
+ function runWithAutoTraceScope(scope, fn) {
4132
4235
  initializeAutoTraceStorage();
4133
- const scope = { context, depth };
4134
4236
  if (autoTraceState.storage) {
4135
4237
  return autoTraceState.storage.run(scope, fn);
4136
4238
  }
@@ -4142,41 +4244,65 @@ function runWithAutoTraceContext(context, fn, depth = 0) {
4142
4244
  autoTraceState.browserScope = previous;
4143
4245
  }
4144
4246
  }
4247
+ function currentAutoTraceEntries() {
4248
+ return currentAutoTraceScope()?.entries ?? [];
4249
+ }
4250
+ function replaceEntry(entries, previous, updated) {
4251
+ return entries.map((entry) => entry === previous ? updated : entry);
4252
+ }
4253
+ function runWithAutoTraceEntry(previous, updated, fn) {
4254
+ const result = runWithAutoTraceScope(
4255
+ { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },
4256
+ fn
4257
+ );
4258
+ if (isAutoTraceAsyncGenerator(result)) {
4259
+ return wrapAutoTraceEntryAsyncGenerator(previous, updated, result);
4260
+ }
4261
+ return result;
4262
+ }
4263
+ function wrapAutoTraceEntryAsyncGenerator(previous, updated, source) {
4264
+ const step = (method, value) => runWithAutoTraceScope(
4265
+ { entries: replaceEntry(currentAutoTraceEntries(), previous, updated) },
4266
+ () => source[method](value)
4267
+ );
4268
+ const wrapped = {
4269
+ next: (value) => step("next", value),
4270
+ return: (value) => step("return", value),
4271
+ throw: (error) => step("throw", error),
4272
+ [Symbol.asyncIterator]: () => wrapped
4273
+ };
4274
+ return wrapped;
4275
+ }
4276
+ function clearAutoTraceNodeConfiguration(fn) {
4277
+ return runWithAutoTraceScope({ entries: currentAutoTraceEntries() }, fn);
4278
+ }
4145
4279
  function runWithAutoTraceNodeConfiguration(nodeConfiguration, fn) {
4146
4280
  const scope = currentAutoTraceScope();
4147
- if (!scope) {
4281
+ if (!scope || scope.entries.length === 0) {
4148
4282
  return fn();
4149
4283
  }
4150
- const configuredScope = { ...scope, nodeConfiguration };
4151
- let result;
4152
- if (autoTraceState.storage) {
4153
- result = autoTraceState.storage.run(configuredScope, fn);
4154
- } else {
4155
- const previous = autoTraceState.browserScope;
4156
- autoTraceState.browserScope = configuredScope;
4157
- try {
4158
- result = fn();
4159
- } finally {
4160
- autoTraceState.browserScope = previous;
4161
- }
4162
- }
4284
+ const result = runWithAutoTraceScope({ ...scope, nodeConfiguration }, fn);
4163
4285
  if (isAutoTraceAsyncGenerator(result)) {
4164
4286
  return wrapAutoTraceNodeAsyncGenerator(nodeConfiguration, result);
4165
4287
  }
4166
4288
  return result;
4167
4289
  }
4168
- function runWithAutoTraceRootContext(context, fn) {
4290
+ function runWithAutoTraceRootContext(context, spanStack, fn) {
4169
4291
  autoTraceState.activeRoots += 1;
4292
+ const entries = [
4293
+ ...currentAutoTraceEntries(),
4294
+ { context, depth: 0, spanStack }
4295
+ ];
4170
4296
  let result;
4171
4297
  try {
4172
- result = runWithAutoTraceContext(context, fn);
4298
+ result = runWithAutoTraceScope({ entries }, fn);
4173
4299
  } catch (error) {
4174
4300
  autoTraceState.activeRoots -= 1;
4175
4301
  throw error;
4176
4302
  }
4177
4303
  if (isAutoTraceAsyncGenerator(result)) {
4178
4304
  autoTraceState.activeRoots -= 1;
4179
- return wrapAutoTraceAsyncGenerator(context, result);
4305
+ return wrapAutoTraceAsyncGenerator(context, spanStack, result);
4180
4306
  }
4181
4307
  if (result instanceof Promise) {
4182
4308
  return result.finally(() => {
@@ -4186,6 +4312,15 @@ function runWithAutoTraceRootContext(context, fn) {
4186
4312
  autoTraceState.activeRoots -= 1;
4187
4313
  return result;
4188
4314
  }
4315
+ function invokeThroughAutoTraceEntries(entries, step, fn) {
4316
+ let run = fn;
4317
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
4318
+ const entry = entries[index];
4319
+ const next = run;
4320
+ run = () => step(entry, next);
4321
+ }
4322
+ return run();
4323
+ }
4189
4324
  function isAutoTraceAsyncGenerator(value) {
4190
4325
  if (value === null || typeof value !== "object") {
4191
4326
  return false;
@@ -4193,8 +4328,8 @@ function isAutoTraceAsyncGenerator(value) {
4193
4328
  const candidate = value;
4194
4329
  return typeof candidate.next === "function" && typeof candidate.return === "function" && typeof candidate.throw === "function" && typeof candidate[Symbol.asyncIterator] === "function";
4195
4330
  }
4196
- function wrapAutoTraceAsyncGenerator(context, source) {
4197
- const step = (method, value) => runWithAutoTraceRootContext(context, () => source[method](value));
4331
+ function wrapAutoTraceAsyncGenerator(context, spanStack, source) {
4332
+ const step = (method, value) => runWithAutoTraceRootContext(context, spanStack, () => source[method](value));
4198
4333
  const wrapped = {
4199
4334
  next: (value) => step("next", value),
4200
4335
  return: (value) => step("return", value),
@@ -4220,7 +4355,7 @@ function __bitfabAutoTraceActive() {
4220
4355
  if (autoTraceState.activeRoots === 0) {
4221
4356
  return false;
4222
4357
  }
4223
- return currentAutoTraceScope() !== void 0;
4358
+ return currentAutoTraceEntries().length > 0;
4224
4359
  }
4225
4360
  function currentAutoTraceScope() {
4226
4361
  initializeAutoTraceStorage();
@@ -4573,24 +4708,239 @@ function mixedTracingError(enteredApi, entered, enclosing, traceFunctionKey) {
4573
4708
  `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]}`
4574
4709
  );
4575
4710
  }
4576
- function assertSurfacesCompatible(requested, resolved, parentSurface, traceFunctionKey) {
4711
+ function assertSurfacesCompatible(requested, resolved2, parentSurface, traceFunctionKey) {
4577
4712
  if (requested === "inherit" || requested === "neutral") {
4578
4713
  return;
4579
4714
  }
4580
- if (resolved === void 0 || parentSurface === void 0) {
4715
+ if (resolved2 === void 0 || parentSurface === void 0) {
4581
4716
  return;
4582
4717
  }
4583
- if (parentSurface === resolved) {
4718
+ if (parentSurface === resolved2) {
4584
4719
  return;
4585
4720
  }
4586
4721
  throw mixedTracingError(
4587
- SURFACE_API[resolved],
4588
- resolved,
4722
+ SURFACE_API[resolved2],
4723
+ resolved2,
4589
4724
  parentSurface,
4590
4725
  traceFunctionKey
4591
4726
  );
4592
4727
  }
4593
4728
 
4729
+ // src/commitRef.ts
4730
+ init_gitCommand();
4731
+ init_readEnv();
4732
+ var EXPLICIT_SHA_ENV = "BITFAB_COMMIT_SHA";
4733
+ var DISABLE_ENV = "BITFAB_DISABLE_COMMIT_REF";
4734
+ var GIT_TIMEOUT_MS = 2e3;
4735
+ var GIT_MAX_BUFFER = 1024 * 1024;
4736
+ var VERCEL_PROVIDER_HOSTS = {
4737
+ github: "github.com",
4738
+ gitlab: "gitlab.com",
4739
+ bitbucket: "bitbucket.org"
4740
+ };
4741
+ function read(env, name) {
4742
+ if (name === null) {
4743
+ return null;
4744
+ }
4745
+ const value = env(name)?.trim();
4746
+ return value ? value : null;
4747
+ }
4748
+ function remoteFrom(...names) {
4749
+ return (env) => {
4750
+ const parts = names.map((name) => read(env, name));
4751
+ if (parts.some((part) => part === null)) {
4752
+ return null;
4753
+ }
4754
+ return normalizeRemote(parts.join("/"));
4755
+ };
4756
+ }
4757
+ function vercelRemote(env) {
4758
+ const provider = read(env, "VERCEL_GIT_PROVIDER")?.toLowerCase() ?? "";
4759
+ const host = VERCEL_PROVIDER_HOSTS[provider];
4760
+ const owner = read(env, "VERCEL_GIT_REPO_OWNER");
4761
+ const slug = read(env, "VERCEL_GIT_REPO_SLUG");
4762
+ if (!host || !owner || !slug) {
4763
+ return null;
4764
+ }
4765
+ return `${host}/${owner}/${slug}`;
4766
+ }
4767
+ function noRemote() {
4768
+ return null;
4769
+ }
4770
+ var PLATFORM_ENVS = [
4771
+ ["VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF", vercelRemote],
4772
+ [
4773
+ "GITHUB_SHA",
4774
+ "GITHUB_REF_NAME",
4775
+ remoteFrom("GITHUB_SERVER_URL", "GITHUB_REPOSITORY")
4776
+ ],
4777
+ ["RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH", noRemote],
4778
+ ["RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH", noRemote],
4779
+ ["SOURCE_VERSION", null, noRemote],
4780
+ ["CF_PAGES_COMMIT_SHA", "CF_PAGES_BRANCH", noRemote],
4781
+ ["CI_COMMIT_SHA", "CI_COMMIT_REF_NAME", remoteFrom("CI_REPOSITORY_URL")],
4782
+ [
4783
+ "BUILD_SOURCEVERSION",
4784
+ "BUILD_SOURCEBRANCHNAME",
4785
+ remoteFrom("BUILD_REPOSITORY_URI")
4786
+ ],
4787
+ ["CIRCLE_SHA1", "CIRCLE_BRANCH", remoteFrom("CIRCLE_REPOSITORY_URL")]
4788
+ ];
4789
+ var COMMIT_REF_ENV_NAMES = [
4790
+ EXPLICIT_SHA_ENV,
4791
+ DISABLE_ENV,
4792
+ ...PLATFORM_ENVS.flatMap(
4793
+ ([sha, branch]) => branch === null ? [sha] : [sha, branch]
4794
+ ),
4795
+ "GITHUB_SERVER_URL",
4796
+ "GITHUB_REPOSITORY",
4797
+ "CI_REPOSITORY_URL",
4798
+ "BUILD_REPOSITORY_URI",
4799
+ "CIRCLE_REPOSITORY_URL",
4800
+ "VERCEL_GIT_PROVIDER",
4801
+ "VERCEL_GIT_REPO_OWNER",
4802
+ "VERCEL_GIT_REPO_SLUG"
4803
+ ];
4804
+ function normalizeRemote(raw) {
4805
+ const value = raw?.trim();
4806
+ if (!value) {
4807
+ return null;
4808
+ }
4809
+ let host = "";
4810
+ let path = value;
4811
+ if (value.includes("://")) {
4812
+ try {
4813
+ const parsed = new URL(value);
4814
+ host = parsed.hostname;
4815
+ path = parsed.pathname;
4816
+ } catch {
4817
+ return null;
4818
+ }
4819
+ } else {
4820
+ const separator = value.indexOf(":");
4821
+ if (separator !== -1) {
4822
+ const head = value.slice(0, separator);
4823
+ host = head.slice(head.lastIndexOf("@") + 1);
4824
+ path = value.slice(separator + 1);
4825
+ }
4826
+ }
4827
+ path = path.replace(/^\/+|\/+$/g, "");
4828
+ if (path.endsWith(".git")) {
4829
+ path = path.slice(0, -".git".length).replace(/\/+$/, "");
4830
+ }
4831
+ if (!host) {
4832
+ return path || null;
4833
+ }
4834
+ return path ? `${host}/${path}` : host;
4835
+ }
4836
+ function resolveCommitRefFromEnv(env) {
4837
+ const explicit = read(env, EXPLICIT_SHA_ENV);
4838
+ const platform = PLATFORM_ENVS.find(([sha]) => read(env, sha) !== null);
4839
+ if (!platform) {
4840
+ if (explicit === null) {
4841
+ return null;
4842
+ }
4843
+ return {
4844
+ sha: explicit,
4845
+ branch: null,
4846
+ dirty: null,
4847
+ remote: null,
4848
+ rootSha: null
4849
+ };
4850
+ }
4851
+ const [shaEnv, branchEnv, readRemote] = platform;
4852
+ return {
4853
+ sha: explicit ?? read(env, shaEnv),
4854
+ branch: read(env, branchEnv),
4855
+ dirty: null,
4856
+ remote: readRemote(env),
4857
+ rootSha: null
4858
+ };
4859
+ }
4860
+ async function resolveCommitRefFromGit(cwd) {
4861
+ const git = await gitRunner({
4862
+ timeoutMs: GIT_TIMEOUT_MS,
4863
+ maxBuffer: GIT_MAX_BUFFER,
4864
+ keepProcessAlive: false
4865
+ });
4866
+ if (!git) {
4867
+ return null;
4868
+ }
4869
+ const run = async (args) => (await git(cwd, args))?.trim() ?? null;
4870
+ const sha = await run(["rev-parse", "HEAD"]);
4871
+ if (!sha) {
4872
+ return null;
4873
+ }
4874
+ const [branch, status, remote, roots] = await Promise.all([
4875
+ run(["symbolic-ref", "--short", "-q", "HEAD"]),
4876
+ run(["status", "--porcelain"]),
4877
+ run(["remote", "get-url", "origin"]),
4878
+ run(["rev-list", "--max-parents=0", "HEAD"])
4879
+ ]);
4880
+ return {
4881
+ sha,
4882
+ branch: branch || null,
4883
+ dirty: status === null ? null : status.length > 0,
4884
+ remote: normalizeRemote(remote),
4885
+ rootSha: roots ? roots.split(/\s+/).sort()[0] ?? null : null
4886
+ };
4887
+ }
4888
+ function commitRefWire(ref2) {
4889
+ return {
4890
+ sha: ref2.sha,
4891
+ branch: ref2.branch,
4892
+ dirty: ref2.dirty,
4893
+ remote: ref2.remote,
4894
+ root_sha: ref2.rootSha
4895
+ };
4896
+ }
4897
+ var resolved = false;
4898
+ var ref = null;
4899
+ var gitStarted = false;
4900
+ var settled = Promise.resolve();
4901
+ function startCommitRefResolution() {
4902
+ if (resolved || gitStarted) {
4903
+ return;
4904
+ }
4905
+ if (read(readEnv, DISABLE_ENV) !== null) {
4906
+ resolved = true;
4907
+ return;
4908
+ }
4909
+ const fromEnv = resolveCommitRefFromEnv(readEnv);
4910
+ if (fromEnv) {
4911
+ ref = fromEnv;
4912
+ resolved = true;
4913
+ return;
4914
+ }
4915
+ gitStarted = true;
4916
+ if (typeof process === "undefined") {
4917
+ resolved = true;
4918
+ return;
4919
+ }
4920
+ let cwd;
4921
+ try {
4922
+ cwd = process.cwd?.() ?? ".";
4923
+ } catch {
4924
+ resolved = true;
4925
+ return;
4926
+ }
4927
+ settled = resolveCommitRefFromGit(cwd).then(
4928
+ (fromGit) => {
4929
+ if (!resolved) {
4930
+ ref = fromGit;
4931
+ resolved = true;
4932
+ }
4933
+ },
4934
+ () => {
4935
+ resolved = true;
4936
+ }
4937
+ );
4938
+ }
4939
+ function currentCommitRef() {
4940
+ startCommitRefResolution();
4941
+ return ref;
4942
+ }
4943
+
4594
4944
  // src/client.ts
4595
4945
  init_constants();
4596
4946
 
@@ -5083,11 +5433,11 @@ var BitfabLangGraphCallbackHandler = class {
5083
5433
  this.invocations.set(invocation.rootRunId, invocation);
5084
5434
  }
5085
5435
  if (!willHide) {
5086
- let resolved = parentSpan;
5087
- while (resolved?.hidden === true) {
5088
- resolved = resolved.parentId ? this.runToSpan.get(resolved.parentId) : void 0;
5436
+ let resolved2 = parentSpan;
5437
+ while (resolved2?.hidden === true) {
5438
+ resolved2 = resolved2.parentId ? this.runToSpan.get(resolved2.parentId) : void 0;
5089
5439
  }
5090
- effectiveParentId = resolved ? resolved.spanId : invocation.activeContext?.spanId ?? null;
5440
+ effectiveParentId = resolved2 ? resolved2.spanId : invocation.activeContext?.spanId ?? null;
5091
5441
  } else {
5092
5442
  effectiveParentId = parentRunId ?? null;
5093
5443
  }
@@ -6587,6 +6937,7 @@ var Bitfab = class {
6587
6937
  validateDbSnapshotConfig(config.dbSnapshot);
6588
6938
  }
6589
6939
  this.dbSnapshot = config.dbSnapshot;
6940
+ startCommitRefResolution();
6590
6941
  this.httpClient = new HttpClient({
6591
6942
  apiKey: () => this.resolveApiKey(),
6592
6943
  serviceUrl: this.serviceUrl,
@@ -6757,11 +7108,15 @@ var Bitfab = class {
6757
7108
  type: options.type ?? "custom",
6758
7109
  surface: "opt-out"
6759
7110
  };
6760
- const tracedRoot = this.withSpan(
7111
+ const rootName = options.name ?? name;
7112
+ const buildTracedRoot = (spanOptions) => this.withSpan(
6761
7113
  traceFunctionKey,
6762
- rootOptions,
7114
+ spanOptions,
6763
7115
  function(...args) {
6764
- const capturePolicy = getAutoTraceCapturePolicy(self, traceFunctionKey);
7116
+ const capturePolicy = getAutoTraceCapturePolicy(
7117
+ self,
7118
+ traceFunctionKey
7119
+ );
6765
7120
  self.refreshAutoTraceCapturePolicy(traceFunctionKey);
6766
7121
  let spansUsed = 0;
6767
7122
  let truncated = false;
@@ -6782,19 +7137,54 @@ var Bitfab = class {
6782
7137
  `"${traceFunctionKey}" hit an automatic subtree capture limit (maxDepth=${maxDepth}, maxSpans=${maxSpans}); its trace is incomplete. Raise the limits or narrow the subtree with exclude.`
6783
7138
  );
6784
7139
  };
7140
+ const spanStackOf = (entry) => entry.spanStack;
7141
+ const openChild = (entry, childOptions, inputs, isAsync, invokeFn) => {
7142
+ const runInside = () => runWithAutoTraceEntry(
7143
+ entry,
7144
+ {
7145
+ context: autoTraceContext,
7146
+ depth: entry.depth + 1,
7147
+ spanStack: getSpanStack()
7148
+ },
7149
+ invokeFn
7150
+ );
7151
+ return runWithSpanStack(spanStackOf(entry), () => {
7152
+ if (isAsync) {
7153
+ const tracedAsyncChild = self.withSpan(
7154
+ traceFunctionKey,
7155
+ childOptions,
7156
+ async (..._inputs) => await runInside()
7157
+ );
7158
+ return tracedAsyncChild(...inputs);
7159
+ }
7160
+ const tracedChild = self.withSpan(
7161
+ traceFunctionKey,
7162
+ childOptions,
7163
+ (..._inputs) => runInside()
7164
+ );
7165
+ return tracedChild(...inputs);
7166
+ });
7167
+ };
7168
+ const overBudget = (entry) => {
7169
+ if (entry.depth < maxDepth && spansUsed < maxSpans) {
7170
+ return false;
7171
+ }
7172
+ runWithSpanStack(spanStackOf(entry), warnTruncated);
7173
+ return true;
7174
+ };
6785
7175
  const autoTraceContext = {
6786
- invoke(definition, inputs, invokeFn, depth, nodeConfiguration) {
7176
+ traceFunctionKey,
7177
+ invoke(definition, inputs, invokeFn, entry, nodeConfiguration) {
6787
7178
  const nameParts = definition.name.split(".");
6788
7179
  const simpleName = nameParts[nameParts.length - 1];
6789
- const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
7180
+ const invokeWithoutNode = () => nodeConfiguration === void 0 ? invokeFn() : clearAutoTraceNodeConfiguration(invokeFn);
6790
7181
  if (excluded.has(definition.name) || simpleName !== void 0 && excluded.has(simpleName) || nodeConfiguration === void 0 && definition.wrapper === true && !includeWrappers) {
6791
7182
  return invokeWithoutNode();
6792
7183
  }
6793
7184
  if (nodeConfiguration?.capture === false) {
6794
- return runWithAutoTraceContext(autoTraceContext, invokeFn, depth);
7185
+ return clearAutoTraceNodeConfiguration(invokeFn);
6795
7186
  }
6796
- if (depth >= maxDepth || spansUsed >= maxSpans) {
6797
- warnTruncated();
7187
+ if (overBudget(entry)) {
6798
7188
  return invokeWithoutNode();
6799
7189
  }
6800
7190
  spansUsed += 1;
@@ -6817,34 +7207,81 @@ var Bitfab = class {
6817
7207
  finalize: nodeConfiguration.finalize
6818
7208
  }
6819
7209
  };
6820
- const invokeWithAutoTraceContext = () => runWithAutoTraceContext(autoTraceContext, invokeFn, depth + 1);
6821
- if (definition.async === true) {
6822
- const tracedAsyncChild = self.withSpan(
6823
- traceFunctionKey,
6824
- childOptions,
6825
- async (..._inputs) => await invokeWithAutoTraceContext()
6826
- );
6827
- return tracedAsyncChild(...inputs);
6828
- }
6829
- const tracedChild = self.withSpan(
6830
- traceFunctionKey,
7210
+ return openChild(
7211
+ entry,
6831
7212
  childOptions,
6832
- (..._inputs) => invokeWithAutoTraceContext()
7213
+ inputs,
7214
+ definition.async === true,
7215
+ invokeFn
6833
7216
  );
6834
- return tracedChild(...inputs);
7217
+ },
7218
+ invokeNestedRoot(nestedName, nestedFunctionName, inputs, invokeFn, entry, link) {
7219
+ if (excluded.has(nestedName) || excluded.has(nestedFunctionName) || overBudget(entry)) {
7220
+ return invokeFn();
7221
+ }
7222
+ spansUsed += 1;
7223
+ const childOptions = {
7224
+ name: nestedName,
7225
+ type: "function",
7226
+ captureWhen: "nested",
7227
+ surface: "opt-out",
7228
+ captureContent: true,
7229
+ ...link !== void 0 && { nestedTrace: link }
7230
+ };
7231
+ return openChild(entry, childOptions, inputs, false, invokeFn);
6835
7232
  }
6836
7233
  };
6837
7234
  return runWithAutoTraceRootContext(
6838
7235
  autoTraceContext,
7236
+ getSpanStack(),
6839
7237
  () => fn.apply(this, args)
6840
7238
  );
6841
7239
  }
6842
7240
  );
7241
+ const tracedRoot = buildTracedRoot(rootOptions);
6843
7242
  const autoTraceRoot = function(...args) {
6844
7243
  if (!self.shouldRecord()) {
6845
7244
  return fn.apply(this, args);
6846
7245
  }
6847
- return tracedRoot.apply(this, args);
7246
+ const enclosing = currentAutoTraceEntries();
7247
+ if (enclosing.length === 0) {
7248
+ return tracedRoot.apply(this, args);
7249
+ }
7250
+ const link = getReplayContext() || inSeedScope() ? void 0 : { traceFunctionKey };
7251
+ return invokeThroughAutoTraceEntries(
7252
+ enclosing,
7253
+ (entry, next) => entry.context.invokeNestedRoot(
7254
+ rootName,
7255
+ name,
7256
+ args,
7257
+ next,
7258
+ entry,
7259
+ link
7260
+ ),
7261
+ () => {
7262
+ if (link === void 0) {
7263
+ return fn.apply(this, args);
7264
+ }
7265
+ const innermost = enclosing[enclosing.length - 1];
7266
+ const innermostNow = currentAutoTraceEntries().find(
7267
+ (entry) => entry.context === innermost.context
7268
+ ) ?? innermost;
7269
+ const innermostStack = innermostNow.spanStack;
7270
+ const copy = innermostStack[innermostStack.length - 1];
7271
+ const detachedRoot = buildTracedRoot({
7272
+ ...rootOptions,
7273
+ ...copy !== void 0 && {
7274
+ enclosingTrace: {
7275
+ traceId: copy.traceId,
7276
+ spanId: copy.spanId,
7277
+ traceFunctionKey: innermost.context.traceFunctionKey,
7278
+ link
7279
+ }
7280
+ }
7281
+ });
7282
+ return runWithSpanStack([], () => detachedRoot.apply(this, args));
7283
+ }
7284
+ );
6848
7285
  };
6849
7286
  Object.defineProperty(autoTraceRoot, "_bitfabTraceFunctionKey", {
6850
7287
  value: traceFunctionKey
@@ -7433,6 +7870,10 @@ var Bitfab = class {
7433
7870
  const spanId = randomUuid();
7434
7871
  const parentSpanId = parentContext?.spanId ?? null;
7435
7872
  const isRootSpan = parentSpanId === null;
7873
+ if (options.enclosingTrace !== void 0) {
7874
+ options.enclosingTrace.link.traceId = traceId;
7875
+ options.enclosingTrace.link.rootSpanId = spanId;
7876
+ }
7436
7877
  const requestedSurface = options.surface ?? DEFAULT_SURFACE;
7437
7878
  const surface = resolveSurface(requestedSurface, parentContext?.surface);
7438
7879
  assertSurfacesCompatible(
@@ -7482,7 +7923,9 @@ var Bitfab = class {
7482
7923
  spanType: options.type ?? "custom",
7483
7924
  functionId: options.functionId,
7484
7925
  captureContent: options.captureContent ?? true,
7485
- autoTraceDefinition: options.autoTraceDefinition
7926
+ autoTraceDefinition: options.autoTraceDefinition,
7927
+ nestedTrace: options.nestedTrace,
7928
+ enclosingTrace: options.enclosingTrace
7486
7929
  };
7487
7930
  const sendSpan = async (params) => {
7488
7931
  const replayCtx = getReplayContext();
@@ -7680,15 +8123,15 @@ var Bitfab = class {
7680
8123
  );
7681
8124
  }
7682
8125
  return runWithSpanStack(newStack, async () => {
7683
- const resolved = await resolution;
7684
- if (resolved.matched) {
8126
+ const resolved2 = await resolution;
8127
+ if (resolved2.matched) {
7685
8128
  void sendSpan({
7686
- result: resolved.output,
8129
+ result: resolved2.output,
7687
8130
  mocked: true,
7688
8131
  mockTarget: "output",
7689
8132
  mockSource: "override"
7690
8133
  });
7691
- return resolved.output;
8134
+ return resolved2.output;
7692
8135
  }
7693
8136
  if (shouldMockWithBaseStrategy && !mockSpan) {
7694
8137
  throw new BitfabError(
@@ -7924,6 +8367,10 @@ var Bitfab = class {
7924
8367
  if (params.dbSnapshotRef) {
7925
8368
  rawTrace.db_snapshot_ref = params.dbSnapshotRef;
7926
8369
  }
8370
+ const commitRef = currentCommitRef();
8371
+ if (commitRef) {
8372
+ rawTrace.commit_ref = commitRefWire(commitRef);
8373
+ }
7927
8374
  if (params.ingestionType) {
7928
8375
  rawTrace.ingestion_type = params.ingestionType;
7929
8376
  }
@@ -7988,6 +8435,16 @@ var Bitfab = class {
7988
8435
  function_line: params.autoTraceDefinition.line,
7989
8436
  function_column: params.autoTraceDefinition.column
7990
8437
  },
8438
+ ...params.nestedTrace?.traceId !== void 0 && {
8439
+ nested_trace_id: params.nestedTrace.traceId,
8440
+ nested_trace_function_key: params.nestedTrace.traceFunctionKey,
8441
+ nested_root_span_id: params.nestedTrace.rootSpanId
8442
+ },
8443
+ ...params.enclosingTrace !== void 0 && {
8444
+ enclosing_trace_id: params.enclosingTrace.traceId,
8445
+ enclosing_trace_function_key: params.enclosingTrace.traceFunctionKey,
8446
+ enclosing_span_id: params.enclosingTrace.spanId
8447
+ },
7991
8448
  ...serializedInputs !== void 0 && {
7992
8449
  input: serializedInputs.json,
7993
8450
  ...serializedInputs.meta !== void 0 && {