@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/server.cjs CHANGED
@@ -59,8 +59,8 @@ function mountBearerAuth(app, opts) {
59
59
  ]);
60
60
  const publicRead = opts.publicRead === true;
61
61
  app.addHook("preHandler", (req, reply, done) => {
62
- const path59 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
- if (exactUnauthPaths.has(path59) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path59)) {
62
+ const path60 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
+ if (exactUnauthPaths.has(path60) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path60)) {
64
64
  done();
65
65
  return;
66
66
  }
@@ -192,8 +192,8 @@ function reshapeGrpcRequest(req) {
192
192
  };
193
193
  }
194
194
  function resolveProtoRoot() {
195
- const here = import_node_path40.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
- return import_node_path40.default.resolve(here, "..", "proto");
195
+ const here = import_node_path41.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
+ return import_node_path41.default.resolve(here, "..", "proto");
197
197
  }
198
198
  function loadTraceService() {
199
199
  const protoRoot = resolveProtoRoot();
@@ -261,13 +261,13 @@ async function startOtelGrpcReceiver(opts) {
261
261
  })
262
262
  };
263
263
  }
264
- var import_node_url, import_node_path40, import_node_crypto2, grpc, protoLoader;
264
+ var import_node_url, import_node_path41, import_node_crypto2, grpc, protoLoader;
265
265
  var init_otel_grpc = __esm({
266
266
  "src/otel-grpc.ts"() {
267
267
  "use strict";
268
268
  init_cjs_shims();
269
269
  import_node_url = require("url");
270
- import_node_path40 = __toESM(require("path"), 1);
270
+ import_node_path41 = __toESM(require("path"), 1);
271
271
  import_node_crypto2 = require("crypto");
272
272
  grpc = __toESM(require("@grpc/grpc-js"), 1);
273
273
  protoLoader = __toESM(require("@grpc/proto-loader"), 1);
@@ -413,8 +413,8 @@ function websocketChannelPathOf(attrs) {
413
413
  const v = attrs[key];
414
414
  if (typeof v === "string" && v.length > 0) {
415
415
  const q = v.indexOf("?");
416
- const path59 = q === -1 ? v : v.slice(0, q);
417
- if (path59.length > 0) return path59;
416
+ const path60 = q === -1 ? v : v.slice(0, q);
417
+ if (path60.length > 0) return path60;
418
418
  }
419
419
  }
420
420
  return void 0;
@@ -473,10 +473,10 @@ function parseOtlpRequest(body) {
473
473
  return out;
474
474
  }
475
475
  function loadProtoRoot() {
476
- const here = import_node_path41.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
477
- const protoRoot = import_node_path41.default.resolve(here, "..", "proto");
476
+ const here = import_node_path42.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
477
+ const protoRoot = import_node_path42.default.resolve(here, "..", "proto");
478
478
  const root = new import_protobufjs.default.Root();
479
- root.resolvePath = (_origin, target) => import_node_path41.default.resolve(protoRoot, target);
479
+ root.resolvePath = (_origin, target) => import_node_path42.default.resolve(protoRoot, target);
480
480
  root.loadSync(
481
481
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
482
482
  { keepCase: true }
@@ -691,12 +691,12 @@ async function buildOtelReceiver(opts) {
691
691
  };
692
692
  return decorated;
693
693
  }
694
- var import_node_path41, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
694
+ var import_node_path42, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
695
695
  var init_otel = __esm({
696
696
  "src/otel.ts"() {
697
697
  "use strict";
698
698
  init_cjs_shims();
699
- import_node_path41 = __toESM(require("path"), 1);
699
+ import_node_path42 = __toESM(require("path"), 1);
700
700
  import_node_url2 = require("url");
701
701
  import_fastify = __toESM(require("fastify"), 1);
702
702
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -712,7 +712,7 @@ var init_otel = __esm({
712
712
 
713
713
  // src/server.ts
714
714
  init_cjs_shims();
715
- var import_node_path58 = __toESM(require("path"), 1);
715
+ var import_node_path59 = __toESM(require("path"), 1);
716
716
 
717
717
  // src/graph.ts
718
718
  init_cjs_shims();
@@ -736,7 +736,7 @@ function getGraph(project = DEFAULT_PROJECT) {
736
736
  init_cjs_shims();
737
737
  var import_fastify2 = __toESM(require("fastify"), 1);
738
738
  var import_cors = __toESM(require("@fastify/cors"), 1);
739
- var import_types58 = require("@neat.is/types");
739
+ var import_types59 = require("@neat.is/types");
740
740
 
741
741
  // src/extend/index.ts
742
742
  init_cjs_shims();
@@ -4437,19 +4437,19 @@ function confidenceFromMix(edges, now = Date.now()) {
4437
4437
  function longestIncomingWalk(graph, start, maxDepth) {
4438
4438
  let best = { path: [start], edges: [] };
4439
4439
  const visited = /* @__PURE__ */ new Set([start]);
4440
- function step(node, path59, edges) {
4441
- if (path59.length > best.path.length) {
4442
- best = { path: [...path59], edges: [...edges] };
4440
+ function step(node, path60, edges) {
4441
+ if (path60.length > best.path.length) {
4442
+ best = { path: [...path60], edges: [...edges] };
4443
4443
  }
4444
- if (path59.length - 1 >= maxDepth) return;
4444
+ if (path60.length - 1 >= maxDepth) return;
4445
4445
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
4446
4446
  for (const [srcId, edge] of incoming) {
4447
4447
  if (visited.has(srcId)) continue;
4448
4448
  visited.add(srcId);
4449
- path59.push(srcId);
4449
+ path60.push(srcId);
4450
4450
  edges.push(edge);
4451
- step(srcId, path59, edges);
4452
- path59.pop();
4451
+ step(srcId, path60, edges);
4452
+ path60.pop();
4453
4453
  edges.pop();
4454
4454
  visited.delete(srcId);
4455
4455
  }
@@ -4656,26 +4656,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
4656
4656
  return best;
4657
4657
  }
4658
4658
  function followFailingCallChain(graph, originServiceId, maxDepth) {
4659
- const path59 = [originServiceId];
4659
+ const path60 = [originServiceId];
4660
4660
  const edges = [];
4661
4661
  const visited = /* @__PURE__ */ new Set([originServiceId]);
4662
4662
  let current = originServiceId;
4663
4663
  for (let depth = 0; depth < maxDepth; depth++) {
4664
4664
  const hop = dominantFailingCall(graph, current, visited);
4665
4665
  if (!hop) break;
4666
- path59.push(hop.nextService);
4666
+ path60.push(hop.nextService);
4667
4667
  edges.push(hop.edge);
4668
4668
  visited.add(hop.nextService);
4669
4669
  current = hop.nextService;
4670
4670
  }
4671
4671
  if (edges.length === 0) return null;
4672
- return { path: path59, edges, culprit: current };
4672
+ return { path: path60, edges, culprit: current };
4673
4673
  }
4674
4674
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
4675
4675
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
4676
4676
  if (!chain) return null;
4677
4677
  const culprit = chain.culprit;
4678
- const path59 = [...chain.path];
4678
+ const path60 = [...chain.path];
4679
4679
  const edgeProvenances = chain.edges.map((e) => e.provenance);
4680
4680
  const baseConfidence = confidenceFromMix(chain.edges);
4681
4681
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -4683,14 +4683,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
4683
4683
  if (loc) {
4684
4684
  let rootCauseNode = culprit;
4685
4685
  if (loc.fileNode) {
4686
- path59.push(loc.fileNode);
4686
+ path60.push(loc.fileNode);
4687
4687
  edgeProvenances.push(import_types7.Provenance.OBSERVED);
4688
4688
  rootCauseNode = loc.fileNode;
4689
4689
  }
4690
4690
  return import_types7.RootCauseResultSchema.parse({
4691
4691
  rootCauseNode,
4692
4692
  rootCauseReason: loc.rootCauseReason,
4693
- traversalPath: path59,
4693
+ traversalPath: path60,
4694
4694
  edgeProvenances,
4695
4695
  confidence,
4696
4696
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -4702,7 +4702,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
4702
4702
  return import_types7.RootCauseResultSchema.parse({
4703
4703
  rootCauseNode: culprit,
4704
4704
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
4705
- traversalPath: path59,
4705
+ traversalPath: path60,
4706
4706
  edgeProvenances,
4707
4707
  confidence,
4708
4708
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -7523,7 +7523,7 @@ async function addGrpcMethods(graph, services) {
7523
7523
 
7524
7524
  // src/extract/calls/index.ts
7525
7525
  init_cjs_shims();
7526
- var import_types30 = require("@neat.is/types");
7526
+ var import_types31 = require("@neat.is/types");
7527
7527
 
7528
7528
  // src/extract/calls/http.ts
7529
7529
  init_cjs_shims();
@@ -8979,12 +8979,140 @@ function drizzleEndpointsFromFile(file, serviceDir) {
8979
8979
  return out;
8980
8980
  }
8981
8981
 
8982
+ // src/extract/calls/prisma.ts
8983
+ init_cjs_shims();
8984
+ var import_node_path40 = __toESM(require("path"), 1);
8985
+ var import_types29 = require("@neat.is/types");
8986
+ var SCALAR_TYPES = /* @__PURE__ */ new Set([
8987
+ "Int",
8988
+ "String",
8989
+ "Boolean",
8990
+ "DateTime",
8991
+ "Float",
8992
+ "Decimal",
8993
+ "BigInt",
8994
+ "Bytes",
8995
+ "Json"
8996
+ ]);
8997
+ function stripLineComment(line) {
8998
+ let inStr = false;
8999
+ for (let i = 0; i < line.length; i++) {
9000
+ const ch = line[i];
9001
+ if (ch === '"' && line[i - 1] !== "\\") inStr = !inStr;
9002
+ else if (!inStr && ch === "/" && line[i + 1] === "/") return line.slice(0, i);
9003
+ }
9004
+ return line;
9005
+ }
9006
+ function netBraces(line) {
9007
+ const s = stripLineComment(line).replace(/"(\\.|[^"\\])*"/g, "");
9008
+ let n = 0;
9009
+ for (const ch of s) {
9010
+ if (ch === "{") n++;
9011
+ else if (ch === "}") n--;
9012
+ }
9013
+ return n;
9014
+ }
9015
+ function prismaColumnsFromSchema(file, serviceDir) {
9016
+ const content = file.content;
9017
+ if (!/\bmodel\s+[A-Za-z_]\w*\s*\{/.test(content)) return [];
9018
+ const lines = content.split("\n");
9019
+ const modelNames = /* @__PURE__ */ new Set();
9020
+ const enumNames = /* @__PURE__ */ new Set();
9021
+ for (const line of lines) {
9022
+ const m = line.match(/^\s*model\s+([A-Za-z_]\w*)\s*\{/);
9023
+ if (m) modelNames.add(m[1]);
9024
+ const e = line.match(/^\s*enum\s+([A-Za-z_]\w*)\s*\{/);
9025
+ if (e) enumNames.add(e[1]);
9026
+ }
9027
+ const out = [];
9028
+ const seenTable = /* @__PURE__ */ new Set();
9029
+ const finalize = (b) => {
9030
+ if (seenTable.has(b.tableName)) return;
9031
+ seenTable.add(b.tableName);
9032
+ out.push({
9033
+ infraId: (0, import_types29.infraId)("sql-table", b.tableName),
9034
+ name: b.tableName,
9035
+ kind: "sql-table",
9036
+ edgeType: "CALLS",
9037
+ confidenceKind: "structural",
9038
+ columns: b.columns,
9039
+ evidence: {
9040
+ file: import_node_path40.default.relative(serviceDir, file.path),
9041
+ line: b.startLine,
9042
+ snippet: snippet(content, b.startLine)
9043
+ }
9044
+ });
9045
+ };
9046
+ let current = null;
9047
+ let depth = 0;
9048
+ for (let i = 0; i < lines.length; i++) {
9049
+ const raw = lines[i];
9050
+ const lineNo = i + 1;
9051
+ if (current === null) {
9052
+ const header = raw.match(/^\s*(model|enum|datasource|generator|type)\s+([A-Za-z_]\w*)\b/);
9053
+ if (header && raw.includes("{")) {
9054
+ current = {
9055
+ kind: header[1],
9056
+ tableName: header[2],
9057
+ startLine: lineNo,
9058
+ columns: [],
9059
+ seenCol: /* @__PURE__ */ new Set()
9060
+ };
9061
+ depth = netBraces(raw);
9062
+ if (depth <= 0) {
9063
+ if (current.kind === "model") finalize(current);
9064
+ current = null;
9065
+ }
9066
+ }
9067
+ continue;
9068
+ }
9069
+ depth += netBraces(raw);
9070
+ if (depth <= 0) {
9071
+ if (current.kind === "model") finalize(current);
9072
+ current = null;
9073
+ continue;
9074
+ }
9075
+ if (current.kind !== "model") continue;
9076
+ const trimmed = stripLineComment(raw).trim();
9077
+ if (!trimmed) continue;
9078
+ if (trimmed.startsWith("@@")) {
9079
+ const map = trimmed.match(/@@map\(\s*"([^"]+)"\s*\)/);
9080
+ if (map) current.tableName = map[1];
9081
+ continue;
9082
+ }
9083
+ const fm = trimmed.match(/^([A-Za-z_]\w*)\s+([A-Za-z_]\w*)/);
9084
+ if (!fm) continue;
9085
+ const fieldName = fm[1];
9086
+ const baseType = fm[2];
9087
+ if (/@relation\b/.test(trimmed) || modelNames.has(baseType)) continue;
9088
+ if (!enumNames.has(baseType) && !SCALAR_TYPES.has(baseType)) continue;
9089
+ const mapM = trimmed.match(/(?<!@)@map\(\s*"([^"]+)"\s*\)/);
9090
+ const columnName = mapM ? mapM[1] : fieldName;
9091
+ if (!current.seenCol.has(columnName)) {
9092
+ current.seenCol.add(columnName);
9093
+ current.columns.push(columnName);
9094
+ }
9095
+ }
9096
+ if (current && current.kind === "model") finalize(current);
9097
+ return out;
9098
+ }
9099
+ async function prismaColumnEndpoints(serviceDir) {
9100
+ const schemaPath = await findFirst(serviceDir, [
9101
+ import_node_path40.default.join("prisma", "schema.prisma"),
9102
+ "schema.prisma"
9103
+ ]);
9104
+ if (!schemaPath) return [];
9105
+ const content = await readIfExists(schemaPath);
9106
+ if (!content) return [];
9107
+ return prismaColumnsFromSchema({ path: schemaPath, content }, serviceDir);
9108
+ }
9109
+
8982
9110
  // src/extract/calls/go.ts
8983
9111
  init_cjs_shims();
8984
- var import_node_path42 = __toESM(require("path"), 1);
9112
+ var import_node_path43 = __toESM(require("path"), 1);
8985
9113
  var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
8986
9114
  var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
8987
- var import_types29 = require("@neat.is/types");
9115
+ var import_types30 = require("@neat.is/types");
8988
9116
  init_otel();
8989
9117
  var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
8990
9118
  var PARSE_CHUNK8 = 16384;
@@ -8996,7 +9124,7 @@ function walk5(node, visit) {
8996
9124
  }
8997
9125
  }
8998
9126
  function goSqlEndpointsFromFile(file, serviceDir) {
8999
- if (import_node_path42.default.extname(file.path) !== ".go") return [];
9127
+ if (import_node_path43.default.extname(file.path) !== ".go") return [];
9000
9128
  const parser = new import_tree_sitter10.default();
9001
9129
  parser.setLanguage(import_tree_sitter_go3.default);
9002
9130
  const tree = parser.parse(
@@ -9016,12 +9144,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
9016
9144
  if (!table) return;
9017
9145
  const line = node.startPosition.row + 1;
9018
9146
  out.push({
9019
- infraId: (0, import_types29.infraId)("sql-table", table),
9147
+ infraId: (0, import_types30.infraId)("sql-table", table),
9020
9148
  name: table,
9021
9149
  kind: "sql-table",
9022
9150
  edgeType: "CALLS",
9023
9151
  confidenceKind: "verified-call-site",
9024
- evidence: { file: toPosix(import_node_path42.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
9152
+ evidence: { file: toPosix(import_node_path43.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
9025
9153
  });
9026
9154
  });
9027
9155
  return out;
@@ -9031,11 +9159,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
9031
9159
  function edgeTypeFromEndpoint(ep) {
9032
9160
  switch (ep.edgeType) {
9033
9161
  case "PUBLISHES_TO":
9034
- return import_types30.EdgeType.PUBLISHES_TO;
9162
+ return import_types31.EdgeType.PUBLISHES_TO;
9035
9163
  case "CONSUMES_FROM":
9036
- return import_types30.EdgeType.CONSUMES_FROM;
9164
+ return import_types31.EdgeType.CONSUMES_FROM;
9037
9165
  default:
9038
- return import_types30.EdgeType.CALLS;
9166
+ return import_types31.EdgeType.CALLS;
9039
9167
  }
9040
9168
  }
9041
9169
  function isAwsKind(kind) {
@@ -9070,13 +9198,14 @@ async function addExternalEndpointEdges(graph, services) {
9070
9198
  }
9071
9199
  endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
9072
9200
  endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
9201
+ endpoints.push(...await prismaColumnEndpoints(service.dir));
9073
9202
  if (endpoints.length === 0) continue;
9074
9203
  const seenEdges = /* @__PURE__ */ new Set();
9075
9204
  for (const ep of endpoints) {
9076
9205
  if (!graph.hasNode(ep.infraId)) {
9077
9206
  const node = {
9078
9207
  id: ep.infraId,
9079
- type: import_types30.NodeType.InfraNode,
9208
+ type: import_types31.NodeType.InfraNode,
9080
9209
  name: ep.name,
9081
9210
  // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
9082
9211
  // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
@@ -9089,20 +9218,20 @@ async function addExternalEndpointEdges(graph, services) {
9089
9218
  }
9090
9219
  if (ep.columns && ep.columns.length > 0) {
9091
9220
  const node = graph.getNodeAttributes(ep.infraId);
9092
- if (node.type === import_types30.NodeType.InfraNode) {
9221
+ if (node.type === import_types31.NodeType.InfraNode) {
9093
9222
  graph.replaceNodeAttributes(ep.infraId, {
9094
9223
  ...node,
9095
9224
  columns: foldColumns(
9096
9225
  node.columns,
9097
9226
  ep.columns,
9098
- import_types30.Provenance.EXTRACTED,
9099
- (0, import_types30.confidenceForExtracted)(ep.confidenceKind)
9227
+ import_types31.Provenance.EXTRACTED,
9228
+ (0, import_types31.confidenceForExtracted)(ep.confidenceKind)
9100
9229
  )
9101
9230
  });
9102
9231
  }
9103
9232
  }
9104
9233
  const edgeType = edgeTypeFromEndpoint(ep);
9105
- const confidence = (0, import_types30.confidenceForExtracted)(ep.confidenceKind);
9234
+ const confidence = (0, import_types31.confidenceForExtracted)(ep.confidenceKind);
9106
9235
  const relFile = toPosix(ep.evidence.file);
9107
9236
  const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
9108
9237
  graph,
@@ -9112,7 +9241,7 @@ async function addExternalEndpointEdges(graph, services) {
9112
9241
  );
9113
9242
  nodesAdded += n;
9114
9243
  edgesAdded += e;
9115
- if (!(0, import_types30.passesExtractedFloor)(confidence)) {
9244
+ if (!(0, import_types31.passesExtractedFloor)(confidence)) {
9116
9245
  noteExtractedDropped({
9117
9246
  source: fileNodeId,
9118
9247
  target: ep.infraId,
@@ -9132,7 +9261,7 @@ async function addExternalEndpointEdges(graph, services) {
9132
9261
  source: fileNodeId,
9133
9262
  target: ep.infraId,
9134
9263
  type: edgeType,
9135
- provenance: import_types30.Provenance.EXTRACTED,
9264
+ provenance: import_types31.Provenance.EXTRACTED,
9136
9265
  confidence,
9137
9266
  evidence: ep.evidence
9138
9267
  };
@@ -9158,16 +9287,16 @@ init_cjs_shims();
9158
9287
 
9159
9288
  // src/extract/infra/docker-compose.ts
9160
9289
  init_cjs_shims();
9161
- var import_node_path43 = __toESM(require("path"), 1);
9162
- var import_types32 = require("@neat.is/types");
9290
+ var import_node_path44 = __toESM(require("path"), 1);
9291
+ var import_types33 = require("@neat.is/types");
9163
9292
 
9164
9293
  // src/extract/infra/shared.ts
9165
9294
  init_cjs_shims();
9166
- var import_types31 = require("@neat.is/types");
9295
+ var import_types32 = require("@neat.is/types");
9167
9296
  function makeInfraNode(kind, name, provider = "self", extras) {
9168
9297
  return {
9169
- id: (0, import_types31.infraId)(kind, name),
9170
- type: import_types31.NodeType.InfraNode,
9298
+ id: (0, import_types32.infraId)(kind, name),
9299
+ type: import_types32.NodeType.InfraNode,
9171
9300
  name,
9172
9301
  provider,
9173
9302
  kind,
@@ -9211,8 +9340,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
9211
9340
  source: anchorId,
9212
9341
  target: node.id,
9213
9342
  type: edgeType,
9214
- provenance: import_types31.Provenance.EXTRACTED,
9215
- confidence: (0, import_types31.confidenceForExtracted)("structural"),
9343
+ provenance: import_types32.Provenance.EXTRACTED,
9344
+ confidence: (0, import_types32.confidenceForExtracted)("structural"),
9216
9345
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
9217
9346
  };
9218
9347
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9229,7 +9358,7 @@ function dependsOnList(value) {
9229
9358
  }
9230
9359
  function serviceNameToServiceNode(name, services) {
9231
9360
  for (const s of services) {
9232
- if (s.node.name === name || import_node_path43.default.basename(s.dir) === name) return s.node.id;
9361
+ if (s.node.name === name || import_node_path44.default.basename(s.dir) === name) return s.node.id;
9233
9362
  }
9234
9363
  return null;
9235
9364
  }
@@ -9238,7 +9367,7 @@ async function addComposeInfra(graph, scanPath, services) {
9238
9367
  let edgesAdded = 0;
9239
9368
  let composePath = null;
9240
9369
  for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
9241
- const abs = import_node_path43.default.join(scanPath, name);
9370
+ const abs = import_node_path44.default.join(scanPath, name);
9242
9371
  if (await exists2(abs)) {
9243
9372
  composePath = abs;
9244
9373
  break;
@@ -9251,13 +9380,13 @@ async function addComposeInfra(graph, scanPath, services) {
9251
9380
  } catch (err) {
9252
9381
  recordExtractionError(
9253
9382
  "infra docker-compose",
9254
- import_node_path43.default.relative(scanPath, composePath),
9383
+ import_node_path44.default.relative(scanPath, composePath),
9255
9384
  err
9256
9385
  );
9257
9386
  return { nodesAdded, edgesAdded };
9258
9387
  }
9259
9388
  if (!compose?.services) return { nodesAdded, edgesAdded };
9260
- const evidenceFile = import_node_path43.default.relative(scanPath, composePath).split(import_node_path43.default.sep).join("/");
9389
+ const evidenceFile = import_node_path44.default.relative(scanPath, composePath).split(import_node_path44.default.sep).join("/");
9261
9390
  const composeNameToNodeId = /* @__PURE__ */ new Map();
9262
9391
  for (const [composeName, svc] of Object.entries(compose.services)) {
9263
9392
  const matchedServiceId = serviceNameToServiceNode(composeName, services);
@@ -9279,15 +9408,15 @@ async function addComposeInfra(graph, scanPath, services) {
9279
9408
  for (const dep of dependsOnList(svc.depends_on)) {
9280
9409
  const targetId = composeNameToNodeId.get(dep);
9281
9410
  if (!targetId) continue;
9282
- const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types32.EdgeType.DEPENDS_ON);
9411
+ const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types33.EdgeType.DEPENDS_ON);
9283
9412
  if (graph.hasEdge(edgeId)) continue;
9284
9413
  const edge = {
9285
9414
  id: edgeId,
9286
9415
  source: sourceId,
9287
9416
  target: targetId,
9288
- type: import_types32.EdgeType.DEPENDS_ON,
9289
- provenance: import_types32.Provenance.EXTRACTED,
9290
- confidence: (0, import_types32.confidenceForExtracted)("structural"),
9417
+ type: import_types33.EdgeType.DEPENDS_ON,
9418
+ provenance: import_types33.Provenance.EXTRACTED,
9419
+ confidence: (0, import_types33.confidenceForExtracted)("structural"),
9291
9420
  evidence: { file: evidenceFile }
9292
9421
  };
9293
9422
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9299,9 +9428,9 @@ async function addComposeInfra(graph, scanPath, services) {
9299
9428
 
9300
9429
  // src/extract/infra/dockerfile.ts
9301
9430
  init_cjs_shims();
9302
- var import_node_path44 = __toESM(require("path"), 1);
9431
+ var import_node_path45 = __toESM(require("path"), 1);
9303
9432
  var import_node_fs19 = require("fs");
9304
- var import_types33 = require("@neat.is/types");
9433
+ var import_types34 = require("@neat.is/types");
9305
9434
  function readDockerfile(content) {
9306
9435
  let image = null;
9307
9436
  const ports = [];
@@ -9330,7 +9459,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
9330
9459
  let nodesAdded = 0;
9331
9460
  let edgesAdded = 0;
9332
9461
  for (const service of services) {
9333
- const dockerfilePath = import_node_path44.default.join(service.dir, "Dockerfile");
9462
+ const dockerfilePath = import_node_path45.default.join(service.dir, "Dockerfile");
9334
9463
  if (!await exists2(dockerfilePath)) continue;
9335
9464
  let content;
9336
9465
  try {
@@ -9338,7 +9467,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
9338
9467
  } catch (err) {
9339
9468
  recordExtractionError(
9340
9469
  "infra dockerfile",
9341
- import_node_path44.default.relative(scanPath, dockerfilePath),
9470
+ import_node_path45.default.relative(scanPath, dockerfilePath),
9342
9471
  err
9343
9472
  );
9344
9473
  continue;
@@ -9350,8 +9479,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
9350
9479
  graph.addNode(node.id, node);
9351
9480
  nodesAdded++;
9352
9481
  }
9353
- const relDockerfile = toPosix(import_node_path44.default.relative(service.dir, dockerfilePath));
9354
- const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, dockerfilePath));
9482
+ const relDockerfile = toPosix(import_node_path45.default.relative(service.dir, dockerfilePath));
9483
+ const evidenceFile = toPosix(import_node_path45.default.relative(scanPath, dockerfilePath));
9355
9484
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9356
9485
  graph,
9357
9486
  service.pkg.name,
@@ -9360,15 +9489,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
9360
9489
  );
9361
9490
  nodesAdded += fn;
9362
9491
  edgesAdded += fe;
9363
- const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types33.EdgeType.RUNS_ON);
9492
+ const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types34.EdgeType.RUNS_ON);
9364
9493
  if (!graph.hasEdge(edgeId)) {
9365
9494
  const edge = {
9366
9495
  id: edgeId,
9367
9496
  source: fileNodeId,
9368
9497
  target: node.id,
9369
- type: import_types33.EdgeType.RUNS_ON,
9370
- provenance: import_types33.Provenance.EXTRACTED,
9371
- confidence: (0, import_types33.confidenceForExtracted)("structural"),
9498
+ type: import_types34.EdgeType.RUNS_ON,
9499
+ provenance: import_types34.Provenance.EXTRACTED,
9500
+ confidence: (0, import_types34.confidenceForExtracted)("structural"),
9372
9501
  evidence: {
9373
9502
  file: evidenceFile,
9374
9503
  ...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
@@ -9383,15 +9512,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
9383
9512
  graph.addNode(portNode.id, portNode);
9384
9513
  nodesAdded++;
9385
9514
  }
9386
- const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types33.EdgeType.CONNECTS_TO);
9515
+ const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types34.EdgeType.CONNECTS_TO);
9387
9516
  if (graph.hasEdge(portEdgeId)) continue;
9388
9517
  const portEdge = {
9389
9518
  id: portEdgeId,
9390
9519
  source: fileNodeId,
9391
9520
  target: portNode.id,
9392
- type: import_types33.EdgeType.CONNECTS_TO,
9393
- provenance: import_types33.Provenance.EXTRACTED,
9394
- confidence: (0, import_types33.confidenceForExtracted)("structural"),
9521
+ type: import_types34.EdgeType.CONNECTS_TO,
9522
+ provenance: import_types34.Provenance.EXTRACTED,
9523
+ confidence: (0, import_types34.confidenceForExtracted)("structural"),
9395
9524
  evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
9396
9525
  };
9397
9526
  graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
@@ -9404,8 +9533,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
9404
9533
  // src/extract/infra/terraform.ts
9405
9534
  init_cjs_shims();
9406
9535
  var import_node_fs20 = require("fs");
9407
- var import_node_path45 = __toESM(require("path"), 1);
9408
- var import_types34 = require("@neat.is/types");
9536
+ var import_node_path46 = __toESM(require("path"), 1);
9537
+ var import_types35 = require("@neat.is/types");
9409
9538
  var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
9410
9539
  var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
9411
9540
  async function walkTfFiles(start, depth = 0, max = 5) {
@@ -9415,11 +9544,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
9415
9544
  for (const entry of entries) {
9416
9545
  if (entry.isDirectory()) {
9417
9546
  if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
9418
- const child = import_node_path45.default.join(start, entry.name);
9547
+ const child = import_node_path46.default.join(start, entry.name);
9419
9548
  if (await isPythonVenvDir(child)) continue;
9420
9549
  out.push(...await walkTfFiles(child, depth + 1, max));
9421
9550
  } else if (entry.isFile() && entry.name.endsWith(".tf")) {
9422
- out.push(import_node_path45.default.join(start, entry.name));
9551
+ out.push(import_node_path46.default.join(start, entry.name));
9423
9552
  }
9424
9553
  }
9425
9554
  return out;
@@ -9451,7 +9580,7 @@ async function addTerraformResources(graph, scanPath) {
9451
9580
  const files = await walkTfFiles(scanPath);
9452
9581
  for (const file of files) {
9453
9582
  const content = await import_node_fs20.promises.readFile(file, "utf8");
9454
- const evidenceFile = toPosix(import_node_path45.default.relative(scanPath, file));
9583
+ const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, file));
9455
9584
  const resources = [];
9456
9585
  const byKey = /* @__PURE__ */ new Map();
9457
9586
  RESOURCE_RE.lastIndex = 0;
@@ -9486,16 +9615,16 @@ async function addTerraformResources(graph, scanPath) {
9486
9615
  if (!target) continue;
9487
9616
  if (seen.has(target.nodeId)) continue;
9488
9617
  seen.add(target.nodeId);
9489
- const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types34.EdgeType.DEPENDS_ON);
9618
+ const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types35.EdgeType.DEPENDS_ON);
9490
9619
  if (graph.hasEdge(edgeId)) continue;
9491
9620
  const line = lineAt2(content, resource.bodyOffset + ref.index);
9492
9621
  const edge = {
9493
9622
  id: edgeId,
9494
9623
  source: resource.nodeId,
9495
9624
  target: target.nodeId,
9496
- type: import_types34.EdgeType.DEPENDS_ON,
9497
- provenance: import_types34.Provenance.EXTRACTED,
9498
- confidence: (0, import_types34.confidenceForExtracted)("structural"),
9625
+ type: import_types35.EdgeType.DEPENDS_ON,
9626
+ provenance: import_types35.Provenance.EXTRACTED,
9627
+ confidence: (0, import_types35.confidenceForExtracted)("structural"),
9499
9628
  evidence: { file: evidenceFile, line, snippet: key }
9500
9629
  };
9501
9630
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9509,7 +9638,7 @@ async function addTerraformResources(graph, scanPath) {
9509
9638
  // src/extract/infra/k8s.ts
9510
9639
  init_cjs_shims();
9511
9640
  var import_node_fs21 = require("fs");
9512
- var import_node_path46 = __toESM(require("path"), 1);
9641
+ var import_node_path47 = __toESM(require("path"), 1);
9513
9642
  var import_yaml3 = require("yaml");
9514
9643
  var K8S_KIND_TO_INFRA_KIND = {
9515
9644
  Service: "k8s-service",
@@ -9527,11 +9656,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
9527
9656
  for (const entry of entries) {
9528
9657
  if (entry.isDirectory()) {
9529
9658
  if (IGNORED_DIRS.has(entry.name)) continue;
9530
- const child = import_node_path46.default.join(start, entry.name);
9659
+ const child = import_node_path47.default.join(start, entry.name);
9531
9660
  if (await isPythonVenvDir(child)) continue;
9532
9661
  out.push(...await walkYamlFiles2(child, depth + 1, max));
9533
- } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path46.default.extname(entry.name))) {
9534
- out.push(import_node_path46.default.join(start, entry.name));
9662
+ } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path47.default.extname(entry.name))) {
9663
+ out.push(import_node_path47.default.join(start, entry.name));
9535
9664
  }
9536
9665
  }
9537
9666
  return out;
@@ -9565,13 +9694,13 @@ async function addK8sResources(graph, scanPath) {
9565
9694
  // src/extract/infra/cloudflare.ts
9566
9695
  init_cjs_shims();
9567
9696
  var import_node_fs22 = require("fs");
9568
- var import_node_path47 = __toESM(require("path"), 1);
9697
+ var import_node_path48 = __toESM(require("path"), 1);
9569
9698
  var import_smol_toml2 = require("smol-toml");
9570
- var import_types35 = require("@neat.is/types");
9699
+ var import_types36 = require("@neat.is/types");
9571
9700
  var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
9572
9701
  async function readWranglerConfig(dir) {
9573
9702
  for (const filename of WRANGLER_FILENAMES) {
9574
- const abs = import_node_path47.default.join(dir, filename);
9703
+ const abs = import_node_path48.default.join(dir, filename);
9575
9704
  if (!await exists2(abs)) continue;
9576
9705
  const raw = await import_node_fs22.promises.readFile(abs, "utf8");
9577
9706
  const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -9615,8 +9744,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
9615
9744
  source: anchorId,
9616
9745
  target: node.id,
9617
9746
  type: edgeType,
9618
- provenance: import_types35.Provenance.EXTRACTED,
9619
- confidence: (0, import_types35.confidenceForExtracted)("structural"),
9747
+ provenance: import_types36.Provenance.EXTRACTED,
9748
+ confidence: (0, import_types36.confidenceForExtracted)("structural"),
9620
9749
  evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
9621
9750
  };
9622
9751
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9634,11 +9763,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9634
9763
  try {
9635
9764
  read = await readWranglerConfig(service.dir);
9636
9765
  } catch (err) {
9637
- recordExtractionError("infra cloudflare", import_node_path47.default.relative(scanPath, service.dir), err);
9766
+ recordExtractionError("infra cloudflare", import_node_path48.default.relative(scanPath, service.dir), err);
9638
9767
  continue;
9639
9768
  }
9640
9769
  if (!read || !read.config.name) continue;
9641
- const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, read.relFile)));
9770
+ const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, read.relFile)));
9642
9771
  discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
9643
9772
  }
9644
9773
  for (const worker of discovered) {
@@ -9650,7 +9779,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9650
9779
  }
9651
9780
  let anchorId = service.node.id;
9652
9781
  if (config.main) {
9653
- const entryRelPath = toPosix(import_node_path47.default.normalize(config.main));
9782
+ const entryRelPath = toPosix(import_node_path48.default.normalize(config.main));
9654
9783
  const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
9655
9784
  graph,
9656
9785
  service.pkg.name,
@@ -9677,15 +9806,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9677
9806
  nodesAdded++;
9678
9807
  }
9679
9808
  if (runtimeNode.id !== anchorId) {
9680
- const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types35.EdgeType.RUNS_ON);
9809
+ const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types36.EdgeType.RUNS_ON);
9681
9810
  if (!graph.hasEdge(runsOnId)) {
9682
9811
  const edge = {
9683
9812
  id: runsOnId,
9684
9813
  source: anchorId,
9685
9814
  target: runtimeNode.id,
9686
- type: import_types35.EdgeType.RUNS_ON,
9687
- provenance: import_types35.Provenance.EXTRACTED,
9688
- confidence: (0, import_types35.confidenceForExtracted)("structural"),
9815
+ type: import_types36.EdgeType.RUNS_ON,
9816
+ provenance: import_types36.Provenance.EXTRACTED,
9817
+ confidence: (0, import_types36.confidenceForExtracted)("structural"),
9689
9818
  evidence: {
9690
9819
  file: evidenceFile,
9691
9820
  ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
@@ -9699,7 +9828,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9699
9828
  const result = addResourceEdge(
9700
9829
  graph,
9701
9830
  anchorId,
9702
- import_types35.EdgeType.CONNECTS_TO,
9831
+ import_types36.EdgeType.CONNECTS_TO,
9703
9832
  "cloudflare-route",
9704
9833
  route,
9705
9834
  evidenceFile,
@@ -9723,7 +9852,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9723
9852
  const result = addResourceEdge(
9724
9853
  graph,
9725
9854
  anchorId,
9726
- import_types35.EdgeType.DEPENDS_ON,
9855
+ import_types36.EdgeType.DEPENDS_ON,
9727
9856
  group.kind,
9728
9857
  name,
9729
9858
  evidenceFile,
@@ -9737,7 +9866,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9737
9866
  const result = addResourceEdge(
9738
9867
  graph,
9739
9868
  anchorId,
9740
- import_types35.EdgeType.DEPENDS_ON,
9869
+ import_types36.EdgeType.DEPENDS_ON,
9741
9870
  "cloudflare-cron",
9742
9871
  cron,
9743
9872
  evidenceFile,
@@ -9750,7 +9879,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9750
9879
  const result = addResourceEdge(
9751
9880
  graph,
9752
9881
  anchorId,
9753
- import_types35.EdgeType.DEPENDS_ON,
9882
+ import_types36.EdgeType.DEPENDS_ON,
9754
9883
  "cloudflare-env-var",
9755
9884
  varName,
9756
9885
  evidenceFile,
@@ -9763,15 +9892,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9763
9892
  if (!svc.service) continue;
9764
9893
  const target = workerIndex.get(svc.service);
9765
9894
  if (target && target.anchorId !== anchorId) {
9766
- const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types35.EdgeType.CALLS);
9895
+ const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types36.EdgeType.CALLS);
9767
9896
  if (!graph.hasEdge(edgeId)) {
9768
9897
  const edge = {
9769
9898
  id: edgeId,
9770
9899
  source: anchorId,
9771
9900
  target: target.anchorId,
9772
- type: import_types35.EdgeType.CALLS,
9773
- provenance: import_types35.Provenance.EXTRACTED,
9774
- confidence: (0, import_types35.confidenceForExtracted)("structural"),
9901
+ type: import_types36.EdgeType.CALLS,
9902
+ provenance: import_types36.Provenance.EXTRACTED,
9903
+ confidence: (0, import_types36.confidenceForExtracted)("structural"),
9775
9904
  evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
9776
9905
  };
9777
9906
  graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
@@ -9782,7 +9911,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9782
9911
  const result = addResourceEdge(
9783
9912
  graph,
9784
9913
  anchorId,
9785
- import_types35.EdgeType.DEPENDS_ON,
9914
+ import_types36.EdgeType.DEPENDS_ON,
9786
9915
  "cloudflare-service-binding",
9787
9916
  svc.service,
9788
9917
  evidenceFile,
@@ -9798,12 +9927,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
9798
9927
  // src/extract/infra/vercel.ts
9799
9928
  init_cjs_shims();
9800
9929
  var import_node_fs23 = require("fs");
9801
- var import_node_path48 = __toESM(require("path"), 1);
9802
- var import_types36 = require("@neat.is/types");
9930
+ var import_node_path49 = __toESM(require("path"), 1);
9931
+ var import_types37 = require("@neat.is/types");
9803
9932
  var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
9804
9933
  async function readVercelConfig(dir) {
9805
9934
  for (const filename of VERCEL_CONFIG_FILENAMES) {
9806
- const abs = import_node_path48.default.join(dir, filename);
9935
+ const abs = import_node_path49.default.join(dir, filename);
9807
9936
  if (!await exists2(abs)) continue;
9808
9937
  const raw = await import_node_fs23.promises.readFile(abs, "utf8");
9809
9938
  const config = JSON.parse(maskCommentsInSource(raw));
@@ -9812,7 +9941,7 @@ async function readVercelConfig(dir) {
9812
9941
  return null;
9813
9942
  }
9814
9943
  async function readLinkedProjectName(dir) {
9815
- const abs = import_node_path48.default.join(dir, ".vercel", "project.json");
9944
+ const abs = import_node_path49.default.join(dir, ".vercel", "project.json");
9816
9945
  if (!await exists2(abs)) return void 0;
9817
9946
  const parsed = JSON.parse(await import_node_fs23.promises.readFile(abs, "utf8"));
9818
9947
  return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
@@ -9830,7 +9959,7 @@ async function addVercelServices(graph, services, scanPath) {
9830
9959
  read = await readVercelConfig(service.dir);
9831
9960
  projectName = await readLinkedProjectName(service.dir);
9832
9961
  } catch (err) {
9833
- recordExtractionError("infra vercel", import_node_path48.default.relative(scanPath, service.dir), err);
9962
+ recordExtractionError("infra vercel", import_node_path49.default.relative(scanPath, service.dir), err);
9834
9963
  continue;
9835
9964
  }
9836
9965
  if (!read && !projectName) continue;
@@ -9846,7 +9975,7 @@ async function addVercelServices(graph, services, scanPath) {
9846
9975
  const anchorId = service.node.id;
9847
9976
  if (!read) continue;
9848
9977
  const { config, relFile, raw } = read;
9849
- const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
9978
+ const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
9850
9979
  const add = (edgeType, kind, name) => {
9851
9980
  if (!name) return;
9852
9981
  const result = emitPlatformResourceEdge(
@@ -9862,12 +9991,12 @@ async function addVercelServices(graph, services, scanPath) {
9862
9991
  nodesAdded += result.nodesAdded;
9863
9992
  edgesAdded += result.edgesAdded;
9864
9993
  };
9865
- add(import_types36.EdgeType.RUNS_ON, "vercel", "vercel");
9866
- for (const cron of config.crons ?? []) add(import_types36.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
9867
- for (const varName of Object.keys(config.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9868
- for (const varName of Object.keys(config.build?.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9994
+ add(import_types37.EdgeType.RUNS_ON, "vercel", "vercel");
9995
+ for (const cron of config.crons ?? []) add(import_types37.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
9996
+ for (const varName of Object.keys(config.env ?? {})) add(import_types37.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9997
+ for (const varName of Object.keys(config.build?.env ?? {})) add(import_types37.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
9869
9998
  for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
9870
- add(import_types36.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
9999
+ add(import_types37.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
9871
10000
  }
9872
10001
  }
9873
10002
  return { nodesAdded, edgesAdded };
@@ -9876,13 +10005,13 @@ async function addVercelServices(graph, services, scanPath) {
9876
10005
  // src/extract/infra/railway.ts
9877
10006
  init_cjs_shims();
9878
10007
  var import_node_fs24 = require("fs");
9879
- var import_node_path49 = __toESM(require("path"), 1);
10008
+ var import_node_path50 = __toESM(require("path"), 1);
9880
10009
  var import_smol_toml3 = require("smol-toml");
9881
- var import_types37 = require("@neat.is/types");
10010
+ var import_types38 = require("@neat.is/types");
9882
10011
  var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
9883
10012
  async function readRailwayConfig(dir) {
9884
10013
  for (const filename of RAILWAY_FILENAMES) {
9885
- const abs = import_node_path49.default.join(dir, filename);
10014
+ const abs = import_node_path50.default.join(dir, filename);
9886
10015
  if (!await exists2(abs)) continue;
9887
10016
  const raw = await import_node_fs24.promises.readFile(abs, "utf8");
9888
10017
  const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
@@ -9898,7 +10027,7 @@ async function addRailwayServices(graph, services, scanPath) {
9898
10027
  try {
9899
10028
  read = await readRailwayConfig(service.dir);
9900
10029
  } catch (err) {
9901
- recordExtractionError("infra railway", import_node_path49.default.relative(scanPath, service.dir), err);
10030
+ recordExtractionError("infra railway", import_node_path50.default.relative(scanPath, service.dir), err);
9902
10031
  continue;
9903
10032
  }
9904
10033
  if (!read) continue;
@@ -9908,7 +10037,7 @@ async function addRailwayServices(graph, services, scanPath) {
9908
10037
  }
9909
10038
  const anchorId = service.node.id;
9910
10039
  const { config, relFile, raw } = read;
9911
- const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
10040
+ const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, import_node_path50.default.join(service.dir, relFile)));
9912
10041
  const add = (edgeType, kind, name) => {
9913
10042
  if (!name) return;
9914
10043
  const result = emitPlatformResourceEdge(
@@ -9924,9 +10053,9 @@ async function addRailwayServices(graph, services, scanPath) {
9924
10053
  nodesAdded += result.nodesAdded;
9925
10054
  edgesAdded += result.edgesAdded;
9926
10055
  };
9927
- add(import_types37.EdgeType.RUNS_ON, "railway", "railway");
9928
- add(import_types37.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
9929
- add(import_types37.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
10056
+ add(import_types38.EdgeType.RUNS_ON, "railway", "railway");
10057
+ add(import_types38.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
10058
+ add(import_types38.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
9930
10059
  }
9931
10060
  return { nodesAdded, edgesAdded };
9932
10061
  }
@@ -9934,12 +10063,12 @@ async function addRailwayServices(graph, services, scanPath) {
9934
10063
  // src/extract/infra/supabase.ts
9935
10064
  init_cjs_shims();
9936
10065
  var import_node_fs25 = require("fs");
9937
- var import_node_path50 = __toESM(require("path"), 1);
10066
+ var import_node_path51 = __toESM(require("path"), 1);
9938
10067
  var import_smol_toml4 = require("smol-toml");
9939
- var import_types38 = require("@neat.is/types");
10068
+ var import_types39 = require("@neat.is/types");
9940
10069
  async function readSupabaseConfig(dir) {
9941
- const relFile = import_node_path50.default.join("supabase", "config.toml");
9942
- const abs = import_node_path50.default.join(dir, relFile);
10070
+ const relFile = import_node_path51.default.join("supabase", "config.toml");
10071
+ const abs = import_node_path51.default.join(dir, relFile);
9943
10072
  if (!await exists2(abs)) return null;
9944
10073
  const raw = await import_node_fs25.promises.readFile(abs, "utf8");
9945
10074
  const config = (0, import_smol_toml4.parse)(raw);
@@ -9953,7 +10082,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
9953
10082
  try {
9954
10083
  read = await readSupabaseConfig(service.dir);
9955
10084
  } catch (err) {
9956
- recordExtractionError("infra supabase", import_node_path50.default.relative(scanPath, service.dir), err);
10085
+ recordExtractionError("infra supabase", import_node_path51.default.relative(scanPath, service.dir), err);
9957
10086
  continue;
9958
10087
  }
9959
10088
  if (!read) continue;
@@ -9968,7 +10097,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
9968
10097
  });
9969
10098
  }
9970
10099
  const anchorId = service.node.id;
9971
- const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, import_node_path50.default.join(service.dir, relFile)));
10100
+ const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, import_node_path51.default.join(service.dir, relFile)));
9972
10101
  const add = (edgeType, kind, name) => {
9973
10102
  if (!name) return;
9974
10103
  const result = emitPlatformResourceEdge(
@@ -9984,10 +10113,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
9984
10113
  nodesAdded += result.nodesAdded;
9985
10114
  edgesAdded += result.edgesAdded;
9986
10115
  };
9987
- add(import_types38.EdgeType.RUNS_ON, "supabase", "supabase");
9988
- for (const fn of Object.keys(config.functions ?? {})) add(import_types38.EdgeType.DEPENDS_ON, "supabase-function", fn);
9989
- if (config.storage) add(import_types38.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
9990
- if (config.auth) add(import_types38.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
10116
+ add(import_types39.EdgeType.RUNS_ON, "supabase", "supabase");
10117
+ for (const fn of Object.keys(config.functions ?? {})) add(import_types39.EdgeType.DEPENDS_ON, "supabase-function", fn);
10118
+ if (config.storage) add(import_types39.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
10119
+ if (config.auth) add(import_types39.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
9991
10120
  }
9992
10121
  return { nodesAdded, edgesAdded };
9993
10122
  }
@@ -10009,17 +10138,17 @@ async function addInfra(graph, scanPath, services) {
10009
10138
  }
10010
10139
 
10011
10140
  // src/extract/index.ts
10012
- var import_node_path52 = __toESM(require("path"), 1);
10141
+ var import_node_path53 = __toESM(require("path"), 1);
10013
10142
 
10014
10143
  // src/extract/retire.ts
10015
10144
  init_cjs_shims();
10016
10145
  var import_node_fs26 = require("fs");
10017
- var import_node_path51 = __toESM(require("path"), 1);
10018
- var import_types39 = require("@neat.is/types");
10146
+ var import_node_path52 = __toESM(require("path"), 1);
10147
+ var import_types40 = require("@neat.is/types");
10019
10148
  function dropOrphanedFileNodes(graph) {
10020
10149
  const orphans = [];
10021
10150
  graph.forEachNode((id, attrs) => {
10022
- if (attrs.type !== import_types39.NodeType.FileNode) return;
10151
+ if (attrs.type !== import_types40.NodeType.FileNode) return;
10023
10152
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
10024
10153
  orphans.push(id);
10025
10154
  }
@@ -10032,14 +10161,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
10032
10161
  const bases = [scanPath, ...serviceDirs];
10033
10162
  graph.forEachEdge((id, attrs) => {
10034
10163
  const edge = attrs;
10035
- if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
10164
+ if (edge.provenance !== import_types40.Provenance.EXTRACTED) return;
10036
10165
  const evidenceFile = edge.evidence?.file;
10037
10166
  if (!evidenceFile) return;
10038
- if (import_node_path51.default.isAbsolute(evidenceFile)) {
10167
+ if (import_node_path52.default.isAbsolute(evidenceFile)) {
10039
10168
  if (!(0, import_node_fs26.existsSync)(evidenceFile)) toDrop.push(id);
10040
10169
  return;
10041
10170
  }
10042
- const found = bases.some((base) => (0, import_node_fs26.existsSync)(import_node_path51.default.join(base, evidenceFile)));
10171
+ const found = bases.some((base) => (0, import_node_fs26.existsSync)(import_node_path52.default.join(base, evidenceFile)));
10043
10172
  if (!found) toDrop.push(id);
10044
10173
  });
10045
10174
  for (const id of toDrop) graph.dropEdge(id);
@@ -10092,7 +10221,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
10092
10221
  }
10093
10222
  const droppedEntries = drainDroppedExtracted();
10094
10223
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
10095
- const rejectedPath = import_node_path52.default.join(import_node_path52.default.dirname(opts.errorsPath), "rejected.ndjson");
10224
+ const rejectedPath = import_node_path53.default.join(import_node_path53.default.dirname(opts.errorsPath), "rejected.ndjson");
10096
10225
  try {
10097
10226
  await writeRejectedExtracted(droppedEntries, rejectedPath);
10098
10227
  } catch (err) {
@@ -10204,8 +10333,8 @@ function canonicalJson(value) {
10204
10333
  // src/persist.ts
10205
10334
  init_cjs_shims();
10206
10335
  var import_node_fs28 = require("fs");
10207
- var import_node_path53 = __toESM(require("path"), 1);
10208
- var import_types40 = require("@neat.is/types");
10336
+ var import_node_path54 = __toESM(require("path"), 1);
10337
+ var import_types41 = require("@neat.is/types");
10209
10338
  var SCHEMA_VERSION = 6;
10210
10339
  function migrateV1ToV2(payload) {
10211
10340
  const nodes = payload.graph.nodes;
@@ -10229,7 +10358,7 @@ function migrateV5ToV6(payload) {
10229
10358
  if (Array.isArray(nodes)) {
10230
10359
  for (const node of nodes) {
10231
10360
  const attrs = node.attributes;
10232
- if (!attrs || attrs.type !== import_types40.NodeType.InfraNode) continue;
10361
+ if (!attrs || attrs.type !== import_types41.NodeType.InfraNode) continue;
10233
10362
  if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
10234
10363
  if (!Array.isArray(attrs.columns)) attrs.columns = [];
10235
10364
  }
@@ -10242,12 +10371,12 @@ function migrateV2ToV3(payload) {
10242
10371
  for (const edge of edges) {
10243
10372
  const attrs = edge.attributes;
10244
10373
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
10245
- attrs.provenance = import_types40.Provenance.OBSERVED;
10374
+ attrs.provenance = import_types41.Provenance.OBSERVED;
10246
10375
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
10247
10376
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
10248
10377
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
10249
10378
  if (type && source && target) {
10250
- const newId = (0, import_types40.observedEdgeId)(source, target, type);
10379
+ const newId = (0, import_types41.observedEdgeId)(source, target, type);
10251
10380
  attrs.id = newId;
10252
10381
  if (edge.key) edge.key = newId;
10253
10382
  }
@@ -10256,7 +10385,7 @@ function migrateV2ToV3(payload) {
10256
10385
  return { ...payload, schemaVersion: 3 };
10257
10386
  }
10258
10387
  async function ensureDir(filePath) {
10259
- await import_node_fs28.promises.mkdir(import_node_path53.default.dirname(filePath), { recursive: true });
10388
+ await import_node_fs28.promises.mkdir(import_node_path54.default.dirname(filePath), { recursive: true });
10260
10389
  }
10261
10390
  async function saveGraphToDisk(graph, outPath) {
10262
10391
  await ensureDir(outPath);
@@ -10343,23 +10472,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
10343
10472
 
10344
10473
  // src/projects.ts
10345
10474
  init_cjs_shims();
10346
- var import_node_path54 = __toESM(require("path"), 1);
10475
+ var import_node_path55 = __toESM(require("path"), 1);
10347
10476
  function pathsForProject(project, baseDir) {
10348
10477
  if (project === DEFAULT_PROJECT) {
10349
10478
  return {
10350
- snapshotPath: import_node_path54.default.join(baseDir, "graph.json"),
10351
- errorsPath: import_node_path54.default.join(baseDir, "errors.ndjson"),
10352
- staleEventsPath: import_node_path54.default.join(baseDir, "stale-events.ndjson"),
10353
- embeddingsCachePath: import_node_path54.default.join(baseDir, "embeddings.json"),
10354
- policyViolationsPath: import_node_path54.default.join(baseDir, "policy-violations.ndjson")
10479
+ snapshotPath: import_node_path55.default.join(baseDir, "graph.json"),
10480
+ errorsPath: import_node_path55.default.join(baseDir, "errors.ndjson"),
10481
+ staleEventsPath: import_node_path55.default.join(baseDir, "stale-events.ndjson"),
10482
+ embeddingsCachePath: import_node_path55.default.join(baseDir, "embeddings.json"),
10483
+ policyViolationsPath: import_node_path55.default.join(baseDir, "policy-violations.ndjson")
10355
10484
  };
10356
10485
  }
10357
10486
  return {
10358
- snapshotPath: import_node_path54.default.join(baseDir, `${project}.json`),
10359
- errorsPath: import_node_path54.default.join(baseDir, `errors.${project}.ndjson`),
10360
- staleEventsPath: import_node_path54.default.join(baseDir, `stale-events.${project}.ndjson`),
10361
- embeddingsCachePath: import_node_path54.default.join(baseDir, `embeddings.${project}.json`),
10362
- policyViolationsPath: import_node_path54.default.join(baseDir, `policy-violations.${project}.ndjson`)
10487
+ snapshotPath: import_node_path55.default.join(baseDir, `${project}.json`),
10488
+ errorsPath: import_node_path55.default.join(baseDir, `errors.${project}.ndjson`),
10489
+ staleEventsPath: import_node_path55.default.join(baseDir, `stale-events.${project}.ndjson`),
10490
+ embeddingsCachePath: import_node_path55.default.join(baseDir, `embeddings.${project}.json`),
10491
+ policyViolationsPath: import_node_path55.default.join(baseDir, `policy-violations.${project}.ndjson`)
10363
10492
  };
10364
10493
  }
10365
10494
  var Projects = class {
@@ -10401,18 +10530,18 @@ function parseExtraProjects(raw) {
10401
10530
  init_cjs_shims();
10402
10531
  var import_node_fs29 = require("fs");
10403
10532
  var import_node_os3 = __toESM(require("os"), 1);
10404
- var import_node_path55 = __toESM(require("path"), 1);
10405
- var import_types41 = require("@neat.is/types");
10533
+ var import_node_path56 = __toESM(require("path"), 1);
10534
+ var import_types42 = require("@neat.is/types");
10406
10535
  function neatHome() {
10407
10536
  const override = process.env.NEAT_HOME;
10408
- if (override && override.length > 0) return import_node_path55.default.resolve(override);
10409
- return import_node_path55.default.join(import_node_os3.default.homedir(), ".neat");
10537
+ if (override && override.length > 0) return import_node_path56.default.resolve(override);
10538
+ return import_node_path56.default.join(import_node_os3.default.homedir(), ".neat");
10410
10539
  }
10411
10540
  function registryPath() {
10412
- return import_node_path55.default.join(neatHome(), "projects.json");
10541
+ return import_node_path56.default.join(neatHome(), "projects.json");
10413
10542
  }
10414
10543
  function daemonsDir() {
10415
- return import_node_path55.default.join(neatHome(), "daemons");
10544
+ return import_node_path56.default.join(neatHome(), "daemons");
10416
10545
  }
10417
10546
  function isFiniteInt(v) {
10418
10547
  return typeof v === "number" && Number.isFinite(v);
@@ -10453,7 +10582,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
10453
10582
  const out = [];
10454
10583
  for (const name of names) {
10455
10584
  if (!name.endsWith(".json")) continue;
10456
- const file = import_node_path55.default.join(dir, name);
10585
+ const file = import_node_path56.default.join(dir, name);
10457
10586
  let raw;
10458
10587
  try {
10459
10588
  raw = await import_node_fs29.promises.readFile(file, "utf8");
@@ -10492,7 +10621,7 @@ async function readRegistry() {
10492
10621
  throw err;
10493
10622
  }
10494
10623
  const parsed = JSON.parse(raw);
10495
- return import_types41.RegistryFileSchema.parse(parsed);
10624
+ return import_types42.RegistryFileSchema.parse(parsed);
10496
10625
  }
10497
10626
  async function getProject(name) {
10498
10627
  const reg = await readRegistry();
@@ -10567,7 +10696,7 @@ init_auth();
10567
10696
  // src/connectors-config.ts
10568
10697
  init_cjs_shims();
10569
10698
  var import_node_os4 = __toESM(require("os"), 1);
10570
- var import_node_path56 = __toESM(require("path"), 1);
10699
+ var import_node_path57 = __toESM(require("path"), 1);
10571
10700
  var import_node_fs30 = require("fs");
10572
10701
  var CONNECTORS_CONFIG_VERSION = 1;
10573
10702
  var EnvRefUnsetError = class extends Error {
@@ -10582,11 +10711,11 @@ var EnvRefUnsetError = class extends Error {
10582
10711
  };
10583
10712
  function neatHome2() {
10584
10713
  const override = process.env.NEAT_HOME;
10585
- if (override && override.length > 0) return import_node_path56.default.resolve(override);
10586
- return import_node_path56.default.join(import_node_os4.default.homedir(), ".neat");
10714
+ if (override && override.length > 0) return import_node_path57.default.resolve(override);
10715
+ return import_node_path57.default.join(import_node_os4.default.homedir(), ".neat");
10587
10716
  }
10588
10717
  function connectorsConfigPath(home = neatHome2()) {
10589
- return import_node_path56.default.join(home, "connectors.json");
10718
+ return import_node_path57.default.join(home, "connectors.json");
10590
10719
  }
10591
10720
  var MODE_MASK_LOOSER_THAN_0600 = 63;
10592
10721
  async function warnIfModeLooserThan0600(file) {
@@ -10773,15 +10902,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
10773
10902
 
10774
10903
  // src/connectors/index.ts
10775
10904
  init_cjs_shims();
10776
- var import_types42 = require("@neat.is/types");
10905
+ var import_types43 = require("@neat.is/types");
10777
10906
  var NO_ENV = "unknown";
10778
10907
  function staticCallSiteFor(graph, serviceName, targetNodeId) {
10779
10908
  if (!graph.hasNode(targetNodeId)) return void 0;
10780
10909
  const sites = [];
10781
10910
  for (const edgeId of graph.inboundEdges(targetNodeId)) {
10782
10911
  const edge = graph.getEdgeAttributes(edgeId);
10783
- if (edge.provenance !== import_types42.Provenance.EXTRACTED) continue;
10784
- const parsed = (0, import_types42.parseFileId)(edge.source);
10912
+ if (edge.provenance !== import_types43.Provenance.EXTRACTED) continue;
10913
+ const parsed = (0, import_types43.parseFileId)(edge.source);
10785
10914
  if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
10786
10915
  const site = { relPath: edge.evidence.file };
10787
10916
  if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
@@ -10792,7 +10921,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
10792
10921
  function routeCallSiteFor(graph, targetNodeId) {
10793
10922
  if (!graph.hasNode(targetNodeId)) return void 0;
10794
10923
  const attrs = graph.getNodeAttributes(targetNodeId);
10795
- if (attrs.type !== import_types42.NodeType.RouteNode || !attrs.path) return void 0;
10924
+ if (attrs.type !== import_types43.NodeType.RouteNode || !attrs.path) return void 0;
10796
10925
  const site = { relPath: attrs.path };
10797
10926
  if (attrs.line !== void 0) site.line = attrs.line;
10798
10927
  return site;
@@ -11228,10 +11357,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
11228
11357
  // src/connectors/supabase/map.ts
11229
11358
  var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
11230
11359
  var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
11231
- function targetFromRestPath(path59) {
11232
- const rpcMatch = REST_RPC_PATH_RE.exec(path59);
11360
+ function targetFromRestPath(path60) {
11361
+ const rpcMatch = REST_RPC_PATH_RE.exec(path60);
11233
11362
  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
11234
- const tableMatch = REST_TABLE_PATH_RE.exec(path59);
11363
+ const tableMatch = REST_TABLE_PATH_RE.exec(path60);
11235
11364
  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
11236
11365
  return null;
11237
11366
  }
@@ -11342,23 +11471,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
11342
11471
 
11343
11472
  // src/connectors/supabase/resolve.ts
11344
11473
  init_cjs_shims();
11345
- var import_types44 = require("@neat.is/types");
11474
+ var import_types45 = require("@neat.is/types");
11346
11475
  function createSupabaseResolveTarget(graph, config) {
11347
11476
  return (signal, _ctx) => {
11348
11477
  if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
11349
11478
  return null;
11350
11479
  }
11351
- const subResourceId = (0, import_types44.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
11480
+ const subResourceId = (0, import_types45.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
11352
11481
  if (graph.hasNode(subResourceId)) {
11353
- return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
11482
+ return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
11354
11483
  }
11355
- const bareResourceId = (0, import_types44.infraId)(signal.targetKind, signal.targetName);
11484
+ const bareResourceId = (0, import_types45.infraId)(signal.targetKind, signal.targetName);
11356
11485
  if (graph.hasNode(bareResourceId)) {
11357
- return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
11486
+ return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
11358
11487
  }
11359
- const projectLevelId = (0, import_types44.infraId)("supabase", config.nodeRef);
11488
+ const projectLevelId = (0, import_types45.infraId)("supabase", config.nodeRef);
11360
11489
  if (graph.hasNode(projectLevelId)) {
11361
- return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
11490
+ return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
11362
11491
  }
11363
11492
  return null;
11364
11493
  };
@@ -11451,7 +11580,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
11451
11580
 
11452
11581
  // src/connectors/railway/index.ts
11453
11582
  init_cjs_shims();
11454
- var import_types48 = require("@neat.is/types");
11583
+ var import_types49 = require("@neat.is/types");
11455
11584
 
11456
11585
  // src/connectors/railway/client.ts
11457
11586
  init_cjs_shims();
@@ -11602,7 +11731,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
11602
11731
  const out = [];
11603
11732
  graph.forEachNode((_id, attrs) => {
11604
11733
  const node = attrs;
11605
- if (node.type !== import_types48.NodeType.RouteNode) return;
11734
+ if (node.type !== import_types49.NodeType.RouteNode) return;
11606
11735
  const route = attrs;
11607
11736
  if (route.service !== serviceName) return;
11608
11737
  out.push({
@@ -11706,12 +11835,12 @@ function createRailwayResolveTarget(config) {
11706
11835
  const serviceName = config.serviceNameById[config.serviceId];
11707
11836
  if (!serviceName) return null;
11708
11837
  if (signal.targetKind === ROUTE_TARGET_KIND) {
11709
- return { targetNodeId: signal.targetName, serviceName, edgeType: import_types48.EdgeType.CALLS };
11838
+ return { targetNodeId: signal.targetName, serviceName, edgeType: import_types49.EdgeType.CALLS };
11710
11839
  }
11711
11840
  if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
11712
11841
  const peerName = config.serviceNameById[signal.targetName];
11713
11842
  if (!peerName) return null;
11714
- return { targetNodeId: (0, import_types48.serviceId)(peerName), serviceName, edgeType: import_types48.EdgeType.CONNECTS_TO };
11843
+ return { targetNodeId: (0, import_types49.serviceId)(peerName), serviceName, edgeType: import_types49.EdgeType.CONNECTS_TO };
11715
11844
  }
11716
11845
  return null;
11717
11846
  };
@@ -11835,9 +11964,9 @@ function parseFirebaseTargetName(targetName) {
11835
11964
  const secondSep = rest.indexOf(FIELD_SEP);
11836
11965
  if (secondSep === -1) return null;
11837
11966
  const method = rest.slice(0, secondSep);
11838
- const path59 = rest.slice(secondSep + 1);
11839
- if (!resourceName || !method || !path59) return null;
11840
- return { resourceName, method, path: path59 };
11967
+ const path60 = rest.slice(secondSep + 1);
11968
+ if (!resourceName || !method || !path60) return null;
11969
+ return { resourceName, method, path: path60 };
11841
11970
  }
11842
11971
  function resourceNameFor(type, labels) {
11843
11972
  if (!labels) return null;
@@ -11875,14 +12004,14 @@ function mapLogEntryToSignal(entry) {
11875
12004
  if (!req) return null;
11876
12005
  if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
11877
12006
  const method = req.requestMethod.toUpperCase();
11878
- const path59 = pathFromRequestUrl(req.requestUrl);
11879
- if (path59 === null) return null;
12007
+ const path60 = pathFromRequestUrl(req.requestUrl);
12008
+ if (path60 === null) return null;
11880
12009
  const timestamp = entry.timestamp;
11881
12010
  if (typeof timestamp !== "string" || timestamp.length === 0) return null;
11882
12011
  const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
11883
12012
  return {
11884
12013
  targetKind: resourceType,
11885
- targetName: packFirebaseTargetName({ resourceName, method, path: path59 }),
12014
+ targetName: packFirebaseTargetName({ resourceName, method, path: path60 }),
11886
12015
  callCount: 1,
11887
12016
  errorCount: isError ? 1 : 0,
11888
12017
  lastObservedIso: timestamp
@@ -11899,7 +12028,7 @@ function mapLogEntriesToSignals(entries) {
11899
12028
 
11900
12029
  // src/connectors/firebase/resolve.ts
11901
12030
  init_cjs_shims();
11902
- var import_types49 = require("@neat.is/types");
12031
+ var import_types50 = require("@neat.is/types");
11903
12032
  function neatServiceNameFor(resourceType, resourceName, serviceMap) {
11904
12033
  switch (resourceType) {
11905
12034
  case "cloud_function":
@@ -11914,7 +12043,7 @@ function routeEntriesFor(graph, serviceName) {
11914
12043
  const entries = [];
11915
12044
  graph.forEachNode((_id, attrs) => {
11916
12045
  const node = attrs;
11917
- if (node.type !== import_types49.NodeType.RouteNode) return;
12046
+ if (node.type !== import_types50.NodeType.RouteNode) return;
11918
12047
  const route = attrs;
11919
12048
  if (route.service !== serviceName) return;
11920
12049
  entries.push({
@@ -11946,7 +12075,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
11946
12075
  return {
11947
12076
  targetNodeId: match.routeNodeId,
11948
12077
  serviceName,
11949
- edgeType: import_types49.EdgeType.CALLS
12078
+ edgeType: import_types50.EdgeType.CALLS
11950
12079
  };
11951
12080
  };
11952
12081
  }
@@ -11973,7 +12102,7 @@ init_cjs_shims();
11973
12102
 
11974
12103
  // src/connectors/cloudflare/connector.ts
11975
12104
  init_cjs_shims();
11976
- var import_types51 = require("@neat.is/types");
12105
+ var import_types52 = require("@neat.is/types");
11977
12106
 
11978
12107
  // src/connectors/cloudflare/client.ts
11979
12108
  init_cjs_shims();
@@ -12089,7 +12218,7 @@ function mapEventToSignal(event) {
12089
12218
  if (Number.isNaN(observedAt.getTime())) return null;
12090
12219
  const statusCode = metadata?.statusCode;
12091
12220
  const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
12092
- const path59 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
12221
+ const path60 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
12093
12222
  return {
12094
12223
  targetKind: CLOUDFLARE_TARGET_KIND,
12095
12224
  targetName: scriptName,
@@ -12097,7 +12226,7 @@ function mapEventToSignal(event) {
12097
12226
  errorCount: isError ? 1 : 0,
12098
12227
  lastObservedIso: observedAt.toISOString(),
12099
12228
  method,
12100
- ...path59 ? { path: path59 } : {},
12229
+ ...path60 ? { path: path60 } : {},
12101
12230
  ...typeof statusCode === "number" ? { statusCode } : {},
12102
12231
  ...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
12103
12232
  };
@@ -12137,19 +12266,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
12137
12266
  graph.forEachNode((id, attrs) => {
12138
12267
  if (found) return;
12139
12268
  const a = attrs;
12140
- if (a.type === import_types51.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
12269
+ if (a.type === import_types52.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
12141
12270
  found = id;
12142
12271
  }
12143
12272
  });
12144
12273
  return found;
12145
12274
  }
12146
- function findMatchingRouteNode(graph, serviceName, method, path59) {
12147
- const normalizedPath = normalizePathTemplate(path59);
12275
+ function findMatchingRouteNode(graph, serviceName, method, path60) {
12276
+ const normalizedPath = normalizePathTemplate(path60);
12148
12277
  let found = null;
12149
12278
  graph.forEachNode((id, attrs) => {
12150
12279
  if (found) return;
12151
12280
  const a = attrs;
12152
- if (a.type !== import_types51.NodeType.RouteNode || a.service !== serviceName) return;
12281
+ if (a.type !== import_types52.NodeType.RouteNode || a.service !== serviceName) return;
12153
12282
  if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
12154
12283
  const routeMethod = (a.method ?? "").toUpperCase();
12155
12284
  if (routeMethod !== "ALL" && routeMethod !== method) return;
@@ -12161,18 +12290,18 @@ function createCloudflareResolveTarget(config, graph) {
12161
12290
  return (signal) => {
12162
12291
  if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
12163
12292
  const scriptName = signal.targetName;
12164
- const { method, path: path59 } = signal;
12293
+ const { method, path: path60 } = signal;
12165
12294
  const resolveRouteGrain = (serviceName, wholeFileId) => {
12166
- if (!method || !path59) return wholeFileId;
12167
- return findMatchingRouteNode(graph, serviceName, method, path59) ?? wholeFileId;
12295
+ if (!method || !path60) return wholeFileId;
12296
+ return findMatchingRouteNode(graph, serviceName, method, path60) ?? wholeFileId;
12168
12297
  };
12169
12298
  const mapping = config.workers?.[scriptName];
12170
12299
  if (mapping) {
12171
- const wholeFileId = (0, import_types51.fileId)(mapping.service, mapping.entryFile);
12300
+ const wholeFileId = (0, import_types52.fileId)(mapping.service, mapping.entryFile);
12172
12301
  return {
12173
12302
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
12174
12303
  serviceName: mapping.service,
12175
- edgeType: import_types51.EdgeType.CALLS
12304
+ edgeType: import_types52.EdgeType.CALLS
12176
12305
  };
12177
12306
  }
12178
12307
  const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
@@ -12181,13 +12310,13 @@ function createCloudflareResolveTarget(config, graph) {
12181
12310
  return {
12182
12311
  targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
12183
12312
  serviceName: fileNode.service,
12184
- edgeType: import_types51.EdgeType.CALLS
12313
+ edgeType: import_types52.EdgeType.CALLS
12185
12314
  };
12186
12315
  }
12187
12316
  return {
12188
- targetNodeId: (0, import_types51.infraId)("cloudflare-worker", scriptName),
12317
+ targetNodeId: (0, import_types52.infraId)("cloudflare-worker", scriptName),
12189
12318
  serviceName: scriptName,
12190
- edgeType: import_types51.EdgeType.CALLS,
12319
+ edgeType: import_types52.EdgeType.CALLS,
12191
12320
  ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
12192
12321
  };
12193
12322
  };
@@ -12383,14 +12512,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
12383
12512
 
12384
12513
  // src/connectors/neon/resolve.ts
12385
12514
  init_cjs_shims();
12386
- var import_types55 = require("@neat.is/types");
12515
+ var import_types56 = require("@neat.is/types");
12387
12516
  function createNeonResolveTarget(config) {
12388
12517
  return (signal) => {
12389
12518
  if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
12390
12519
  return {
12391
- targetNodeId: (0, import_types55.infraId)("sql-table", signal.targetName),
12520
+ targetNodeId: (0, import_types56.infraId)("sql-table", signal.targetName),
12392
12521
  serviceName: config.serviceName,
12393
- edgeType: import_types55.EdgeType.CALLS,
12522
+ edgeType: import_types56.EdgeType.CALLS,
12394
12523
  ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
12395
12524
  };
12396
12525
  };
@@ -12912,11 +13041,11 @@ function registerRoutes(scope, ctx) {
12912
13041
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
12913
13042
  const parsed = [];
12914
13043
  for (const c of candidates) {
12915
- const r = import_types58.DivergenceTypeSchema.safeParse(c);
13044
+ const r = import_types59.DivergenceTypeSchema.safeParse(c);
12916
13045
  if (!r.success) {
12917
13046
  return reply.code(400).send({
12918
13047
  error: `unknown divergence type "${c}"`,
12919
- allowed: import_types58.DivergenceTypeSchema.options
13048
+ allowed: import_types59.DivergenceTypeSchema.options
12920
13049
  });
12921
13050
  }
12922
13051
  parsed.push(r.data);
@@ -13225,7 +13354,7 @@ function registerRoutes(scope, ctx) {
13225
13354
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
13226
13355
  let violations = await log.readAll();
13227
13356
  if (req.query.severity) {
13228
- const sev = import_types58.PolicySeveritySchema.safeParse(req.query.severity);
13357
+ const sev = import_types59.PolicySeveritySchema.safeParse(req.query.severity);
13229
13358
  if (!sev.success) {
13230
13359
  return reply.code(400).send({
13231
13360
  error: "invalid severity",
@@ -13264,7 +13393,7 @@ function registerRoutes(scope, ctx) {
13264
13393
  scope.post("/policies/check", async (req, reply) => {
13265
13394
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
13266
13395
  if (!proj) return;
13267
- const parsed = import_types58.PoliciesCheckBodySchema.safeParse(req.body ?? {});
13396
+ const parsed = import_types59.PoliciesCheckBodySchema.safeParse(req.body ?? {});
13268
13397
  if (!parsed.success) {
13269
13398
  return reply.code(400).send({
13270
13399
  error: "invalid /policies/check body",
@@ -13586,7 +13715,7 @@ init_otel_grpc();
13586
13715
  // src/search.ts
13587
13716
  init_cjs_shims();
13588
13717
  var import_node_fs31 = require("fs");
13589
- var import_node_path57 = __toESM(require("path"), 1);
13718
+ var import_node_path58 = __toESM(require("path"), 1);
13590
13719
  var import_node_crypto4 = require("crypto");
13591
13720
  var DEFAULT_LIMIT = 10;
13592
13721
  var NOMIC_DIM = 768;
@@ -13749,7 +13878,7 @@ async function readCache(cachePath) {
13749
13878
  }
13750
13879
  }
13751
13880
  async function writeCache(cachePath, cache) {
13752
- await import_node_fs31.promises.mkdir(import_node_path57.default.dirname(cachePath), { recursive: true });
13881
+ await import_node_fs31.promises.mkdir(import_node_path58.default.dirname(cachePath), { recursive: true });
13753
13882
  await import_node_fs31.promises.writeFile(cachePath, JSON.stringify(cache));
13754
13883
  }
13755
13884
  var VectorIndex = class {
@@ -13930,14 +14059,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
13930
14059
  async function main() {
13931
14060
  const baseDirEnv = process.env.NEAT_OUT_DIR;
13932
14061
  const legacyOutPath = process.env.NEAT_OUT_PATH;
13933
- const baseDir = baseDirEnv ? import_node_path58.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path58.default.resolve(import_node_path58.default.dirname(legacyOutPath)) : import_node_path58.default.resolve("./neat-out");
13934
- const defaultScanPath = import_node_path58.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
14062
+ const baseDir = baseDirEnv ? import_node_path59.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path59.default.resolve(import_node_path59.default.dirname(legacyOutPath)) : import_node_path59.default.resolve("./neat-out");
14063
+ const defaultScanPath = import_node_path59.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
13935
14064
  const registry = new Projects();
13936
14065
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
13937
14066
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
13938
14067
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
13939
14068
  const projectScan = process.env[envKey];
13940
- await bootProject(registry, name, projectScan ? import_node_path58.default.resolve(projectScan) : void 0, baseDir);
14069
+ await bootProject(registry, name, projectScan ? import_node_path59.default.resolve(projectScan) : void 0, baseDir);
13941
14070
  }
13942
14071
  const host = process.env.HOST ?? "0.0.0.0";
13943
14072
  const port = Number(process.env.PORT ?? 8080);