@neat.is/core 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -639,6 +639,7 @@ init_cjs_shims();
639
639
  init_cjs_shims();
640
640
  var import_node_fs3 = require("fs");
641
641
  var import_node_path3 = __toESM(require("path"), 1);
642
+ var sourceMapJs = __toESM(require("source-map-js"), 1);
642
643
 
643
644
  // src/policy.ts
644
645
  init_cjs_shims();
@@ -1693,6 +1694,14 @@ function warnUnidentifiedSpan(project) {
1693
1694
  `[neatd] span lacked service.name; routed to 'unidentified' in project ${project}; check your OTel SDK config.`
1694
1695
  );
1695
1696
  }
1697
+ var noSourceMapWarnedServices = /* @__PURE__ */ new Set();
1698
+ function warnNoSourceMaps(serviceName) {
1699
+ if (noSourceMapWarnedServices.has(serviceName)) return;
1700
+ noSourceMapWarnedServices.add(serviceName);
1701
+ console.warn(
1702
+ `[neat] ${serviceName}: no .map files found under dist/; observed file edges will land on dist paths, not src. Set sourceMap: true in tsconfig to enable file-level reconciliation.`
1703
+ );
1704
+ }
1696
1705
  function pickAttr(span, ...keys) {
1697
1706
  for (const k of keys) {
1698
1707
  const v = span.attributes[k];
@@ -1735,8 +1744,13 @@ function languageForExt(relPath) {
1735
1744
  return void 0;
1736
1745
  }
1737
1746
  }
1738
- function relPathForRuntimeFile(filepath, serviceNode) {
1747
+ function relPathForRuntimeFile(filepath, serviceNode, scanPath) {
1739
1748
  let p = toPosix(filepath).replace(/^file:\/\//, "");
1749
+ if (scanPath && scanPath.length > 0) {
1750
+ const absRoot = toPosix(import_node_path3.default.resolve(scanPath, serviceNode?.repoPath ?? ""));
1751
+ const anchor = absRoot.endsWith("/") ? absRoot : `${absRoot}/`;
1752
+ if (p.startsWith(anchor)) return p.slice(anchor.length);
1753
+ }
1740
1754
  const root = serviceNode?.repoPath;
1741
1755
  if (root && root !== "." && root.length > 0) {
1742
1756
  const rootPosix = toPosix(root);
@@ -1753,16 +1767,65 @@ function relPathForRuntimeFile(filepath, serviceNode) {
1753
1767
  p = p.replace(/^[A-Za-z]:/, "").replace(/^\/+/, "");
1754
1768
  return p.length > 0 ? p : null;
1755
1769
  }
1756
- function callSiteFromSpan(span, serviceNode) {
1770
+ var sourceMapCache = /* @__PURE__ */ new Map();
1771
+ function resolveDistToSrc(absFilepath, line) {
1772
+ if (!absFilepath.endsWith(".js")) return null;
1773
+ let entry2 = sourceMapCache.get(absFilepath);
1774
+ if (entry2 === void 0) {
1775
+ entry2 = null;
1776
+ const mapPath = `${absFilepath}.map`;
1777
+ try {
1778
+ if ((0, import_node_fs3.existsSync)(mapPath)) {
1779
+ const raw = JSON.parse((0, import_node_fs3.readFileSync)(mapPath, "utf8"));
1780
+ const consumer = new sourceMapJs.SourceMapConsumer(raw);
1781
+ entry2 = { consumer, dir: import_node_path3.default.dirname(mapPath) };
1782
+ }
1783
+ } catch {
1784
+ entry2 = null;
1785
+ }
1786
+ sourceMapCache.set(absFilepath, entry2);
1787
+ }
1788
+ if (!entry2) return null;
1789
+ try {
1790
+ const pos = entry2.consumer.originalPositionFor({
1791
+ line: line !== void 0 && Number.isFinite(line) ? line : 1,
1792
+ column: 0
1793
+ });
1794
+ if (!pos || !pos.source) return null;
1795
+ const root = entry2.consumer.sourceRoot ?? "";
1796
+ const resolved = import_node_path3.default.resolve(entry2.dir, root, pos.source);
1797
+ return { filepath: resolved, ...pos.line ? { line: pos.line } : {} };
1798
+ } catch {
1799
+ return null;
1800
+ }
1801
+ }
1802
+ function callSiteFromSpan(span, serviceNode, scanPath) {
1757
1803
  const filepath = span.attributes[CODE_FILEPATH_ATTR];
1758
1804
  if (typeof filepath !== "string" || filepath.length === 0) return null;
1759
- const relPath = relPathForRuntimeFile(filepath, serviceNode);
1760
- if (!relPath) return null;
1761
1805
  const linenoRaw = span.attributes[CODE_LINENO_ATTR];
1762
- const line = typeof linenoRaw === "number" && Number.isFinite(linenoRaw) ? linenoRaw : void 0;
1806
+ let line = typeof linenoRaw === "number" && Number.isFinite(linenoRaw) ? linenoRaw : void 0;
1807
+ const abs = toPosix(filepath).replace(/^file:\/\//, "");
1808
+ const resolved = resolveDistToSrc(abs, line);
1809
+ let effectivePath = filepath;
1810
+ let originalRelPath;
1811
+ if (resolved) {
1812
+ originalRelPath = relPathForRuntimeFile(filepath, serviceNode, scanPath) ?? void 0;
1813
+ effectivePath = resolved.filepath;
1814
+ if (resolved.line !== void 0) line = resolved.line;
1815
+ }
1816
+ const relPath = relPathForRuntimeFile(effectivePath, serviceNode, scanPath);
1817
+ if (!relPath) return null;
1818
+ if (!resolved && abs.endsWith(".js") && relPath.startsWith("dist/") && serviceNode?.name) {
1819
+ warnNoSourceMaps(serviceNode.name);
1820
+ }
1763
1821
  const fnRaw = span.attributes[CODE_FUNCTION_ATTR];
1764
1822
  const fn = typeof fnRaw === "string" && fnRaw.length > 0 ? fnRaw : void 0;
1765
- return { relPath, ...line !== void 0 ? { line } : {}, ...fn ? { fn } : {} };
1823
+ return {
1824
+ relPath,
1825
+ ...line !== void 0 ? { line } : {},
1826
+ ...fn ? { fn } : {},
1827
+ ...originalRelPath && originalRelPath !== relPath ? { originalRelPath } : {}
1828
+ };
1766
1829
  }
1767
1830
  function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
1768
1831
  const fileNodeId = (0, import_types3.fileId)(serviceName, callSite.relPath);
@@ -1774,6 +1837,7 @@ function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
1774
1837
  service: serviceName,
1775
1838
  path: callSite.relPath,
1776
1839
  ...language ? { language } : {},
1840
+ ...callSite.originalRelPath ? { originalPath: callSite.originalRelPath } : {},
1777
1841
  discoveredVia: "otel"
1778
1842
  };
1779
1843
  graph.addNode(fileNodeId, node);
@@ -1799,6 +1863,12 @@ function makeInferredEdgeId(type, source, target) {
1799
1863
  }
1800
1864
  var INFERRED_CONFIDENCE = 0.6;
1801
1865
  var STITCH_MAX_DEPTH = 2;
1866
+ var WIRE_SPAN_KIND_CLIENT = 3;
1867
+ var WIRE_SPAN_KIND_PRODUCER = 4;
1868
+ function spanMintsObservedEdge(kind) {
1869
+ if (kind === void 0 || kind === 0) return true;
1870
+ return kind === WIRE_SPAN_KIND_CLIENT || kind === WIRE_SPAN_KIND_PRODUCER;
1871
+ }
1802
1872
  var PARENT_SPAN_CACHE_SIZE = 1e4;
1803
1873
  var PARENT_SPAN_CACHE_TTL_MS = 5 * 60 * 1e3;
1804
1874
  var parentSpanCache = /* @__PURE__ */ new Map();
@@ -2034,12 +2104,13 @@ async function handleSpan(ctx, span) {
2034
2104
  const isError = span.statusCode === 2;
2035
2105
  cacheSpanService(span, nowMs);
2036
2106
  const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId);
2037
- const callSite = callSiteFromSpan(span, sourceServiceNode);
2107
+ const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath);
2038
2108
  const observedSource = () => callSite ? ensureObservedFileNode(ctx.graph, span.service, sourceId, callSite) : sourceId;
2039
2109
  let affectedNode = sourceId;
2110
+ const mintsFromCallerSide = spanMintsObservedEdge(span.kind);
2040
2111
  if (span.dbSystem) {
2041
2112
  const host = pickAddress(span);
2042
- if (host) {
2113
+ if (mintsFromCallerSide && host) {
2043
2114
  ensureDatabaseNode(ctx.graph, host, span.dbSystem);
2044
2115
  const targetId = (0, import_types3.databaseId)(host);
2045
2116
  const result = upsertObservedEdge(
@@ -2055,7 +2126,7 @@ async function handleSpan(ctx, span) {
2055
2126
  } else {
2056
2127
  const host = pickAddress(span);
2057
2128
  let resolvedViaAddress = false;
2058
- if (host && host !== span.service) {
2129
+ if (mintsFromCallerSide && host && host !== span.service) {
2059
2130
  const targetId = resolveServiceId(ctx.graph, host, env);
2060
2131
  if (targetId && targetId !== sourceId) {
2061
2132
  upsertObservedEdge(
@@ -3851,8 +3922,14 @@ function collectStringLiterals(node, out) {
3851
3922
  if (child) collectStringLiterals(child, out);
3852
3923
  }
3853
3924
  }
3925
+ var PARSE_CHUNK = 16384;
3926
+ function parseSource(parser, source) {
3927
+ return parser.parse(
3928
+ (index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK)
3929
+ );
3930
+ }
3854
3931
  function callsFromSource(source, parser, knownHosts) {
3855
- const tree = parser.parse(source);
3932
+ const tree = parseSource(parser, source);
3856
3933
  const literals = [];
3857
3934
  collectStringLiterals(tree.rootNode, literals);
3858
3935
  const out = [];
@@ -5298,6 +5375,66 @@ function registryPath() {
5298
5375
  function registryLockPath() {
5299
5376
  return import_node_path34.default.join(neatHome(), "projects.json.lock");
5300
5377
  }
5378
+ function daemonPidPath() {
5379
+ return import_node_path34.default.join(neatHome(), "neatd.pid");
5380
+ }
5381
+ function isPidAliveDefault(pid) {
5382
+ try {
5383
+ process.kill(pid, 0);
5384
+ return true;
5385
+ } catch (err) {
5386
+ return err.code === "EPERM";
5387
+ }
5388
+ }
5389
+ async function readPidFile(file) {
5390
+ try {
5391
+ const raw = await import_node_fs21.promises.readFile(file, "utf8");
5392
+ const pid = Number.parseInt(raw.trim(), 10);
5393
+ return Number.isInteger(pid) && pid > 0 ? pid : void 0;
5394
+ } catch {
5395
+ return void 0;
5396
+ }
5397
+ }
5398
+ var defaultLockHolderProbe = {
5399
+ isPidAlive: isPidAliveDefault,
5400
+ daemonPidFromFile: () => readPidFile(daemonPidPath()),
5401
+ async daemonResponds() {
5402
+ const base = process.env.NEAT_API_URL ?? "http://localhost:8080";
5403
+ try {
5404
+ await fetch(`${base}/health`, { signal: AbortSignal.timeout(750) });
5405
+ return true;
5406
+ } catch {
5407
+ return false;
5408
+ }
5409
+ }
5410
+ };
5411
+ async function readLockPid(lockPath) {
5412
+ return readPidFile(lockPath);
5413
+ }
5414
+ async function classifyLockHolder(lockPath, probe = defaultLockHolderProbe) {
5415
+ const lockPid = await readLockPid(lockPath);
5416
+ const daemonPid = await probe.daemonPidFromFile();
5417
+ if (daemonPid !== void 0 && daemonPid !== process.pid && probe.isPidAlive(daemonPid) && // The lock already names the daemon, or the daemon answers on its port.
5418
+ // Either confirms a live daemon is in the picture (the second guards
5419
+ // against a stale pidfile whose PID got reused).
5420
+ (daemonPid === lockPid || await probe.daemonResponds())) {
5421
+ return { kind: "daemon", pid: daemonPid };
5422
+ }
5423
+ if (lockPid !== void 0 && lockPid !== process.pid && probe.isPidAlive(lockPid)) {
5424
+ return { kind: "command", pid: lockPid };
5425
+ }
5426
+ return { kind: "stale" };
5427
+ }
5428
+ function lockHolderMessage(holder, lockPath, timeoutMs) {
5429
+ switch (holder.kind) {
5430
+ case "daemon":
5431
+ return `The neat daemon (pid ${holder.pid}) is holding the registry lock. Register this project through the daemon, or stop neatd and re-run \`neat init\`.`;
5432
+ case "command":
5433
+ return `Another neat command (pid ${holder.pid}) is holding the registry lock. Wait for it to finish, or check \`ps\` if you're not sure what's running.`;
5434
+ case "stale":
5435
+ return `neat registry: timed out after ${timeoutMs}ms waiting for ${lockPath}. Another neat process is holding the lock; if no such process exists, remove the file by hand.`;
5436
+ }
5437
+ }
5301
5438
  async function normalizeProjectPath(input) {
5302
5439
  const resolved = import_node_path34.default.resolve(input);
5303
5440
  try {
@@ -5318,21 +5455,31 @@ async function writeAtomically(target, contents) {
5318
5455
  }
5319
5456
  await import_node_fs21.promises.rename(tmp, target);
5320
5457
  }
5321
- async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS) {
5458
+ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
5322
5459
  const deadline = Date.now() + timeoutMs;
5323
5460
  await import_node_fs21.promises.mkdir(import_node_path34.default.dirname(lockPath), { recursive: true });
5461
+ let probedHolder = false;
5324
5462
  while (true) {
5325
5463
  try {
5326
5464
  const fd = await import_node_fs21.promises.open(lockPath, "wx");
5327
- await fd.close();
5465
+ try {
5466
+ await fd.writeFile(`${process.pid}
5467
+ `, "utf8");
5468
+ } finally {
5469
+ await fd.close();
5470
+ }
5328
5471
  return;
5329
5472
  } catch (err) {
5330
5473
  const code = err.code;
5331
5474
  if (code !== "EEXIST") throw err;
5475
+ if (!probedHolder) {
5476
+ probedHolder = true;
5477
+ const holder = await classifyLockHolder(lockPath, probe);
5478
+ if (holder.kind === "daemon") throw new Error(lockHolderMessage(holder, lockPath, timeoutMs));
5479
+ }
5332
5480
  if (Date.now() >= deadline) {
5333
- throw new Error(
5334
- `neat registry: timed out after ${timeoutMs}ms waiting for ${lockPath}. Another neat process is holding the lock; if no such process exists, remove the file by hand.`
5335
- );
5481
+ const holder = await classifyLockHolder(lockPath, probe);
5482
+ throw new Error(lockHolderMessage(holder, lockPath, timeoutMs));
5336
5483
  }
5337
5484
  await new Promise((r) => setTimeout(r, LOCK_RETRY_MS));
5338
5485
  }
@@ -6525,6 +6672,7 @@ async function startWatch(graph, opts) {
6525
6672
  const onSpan = makeSpanHandler({
6526
6673
  graph,
6527
6674
  errorsPath: opts.errorsPath,
6675
+ scanPath: opts.scanPath,
6528
6676
  project: projectName,
6529
6677
  writeErrorEventInline: false,
6530
6678
  onPolicyTrigger
@@ -6539,6 +6687,7 @@ async function startWatch(graph, opts) {
6539
6687
  const onSpanGrpc = makeSpanHandler({
6540
6688
  graph,
6541
6689
  errorsPath: opts.errorsPath,
6690
+ scanPath: opts.scanPath,
6542
6691
  project: projectName,
6543
6692
  onPolicyTrigger
6544
6693
  });
@@ -6804,13 +6953,20 @@ var import_node_path40 = __toESM(require("path"), 1);
6804
6953
  // src/installers/templates.ts
6805
6954
  init_cjs_shims();
6806
6955
  var OTEL_INIT_HEADER = "// Generated by `neat init --apply` (ADR-069). OpenTelemetry auto-instrumentation hook.";
6807
- var OTEL_INIT_STAMP = "// neat-template-version: 3 \u2014 file-first call-site capture (ADR-089) + OTLP bearer auth (#410).";
6956
+ var OTEL_INIT_STAMP = "// neat-template-version: 4 \u2014 layered file-first capture (ADR-090): stack walk + handler-entry + off-stack facades.";
6808
6957
  var OTEL_OTLP_HEADERS_JS = "if (process.env.NEAT_OTEL_TOKEN) process.env.OTEL_EXPORTER_OTLP_HEADERS ||= 'Authorization=Bearer ' + process.env.NEAT_OTEL_TOKEN";
6809
- function neatCallsiteProcessorSource(ts) {
6810
- const stackT = ts ? ": string" : "";
6958
+ function neatCaptureSource(ts) {
6811
6959
  const spanT = ts ? ": any" : "";
6812
6960
  const strOpt = ts ? ": string | undefined" : "";
6813
- return `function __neatPickUserFrame(stack${stackT}) {
6961
+ const anyT = ts ? ": any" : "";
6962
+ const fnT = ts ? ": any" : "";
6963
+ const arrAny = ts ? ": any[]" : "";
6964
+ return `// Context key shared by the facade/handler wraps (writers) and the
6965
+ // processor fallback (reader). Symbol.for keeps it stable even if the wraps
6966
+ // and the processor end up in different module instances.
6967
+ const NEAT_USER_FRAME = Symbol.for('neat.user-frame')
6968
+
6969
+ function __neatPickUserFrame(stack${strOpt}) {
6814
6970
  const lines = String(stack || '').split('\\n')
6815
6971
  for (let i = 0; i < lines.length; i++) {
6816
6972
  const raw = lines[i].trim()
@@ -6819,6 +6975,9 @@ function neatCallsiteProcessorSource(ts) {
6819
6975
  if (raw.indexOf('@opentelemetry') !== -1) continue
6820
6976
  if (raw.indexOf('node:') !== -1) continue
6821
6977
  if (raw.indexOf('NeatCallSiteSpanProcessor') !== -1) continue
6978
+ // Skip NEAT's own inlined wraps/helpers (all carry the __neat prefix) so a
6979
+ // facade frame never masquerades as the user's call site.
6980
+ if (raw.indexOf('__neat') !== -1) continue
6822
6981
  const bodyText = raw.slice(3)
6823
6982
  const loc = bodyText.match(/:(\\d+):(\\d+)\\)?$/)
6824
6983
  if (!loc) continue
@@ -6840,32 +6999,245 @@ function neatCallsiteProcessorSource(ts) {
6840
6999
  return null
6841
7000
  }
6842
7001
 
7002
+ // Layer 2/3 fallback source: the frame a handler-entry or facade wrap pushed
7003
+ // into context. Reads the span's own parent context first, then the active
7004
+ // context \u2014 the capture spike confirmed both return the value for undici.
7005
+ function __neatFrameFromContext(parentContext${anyT}) {
7006
+ try {
7007
+ const fromParent =
7008
+ parentContext && typeof parentContext.getValue === 'function'
7009
+ ? parentContext.getValue(NEAT_USER_FRAME)
7010
+ : undefined
7011
+ return fromParent || context.active().getValue(NEAT_USER_FRAME) || null
7012
+ } catch (_e) {
7013
+ return null
7014
+ }
7015
+ }
7016
+
7017
+ function __neatSetCodeAttrs(span${spanT}, frame${anyT}) {
7018
+ span.setAttribute('code.filepath', frame.filepath)
7019
+ if (typeof frame.lineno === 'number') span.setAttribute('code.lineno', frame.lineno)
7020
+ if (frame.function) span.setAttribute('code.function', frame.function)
7021
+ }
7022
+
6843
7023
  class NeatCallSiteSpanProcessor {
6844
- onStart(span${spanT}) {
7024
+ onStart(span${spanT}, parentContext${anyT}) {
6845
7025
  if (!span || (span.kind !== 2 && span.kind !== 3)) return
6846
- const frame = __neatPickUserFrame(new Error().stack)
7026
+ // Layer 1 \u2014 synchronous stack walk (sync-wrapper instrumentations).
7027
+ let frame = __neatPickUserFrame(new Error().stack)
7028
+ // Layer 2/3 \u2014 the handler-entry or off-stack-facade frame from context.
7029
+ if (!frame) frame = __neatFrameFromContext(parentContext)
6847
7030
  if (!frame) return
6848
- span.setAttribute('code.filepath', frame.filepath)
6849
- if (typeof frame.lineno === 'number') span.setAttribute('code.lineno', frame.lineno)
6850
- if (frame.function) span.setAttribute('code.function', frame.function)
7031
+ __neatSetCodeAttrs(span, frame)
6851
7032
  }
6852
7033
  onEnd() {}
6853
7034
  forceFlush() { return Promise.resolve() }
6854
7035
  shutdown() { return Promise.resolve() }
7036
+ }
7037
+
7038
+ // Capture the caller's synchronous frame at the wrap point and run \`fn\` with
7039
+ // that frame pushed into the active context (file-awareness.md \xA74 layer 3). An
7040
+ // off-stack instrumentation that creates its span inside \`fn\` inherits the
7041
+ // frame; the processor reads it via __neatFrameFromContext.
7042
+ function __neatRunWithUserFrame(fn${fnT}) {
7043
+ const frame = __neatPickUserFrame(new Error().stack)
7044
+ if (!frame) return fn()
7045
+ return context.with(context.active().setValue(NEAT_USER_FRAME, frame), fn)
7046
+ }
7047
+
7048
+ // Handler-entry attribution (file-awareness.md \xA74 layer 2). Stamp the framework
7049
+ // SERVER span with the handler frame captured at route registration, and push
7050
+ // the same frame into context so downstream CLIENT/PRODUCER spans inherit the
7051
+ // handler-file floor when their own stack carries none.
7052
+ function __neatStampHandler(frame${anyT}, run${fnT}) {
7053
+ try {
7054
+ const active = trace.getActiveSpan()
7055
+ if (active && active.kind === 1 && typeof active.setAttribute === 'function') {
7056
+ __neatSetCodeAttrs(active, frame)
7057
+ }
7058
+ } catch (_e) {}
7059
+ try {
7060
+ return context.with(context.active().setValue(NEAT_USER_FRAME, frame), run)
7061
+ } catch (_e) {
7062
+ return run()
7063
+ }
7064
+ }
7065
+
7066
+ // require-in-the-middle is a transitive dependency of the OTel instrumentation
7067
+ // packages NEAT installs, so it resolves in any instrumented CJS service.
7068
+ // Guarded: when it's absent (or the host runs as pure ESM, where require isn't
7069
+ // defined) the off-stack/handler wraps degrade to the stack walk + context
7070
+ // floor, never to a crash.
7071
+ function __neatHook(modules${arrAny}, onload${fnT}) {
7072
+ try {
7073
+ const RITM = require('require-in-the-middle')
7074
+ const Hook = RITM && RITM.Hook ? RITM.Hook : RITM
7075
+ new Hook(modules, { internals: false }, onload)
7076
+ return true
7077
+ } catch (_e) {
7078
+ return false
7079
+ }
7080
+ }
7081
+
7082
+ // Off-stack facade: Node's built-in fetch / undici. The instrumentation creates
7083
+ // the CLIENT span inside a diagnostics_channel handler detached from the
7084
+ // caller's stack, so wrap the global so the user frame is in context when the
7085
+ // span is created. The capture spike (2026-05-28) validated this on real
7086
+ // undici. .name is restored to 'fetch' for ecosystem compatibility; the inner
7087
+ // __neat name is what the frame skip keys on.
7088
+ function __neatWrapFetch() {
7089
+ try {
7090
+ const g${anyT} = globalThis
7091
+ if (typeof g.fetch === 'function' && !g.fetch.__neatWrapped) {
7092
+ const realFetch = g.fetch
7093
+ // The wrapper keeps its __neat-prefixed name so the frame skip in
7094
+ // __neatPickUserFrame never mistakes the wrapper's own frame for the
7095
+ // user's call site (renaming it to 'fetch' would defeat the skip).
7096
+ const __neatFetch${anyT} = function (input${anyT}, init${anyT}) {
7097
+ return __neatRunWithUserFrame(function () { return realFetch(input, init) })
7098
+ }
7099
+ __neatFetch.__neatWrapped = true
7100
+ g.fetch = __neatFetch
7101
+ }
7102
+ } catch (_e) {}
7103
+ }
7104
+
7105
+ // Off-stack facade: @prisma/client. Prisma's query engine backdates its spans
7106
+ // from Rust, off the caller's stack. Wrap the model methods on the client
7107
+ // prototype so the call-site frame (still synchronous at \`prisma.user.find\`)
7108
+ // is pushed into context for the engine dispatch.
7109
+ function __neatWrapPrisma() {
7110
+ __neatHook(['@prisma/client'], function (exports${anyT}) {
7111
+ try {
7112
+ const Client = exports && exports.PrismaClient
7113
+ if (typeof Client === 'function' && !Client.__neatWrapped) {
7114
+ const ops = ['findUnique','findUniqueOrThrow','findFirst','findFirstOrThrow','findMany','create','createMany','update','updateMany','upsert','delete','deleteMany','count','aggregate','groupBy']
7115
+ const __neatPrismaWrapModel = function (model${anyT}) {
7116
+ if (!model || model.__neatWrapped) return model
7117
+ for (let i = 0; i < ops.length; i++) {
7118
+ const op = ops[i]
7119
+ const orig = model[op]
7120
+ if (typeof orig !== 'function') continue
7121
+ model[op] = function __neatPrismaOp(${ts ? "...args: any[]" : "...args"}) {
7122
+ const self = this
7123
+ return __neatRunWithUserFrame(function () { return orig.apply(self, args) })
7124
+ }
7125
+ }
7126
+ model.__neatWrapped = true
7127
+ return model
7128
+ }
7129
+ const proto = Client.prototype
7130
+ const handler = function (model${anyT}) { return __neatPrismaWrapModel(model) }
7131
+ // Model accessors are lazily created getters on the instance; wrap the
7132
+ // \`$extends\`-free common path by trapping property access via a proxy
7133
+ // on each constructed client.
7134
+ exports.PrismaClient = new Proxy(Client, {
7135
+ construct(Target${anyT}, argList${anyT}, NewTarget${anyT}) {
7136
+ const instance = Reflect.construct(Target, argList, NewTarget)
7137
+ return new Proxy(instance, {
7138
+ get(target${anyT}, prop${anyT}, receiver${anyT}) {
7139
+ const value = Reflect.get(target, prop, receiver)
7140
+ if (value && typeof value === 'object' && typeof prop === 'string' && prop[0] !== '$' && prop[0] !== '_') {
7141
+ return handler(value)
7142
+ }
7143
+ return value
7144
+ },
7145
+ })
7146
+ },
7147
+ })
7148
+ exports.PrismaClient.__neatWrapped = true
7149
+ void proto
7150
+ }
7151
+ } catch (_e) {}
7152
+ return exports
7153
+ })
7154
+ }
7155
+
7156
+ // Handler-entry facades. express / connect share the Layer model (each route
7157
+ // handler is a function registered on a Router); the wrap captures the
7158
+ // registration frame and stamps + propagates it when the handler runs. The
7159
+ // registry is the extensibility seam \u2014 koa, fastify (via @fastify/otel),
7160
+ // nestjs, restify, and hapi add an entry as their patch surface is wired.
7161
+ function __neatWrapConnectStyle(mod${anyT}) {
7162
+ try {
7163
+ // express() returns an app whose route verbs live on Router.prototype and
7164
+ // the application proto; connect apps expose \`use\`. Wrap the registration
7165
+ // verbs so the user handler is wound with its registration frame.
7166
+ const verbs = ['use','get','post','put','delete','patch','all','options','head']
7167
+ const wrapTarget = function (target${anyT}) {
7168
+ if (!target || target.__neatVerbsWrapped) return
7169
+ for (let i = 0; i < verbs.length; i++) {
7170
+ const verb = verbs[i]
7171
+ const orig = target[verb]
7172
+ if (typeof orig !== 'function') continue
7173
+ target[verb] = function __neatVerb(${ts ? "...args: any[]" : "...args"}) {
7174
+ const frame = __neatPickUserFrame(new Error().stack)
7175
+ if (frame) {
7176
+ for (let a = 0; a < args.length; a++) {
7177
+ const h = args[a]
7178
+ if (typeof h === 'function' && !h.__neatHandlerWrapped && h.length <= 4) {
7179
+ const inner = h
7180
+ const __neatHandler${anyT} = function (${ts ? "...hargs: any[]" : "...hargs"}) {
7181
+ const self = this
7182
+ return __neatStampHandler(frame, function () { return inner.apply(self, hargs) })
7183
+ }
7184
+ __neatHandler.__neatHandlerWrapped = true
7185
+ args[a] = __neatHandler
7186
+ }
7187
+ }
7188
+ }
7189
+ return orig.apply(this, args)
7190
+ }
7191
+ }
7192
+ target.__neatVerbsWrapped = true
7193
+ }
7194
+ if (mod && mod.Router && mod.Router.prototype) wrapTarget(mod.Router.prototype)
7195
+ if (mod && mod.application) wrapTarget(mod.application)
7196
+ if (mod && mod.prototype) wrapTarget(mod.prototype)
7197
+ } catch (_e) {}
7198
+ }
7199
+
7200
+ function __neatInstallHandlerEntry() {
7201
+ __neatHook(['express'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })
7202
+ __neatHook(['connect'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })
7203
+ }
7204
+
7205
+ // Install every off-stack and handler-entry wrap. Called once after sdk.start()
7206
+ // \u2014 before user code requires the framework / Prisma modules, so the hooks land
7207
+ // on first require. Each wrap is independently guarded.
7208
+ function __neatInstallFacades() {
7209
+ __neatWrapFetch()
7210
+ __neatWrapPrisma()
7211
+ __neatInstallHandlerEntry()
6855
7212
  }`;
6856
7213
  }
6857
- var CALLSITE_PROCESSOR_JS = neatCallsiteProcessorSource(false);
6858
- var CALLSITE_PROCESSOR_TS = neatCallsiteProcessorSource(true);
6859
- function neatRegisterCallsiteSource(ts) {
7214
+ var CALLSITE_PROCESSOR_JS = neatCaptureSource(false);
7215
+ var CALLSITE_PROCESSOR_TS = neatCaptureSource(true);
7216
+ function neatWireCaptureSource(ts) {
6860
7217
  const providerT = ts ? ": any" : "";
6861
7218
  return `try {
6862
7219
  const provider${providerT} = trace.getTracerProvider()
6863
7220
  const delegate = provider && typeof provider.getDelegate === 'function' ? provider.getDelegate() : provider
6864
- if (delegate && typeof delegate.addSpanProcessor === 'function') {
6865
- delegate.addSpanProcessor(new NeatCallSiteSpanProcessor())
6866
- }
6867
- } catch {
6868
- // capture is best-effort; span export is unaffected
7221
+ if (!delegate || typeof delegate.addSpanProcessor !== 'function') {
7222
+ throw new Error('[neat] could not resolve a TracerProvider to attach the call-site processor; file-first OBSERVED capture would be silent (file-awareness.md \xA74)')
7223
+ }
7224
+ const __neatProcessor = new NeatCallSiteSpanProcessor()
7225
+ delegate.addSpanProcessor(__neatProcessor)
7226
+ // Post-init assertion: confirm attachment on providers that expose their
7227
+ // processor list. An un-introspectable provider is trusted (we just called
7228
+ // its addSpanProcessor); a list that exists and lacks our processor throws.
7229
+ const registered = delegate._registeredSpanProcessors
7230
+ if (Array.isArray(registered) && registered.indexOf(__neatProcessor) === -1) {
7231
+ throw new Error('[neat] call-site processor did not attach to the active TracerProvider (file-awareness.md \xA74)')
7232
+ }
7233
+ } catch (err) {
7234
+ throw err
7235
+ }
7236
+ try {
7237
+ __neatInstallFacades()
7238
+ } catch (_e) {
7239
+ // Facade install is best-effort: the stack-walk + handler-entry floor still
7240
+ // attribute the sync-wrapper majority even if an off-stack wrap fails.
6869
7241
  }`;
6870
7242
  }
6871
7243
  var OTEL_INIT_CJS = `${OTEL_INIT_HEADER}
@@ -6876,7 +7248,7 @@ ${OTEL_OTLP_HEADERS_JS}
6876
7248
 
6877
7249
  const { NodeSDK } = require('@opentelemetry/sdk-node')
6878
7250
  const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')
6879
- const { trace } = require('@opentelemetry/api')
7251
+ const { trace, context } = require('@opentelemetry/api')
6880
7252
 
6881
7253
  ${CALLSITE_PROCESSOR_JS}
6882
7254
 
@@ -6884,7 +7256,7 @@ const instrumentations = [getNodeAutoInstrumentations()]
6884
7256
  __INSTRUMENTATION_BLOCK__
6885
7257
  const sdk = new NodeSDK({ instrumentations })
6886
7258
  sdk.start()
6887
- ${neatRegisterCallsiteSource(false)}
7259
+ ${neatWireCaptureSource(false)}
6888
7260
  `;
6889
7261
  var OTEL_INIT_ESM = `${OTEL_INIT_HEADER}
6890
7262
  ${OTEL_INIT_STAMP}
@@ -6894,7 +7266,7 @@ ${OTEL_OTLP_HEADERS_JS}
6894
7266
 
6895
7267
  import { NodeSDK } from '@opentelemetry/sdk-node'
6896
7268
  import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
6897
- import { trace } from '@opentelemetry/api'
7269
+ import { trace, context } from '@opentelemetry/api'
6898
7270
 
6899
7271
  ${CALLSITE_PROCESSOR_JS}
6900
7272
 
@@ -6902,17 +7274,22 @@ const instrumentations = [getNodeAutoInstrumentations()]
6902
7274
  __INSTRUMENTATION_BLOCK__
6903
7275
  const sdk = new NodeSDK({ instrumentations })
6904
7276
  sdk.start()
6905
- ${neatRegisterCallsiteSource(false)}
7277
+ ${neatWireCaptureSource(false)}
6906
7278
  `;
6907
7279
  var OTEL_INIT_TS = `${OTEL_INIT_HEADER}
6908
7280
  ${OTEL_INIT_STAMP}
7281
+ // @ts-nocheck \u2014 generated runtime shim. The layered capture mechanism uses
7282
+ // dynamic patterns (facade wraps, Proxy traps, a createRequire bridge) that a
7283
+ // strict user tsconfig would reject; suppressing type-checking here keeps the
7284
+ // generated file from breaking the host project's \`tsc\` gate (#427) without
7285
+ // constraining the runtime logic. The file is regenerated, never hand-edited.
6909
7286
  process.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'
6910
7287
  process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'
6911
7288
  ${OTEL_OTLP_HEADERS_JS}
6912
7289
 
6913
7290
  import { NodeSDK } from '@opentelemetry/sdk-node'
6914
7291
  import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
6915
- import { trace } from '@opentelemetry/api'
7292
+ import { trace, context } from '@opentelemetry/api'
6916
7293
 
6917
7294
  ${CALLSITE_PROCESSOR_TS}
6918
7295
 
@@ -6920,7 +7297,7 @@ const instrumentations = [getNodeAutoInstrumentations()]
6920
7297
  __INSTRUMENTATION_BLOCK__
6921
7298
  const sdk = new NodeSDK({ instrumentations })
6922
7299
  sdk.start()
6923
- ${neatRegisterCallsiteSource(true)}
7300
+ ${neatWireCaptureSource(true)}
6924
7301
  `;
6925
7302
  function renderNodeOtelInit(template, serviceName, projectName, registrations = []) {
6926
7303
  const block = registrations.length === 0 ? "" : `