@neat.is/core 0.7.1 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -60,8 +60,8 @@ function mountBearerAuth(app, opts) {
60
60
  ]);
61
61
  const publicRead = opts.publicRead === true;
62
62
  app.addHook("preHandler", (req, reply, done) => {
63
- const path59 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
64
- if (exactUnauthPaths.has(path59) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path59)) {
63
+ const path60 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
64
+ if (exactUnauthPaths.has(path60) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path60)) {
65
65
  done();
66
66
  return;
67
67
  }
@@ -193,8 +193,8 @@ function reshapeGrpcRequest(req) {
193
193
  };
194
194
  }
195
195
  function resolveProtoRoot() {
196
- const here = import_node_path38.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
197
- return import_node_path38.default.resolve(here, "..", "proto");
196
+ const here = import_node_path39.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
197
+ return import_node_path39.default.resolve(here, "..", "proto");
198
198
  }
199
199
  function loadTraceService() {
200
200
  const protoRoot = resolveProtoRoot();
@@ -262,13 +262,13 @@ async function startOtelGrpcReceiver(opts) {
262
262
  })
263
263
  };
264
264
  }
265
- var import_node_url, import_node_path38, import_node_crypto2, grpc, protoLoader;
265
+ var import_node_url, import_node_path39, import_node_crypto2, grpc, protoLoader;
266
266
  var init_otel_grpc = __esm({
267
267
  "src/otel-grpc.ts"() {
268
268
  "use strict";
269
269
  init_cjs_shims();
270
270
  import_node_url = require("url");
271
- import_node_path38 = __toESM(require("path"), 1);
271
+ import_node_path39 = __toESM(require("path"), 1);
272
272
  import_node_crypto2 = require("crypto");
273
273
  grpc = __toESM(require("@grpc/grpc-js"), 1);
274
274
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
@@ -414,8 +414,8 @@ function websocketChannelPathOf(attrs) {
414
414
  const v = attrs[key];
415
415
  if (typeof v === "string" && v.length > 0) {
416
416
  const q = v.indexOf("?");
417
- const path59 = q === -1 ? v : v.slice(0, q);
418
- if (path59.length > 0) return path59;
417
+ const path60 = q === -1 ? v : v.slice(0, q);
418
+ if (path60.length > 0) return path60;
419
419
  }
420
420
  }
421
421
  return void 0;
@@ -474,10 +474,10 @@ function parseOtlpRequest(body) {
474
474
  return out;
475
475
  }
476
476
  function loadProtoRoot() {
477
- const here = import_node_path39.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
478
- const protoRoot = import_node_path39.default.resolve(here, "..", "proto");
477
+ const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
478
+ const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
479
479
  const root = new import_protobufjs.default.Root();
480
- root.resolvePath = (_origin, target) => import_node_path39.default.resolve(protoRoot, target);
480
+ root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
481
481
  root.loadSync(
482
482
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
483
483
  { keepCase: true }
@@ -716,12 +716,12 @@ function logSpanHandler(span) {
716
716
  `otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
717
717
  );
718
718
  }
719
- var import_node_path39, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
719
+ var import_node_path40, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
720
720
  var init_otel = __esm({
721
721
  "src/otel.ts"() {
722
722
  "use strict";
723
723
  init_cjs_shims();
724
- import_node_path39 = __toESM(require("path"), 1);
724
+ import_node_path40 = __toESM(require("path"), 1);
725
725
  import_node_url2 = require("url");
726
726
  import_fastify = __toESM(require("fastify"), 1);
727
727
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -1314,19 +1314,19 @@ function confidenceFromMix(edges, now = Date.now()) {
1314
1314
  function longestIncomingWalk(graph, start, maxDepth) {
1315
1315
  let best = { path: [start], edges: [] };
1316
1316
  const visited = /* @__PURE__ */ new Set([start]);
1317
- function step(node, path59, edges) {
1318
- if (path59.length > best.path.length) {
1319
- best = { path: [...path59], edges: [...edges] };
1317
+ function step(node, path60, edges) {
1318
+ if (path60.length > best.path.length) {
1319
+ best = { path: [...path60], edges: [...edges] };
1320
1320
  }
1321
- if (path59.length - 1 >= maxDepth) return;
1321
+ if (path60.length - 1 >= maxDepth) return;
1322
1322
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
1323
1323
  for (const [srcId, edge] of incoming) {
1324
1324
  if (visited.has(srcId)) continue;
1325
1325
  visited.add(srcId);
1326
- path59.push(srcId);
1326
+ path60.push(srcId);
1327
1327
  edges.push(edge);
1328
- step(srcId, path59, edges);
1329
- path59.pop();
1328
+ step(srcId, path60, edges);
1329
+ path60.pop();
1330
1330
  edges.pop();
1331
1331
  visited.delete(srcId);
1332
1332
  }
@@ -1533,26 +1533,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
1533
1533
  return best;
1534
1534
  }
1535
1535
  function followFailingCallChain(graph, originServiceId, maxDepth) {
1536
- const path59 = [originServiceId];
1536
+ const path60 = [originServiceId];
1537
1537
  const edges = [];
1538
1538
  const visited = /* @__PURE__ */ new Set([originServiceId]);
1539
1539
  let current = originServiceId;
1540
1540
  for (let depth = 0; depth < maxDepth; depth++) {
1541
1541
  const hop = dominantFailingCall(graph, current, visited);
1542
1542
  if (!hop) break;
1543
- path59.push(hop.nextService);
1543
+ path60.push(hop.nextService);
1544
1544
  edges.push(hop.edge);
1545
1545
  visited.add(hop.nextService);
1546
1546
  current = hop.nextService;
1547
1547
  }
1548
1548
  if (edges.length === 0) return null;
1549
- return { path: path59, edges, culprit: current };
1549
+ return { path: path60, edges, culprit: current };
1550
1550
  }
1551
1551
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1552
1552
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
1553
1553
  if (!chain) return null;
1554
1554
  const culprit = chain.culprit;
1555
- const path59 = [...chain.path];
1555
+ const path60 = [...chain.path];
1556
1556
  const edgeProvenances = chain.edges.map((e) => e.provenance);
1557
1557
  const baseConfidence = confidenceFromMix(chain.edges);
1558
1558
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -1560,14 +1560,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1560
1560
  if (loc) {
1561
1561
  let rootCauseNode = culprit;
1562
1562
  if (loc.fileNode) {
1563
- path59.push(loc.fileNode);
1563
+ path60.push(loc.fileNode);
1564
1564
  edgeProvenances.push(import_types.Provenance.OBSERVED);
1565
1565
  rootCauseNode = loc.fileNode;
1566
1566
  }
1567
1567
  return import_types.RootCauseResultSchema.parse({
1568
1568
  rootCauseNode,
1569
1569
  rootCauseReason: loc.rootCauseReason,
1570
- traversalPath: path59,
1570
+ traversalPath: path60,
1571
1571
  edgeProvenances,
1572
1572
  confidence,
1573
1573
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -1579,7 +1579,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1579
1579
  return import_types.RootCauseResultSchema.parse({
1580
1580
  rootCauseNode: culprit,
1581
1581
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
1582
- traversalPath: path59,
1582
+ traversalPath: path60,
1583
1583
  edgeProvenances,
1584
1584
  confidence,
1585
1585
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -6949,7 +6949,7 @@ async function addGrpcMethods(graph, services) {
6949
6949
 
6950
6950
  // src/extract/calls/index.ts
6951
6951
  init_cjs_shims();
6952
- var import_types29 = require("@neat.is/types");
6952
+ var import_types30 = require("@neat.is/types");
6953
6953
 
6954
6954
  // src/extract/calls/http.ts
6955
6955
  init_cjs_shims();
@@ -8405,12 +8405,140 @@ function drizzleEndpointsFromFile(file, serviceDir) {
8405
8405
  return out;
8406
8406
  }
8407
8407
 
8408
+ // src/extract/calls/prisma.ts
8409
+ init_cjs_shims();
8410
+ var import_node_path38 = __toESM(require("path"), 1);
8411
+ var import_types28 = require("@neat.is/types");
8412
+ var SCALAR_TYPES = /* @__PURE__ */ new Set([
8413
+ "Int",
8414
+ "String",
8415
+ "Boolean",
8416
+ "DateTime",
8417
+ "Float",
8418
+ "Decimal",
8419
+ "BigInt",
8420
+ "Bytes",
8421
+ "Json"
8422
+ ]);
8423
+ function stripLineComment(line) {
8424
+ let inStr = false;
8425
+ for (let i = 0; i < line.length; i++) {
8426
+ const ch = line[i];
8427
+ if (ch === '"' && line[i - 1] !== "\\") inStr = !inStr;
8428
+ else if (!inStr && ch === "/" && line[i + 1] === "/") return line.slice(0, i);
8429
+ }
8430
+ return line;
8431
+ }
8432
+ function netBraces(line) {
8433
+ const s = stripLineComment(line).replace(/"(\\.|[^"\\])*"/g, "");
8434
+ let n = 0;
8435
+ for (const ch of s) {
8436
+ if (ch === "{") n++;
8437
+ else if (ch === "}") n--;
8438
+ }
8439
+ return n;
8440
+ }
8441
+ function prismaColumnsFromSchema(file, serviceDir) {
8442
+ const content = file.content;
8443
+ if (!/\bmodel\s+[A-Za-z_]\w*\s*\{/.test(content)) return [];
8444
+ const lines = content.split("\n");
8445
+ const modelNames = /* @__PURE__ */ new Set();
8446
+ const enumNames = /* @__PURE__ */ new Set();
8447
+ for (const line of lines) {
8448
+ const m = line.match(/^\s*model\s+([A-Za-z_]\w*)\s*\{/);
8449
+ if (m) modelNames.add(m[1]);
8450
+ const e = line.match(/^\s*enum\s+([A-Za-z_]\w*)\s*\{/);
8451
+ if (e) enumNames.add(e[1]);
8452
+ }
8453
+ const out = [];
8454
+ const seenTable = /* @__PURE__ */ new Set();
8455
+ const finalize = (b) => {
8456
+ if (seenTable.has(b.tableName)) return;
8457
+ seenTable.add(b.tableName);
8458
+ out.push({
8459
+ infraId: (0, import_types28.infraId)("sql-table", b.tableName),
8460
+ name: b.tableName,
8461
+ kind: "sql-table",
8462
+ edgeType: "CALLS",
8463
+ confidenceKind: "structural",
8464
+ columns: b.columns,
8465
+ evidence: {
8466
+ file: import_node_path38.default.relative(serviceDir, file.path),
8467
+ line: b.startLine,
8468
+ snippet: snippet(content, b.startLine)
8469
+ }
8470
+ });
8471
+ };
8472
+ let current = null;
8473
+ let depth = 0;
8474
+ for (let i = 0; i < lines.length; i++) {
8475
+ const raw = lines[i];
8476
+ const lineNo = i + 1;
8477
+ if (current === null) {
8478
+ const header = raw.match(/^\s*(model|enum|datasource|generator|type)\s+([A-Za-z_]\w*)\b/);
8479
+ if (header && raw.includes("{")) {
8480
+ current = {
8481
+ kind: header[1],
8482
+ tableName: header[2],
8483
+ startLine: lineNo,
8484
+ columns: [],
8485
+ seenCol: /* @__PURE__ */ new Set()
8486
+ };
8487
+ depth = netBraces(raw);
8488
+ if (depth <= 0) {
8489
+ if (current.kind === "model") finalize(current);
8490
+ current = null;
8491
+ }
8492
+ }
8493
+ continue;
8494
+ }
8495
+ depth += netBraces(raw);
8496
+ if (depth <= 0) {
8497
+ if (current.kind === "model") finalize(current);
8498
+ current = null;
8499
+ continue;
8500
+ }
8501
+ if (current.kind !== "model") continue;
8502
+ const trimmed = stripLineComment(raw).trim();
8503
+ if (!trimmed) continue;
8504
+ if (trimmed.startsWith("@@")) {
8505
+ const map = trimmed.match(/@@map\(\s*"([^"]+)"\s*\)/);
8506
+ if (map) current.tableName = map[1];
8507
+ continue;
8508
+ }
8509
+ const fm = trimmed.match(/^([A-Za-z_]\w*)\s+([A-Za-z_]\w*)/);
8510
+ if (!fm) continue;
8511
+ const fieldName = fm[1];
8512
+ const baseType = fm[2];
8513
+ if (/@relation\b/.test(trimmed) || modelNames.has(baseType)) continue;
8514
+ if (!enumNames.has(baseType) && !SCALAR_TYPES.has(baseType)) continue;
8515
+ const mapM = trimmed.match(/(?<!@)@map\(\s*"([^"]+)"\s*\)/);
8516
+ const columnName = mapM ? mapM[1] : fieldName;
8517
+ if (!current.seenCol.has(columnName)) {
8518
+ current.seenCol.add(columnName);
8519
+ current.columns.push(columnName);
8520
+ }
8521
+ }
8522
+ if (current && current.kind === "model") finalize(current);
8523
+ return out;
8524
+ }
8525
+ async function prismaColumnEndpoints(serviceDir) {
8526
+ const schemaPath = await findFirst(serviceDir, [
8527
+ import_node_path38.default.join("prisma", "schema.prisma"),
8528
+ "schema.prisma"
8529
+ ]);
8530
+ if (!schemaPath) return [];
8531
+ const content = await readIfExists(schemaPath);
8532
+ if (!content) return [];
8533
+ return prismaColumnsFromSchema({ path: schemaPath, content }, serviceDir);
8534
+ }
8535
+
8408
8536
  // src/extract/calls/go.ts
8409
8537
  init_cjs_shims();
8410
- var import_node_path40 = __toESM(require("path"), 1);
8538
+ var import_node_path41 = __toESM(require("path"), 1);
8411
8539
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
8412
8540
  var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
8413
- var import_types28 = require("@neat.is/types");
8541
+ var import_types29 = require("@neat.is/types");
8414
8542
  init_otel();
8415
8543
  var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
8416
8544
  var PARSE_CHUNK8 = 16384;
@@ -8422,7 +8550,7 @@ function walk5(node, visit) {
8422
8550
  }
8423
8551
  }
8424
8552
  function goSqlEndpointsFromFile(file, serviceDir) {
8425
- if (import_node_path40.default.extname(file.path) !== ".go") return [];
8553
+ if (import_node_path41.default.extname(file.path) !== ".go") return [];
8426
8554
  const parser = new import_tree_sitter10.default();
8427
8555
  parser.setLanguage(import_tree_sitter_go3.default);
8428
8556
  const tree = parser.parse(
@@ -8442,12 +8570,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
8442
8570
  if (!table) return;
8443
8571
  const line = node.startPosition.row + 1;
8444
8572
  out.push({
8445
- infraId: (0, import_types28.infraId)("sql-table", table),
8573
+ infraId: (0, import_types29.infraId)("sql-table", table),
8446
8574
  name: table,
8447
8575
  kind: "sql-table",
8448
8576
  edgeType: "CALLS",
8449
8577
  confidenceKind: "verified-call-site",
8450
- evidence: { file: toPosix(import_node_path40.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
8578
+ evidence: { file: toPosix(import_node_path41.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
8451
8579
  });
8452
8580
  });
8453
8581
  return out;
@@ -8457,11 +8585,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
8457
8585
  function edgeTypeFromEndpoint(ep) {
8458
8586
  switch (ep.edgeType) {
8459
8587
  case "PUBLISHES_TO":
8460
- return import_types29.EdgeType.PUBLISHES_TO;
8588
+ return import_types30.EdgeType.PUBLISHES_TO;
8461
8589
  case "CONSUMES_FROM":
8462
- return import_types29.EdgeType.CONSUMES_FROM;
8590
+ return import_types30.EdgeType.CONSUMES_FROM;
8463
8591
  default:
8464
- return import_types29.EdgeType.CALLS;
8592
+ return import_types30.EdgeType.CALLS;
8465
8593
  }
8466
8594
  }
8467
8595
  function isAwsKind(kind) {
@@ -8496,13 +8624,14 @@ async function addExternalEndpointEdges(graph, services) {
8496
8624
  }
8497
8625
  endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
8498
8626
  endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
8627
+ endpoints.push(...await prismaColumnEndpoints(service.dir));
8499
8628
  if (endpoints.length === 0) continue;
8500
8629
  const seenEdges = /* @__PURE__ */ new Set();
8501
8630
  for (const ep of endpoints) {
8502
8631
  if (!graph.hasNode(ep.infraId)) {
8503
8632
  const node = {
8504
8633
  id: ep.infraId,
8505
- type: import_types29.NodeType.InfraNode,
8634
+ type: import_types30.NodeType.InfraNode,
8506
8635
  name: ep.name,
8507
8636
  // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
8508
8637
  // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
@@ -8515,20 +8644,20 @@ async function addExternalEndpointEdges(graph, services) {
8515
8644
  }
8516
8645
  if (ep.columns && ep.columns.length > 0) {
8517
8646
  const node = graph.getNodeAttributes(ep.infraId);
8518
- if (node.type === import_types29.NodeType.InfraNode) {
8647
+ if (node.type === import_types30.NodeType.InfraNode) {
8519
8648
  graph.replaceNodeAttributes(ep.infraId, {
8520
8649
  ...node,
8521
8650
  columns: foldColumns(
8522
8651
  node.columns,
8523
8652
  ep.columns,
8524
- import_types29.Provenance.EXTRACTED,
8525
- (0, import_types29.confidenceForExtracted)(ep.confidenceKind)
8653
+ import_types30.Provenance.EXTRACTED,
8654
+ (0, import_types30.confidenceForExtracted)(ep.confidenceKind)
8526
8655
  )
8527
8656
  });
8528
8657
  }
8529
8658
  }
8530
8659
  const edgeType = edgeTypeFromEndpoint(ep);
8531
- const confidence = (0, import_types29.confidenceForExtracted)(ep.confidenceKind);
8660
+ const confidence = (0, import_types30.confidenceForExtracted)(ep.confidenceKind);
8532
8661
  const relFile = toPosix(ep.evidence.file);
8533
8662
  const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
8534
8663
  graph,
@@ -8538,7 +8667,7 @@ async function addExternalEndpointEdges(graph, services) {
8538
8667
  );
8539
8668
  nodesAdded += n;
8540
8669
  edgesAdded += e;
8541
- if (!(0, import_types29.passesExtractedFloor)(confidence)) {
8670
+ if (!(0, import_types30.passesExtractedFloor)(confidence)) {
8542
8671
  noteExtractedDropped({
8543
8672
  source: fileNodeId,
8544
8673
  target: ep.infraId,
@@ -8558,7 +8687,7 @@ async function addExternalEndpointEdges(graph, services) {
8558
8687
  source: fileNodeId,
8559
8688
  target: ep.infraId,
8560
8689
  type: edgeType,
8561
- provenance: import_types29.Provenance.EXTRACTED,
8690
+ provenance: import_types30.Provenance.EXTRACTED,
8562
8691
  confidence,
8563
8692
  evidence: ep.evidence
8564
8693
  };
@@ -8584,16 +8713,16 @@ init_cjs_shims();
8584
8713
 
8585
8714
  // src/extract/infra/docker-compose.ts
8586
8715
  init_cjs_shims();
8587
- var import_node_path41 = __toESM(require("path"), 1);
8588
- var import_types31 = require("@neat.is/types");
8716
+ var import_node_path42 = __toESM(require("path"), 1);
8717
+ var import_types32 = require("@neat.is/types");
8589
8718
 
8590
8719
  // src/extract/infra/shared.ts
8591
8720
  init_cjs_shims();
8592
- var import_types30 = require("@neat.is/types");
8721
+ var import_types31 = require("@neat.is/types");
8593
8722
  function makeInfraNode(kind, name, provider = "self", extras) {
8594
8723
  return {
8595
- id: (0, import_types30.infraId)(kind, name),
8596
- type: import_types30.NodeType.InfraNode,
8724
+ id: (0, import_types31.infraId)(kind, name),
8725
+ type: import_types31.NodeType.InfraNode,
8597
8726
  name,
8598
8727
  provider,
8599
8728
  kind,
@@ -8637,8 +8766,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
8637
8766
  source: anchorId,
8638
8767
  target: node.id,
8639
8768
  type: edgeType,
8640
- provenance: import_types30.Provenance.EXTRACTED,
8641
- confidence: (0, import_types30.confidenceForExtracted)("structural"),
8769
+ provenance: import_types31.Provenance.EXTRACTED,
8770
+ confidence: (0, import_types31.confidenceForExtracted)("structural"),
8642
8771
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
8643
8772
  };
8644
8773
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -8655,7 +8784,7 @@ function dependsOnList(value) {
8655
8784
  }
8656
8785
  function serviceNameToServiceNode(name, services) {
8657
8786
  for (const s of services) {
8658
- if (s.node.name === name || import_node_path41.default.basename(s.dir) === name) return s.node.id;
8787
+ if (s.node.name === name || import_node_path42.default.basename(s.dir) === name) return s.node.id;
8659
8788
  }
8660
8789
  return null;
8661
8790
  }
@@ -8664,7 +8793,7 @@ async function addComposeInfra(graph, scanPath, services) {
8664
8793
  let edgesAdded = 0;
8665
8794
  let composePath = null;
8666
8795
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
8667
- const abs = import_node_path41.default.join(scanPath, name);
8796
+ const abs = import_node_path42.default.join(scanPath, name);
8668
8797
  if (await exists(abs)) {
8669
8798
  composePath = abs;
8670
8799
  break;
@@ -8677,13 +8806,13 @@ async function addComposeInfra(graph, scanPath, services) {
8677
8806
  } catch (err) {
8678
8807
  recordExtractionError(
8679
8808
  "infra docker-compose",
8680
- import_node_path41.default.relative(scanPath, composePath),
8809
+ import_node_path42.default.relative(scanPath, composePath),
8681
8810
  err
8682
8811
  );
8683
8812
  return { nodesAdded, edgesAdded };
8684
8813
  }
8685
8814
  if (!compose?.services) return { nodesAdded, edgesAdded };
8686
- const evidenceFile = import_node_path41.default.relative(scanPath, composePath).split(import_node_path41.default.sep).join("/");
8815
+ const evidenceFile = import_node_path42.default.relative(scanPath, composePath).split(import_node_path42.default.sep).join("/");
8687
8816
  const composeNameToNodeId = /* @__PURE__ */ new Map();
8688
8817
  for (const [composeName, svc] of Object.entries(compose.services)) {
8689
8818
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -8705,15 +8834,15 @@ async function addComposeInfra(graph, scanPath, services) {
8705
8834
  for (const dep of dependsOnList(svc.depends_on)) {
8706
8835
  const targetId = composeNameToNodeId.get(dep);
8707
8836
  if (!targetId) continue;
8708
- const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types31.EdgeType.DEPENDS_ON);
8837
+ const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types32.EdgeType.DEPENDS_ON);
8709
8838
  if (graph.hasEdge(edgeId)) continue;
8710
8839
  const edge = {
8711
8840
  id: edgeId,
8712
8841
  source: sourceId,
8713
8842
  target: targetId,
8714
- type: import_types31.EdgeType.DEPENDS_ON,
8715
- provenance: import_types31.Provenance.EXTRACTED,
8716
- confidence: (0, import_types31.confidenceForExtracted)("structural"),
8843
+ type: import_types32.EdgeType.DEPENDS_ON,
8844
+ provenance: import_types32.Provenance.EXTRACTED,
8845
+ confidence: (0, import_types32.confidenceForExtracted)("structural"),
8717
8846
  evidence: { file: evidenceFile }
8718
8847
  };
8719
8848
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -8725,9 +8854,9 @@ async function addComposeInfra(graph, scanPath, services) {
8725
8854
 
8726
8855
  // src/extract/infra/dockerfile.ts
8727
8856
  init_cjs_shims();
8728
- var import_node_path42 = __toESM(require("path"), 1);
8857
+ var import_node_path43 = __toESM(require("path"), 1);
8729
8858
  var import_node_fs17 = require("fs");
8730
- var import_types32 = require("@neat.is/types");
8859
+ var import_types33 = require("@neat.is/types");
8731
8860
  function readDockerfile(content) {
8732
8861
  let image = null;
8733
8862
  const ports = [];
@@ -8756,7 +8885,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8756
8885
  let nodesAdded = 0;
8757
8886
  let edgesAdded = 0;
8758
8887
  for (const service of services) {
8759
- const dockerfilePath = import_node_path42.default.join(service.dir, "Dockerfile");
8888
+ const dockerfilePath = import_node_path43.default.join(service.dir, "Dockerfile");
8760
8889
  if (!await exists(dockerfilePath)) continue;
8761
8890
  let content;
8762
8891
  try {
@@ -8764,7 +8893,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8764
8893
  } catch (err) {
8765
8894
  recordExtractionError(
8766
8895
  "infra dockerfile",
8767
- import_node_path42.default.relative(scanPath, dockerfilePath),
8896
+ import_node_path43.default.relative(scanPath, dockerfilePath),
8768
8897
  err
8769
8898
  );
8770
8899
  continue;
@@ -8776,8 +8905,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8776
8905
  graph.addNode(node.id, node);
8777
8906
  nodesAdded++;
8778
8907
  }
8779
- const relDockerfile = toPosix(import_node_path42.default.relative(service.dir, dockerfilePath));
8780
- const evidenceFile = toPosix(import_node_path42.default.relative(scanPath, dockerfilePath));
8908
+ const relDockerfile = toPosix(import_node_path43.default.relative(service.dir, dockerfilePath));
8909
+ const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, dockerfilePath));
8781
8910
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
8782
8911
  graph,
8783
8912
  service.pkg.name,
@@ -8786,15 +8915,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8786
8915
  );
8787
8916
  nodesAdded += fn;
8788
8917
  edgesAdded += fe;
8789
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types32.EdgeType.RUNS_ON);
8918
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types33.EdgeType.RUNS_ON);
8790
8919
  if (!graph.hasEdge(edgeId)) {
8791
8920
  const edge = {
8792
8921
  id: edgeId,
8793
8922
  source: fileNodeId,
8794
8923
  target: node.id,
8795
- type: import_types32.EdgeType.RUNS_ON,
8796
- provenance: import_types32.Provenance.EXTRACTED,
8797
- confidence: (0, import_types32.confidenceForExtracted)("structural"),
8924
+ type: import_types33.EdgeType.RUNS_ON,
8925
+ provenance: import_types33.Provenance.EXTRACTED,
8926
+ confidence: (0, import_types33.confidenceForExtracted)("structural"),
8798
8927
  evidence: {
8799
8928
  file: evidenceFile,
8800
8929
  ...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
@@ -8809,15 +8938,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8809
8938
  graph.addNode(portNode.id, portNode);
8810
8939
  nodesAdded++;
8811
8940
  }
8812
- const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types32.EdgeType.CONNECTS_TO);
8941
+ const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types33.EdgeType.CONNECTS_TO);
8813
8942
  if (graph.hasEdge(portEdgeId)) continue;
8814
8943
  const portEdge = {
8815
8944
  id: portEdgeId,
8816
8945
  source: fileNodeId,
8817
8946
  target: portNode.id,
8818
- type: import_types32.EdgeType.CONNECTS_TO,
8819
- provenance: import_types32.Provenance.EXTRACTED,
8820
- confidence: (0, import_types32.confidenceForExtracted)("structural"),
8947
+ type: import_types33.EdgeType.CONNECTS_TO,
8948
+ provenance: import_types33.Provenance.EXTRACTED,
8949
+ confidence: (0, import_types33.confidenceForExtracted)("structural"),
8821
8950
  evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
8822
8951
  };
8823
8952
  graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
@@ -8830,8 +8959,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
8830
8959
  // src/extract/infra/terraform.ts
8831
8960
  init_cjs_shims();
8832
8961
  var import_node_fs18 = require("fs");
8833
- var import_node_path43 = __toESM(require("path"), 1);
8834
- var import_types33 = require("@neat.is/types");
8962
+ var import_node_path44 = __toESM(require("path"), 1);
8963
+ var import_types34 = require("@neat.is/types");
8835
8964
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
8836
8965
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
8837
8966
  async function walkTfFiles(start, depth = 0, max = 5) {
@@ -8841,11 +8970,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
8841
8970
  for (const entry of entries) {
8842
8971
  if (entry.isDirectory()) {
8843
8972
  if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
8844
- const child = import_node_path43.default.join(start, entry.name);
8973
+ const child = import_node_path44.default.join(start, entry.name);
8845
8974
  if (await isPythonVenvDir(child)) continue;
8846
8975
  out.push(...await walkTfFiles(child, depth + 1, max));
8847
8976
  } else if (entry.isFile() && entry.name.endsWith(".tf")) {
8848
- out.push(import_node_path43.default.join(start, entry.name));
8977
+ out.push(import_node_path44.default.join(start, entry.name));
8849
8978
  }
8850
8979
  }
8851
8980
  return out;
@@ -8877,7 +9006,7 @@ async function addTerraformResources(graph, scanPath) {
8877
9006
  const files = await walkTfFiles(scanPath);
8878
9007
  for (const file of files) {
8879
9008
  const content = await import_node_fs18.promises.readFile(file, "utf8");
8880
- const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, file));
9009
+ const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, file));
8881
9010
  const resources = [];
8882
9011
  const byKey = /* @__PURE__ */ new Map();
8883
9012
  RESOURCE_RE.lastIndex = 0;
@@ -8912,16 +9041,16 @@ async function addTerraformResources(graph, scanPath) {
8912
9041
  if (!target) continue;
8913
9042
  if (seen.has(target.nodeId)) continue;
8914
9043
  seen.add(target.nodeId);
8915
- const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types33.EdgeType.DEPENDS_ON);
9044
+ const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types34.EdgeType.DEPENDS_ON);
8916
9045
  if (graph.hasEdge(edgeId)) continue;
8917
9046
  const line = lineAt2(content, resource.bodyOffset + ref.index);
8918
9047
  const edge = {
8919
9048
  id: edgeId,
8920
9049
  source: resource.nodeId,
8921
9050
  target: target.nodeId,
8922
- type: import_types33.EdgeType.DEPENDS_ON,
8923
- provenance: import_types33.Provenance.EXTRACTED,
8924
- confidence: (0, import_types33.confidenceForExtracted)("structural"),
9051
+ type: import_types34.EdgeType.DEPENDS_ON,
9052
+ provenance: import_types34.Provenance.EXTRACTED,
9053
+ confidence: (0, import_types34.confidenceForExtracted)("structural"),
8925
9054
  evidence: { file: evidenceFile, line, snippet: key }
8926
9055
  };
8927
9056
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -8935,7 +9064,7 @@ async function addTerraformResources(graph, scanPath) {
8935
9064
  // src/extract/infra/k8s.ts
8936
9065
  init_cjs_shims();
8937
9066
  var import_node_fs19 = require("fs");
8938
- var import_node_path44 = __toESM(require("path"), 1);
9067
+ var import_node_path45 = __toESM(require("path"), 1);
8939
9068
  var import_yaml3 = require("yaml");
8940
9069
  var K8S_KIND_TO_INFRA_KIND = {
8941
9070
  Service: "k8s-service",
@@ -8953,11 +9082,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
8953
9082
  for (const entry of entries) {
8954
9083
  if (entry.isDirectory()) {
8955
9084
  if (IGNORED_DIRS.has(entry.name)) continue;
8956
- const child = import_node_path44.default.join(start, entry.name);
9085
+ const child = import_node_path45.default.join(start, entry.name);
8957
9086
  if (await isPythonVenvDir(child)) continue;
8958
9087
  out.push(...await walkYamlFiles2(child, depth + 1, max));
8959
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path44.default.extname(entry.name))) {
8960
- out.push(import_node_path44.default.join(start, entry.name));
9088
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path45.default.extname(entry.name))) {
9089
+ out.push(import_node_path45.default.join(start, entry.name));
8961
9090
  }
8962
9091
  }
8963
9092
  return out;
@@ -8991,13 +9120,13 @@ async function addK8sResources(graph, scanPath) {
8991
9120
  // src/extract/infra/cloudflare.ts
8992
9121
  init_cjs_shims();
8993
9122
  var import_node_fs20 = require("fs");
8994
- var import_node_path45 = __toESM(require("path"), 1);
9123
+ var import_node_path46 = __toESM(require("path"), 1);
8995
9124
  var import_smol_toml2 = require("smol-toml");
8996
- var import_types34 = require("@neat.is/types");
9125
+ var import_types35 = require("@neat.is/types");
8997
9126
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
8998
9127
  async function readWranglerConfig(dir) {
8999
9128
  for (const filename of WRANGLER_FILENAMES) {
9000
- const abs = import_node_path45.default.join(dir, filename);
9129
+ const abs = import_node_path46.default.join(dir, filename);
9001
9130
  if (!await exists(abs)) continue;
9002
9131
  const raw = await import_node_fs20.promises.readFile(abs, "utf8");
9003
9132
  const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -9041,8 +9170,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
9041
9170
  source: anchorId,
9042
9171
  target: node.id,
9043
9172
  type: edgeType,
9044
- provenance: import_types34.Provenance.EXTRACTED,
9045
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9173
+ provenance: import_types35.Provenance.EXTRACTED,
9174
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9046
9175
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
9047
9176
  };
9048
9177
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9060,11 +9189,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9060
9189
  try {
9061
9190
  read = await readWranglerConfig(service.dir);
9062
9191
  } catch (err) {
9063
- recordExtractionError("infra cloudflare", import_node_path45.default.relative(scanPath, service.dir), err);
9192
+ recordExtractionError("infra cloudflare", import_node_path46.default.relative(scanPath, service.dir), err);
9064
9193
  continue;
9065
9194
  }
9066
9195
  if (!read || !read.config.name) continue;
9067
- const evidenceFile = toPosix(import_node_path45.default.relative(scanPath, import_node_path45.default.join(service.dir, read.relFile)));
9196
+ const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, read.relFile)));
9068
9197
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
9069
9198
  }
9070
9199
  for (const worker of discovered) {
@@ -9076,7 +9205,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9076
9205
  }
9077
9206
  let anchorId = service.node.id;
9078
9207
  if (config.main) {
9079
- const entryRelPath = toPosix(import_node_path45.default.normalize(config.main));
9208
+ const entryRelPath = toPosix(import_node_path46.default.normalize(config.main));
9080
9209
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9081
9210
  graph,
9082
9211
  service.pkg.name,
@@ -9103,15 +9232,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9103
9232
  nodesAdded++;
9104
9233
  }
9105
9234
  if (runtimeNode.id !== anchorId) {
9106
- const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types34.EdgeType.RUNS_ON);
9235
+ const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types35.EdgeType.RUNS_ON);
9107
9236
  if (!graph.hasEdge(runsOnId)) {
9108
9237
  const edge = {
9109
9238
  id: runsOnId,
9110
9239
  source: anchorId,
9111
9240
  target: runtimeNode.id,
9112
- type: import_types34.EdgeType.RUNS_ON,
9113
- provenance: import_types34.Provenance.EXTRACTED,
9114
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9241
+ type: import_types35.EdgeType.RUNS_ON,
9242
+ provenance: import_types35.Provenance.EXTRACTED,
9243
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9115
9244
  evidence: {
9116
9245
  file: evidenceFile,
9117
9246
  ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
@@ -9125,7 +9254,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9125
9254
  const result = addResourceEdge(
9126
9255
  graph,
9127
9256
  anchorId,
9128
- import_types34.EdgeType.CONNECTS_TO,
9257
+ import_types35.EdgeType.CONNECTS_TO,
9129
9258
  "cloudflare-route",
9130
9259
  route,
9131
9260
  evidenceFile,
@@ -9149,7 +9278,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9149
9278
  const result = addResourceEdge(
9150
9279
  graph,
9151
9280
  anchorId,
9152
- import_types34.EdgeType.DEPENDS_ON,
9281
+ import_types35.EdgeType.DEPENDS_ON,
9153
9282
  group.kind,
9154
9283
  name,
9155
9284
  evidenceFile,
@@ -9163,7 +9292,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9163
9292
  const result = addResourceEdge(
9164
9293
  graph,
9165
9294
  anchorId,
9166
- import_types34.EdgeType.DEPENDS_ON,
9295
+ import_types35.EdgeType.DEPENDS_ON,
9167
9296
  "cloudflare-cron",
9168
9297
  cron,
9169
9298
  evidenceFile,
@@ -9176,7 +9305,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9176
9305
  const result = addResourceEdge(
9177
9306
  graph,
9178
9307
  anchorId,
9179
- import_types34.EdgeType.DEPENDS_ON,
9308
+ import_types35.EdgeType.DEPENDS_ON,
9180
9309
  "cloudflare-env-var",
9181
9310
  varName,
9182
9311
  evidenceFile,
@@ -9189,15 +9318,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9189
9318
  if (!svc.service) continue;
9190
9319
  const target = workerIndex.get(svc.service);
9191
9320
  if (target && target.anchorId !== anchorId) {
9192
- const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types34.EdgeType.CALLS);
9321
+ const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types35.EdgeType.CALLS);
9193
9322
  if (!graph.hasEdge(edgeId)) {
9194
9323
  const edge = {
9195
9324
  id: edgeId,
9196
9325
  source: anchorId,
9197
9326
  target: target.anchorId,
9198
- type: import_types34.EdgeType.CALLS,
9199
- provenance: import_types34.Provenance.EXTRACTED,
9200
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9327
+ type: import_types35.EdgeType.CALLS,
9328
+ provenance: import_types35.Provenance.EXTRACTED,
9329
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9201
9330
  evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
9202
9331
  };
9203
9332
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9208,7 +9337,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9208
9337
  const result = addResourceEdge(
9209
9338
  graph,
9210
9339
  anchorId,
9211
- import_types34.EdgeType.DEPENDS_ON,
9340
+ import_types35.EdgeType.DEPENDS_ON,
9212
9341
  "cloudflare-service-binding",
9213
9342
  svc.service,
9214
9343
  evidenceFile,
@@ -9224,12 +9353,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9224
9353
  // src/extract/infra/vercel.ts
9225
9354
  init_cjs_shims();
9226
9355
  var import_node_fs21 = require("fs");
9227
- var import_node_path46 = __toESM(require("path"), 1);
9228
- var import_types35 = require("@neat.is/types");
9356
+ var import_node_path47 = __toESM(require("path"), 1);
9357
+ var import_types36 = require("@neat.is/types");
9229
9358
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
9230
9359
  async function readVercelConfig(dir) {
9231
9360
  for (const filename of VERCEL_CONFIG_FILENAMES) {
9232
- const abs = import_node_path46.default.join(dir, filename);
9361
+ const abs = import_node_path47.default.join(dir, filename);
9233
9362
  if (!await exists(abs)) continue;
9234
9363
  const raw = await import_node_fs21.promises.readFile(abs, "utf8");
9235
9364
  const config = JSON.parse(maskCommentsInSource(raw));
@@ -9238,7 +9367,7 @@ async function readVercelConfig(dir) {
9238
9367
  return null;
9239
9368
  }
9240
9369
  async function readLinkedProjectName(dir) {
9241
- const abs = import_node_path46.default.join(dir, ".vercel", "project.json");
9370
+ const abs = import_node_path47.default.join(dir, ".vercel", "project.json");
9242
9371
  if (!await exists(abs)) return void 0;
9243
9372
  const parsed = JSON.parse(await import_node_fs21.promises.readFile(abs, "utf8"));
9244
9373
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
@@ -9256,7 +9385,7 @@ async function addVercelServices(graph, services, scanPath) {
9256
9385
  read = await readVercelConfig(service.dir);
9257
9386
  projectName = await readLinkedProjectName(service.dir);
9258
9387
  } catch (err) {
9259
- recordExtractionError("infra vercel", import_node_path46.default.relative(scanPath, service.dir), err);
9388
+ recordExtractionError("infra vercel", import_node_path47.default.relative(scanPath, service.dir), err);
9260
9389
  continue;
9261
9390
  }
9262
9391
  if (!read && !projectName) continue;
@@ -9272,7 +9401,7 @@ async function addVercelServices(graph, services, scanPath) {
9272
9401
  const anchorId = service.node.id;
9273
9402
  if (!read) continue;
9274
9403
  const { config, relFile, raw } = read;
9275
- const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, relFile)));
9404
+ const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
9276
9405
  const add = (edgeType, kind, name) => {
9277
9406
  if (!name) return;
9278
9407
  const result = emitPlatformResourceEdge(
@@ -9288,12 +9417,12 @@ async function addVercelServices(graph, services, scanPath) {
9288
9417
  nodesAdded += result.nodesAdded;
9289
9418
  edgesAdded += result.edgesAdded;
9290
9419
  };
9291
- add(import_types35.EdgeType.RUNS_ON, "vercel", "vercel");
9292
- for (const cron of config.crons ?? []) add(import_types35.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
9293
- for (const varName of Object.keys(config.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9294
- for (const varName of Object.keys(config.build?.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9420
+ add(import_types36.EdgeType.RUNS_ON, "vercel", "vercel");
9421
+ for (const cron of config.crons ?? []) add(import_types36.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
9422
+ for (const varName of Object.keys(config.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9423
+ for (const varName of Object.keys(config.build?.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9295
9424
  for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
9296
- add(import_types35.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
9425
+ add(import_types36.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
9297
9426
  }
9298
9427
  }
9299
9428
  return { nodesAdded, edgesAdded };
@@ -9302,13 +9431,13 @@ async function addVercelServices(graph, services, scanPath) {
9302
9431
  // src/extract/infra/railway.ts
9303
9432
  init_cjs_shims();
9304
9433
  var import_node_fs22 = require("fs");
9305
- var import_node_path47 = __toESM(require("path"), 1);
9434
+ var import_node_path48 = __toESM(require("path"), 1);
9306
9435
  var import_smol_toml3 = require("smol-toml");
9307
- var import_types36 = require("@neat.is/types");
9436
+ var import_types37 = require("@neat.is/types");
9308
9437
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
9309
9438
  async function readRailwayConfig(dir) {
9310
9439
  for (const filename of RAILWAY_FILENAMES) {
9311
- const abs = import_node_path47.default.join(dir, filename);
9440
+ const abs = import_node_path48.default.join(dir, filename);
9312
9441
  if (!await exists(abs)) continue;
9313
9442
  const raw = await import_node_fs22.promises.readFile(abs, "utf8");
9314
9443
  const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -9324,7 +9453,7 @@ async function addRailwayServices(graph, services, scanPath) {
9324
9453
  try {
9325
9454
  read = await readRailwayConfig(service.dir);
9326
9455
  } catch (err) {
9327
- recordExtractionError("infra railway", import_node_path47.default.relative(scanPath, service.dir), err);
9456
+ recordExtractionError("infra railway", import_node_path48.default.relative(scanPath, service.dir), err);
9328
9457
  continue;
9329
9458
  }
9330
9459
  if (!read) continue;
@@ -9334,7 +9463,7 @@ async function addRailwayServices(graph, services, scanPath) {
9334
9463
  }
9335
9464
  const anchorId = service.node.id;
9336
9465
  const { config, relFile, raw } = read;
9337
- const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
9466
+ const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
9338
9467
  const add = (edgeType, kind, name) => {
9339
9468
  if (!name) return;
9340
9469
  const result = emitPlatformResourceEdge(
@@ -9350,9 +9479,9 @@ async function addRailwayServices(graph, services, scanPath) {
9350
9479
  nodesAdded += result.nodesAdded;
9351
9480
  edgesAdded += result.edgesAdded;
9352
9481
  };
9353
- add(import_types36.EdgeType.RUNS_ON, "railway", "railway");
9354
- add(import_types36.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
9355
- add(import_types36.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
9482
+ add(import_types37.EdgeType.RUNS_ON, "railway", "railway");
9483
+ add(import_types37.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
9484
+ add(import_types37.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
9356
9485
  }
9357
9486
  return { nodesAdded, edgesAdded };
9358
9487
  }
@@ -9360,12 +9489,12 @@ async function addRailwayServices(graph, services, scanPath) {
9360
9489
  // src/extract/infra/supabase.ts
9361
9490
  init_cjs_shims();
9362
9491
  var import_node_fs23 = require("fs");
9363
- var import_node_path48 = __toESM(require("path"), 1);
9492
+ var import_node_path49 = __toESM(require("path"), 1);
9364
9493
  var import_smol_toml4 = require("smol-toml");
9365
- var import_types37 = require("@neat.is/types");
9494
+ var import_types38 = require("@neat.is/types");
9366
9495
  async function readSupabaseConfig(dir) {
9367
- const relFile = import_node_path48.default.join("supabase", "config.toml");
9368
- const abs = import_node_path48.default.join(dir, relFile);
9496
+ const relFile = import_node_path49.default.join("supabase", "config.toml");
9497
+ const abs = import_node_path49.default.join(dir, relFile);
9369
9498
  if (!await exists(abs)) return null;
9370
9499
  const raw = await import_node_fs23.promises.readFile(abs, "utf8");
9371
9500
  const config = (0, import_smol_toml4.parse)(raw);
@@ -9379,7 +9508,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
9379
9508
  try {
9380
9509
  read = await readSupabaseConfig(service.dir);
9381
9510
  } catch (err) {
9382
- recordExtractionError("infra supabase", import_node_path48.default.relative(scanPath, service.dir), err);
9511
+ recordExtractionError("infra supabase", import_node_path49.default.relative(scanPath, service.dir), err);
9383
9512
  continue;
9384
9513
  }
9385
9514
  if (!read) continue;
@@ -9394,7 +9523,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
9394
9523
  });
9395
9524
  }
9396
9525
  const anchorId = service.node.id;
9397
- const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
9526
+ const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
9398
9527
  const add = (edgeType, kind, name) => {
9399
9528
  if (!name) return;
9400
9529
  const result = emitPlatformResourceEdge(
@@ -9410,10 +9539,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
9410
9539
  nodesAdded += result.nodesAdded;
9411
9540
  edgesAdded += result.edgesAdded;
9412
9541
  };
9413
- add(import_types37.EdgeType.RUNS_ON, "supabase", "supabase");
9414
- for (const fn of Object.keys(config.functions ?? {})) add(import_types37.EdgeType.DEPENDS_ON, "supabase-function", fn);
9415
- if (config.storage) add(import_types37.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
9416
- if (config.auth) add(import_types37.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
9542
+ add(import_types38.EdgeType.RUNS_ON, "supabase", "supabase");
9543
+ for (const fn of Object.keys(config.functions ?? {})) add(import_types38.EdgeType.DEPENDS_ON, "supabase-function", fn);
9544
+ if (config.storage) add(import_types38.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
9545
+ if (config.auth) add(import_types38.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
9417
9546
  }
9418
9547
  return { nodesAdded, edgesAdded };
9419
9548
  }
@@ -9435,17 +9564,17 @@ async function addInfra(graph, scanPath, services) {
9435
9564
  }
9436
9565
 
9437
9566
  // src/extract/index.ts
9438
- var import_node_path50 = __toESM(require("path"), 1);
9567
+ var import_node_path51 = __toESM(require("path"), 1);
9439
9568
 
9440
9569
  // src/extract/retire.ts
9441
9570
  init_cjs_shims();
9442
9571
  var import_node_fs24 = require("fs");
9443
- var import_node_path49 = __toESM(require("path"), 1);
9444
- var import_types38 = require("@neat.is/types");
9572
+ var import_node_path50 = __toESM(require("path"), 1);
9573
+ var import_types39 = require("@neat.is/types");
9445
9574
  function dropOrphanedFileNodes(graph) {
9446
9575
  const orphans = [];
9447
9576
  graph.forEachNode((id, attrs) => {
9448
- if (attrs.type !== import_types38.NodeType.FileNode) return;
9577
+ if (attrs.type !== import_types39.NodeType.FileNode) return;
9449
9578
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
9450
9579
  orphans.push(id);
9451
9580
  }
@@ -9458,14 +9587,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
9458
9587
  const bases = [scanPath, ...serviceDirs];
9459
9588
  graph.forEachEdge((id, attrs) => {
9460
9589
  const edge = attrs;
9461
- if (edge.provenance !== import_types38.Provenance.EXTRACTED) return;
9590
+ if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
9462
9591
  const evidenceFile = edge.evidence?.file;
9463
9592
  if (!evidenceFile) return;
9464
- if (import_node_path49.default.isAbsolute(evidenceFile)) {
9593
+ if (import_node_path50.default.isAbsolute(evidenceFile)) {
9465
9594
  if (!(0, import_node_fs24.existsSync)(evidenceFile)) toDrop.push(id);
9466
9595
  return;
9467
9596
  }
9468
- const found = bases.some((base) => (0, import_node_fs24.existsSync)(import_node_path49.default.join(base, evidenceFile)));
9597
+ const found = bases.some((base) => (0, import_node_fs24.existsSync)(import_node_path50.default.join(base, evidenceFile)));
9469
9598
  if (!found) toDrop.push(id);
9470
9599
  });
9471
9600
  for (const id of toDrop) graph.dropEdge(id);
@@ -9518,7 +9647,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
9518
9647
  }
9519
9648
  const droppedEntries = drainDroppedExtracted();
9520
9649
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
9521
- const rejectedPath = import_node_path50.default.join(import_node_path50.default.dirname(opts.errorsPath), "rejected.ndjson");
9650
+ const rejectedPath = import_node_path51.default.join(import_node_path51.default.dirname(opts.errorsPath), "rejected.ndjson");
9522
9651
  try {
9523
9652
  await writeRejectedExtracted(droppedEntries, rejectedPath);
9524
9653
  } catch (err) {
@@ -9553,8 +9682,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
9553
9682
  // src/persist.ts
9554
9683
  init_cjs_shims();
9555
9684
  var import_node_fs25 = require("fs");
9556
- var import_node_path51 = __toESM(require("path"), 1);
9557
- var import_types39 = require("@neat.is/types");
9685
+ var import_node_path52 = __toESM(require("path"), 1);
9686
+ var import_types40 = require("@neat.is/types");
9558
9687
  var SCHEMA_VERSION = 6;
9559
9688
  function migrateV1ToV2(payload) {
9560
9689
  const nodes = payload.graph.nodes;
@@ -9578,7 +9707,7 @@ function migrateV5ToV6(payload) {
9578
9707
  if (Array.isArray(nodes)) {
9579
9708
  for (const node of nodes) {
9580
9709
  const attrs = node.attributes;
9581
- if (!attrs || attrs.type !== import_types39.NodeType.InfraNode) continue;
9710
+ if (!attrs || attrs.type !== import_types40.NodeType.InfraNode) continue;
9582
9711
  if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
9583
9712
  if (!Array.isArray(attrs.columns)) attrs.columns = [];
9584
9713
  }
@@ -9591,12 +9720,12 @@ function migrateV2ToV3(payload) {
9591
9720
  for (const edge of edges) {
9592
9721
  const attrs = edge.attributes;
9593
9722
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
9594
- attrs.provenance = import_types39.Provenance.OBSERVED;
9723
+ attrs.provenance = import_types40.Provenance.OBSERVED;
9595
9724
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
9596
9725
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
9597
9726
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
9598
9727
  if (type && source && target) {
9599
- const newId = (0, import_types39.observedEdgeId)(source, target, type);
9728
+ const newId = (0, import_types40.observedEdgeId)(source, target, type);
9600
9729
  attrs.id = newId;
9601
9730
  if (edge.key) edge.key = newId;
9602
9731
  }
@@ -9605,7 +9734,7 @@ function migrateV2ToV3(payload) {
9605
9734
  return { ...payload, schemaVersion: 3 };
9606
9735
  }
9607
9736
  async function ensureDir(filePath) {
9608
- await import_node_fs25.promises.mkdir(import_node_path51.default.dirname(filePath), { recursive: true });
9737
+ await import_node_fs25.promises.mkdir(import_node_path52.default.dirname(filePath), { recursive: true });
9609
9738
  }
9610
9739
  async function saveGraphToDisk(graph, outPath) {
9611
9740
  await ensureDir(outPath);
@@ -9694,19 +9823,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
9694
9823
  init_cjs_shims();
9695
9824
  var import_fastify2 = __toESM(require("fastify"), 1);
9696
9825
  var import_cors = __toESM(require("@fastify/cors"), 1);
9697
- var import_types58 = require("@neat.is/types");
9826
+ var import_types59 = require("@neat.is/types");
9698
9827
 
9699
9828
  // src/extend/index.ts
9700
9829
  init_cjs_shims();
9701
9830
  var import_node_fs27 = require("fs");
9702
- var import_node_path53 = __toESM(require("path"), 1);
9831
+ var import_node_path54 = __toESM(require("path"), 1);
9703
9832
  var import_node_os2 = __toESM(require("os"), 1);
9704
9833
  var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
9705
9834
 
9706
9835
  // src/installers/package-manager.ts
9707
9836
  init_cjs_shims();
9708
9837
  var import_node_fs26 = require("fs");
9709
- var import_node_path52 = __toESM(require("path"), 1);
9838
+ var import_node_path53 = __toESM(require("path"), 1);
9710
9839
  var import_node_child_process = require("child_process");
9711
9840
  var LOCKFILE_PRIORITY = [
9712
9841
  { lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
@@ -9728,22 +9857,22 @@ async function exists2(p) {
9728
9857
  }
9729
9858
  }
9730
9859
  async function detectPackageManager(serviceDir) {
9731
- let dir = import_node_path52.default.resolve(serviceDir);
9860
+ let dir = import_node_path53.default.resolve(serviceDir);
9732
9861
  const stops = /* @__PURE__ */ new Set();
9733
9862
  for (let i = 0; i < 64; i++) {
9734
9863
  if (stops.has(dir)) break;
9735
9864
  stops.add(dir);
9736
9865
  for (const candidate of LOCKFILE_PRIORITY) {
9737
- const lockPath = import_node_path52.default.join(dir, candidate.lockfile);
9866
+ const lockPath = import_node_path53.default.join(dir, candidate.lockfile);
9738
9867
  if (await exists2(lockPath)) {
9739
9868
  return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
9740
9869
  }
9741
9870
  }
9742
- const parent = import_node_path52.default.dirname(dir);
9871
+ const parent = import_node_path53.default.dirname(dir);
9743
9872
  if (parent === dir) break;
9744
9873
  dir = parent;
9745
9874
  }
9746
- return { pm: "npm", cwd: import_node_path52.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
9875
+ return { pm: "npm", cwd: import_node_path53.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
9747
9876
  }
9748
9877
  async function runPackageManagerInstall(cmd) {
9749
9878
  return new Promise((resolve) => {
@@ -9792,7 +9921,7 @@ async function fileExists2(p) {
9792
9921
  }
9793
9922
  }
9794
9923
  async function readPackageJson(scanPath) {
9795
- const pkgPath = import_node_path53.default.join(scanPath, "package.json");
9924
+ const pkgPath = import_node_path54.default.join(scanPath, "package.json");
9796
9925
  const raw = await import_node_fs27.promises.readFile(pkgPath, "utf8");
9797
9926
  return JSON.parse(raw);
9798
9927
  }
@@ -9811,11 +9940,11 @@ async function findHookFiles(scanPath) {
9811
9940
  for (const entry of entries) {
9812
9941
  if (entry.isDirectory()) {
9813
9942
  if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
9814
- await walk6(import_node_path53.default.join(dir, entry.name));
9943
+ await walk6(import_node_path54.default.join(dir, entry.name));
9815
9944
  } else if (entry.isFile()) {
9816
9945
  if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
9817
- const rel = import_node_path53.default.relative(scanPath, import_node_path53.default.join(dir, entry.name));
9818
- found.push(rel.split(import_node_path53.default.sep).join("/"));
9946
+ const rel = import_node_path54.default.relative(scanPath, import_node_path54.default.join(dir, entry.name));
9947
+ found.push(rel.split(import_node_path54.default.sep).join("/"));
9819
9948
  }
9820
9949
  }
9821
9950
  }
@@ -9826,7 +9955,7 @@ async function findHookFiles(scanPath) {
9826
9955
  async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
9827
9956
  let fallback = null;
9828
9957
  for (const file of hookFiles) {
9829
- const content = await import_node_fs27.promises.readFile(import_node_path53.default.join(scanPath, file), "utf8");
9958
+ const content = await import_node_fs27.promises.readFile(import_node_path54.default.join(scanPath, file), "utf8");
9830
9959
  const patched = splicedContent(content, snippet2);
9831
9960
  if (patched !== null) return { file, content, patched };
9832
9961
  if (fallback === null) fallback = { file, content };
@@ -9834,11 +9963,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
9834
9963
  return { file: fallback.file, content: fallback.content, patched: null };
9835
9964
  }
9836
9965
  function extendLogPath() {
9837
- return process.env.NEAT_EXTEND_LOG ?? import_node_path53.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
9966
+ return process.env.NEAT_EXTEND_LOG ?? import_node_path54.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
9838
9967
  }
9839
9968
  async function appendExtendLog(entry) {
9840
9969
  const logPath = extendLogPath();
9841
- await import_node_fs27.promises.mkdir(import_node_path53.default.dirname(logPath), { recursive: true });
9970
+ await import_node_fs27.promises.mkdir(import_node_path54.default.dirname(logPath), { recursive: true });
9842
9971
  await import_node_fs27.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
9843
9972
  }
9844
9973
  function splicedContent(fileContent, snippet2) {
@@ -9897,7 +10026,7 @@ function lookupInstrumentation(library, installedVersion) {
9897
10026
  }
9898
10027
  async function describeProjectInstrumentation(ctx) {
9899
10028
  const hookFiles = await findHookFiles(ctx.scanPath);
9900
- const envNeat = await fileExists2(import_node_path53.default.join(ctx.scanPath, ".env.neat"));
10029
+ const envNeat = await fileExists2(import_node_path54.default.join(ctx.scanPath, ".env.neat"));
9901
10030
  const registryInstrPackages = new Set(
9902
10031
  (0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
9903
10032
  );
@@ -9919,7 +10048,7 @@ async function applyExtension(ctx, args, options) {
9919
10048
  );
9920
10049
  }
9921
10050
  for (const file of hookFiles) {
9922
- const content = await import_node_fs27.promises.readFile(import_node_path53.default.join(ctx.scanPath, file), "utf8");
10051
+ const content = await import_node_fs27.promises.readFile(import_node_path54.default.join(ctx.scanPath, file), "utf8");
9923
10052
  if (content.includes(args.registration_snippet)) {
9924
10053
  return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
9925
10054
  }
@@ -9931,10 +10060,10 @@ async function applyExtension(ctx, args, options) {
9931
10060
  );
9932
10061
  }
9933
10062
  const primaryFile = primary.file;
9934
- const primaryPath = import_node_path53.default.join(ctx.scanPath, primaryFile);
10063
+ const primaryPath = import_node_path54.default.join(ctx.scanPath, primaryFile);
9935
10064
  const filesTouched = [];
9936
10065
  const depsAdded = [];
9937
- const pkgPath = import_node_path53.default.join(ctx.scanPath, "package.json");
10066
+ const pkgPath = import_node_path54.default.join(ctx.scanPath, "package.json");
9938
10067
  const pkg = await readPackageJson(ctx.scanPath);
9939
10068
  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
9940
10069
  pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
@@ -9973,7 +10102,7 @@ async function dryRunExtension(ctx, args) {
9973
10102
  };
9974
10103
  }
9975
10104
  for (const file of hookFiles) {
9976
- const content = await import_node_fs27.promises.readFile(import_node_path53.default.join(ctx.scanPath, file), "utf8");
10105
+ const content = await import_node_fs27.promises.readFile(import_node_path54.default.join(ctx.scanPath, file), "utf8");
9977
10106
  if (content.includes(args.registration_snippet)) {
9978
10107
  return {
9979
10108
  library: args.library,
@@ -10014,7 +10143,7 @@ async function rollbackExtension(ctx, args) {
10014
10143
  if (!match) {
10015
10144
  return { undone: false, message: "no apply found for library" };
10016
10145
  }
10017
- const pkgPath = import_node_path53.default.join(ctx.scanPath, "package.json");
10146
+ const pkgPath = import_node_path54.default.join(ctx.scanPath, "package.json");
10018
10147
  if (await fileExists2(pkgPath)) {
10019
10148
  const pkg = await readPackageJson(ctx.scanPath);
10020
10149
  if (pkg.dependencies?.[match.instrumentation_package]) {
@@ -10025,7 +10154,7 @@ async function rollbackExtension(ctx, args) {
10025
10154
  }
10026
10155
  const hookFiles = await findHookFiles(ctx.scanPath);
10027
10156
  for (const file of hookFiles) {
10028
- const filePath = import_node_path53.default.join(ctx.scanPath, file);
10157
+ const filePath = import_node_path54.default.join(ctx.scanPath, file);
10029
10158
  const content = await import_node_fs27.promises.readFile(filePath, "utf8");
10030
10159
  if (content.includes(match.registration_snippet)) {
10031
10160
  const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
@@ -10041,39 +10170,39 @@ async function rollbackExtension(ctx, args) {
10041
10170
 
10042
10171
  // src/divergences.ts
10043
10172
  init_cjs_shims();
10044
- var import_types40 = require("@neat.is/types");
10173
+ var import_types41 = require("@neat.is/types");
10045
10174
  function bucketKey(source, target, type) {
10046
10175
  return `${type}|${source}|${target}`;
10047
10176
  }
10048
10177
  function bucketSourceFor(graph, edge) {
10049
- if (edge.type !== import_types40.EdgeType.CONNECTS_TO) return edge.source;
10050
- const parsed = (0, import_types40.parseFileId)(edge.source);
10178
+ if (edge.type !== import_types41.EdgeType.CONNECTS_TO) return edge.source;
10179
+ const parsed = (0, import_types41.parseFileId)(edge.source);
10051
10180
  if (!parsed || !graph.hasNode(edge.target)) return edge.source;
10052
10181
  const target = graph.getNodeAttributes(edge.target);
10053
- if (target.type !== import_types40.NodeType.DatabaseNode) return edge.source;
10054
- return (0, import_types40.serviceId)(parsed.service);
10182
+ if (target.type !== import_types41.NodeType.DatabaseNode) return edge.source;
10183
+ return (0, import_types41.serviceId)(parsed.service);
10055
10184
  }
10056
10185
  function bucketEdges(graph) {
10057
10186
  const buckets2 = /* @__PURE__ */ new Map();
10058
10187
  graph.forEachEdge((id, attrs) => {
10059
10188
  const e = attrs;
10060
- const parsed = (0, import_types40.parseEdgeId)(id);
10189
+ const parsed = (0, import_types41.parseEdgeId)(id);
10061
10190
  const provenance = parsed?.provenance ?? e.provenance;
10062
10191
  const source = bucketSourceFor(graph, e);
10063
10192
  const key = bucketKey(source, e.target, e.type);
10064
10193
  const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
10065
10194
  switch (provenance) {
10066
- case import_types40.Provenance.EXTRACTED:
10195
+ case import_types41.Provenance.EXTRACTED:
10067
10196
  cur.extracted = e;
10068
10197
  break;
10069
- case import_types40.Provenance.OBSERVED:
10198
+ case import_types41.Provenance.OBSERVED:
10070
10199
  cur.observed = e;
10071
10200
  break;
10072
- case import_types40.Provenance.INFERRED:
10201
+ case import_types41.Provenance.INFERRED:
10073
10202
  cur.inferred = e;
10074
10203
  break;
10075
10204
  default:
10076
- if (e.provenance === import_types40.Provenance.STALE) cur.stale = e;
10205
+ if (e.provenance === import_types41.Provenance.STALE) cur.stale = e;
10077
10206
  }
10078
10207
  buckets2.set(key, cur);
10079
10208
  });
@@ -10082,17 +10211,17 @@ function bucketEdges(graph) {
10082
10211
  function nodeIsFrontier(graph, nodeId) {
10083
10212
  if (!graph.hasNode(nodeId)) return false;
10084
10213
  const attrs = graph.getNodeAttributes(nodeId);
10085
- return attrs.type === import_types40.NodeType.FrontierNode;
10214
+ return attrs.type === import_types41.NodeType.FrontierNode;
10086
10215
  }
10087
10216
  function nodeIsWebsocketChannel(graph, nodeId) {
10088
10217
  if (!graph.hasNode(nodeId)) return false;
10089
10218
  const attrs = graph.getNodeAttributes(nodeId);
10090
- return attrs.type === import_types40.NodeType.WebSocketChannelNode;
10219
+ return attrs.type === import_types41.NodeType.WebSocketChannelNode;
10091
10220
  }
10092
10221
  function nodeIsSymbol(graph, nodeId) {
10093
10222
  if (!graph.hasNode(nodeId)) return false;
10094
10223
  const attrs = graph.getNodeAttributes(nodeId);
10095
- return attrs.type === import_types40.NodeType.SymbolNode;
10224
+ return attrs.type === import_types41.NodeType.SymbolNode;
10096
10225
  }
10097
10226
  function clampConfidence(n) {
10098
10227
  if (!Number.isFinite(n)) return 0;
@@ -10112,14 +10241,14 @@ function gradedConfidence(edge) {
10112
10241
  return clampConfidence(confidenceForEdge(edge));
10113
10242
  }
10114
10243
  var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
10115
- import_types40.EdgeType.CALLS,
10116
- import_types40.EdgeType.CONNECTS_TO,
10117
- import_types40.EdgeType.PUBLISHES_TO,
10118
- import_types40.EdgeType.CONSUMES_FROM
10244
+ import_types41.EdgeType.CALLS,
10245
+ import_types41.EdgeType.CONNECTS_TO,
10246
+ import_types41.EdgeType.PUBLISHES_TO,
10247
+ import_types41.EdgeType.CONSUMES_FROM
10119
10248
  ]);
10120
10249
  function detectMissingDivergences(graph, bucket) {
10121
10250
  const out = [];
10122
- if (bucket.type === import_types40.EdgeType.CONTAINS) return out;
10251
+ if (bucket.type === import_types41.EdgeType.CONTAINS) return out;
10123
10252
  if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
10124
10253
  if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
10125
10254
  if (!nodeIsFrontier(graph, bucket.target)) {
@@ -10161,7 +10290,7 @@ function declaredHostFor(svc) {
10161
10290
  function hasExtractedConfiguredBy(graph, svcId) {
10162
10291
  for (const edgeId of graph.outboundEdges(svcId)) {
10163
10292
  const e = graph.getEdgeAttributes(edgeId);
10164
- if (e.type === import_types40.EdgeType.CONFIGURED_BY && e.provenance === import_types40.Provenance.EXTRACTED) {
10293
+ if (e.type === import_types41.EdgeType.CONFIGURED_BY && e.provenance === import_types41.Provenance.EXTRACTED) {
10165
10294
  return true;
10166
10295
  }
10167
10296
  }
@@ -10174,10 +10303,10 @@ function detectHostMismatch(graph, svcId, svc) {
10174
10303
  const out = [];
10175
10304
  for (const edgeId of graph.outboundEdges(svcId)) {
10176
10305
  const edge = graph.getEdgeAttributes(edgeId);
10177
- if (edge.type !== import_types40.EdgeType.CONNECTS_TO) continue;
10178
- if (edge.provenance !== import_types40.Provenance.OBSERVED) continue;
10306
+ if (edge.type !== import_types41.EdgeType.CONNECTS_TO) continue;
10307
+ if (edge.provenance !== import_types41.Provenance.OBSERVED) continue;
10179
10308
  const target = graph.getNodeAttributes(edge.target);
10180
- if (target.type !== import_types40.NodeType.DatabaseNode) continue;
10309
+ if (target.type !== import_types41.NodeType.DatabaseNode) continue;
10181
10310
  const observedHost = target.host?.trim();
10182
10311
  if (!observedHost) continue;
10183
10312
  if (observedHost === declaredHost) continue;
@@ -10199,10 +10328,10 @@ function detectCompatDivergences(graph, svcId, svc) {
10199
10328
  const deps = svc.dependencies ?? {};
10200
10329
  for (const edgeId of graph.outboundEdges(svcId)) {
10201
10330
  const edge = graph.getEdgeAttributes(edgeId);
10202
- if (edge.type !== import_types40.EdgeType.CONNECTS_TO) continue;
10203
- if (edge.provenance !== import_types40.Provenance.OBSERVED) continue;
10331
+ if (edge.type !== import_types41.EdgeType.CONNECTS_TO) continue;
10332
+ if (edge.provenance !== import_types41.Provenance.OBSERVED) continue;
10204
10333
  const target = graph.getNodeAttributes(edge.target);
10205
- if (target.type !== import_types40.NodeType.DatabaseNode) continue;
10334
+ if (target.type !== import_types41.NodeType.DatabaseNode) continue;
10206
10335
  for (const pair of compatPairs()) {
10207
10336
  if (pair.engine !== target.engine) continue;
10208
10337
  const declared = deps[pair.driver];
@@ -10299,7 +10428,7 @@ function suppressHostMismatchHalves(all) {
10299
10428
  for (const d of all) {
10300
10429
  if (d.type !== "host-mismatch") continue;
10301
10430
  observedHalf.add(`${d.source}->${d.target}`);
10302
- declaredHalf.add((0, import_types40.databaseId)(d.extractedHost));
10431
+ declaredHalf.add((0, import_types41.databaseId)(d.extractedHost));
10303
10432
  }
10304
10433
  if (observedHalf.size === 0) return all;
10305
10434
  return all.filter((d) => {
@@ -10318,13 +10447,13 @@ function computeDivergences(graph, opts = {}) {
10318
10447
  }
10319
10448
  graph.forEachNode((nodeId, attrs) => {
10320
10449
  const n = attrs;
10321
- if (n.type === import_types40.NodeType.ServiceNode) {
10450
+ if (n.type === import_types41.NodeType.ServiceNode) {
10322
10451
  const svc = n;
10323
10452
  for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
10324
10453
  for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
10325
10454
  return;
10326
10455
  }
10327
- if (n.type === import_types40.NodeType.InfraNode && n.kind === "sql-table") {
10456
+ if (n.type === import_types41.NodeType.InfraNode && n.kind === "sql-table") {
10328
10457
  for (const d of detectColumnDrift(n)) all.push(d);
10329
10458
  }
10330
10459
  });
@@ -10360,7 +10489,7 @@ function computeDivergences(graph, opts = {}) {
10360
10489
  const bc = "column" in b && b.column ? b.column : "";
10361
10490
  return ac.localeCompare(bc);
10362
10491
  });
10363
- return import_types40.DivergenceResultSchema.parse({
10492
+ return import_types41.DivergenceResultSchema.parse({
10364
10493
  divergences: filtered,
10365
10494
  totalAffected: filtered.length,
10366
10495
  computedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -10491,23 +10620,23 @@ function canonicalJson(value) {
10491
10620
 
10492
10621
  // src/projects.ts
10493
10622
  init_cjs_shims();
10494
- var import_node_path54 = __toESM(require("path"), 1);
10623
+ var import_node_path55 = __toESM(require("path"), 1);
10495
10624
  function pathsForProject(project, baseDir) {
10496
10625
  if (project === DEFAULT_PROJECT) {
10497
10626
  return {
10498
- snapshotPath: import_node_path54.default.join(baseDir, "graph.json"),
10499
- errorsPath: import_node_path54.default.join(baseDir, "errors.ndjson"),
10500
- staleEventsPath: import_node_path54.default.join(baseDir, "stale-events.ndjson"),
10501
- embeddingsCachePath: import_node_path54.default.join(baseDir, "embeddings.json"),
10502
- policyViolationsPath: import_node_path54.default.join(baseDir, "policy-violations.ndjson")
10627
+ snapshotPath: import_node_path55.default.join(baseDir, "graph.json"),
10628
+ errorsPath: import_node_path55.default.join(baseDir, "errors.ndjson"),
10629
+ staleEventsPath: import_node_path55.default.join(baseDir, "stale-events.ndjson"),
10630
+ embeddingsCachePath: import_node_path55.default.join(baseDir, "embeddings.json"),
10631
+ policyViolationsPath: import_node_path55.default.join(baseDir, "policy-violations.ndjson")
10503
10632
  };
10504
10633
  }
10505
10634
  return {
10506
- snapshotPath: import_node_path54.default.join(baseDir, `${project}.json`),
10507
- errorsPath: import_node_path54.default.join(baseDir, `errors.${project}.ndjson`),
10508
- staleEventsPath: import_node_path54.default.join(baseDir, `stale-events.${project}.ndjson`),
10509
- embeddingsCachePath: import_node_path54.default.join(baseDir, `embeddings.${project}.json`),
10510
- policyViolationsPath: import_node_path54.default.join(baseDir, `policy-violations.${project}.ndjson`)
10635
+ snapshotPath: import_node_path55.default.join(baseDir, `${project}.json`),
10636
+ errorsPath: import_node_path55.default.join(baseDir, `errors.${project}.ndjson`),
10637
+ staleEventsPath: import_node_path55.default.join(baseDir, `stale-events.${project}.ndjson`),
10638
+ embeddingsCachePath: import_node_path55.default.join(baseDir, `embeddings.${project}.json`),
10639
+ policyViolationsPath: import_node_path55.default.join(baseDir, `policy-violations.${project}.ndjson`)
10511
10640
  };
10512
10641
  }
10513
10642
  var Projects = class {
@@ -10545,26 +10674,26 @@ var Projects = class {
10545
10674
  init_cjs_shims();
10546
10675
  var import_node_fs29 = require("fs");
10547
10676
  var import_node_os3 = __toESM(require("os"), 1);
10548
- var import_node_path55 = __toESM(require("path"), 1);
10549
- var import_types41 = require("@neat.is/types");
10677
+ var import_node_path56 = __toESM(require("path"), 1);
10678
+ var import_types42 = require("@neat.is/types");
10550
10679
  var LOCK_TIMEOUT_MS = 5e3;
10551
10680
  var LOCK_RETRY_MS = 50;
10552
10681
  function neatHome() {
10553
10682
  const override = process.env.NEAT_HOME;
10554
- if (override && override.length > 0) return import_node_path55.default.resolve(override);
10555
- return import_node_path55.default.join(import_node_os3.default.homedir(), ".neat");
10683
+ if (override && override.length > 0) return import_node_path56.default.resolve(override);
10684
+ return import_node_path56.default.join(import_node_os3.default.homedir(), ".neat");
10556
10685
  }
10557
10686
  function registryPath() {
10558
- return import_node_path55.default.join(neatHome(), "projects.json");
10687
+ return import_node_path56.default.join(neatHome(), "projects.json");
10559
10688
  }
10560
10689
  function registryLockPath() {
10561
- return import_node_path55.default.join(neatHome(), "projects.json.lock");
10690
+ return import_node_path56.default.join(neatHome(), "projects.json.lock");
10562
10691
  }
10563
10692
  function daemonPidPath() {
10564
- return import_node_path55.default.join(neatHome(), "neatd.pid");
10693
+ return import_node_path56.default.join(neatHome(), "neatd.pid");
10565
10694
  }
10566
10695
  function daemonsDir() {
10567
- return import_node_path55.default.join(neatHome(), "daemons");
10696
+ return import_node_path56.default.join(neatHome(), "daemons");
10568
10697
  }
10569
10698
  function isFiniteInt(v) {
10570
10699
  return typeof v === "number" && Number.isFinite(v);
@@ -10605,7 +10734,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
10605
10734
  const out = [];
10606
10735
  for (const name of names) {
10607
10736
  if (!name.endsWith(".json")) continue;
10608
- const file = import_node_path55.default.join(dir, name);
10737
+ const file = import_node_path56.default.join(dir, name);
10609
10738
  let raw;
10610
10739
  try {
10611
10740
  raw = await import_node_fs29.promises.readFile(file, "utf8");
@@ -10682,7 +10811,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
10682
10811
  }
10683
10812
  }
10684
10813
  async function normalizeProjectPath(input) {
10685
- const resolved = import_node_path55.default.resolve(input);
10814
+ const resolved = import_node_path56.default.resolve(input);
10686
10815
  try {
10687
10816
  return await import_node_fs29.promises.realpath(resolved);
10688
10817
  } catch {
@@ -10690,7 +10819,7 @@ async function normalizeProjectPath(input) {
10690
10819
  }
10691
10820
  }
10692
10821
  async function writeAtomically(target, contents) {
10693
- await import_node_fs29.promises.mkdir(import_node_path55.default.dirname(target), { recursive: true });
10822
+ await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(target), { recursive: true });
10694
10823
  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
10695
10824
  const fd = await import_node_fs29.promises.open(tmp, "w");
10696
10825
  try {
@@ -10703,7 +10832,7 @@ async function writeAtomically(target, contents) {
10703
10832
  }
10704
10833
  async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
10705
10834
  const deadline = Date.now() + timeoutMs;
10706
- await import_node_fs29.promises.mkdir(import_node_path55.default.dirname(lockPath), { recursive: true });
10835
+ await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(lockPath), { recursive: true });
10707
10836
  let probedHolder = false;
10708
10837
  while (true) {
10709
10838
  try {
@@ -10756,10 +10885,10 @@ async function readRegistry() {
10756
10885
  throw err;
10757
10886
  }
10758
10887
  const parsed = JSON.parse(raw);
10759
- return import_types41.RegistryFileSchema.parse(parsed);
10888
+ return import_types42.RegistryFileSchema.parse(parsed);
10760
10889
  }
10761
10890
  async function writeRegistry(reg) {
10762
- const validated = import_types41.RegistryFileSchema.parse(reg);
10891
+ const validated = import_types42.RegistryFileSchema.parse(reg);
10763
10892
  await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
10764
10893
  }
10765
10894
  var ProjectNameCollisionError = class extends Error {
@@ -10954,7 +11083,7 @@ init_auth();
10954
11083
  // src/connectors-config.ts
10955
11084
  init_cjs_shims();
10956
11085
  var import_node_os4 = __toESM(require("os"), 1);
10957
- var import_node_path56 = __toESM(require("path"), 1);
11086
+ var import_node_path57 = __toESM(require("path"), 1);
10958
11087
  var import_node_fs30 = require("fs");
10959
11088
  var CONNECTORS_CONFIG_VERSION = 1;
10960
11089
  var EnvRefUnsetError = class extends Error {
@@ -10969,11 +11098,11 @@ var EnvRefUnsetError = class extends Error {
10969
11098
  };
10970
11099
  function neatHome2() {
10971
11100
  const override = process.env.NEAT_HOME;
10972
- if (override && override.length > 0) return import_node_path56.default.resolve(override);
10973
- return import_node_path56.default.join(import_node_os4.default.homedir(), ".neat");
11101
+ if (override && override.length > 0) return import_node_path57.default.resolve(override);
11102
+ return import_node_path57.default.join(import_node_os4.default.homedir(), ".neat");
10974
11103
  }
10975
11104
  function connectorsConfigPath(home = neatHome2()) {
10976
- return import_node_path56.default.join(home, "connectors.json");
11105
+ return import_node_path57.default.join(home, "connectors.json");
10977
11106
  }
10978
11107
  var MODE_MASK_LOOSER_THAN_0600 = 63;
10979
11108
  async function warnIfModeLooserThan0600(file) {
@@ -11160,15 +11289,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
11160
11289
 
11161
11290
  // src/connectors/index.ts
11162
11291
  init_cjs_shims();
11163
- var import_types42 = require("@neat.is/types");
11292
+ var import_types43 = require("@neat.is/types");
11164
11293
  var NO_ENV = "unknown";
11165
11294
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
11166
11295
  if (!graph.hasNode(targetNodeId)) return void 0;
11167
11296
  const sites = [];
11168
11297
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
11169
11298
  const edge = graph.getEdgeAttributes(edgeId);
11170
- if (edge.provenance !== import_types42.Provenance.EXTRACTED) continue;
11171
- const parsed = (0, import_types42.parseFileId)(edge.source);
11299
+ if (edge.provenance !== import_types43.Provenance.EXTRACTED) continue;
11300
+ const parsed = (0, import_types43.parseFileId)(edge.source);
11172
11301
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
11173
11302
  const site = { relPath: edge.evidence.file };
11174
11303
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -11179,7 +11308,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
11179
11308
  function routeCallSiteFor(graph, targetNodeId) {
11180
11309
  if (!graph.hasNode(targetNodeId)) return void 0;
11181
11310
  const attrs = graph.getNodeAttributes(targetNodeId);
11182
- if (attrs.type !== import_types42.NodeType.RouteNode || !attrs.path) return void 0;
11311
+ if (attrs.type !== import_types43.NodeType.RouteNode || !attrs.path) return void 0;
11183
11312
  const site = { relPath: attrs.path };
11184
11313
  if (attrs.line !== void 0) site.line = attrs.line;
11185
11314
  return site;
@@ -11656,10 +11785,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
11656
11785
  // src/connectors/supabase/map.ts
11657
11786
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
11658
11787
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
11659
- function targetFromRestPath(path59) {
11660
- const rpcMatch = REST_RPC_PATH_RE.exec(path59);
11788
+ function targetFromRestPath(path60) {
11789
+ const rpcMatch = REST_RPC_PATH_RE.exec(path60);
11661
11790
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
11662
- const tableMatch = REST_TABLE_PATH_RE.exec(path59);
11791
+ const tableMatch = REST_TABLE_PATH_RE.exec(path60);
11663
11792
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
11664
11793
  return null;
11665
11794
  }
@@ -11770,23 +11899,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
11770
11899
 
11771
11900
  // src/connectors/supabase/resolve.ts
11772
11901
  init_cjs_shims();
11773
- var import_types44 = require("@neat.is/types");
11902
+ var import_types45 = require("@neat.is/types");
11774
11903
  function createSupabaseResolveTarget(graph, config) {
11775
11904
  return (signal, _ctx) => {
11776
11905
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
11777
11906
  return null;
11778
11907
  }
11779
- const subResourceId = (0, import_types44.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
11908
+ const subResourceId = (0, import_types45.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
11780
11909
  if (graph.hasNode(subResourceId)) {
11781
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
11910
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
11782
11911
  }
11783
- const bareResourceId = (0, import_types44.infraId)(signal.targetKind, signal.targetName);
11912
+ const bareResourceId = (0, import_types45.infraId)(signal.targetKind, signal.targetName);
11784
11913
  if (graph.hasNode(bareResourceId)) {
11785
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
11914
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
11786
11915
  }
11787
- const projectLevelId = (0, import_types44.infraId)("supabase", config.nodeRef);
11916
+ const projectLevelId = (0, import_types45.infraId)("supabase", config.nodeRef);
11788
11917
  if (graph.hasNode(projectLevelId)) {
11789
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
11918
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
11790
11919
  }
11791
11920
  return null;
11792
11921
  };
@@ -11879,7 +12008,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
11879
12008
 
11880
12009
  // src/connectors/railway/index.ts
11881
12010
  init_cjs_shims();
11882
- var import_types48 = require("@neat.is/types");
12011
+ var import_types49 = require("@neat.is/types");
11883
12012
 
11884
12013
  // src/connectors/railway/client.ts
11885
12014
  init_cjs_shims();
@@ -12030,7 +12159,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
12030
12159
  const out = [];
12031
12160
  graph.forEachNode((_id, attrs) => {
12032
12161
  const node = attrs;
12033
- if (node.type !== import_types48.NodeType.RouteNode) return;
12162
+ if (node.type !== import_types49.NodeType.RouteNode) return;
12034
12163
  const route = attrs;
12035
12164
  if (route.service !== serviceName) return;
12036
12165
  out.push({
@@ -12134,12 +12263,12 @@ function createRailwayResolveTarget(config) {
12134
12263
  const serviceName = config.serviceNameById[config.serviceId];
12135
12264
  if (!serviceName) return null;
12136
12265
  if (signal.targetKind === ROUTE_TARGET_KIND) {
12137
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types48.EdgeType.CALLS };
12266
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types49.EdgeType.CALLS };
12138
12267
  }
12139
12268
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
12140
12269
  const peerName = config.serviceNameById[signal.targetName];
12141
12270
  if (!peerName) return null;
12142
- return { targetNodeId: (0, import_types48.serviceId)(peerName), serviceName, edgeType: import_types48.EdgeType.CONNECTS_TO };
12271
+ return { targetNodeId: (0, import_types49.serviceId)(peerName), serviceName, edgeType: import_types49.EdgeType.CONNECTS_TO };
12143
12272
  }
12144
12273
  return null;
12145
12274
  };
@@ -12263,9 +12392,9 @@ function parseFirebaseTargetName(targetName) {
12263
12392
  const secondSep = rest.indexOf(FIELD_SEP);
12264
12393
  if (secondSep === -1) return null;
12265
12394
  const method = rest.slice(0, secondSep);
12266
- const path59 = rest.slice(secondSep + 1);
12267
- if (!resourceName || !method || !path59) return null;
12268
- return { resourceName, method, path: path59 };
12395
+ const path60 = rest.slice(secondSep + 1);
12396
+ if (!resourceName || !method || !path60) return null;
12397
+ return { resourceName, method, path: path60 };
12269
12398
  }
12270
12399
  function resourceNameFor(type, labels) {
12271
12400
  if (!labels) return null;
@@ -12303,14 +12432,14 @@ function mapLogEntryToSignal(entry) {
12303
12432
  if (!req) return null;
12304
12433
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
12305
12434
  const method = req.requestMethod.toUpperCase();
12306
- const path59 = pathFromRequestUrl(req.requestUrl);
12307
- if (path59 === null) return null;
12435
+ const path60 = pathFromRequestUrl(req.requestUrl);
12436
+ if (path60 === null) return null;
12308
12437
  const timestamp = entry.timestamp;
12309
12438
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
12310
12439
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
12311
12440
  return {
12312
12441
  targetKind: resourceType,
12313
- targetName: packFirebaseTargetName({ resourceName, method, path: path59 }),
12442
+ targetName: packFirebaseTargetName({ resourceName, method, path: path60 }),
12314
12443
  callCount: 1,
12315
12444
  errorCount: isError ? 1 : 0,
12316
12445
  lastObservedIso: timestamp
@@ -12327,7 +12456,7 @@ function mapLogEntriesToSignals(entries) {
12327
12456
 
12328
12457
  // src/connectors/firebase/resolve.ts
12329
12458
  init_cjs_shims();
12330
- var import_types49 = require("@neat.is/types");
12459
+ var import_types50 = require("@neat.is/types");
12331
12460
  function neatServiceNameFor(resourceType, resourceName, serviceMap) {
12332
12461
  switch (resourceType) {
12333
12462
  case "cloud_function":
@@ -12342,7 +12471,7 @@ function routeEntriesFor(graph, serviceName) {
12342
12471
  const entries = [];
12343
12472
  graph.forEachNode((_id, attrs) => {
12344
12473
  const node = attrs;
12345
- if (node.type !== import_types49.NodeType.RouteNode) return;
12474
+ if (node.type !== import_types50.NodeType.RouteNode) return;
12346
12475
  const route = attrs;
12347
12476
  if (route.service !== serviceName) return;
12348
12477
  entries.push({
@@ -12374,7 +12503,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
12374
12503
  return {
12375
12504
  targetNodeId: match.routeNodeId,
12376
12505
  serviceName,
12377
- edgeType: import_types49.EdgeType.CALLS
12506
+ edgeType: import_types50.EdgeType.CALLS
12378
12507
  };
12379
12508
  };
12380
12509
  }
@@ -12401,7 +12530,7 @@ init_cjs_shims();
12401
12530
 
12402
12531
  // src/connectors/cloudflare/connector.ts
12403
12532
  init_cjs_shims();
12404
- var import_types51 = require("@neat.is/types");
12533
+ var import_types52 = require("@neat.is/types");
12405
12534
 
12406
12535
  // src/connectors/cloudflare/client.ts
12407
12536
  init_cjs_shims();
@@ -12517,7 +12646,7 @@ function mapEventToSignal(event) {
12517
12646
  if (Number.isNaN(observedAt.getTime())) return null;
12518
12647
  const statusCode = metadata?.statusCode;
12519
12648
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
12520
- const path59 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
12649
+ const path60 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
12521
12650
  return {
12522
12651
  targetKind: CLOUDFLARE_TARGET_KIND,
12523
12652
  targetName: scriptName,
@@ -12525,7 +12654,7 @@ function mapEventToSignal(event) {
12525
12654
  errorCount: isError ? 1 : 0,
12526
12655
  lastObservedIso: observedAt.toISOString(),
12527
12656
  method,
12528
- ...path59 ? { path: path59 } : {},
12657
+ ...path60 ? { path: path60 } : {},
12529
12658
  ...typeof statusCode === "number" ? { statusCode } : {},
12530
12659
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
12531
12660
  };
@@ -12565,19 +12694,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
12565
12694
  graph.forEachNode((id, attrs) => {
12566
12695
  if (found) return;
12567
12696
  const a = attrs;
12568
- if (a.type === import_types51.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
12697
+ if (a.type === import_types52.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
12569
12698
  found = id;
12570
12699
  }
12571
12700
  });
12572
12701
  return found;
12573
12702
  }
12574
- function findMatchingRouteNode(graph, serviceName, method, path59) {
12575
- const normalizedPath = normalizePathTemplate(path59);
12703
+ function findMatchingRouteNode(graph, serviceName, method, path60) {
12704
+ const normalizedPath = normalizePathTemplate(path60);
12576
12705
  let found = null;
12577
12706
  graph.forEachNode((id, attrs) => {
12578
12707
  if (found) return;
12579
12708
  const a = attrs;
12580
- if (a.type !== import_types51.NodeType.RouteNode || a.service !== serviceName) return;
12709
+ if (a.type !== import_types52.NodeType.RouteNode || a.service !== serviceName) return;
12581
12710
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
12582
12711
  const routeMethod = (a.method ?? "").toUpperCase();
12583
12712
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -12589,18 +12718,18 @@ function createCloudflareResolveTarget(config, graph) {
12589
12718
  return (signal) => {
12590
12719
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
12591
12720
  const scriptName = signal.targetName;
12592
- const { method, path: path59 } = signal;
12721
+ const { method, path: path60 } = signal;
12593
12722
  const resolveRouteGrain = (serviceName, wholeFileId) => {
12594
- if (!method || !path59) return wholeFileId;
12595
- return findMatchingRouteNode(graph, serviceName, method, path59) ?? wholeFileId;
12723
+ if (!method || !path60) return wholeFileId;
12724
+ return findMatchingRouteNode(graph, serviceName, method, path60) ?? wholeFileId;
12596
12725
  };
12597
12726
  const mapping = config.workers?.[scriptName];
12598
12727
  if (mapping) {
12599
- const wholeFileId = (0, import_types51.fileId)(mapping.service, mapping.entryFile);
12728
+ const wholeFileId = (0, import_types52.fileId)(mapping.service, mapping.entryFile);
12600
12729
  return {
12601
12730
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
12602
12731
  serviceName: mapping.service,
12603
- edgeType: import_types51.EdgeType.CALLS
12732
+ edgeType: import_types52.EdgeType.CALLS
12604
12733
  };
12605
12734
  }
12606
12735
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -12609,13 +12738,13 @@ function createCloudflareResolveTarget(config, graph) {
12609
12738
  return {
12610
12739
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
12611
12740
  serviceName: fileNode.service,
12612
- edgeType: import_types51.EdgeType.CALLS
12741
+ edgeType: import_types52.EdgeType.CALLS
12613
12742
  };
12614
12743
  }
12615
12744
  return {
12616
- targetNodeId: (0, import_types51.infraId)("cloudflare-worker", scriptName),
12745
+ targetNodeId: (0, import_types52.infraId)("cloudflare-worker", scriptName),
12617
12746
  serviceName: scriptName,
12618
- edgeType: import_types51.EdgeType.CALLS,
12747
+ edgeType: import_types52.EdgeType.CALLS,
12619
12748
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
12620
12749
  };
12621
12750
  };
@@ -12811,14 +12940,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
12811
12940
 
12812
12941
  // src/connectors/neon/resolve.ts
12813
12942
  init_cjs_shims();
12814
- var import_types55 = require("@neat.is/types");
12943
+ var import_types56 = require("@neat.is/types");
12815
12944
  function createNeonResolveTarget(config) {
12816
12945
  return (signal) => {
12817
12946
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
12818
12947
  return {
12819
- targetNodeId: (0, import_types55.infraId)("sql-table", signal.targetName),
12948
+ targetNodeId: (0, import_types56.infraId)("sql-table", signal.targetName),
12820
12949
  serviceName: config.serviceName,
12821
- edgeType: import_types55.EdgeType.CALLS,
12950
+ edgeType: import_types56.EdgeType.CALLS,
12822
12951
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
12823
12952
  };
12824
12953
  };
@@ -13382,11 +13511,11 @@ function registerRoutes(scope, ctx) {
13382
13511
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
13383
13512
  const parsed = [];
13384
13513
  for (const c of candidates) {
13385
- const r = import_types58.DivergenceTypeSchema.safeParse(c);
13514
+ const r = import_types59.DivergenceTypeSchema.safeParse(c);
13386
13515
  if (!r.success) {
13387
13516
  return reply.code(400).send({
13388
13517
  error: `unknown divergence type "${c}"`,
13389
- allowed: import_types58.DivergenceTypeSchema.options
13518
+ allowed: import_types59.DivergenceTypeSchema.options
13390
13519
  });
13391
13520
  }
13392
13521
  parsed.push(r.data);
@@ -13695,7 +13824,7 @@ function registerRoutes(scope, ctx) {
13695
13824
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
13696
13825
  let violations = await log.readAll();
13697
13826
  if (req.query.severity) {
13698
- const sev = import_types58.PolicySeveritySchema.safeParse(req.query.severity);
13827
+ const sev = import_types59.PolicySeveritySchema.safeParse(req.query.severity);
13699
13828
  if (!sev.success) {
13700
13829
  return reply.code(400).send({
13701
13830
  error: "invalid severity",
@@ -13734,7 +13863,7 @@ function registerRoutes(scope, ctx) {
13734
13863
  scope.post("/policies/check", async (req, reply) => {
13735
13864
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
13736
13865
  if (!proj) return;
13737
- const parsed = import_types58.PoliciesCheckBodySchema.safeParse(req.body ?? {});
13866
+ const parsed = import_types59.PoliciesCheckBodySchema.safeParse(req.body ?? {});
13738
13867
  if (!parsed.success) {
13739
13868
  return reply.code(400).send({
13740
13869
  error: "invalid /policies/check body",
@@ -14056,7 +14185,7 @@ init_otel_grpc();
14056
14185
  // src/daemon.ts
14057
14186
  init_cjs_shims();
14058
14187
  var import_node_fs32 = require("fs");
14059
- var import_node_path58 = __toESM(require("path"), 1);
14188
+ var import_node_path59 = __toESM(require("path"), 1);
14060
14189
  var import_node_module = require("module");
14061
14190
  init_otel();
14062
14191
  init_auth();
@@ -14064,7 +14193,7 @@ init_auth();
14064
14193
  // src/unrouted.ts
14065
14194
  init_cjs_shims();
14066
14195
  var import_node_fs31 = require("fs");
14067
- var import_node_path57 = __toESM(require("path"), 1);
14196
+ var import_node_path58 = __toESM(require("path"), 1);
14068
14197
  function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
14069
14198
  return {
14070
14199
  timestamp: now.toISOString(),
@@ -14074,34 +14203,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
14074
14203
  };
14075
14204
  }
14076
14205
  async function appendUnroutedSpan(neatHome3, record) {
14077
- const target = import_node_path57.default.join(neatHome3, "errors.ndjson");
14206
+ const target = import_node_path58.default.join(neatHome3, "errors.ndjson");
14078
14207
  await import_node_fs31.promises.mkdir(neatHome3, { recursive: true });
14079
14208
  await import_node_fs31.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
14080
14209
  }
14081
14210
  function unroutedErrorsPath(neatHome3) {
14082
- return import_node_path57.default.join(neatHome3, "errors.ndjson");
14211
+ return import_node_path58.default.join(neatHome3, "errors.ndjson");
14083
14212
  }
14084
14213
 
14085
14214
  // src/daemon.ts
14086
- var import_types59 = require("@neat.is/types");
14215
+ var import_types60 = require("@neat.is/types");
14087
14216
  function daemonJsonPath(scanPath) {
14088
- return import_node_path58.default.join(scanPath, "neat-out", "daemon.json");
14217
+ return import_node_path59.default.join(scanPath, "neat-out", "daemon.json");
14089
14218
  }
14090
14219
  function daemonsDiscoveryDir(home) {
14091
14220
  const base = home && home.length > 0 ? home : neatHomeFromEnv();
14092
- return import_node_path58.default.join(base, "daemons");
14221
+ return import_node_path59.default.join(base, "daemons");
14093
14222
  }
14094
14223
  function daemonDiscoveryPath(project, home) {
14095
- return import_node_path58.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
14224
+ return import_node_path59.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
14096
14225
  }
14097
14226
  function sanitizeDiscoveryName(project) {
14098
14227
  return project.replace(/[^A-Za-z0-9._-]/g, "_");
14099
14228
  }
14100
14229
  function neatHomeFromEnv() {
14101
14230
  const env = process.env.NEAT_HOME;
14102
- if (env && env.length > 0) return import_node_path58.default.resolve(env);
14231
+ if (env && env.length > 0) return import_node_path59.default.resolve(env);
14103
14232
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
14104
- return import_node_path58.default.join(home, ".neat");
14233
+ return import_node_path59.default.join(home, ".neat");
14105
14234
  }
14106
14235
  function resolveNeatVersion() {
14107
14236
  if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
@@ -14156,11 +14285,11 @@ function teardownSlot(slot) {
14156
14285
  }
14157
14286
  }
14158
14287
  function neatHomeFor(opts) {
14159
- if (opts.neatHome && opts.neatHome.length > 0) return import_node_path58.default.resolve(opts.neatHome);
14288
+ if (opts.neatHome && opts.neatHome.length > 0) return import_node_path59.default.resolve(opts.neatHome);
14160
14289
  const env = process.env.NEAT_HOME;
14161
- if (env && env.length > 0) return import_node_path58.default.resolve(env);
14290
+ if (env && env.length > 0) return import_node_path59.default.resolve(env);
14162
14291
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
14163
- return import_node_path58.default.join(home, ".neat");
14292
+ return import_node_path59.default.join(home, ".neat");
14164
14293
  }
14165
14294
  function routeSpanToProject(serviceName, projects) {
14166
14295
  if (!serviceName) return DEFAULT_PROJECT;
@@ -14208,11 +14337,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
14208
14337
  if (!serviceName) return true;
14209
14338
  if (serviceNameMatchesProject(serviceName, project)) return true;
14210
14339
  return graph.someNode(
14211
- (_id, attrs) => attrs.type === import_types59.NodeType.ServiceNode && attrs.name === serviceName
14340
+ (_id, attrs) => attrs.type === import_types60.NodeType.ServiceNode && attrs.name === serviceName
14212
14341
  );
14213
14342
  }
14214
14343
  async function bootstrapProject(entry, connectors = [], neatHome3) {
14215
- const paths = pathsForProject(entry.name, import_node_path58.default.join(entry.path, "neat-out"));
14344
+ const paths = pathsForProject(entry.name, import_node_path59.default.join(entry.path, "neat-out"));
14216
14345
  try {
14217
14346
  const stat = await import_node_fs32.promises.stat(entry.path);
14218
14347
  if (!stat.isDirectory()) {
@@ -14328,7 +14457,7 @@ async function startDaemon(opts = {}) {
14328
14457
  const projectArg = typeof opts.project === "string" && opts.project.length > 0 ? opts.project : process.env.NEAT_PROJECT && process.env.NEAT_PROJECT.length > 0 ? process.env.NEAT_PROJECT : null;
14329
14458
  const projectPathArg = opts.projectPath && opts.projectPath.length > 0 ? opts.projectPath : process.env.NEAT_PROJECT_PATH && process.env.NEAT_PROJECT_PATH.length > 0 ? process.env.NEAT_PROJECT_PATH : null;
14330
14459
  const singleProject = projectArg;
14331
- const singleProjectPath = singleProject && projectPathArg ? import_node_path58.default.resolve(projectPathArg) : null;
14460
+ const singleProjectPath = singleProject && projectPathArg ? import_node_path59.default.resolve(projectPathArg) : null;
14332
14461
  if (singleProject && !singleProjectPath) {
14333
14462
  throw new Error(
14334
14463
  `neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
@@ -14343,7 +14472,7 @@ async function startDaemon(opts = {}) {
14343
14472
  );
14344
14473
  }
14345
14474
  }
14346
- const pidPath = import_node_path58.default.join(home, "neatd.pid");
14475
+ const pidPath = import_node_path59.default.join(home, "neatd.pid");
14347
14476
  await writeAtomically(pidPath, `${process.pid}
14348
14477
  `);
14349
14478
  const slots = /* @__PURE__ */ new Map();
@@ -14755,8 +14884,8 @@ async function startDaemon(opts = {}) {
14755
14884
  let registryWatcher = null;
14756
14885
  let reloadTimer = null;
14757
14886
  if (!singleProject) try {
14758
- const regDir = import_node_path58.default.dirname(regPath);
14759
- const regBase = import_node_path58.default.basename(regPath);
14887
+ const regDir = import_node_path59.default.dirname(regPath);
14888
+ const regBase = import_node_path59.default.basename(regPath);
14760
14889
  registryWatcher = (0, import_node_fs32.watch)(regDir, (_eventType, filename) => {
14761
14890
  if (filename !== null && filename !== regBase) return;
14762
14891
  if (reloadTimer) clearTimeout(reloadTimer);