@neat.is/core 0.4.28-dev.20260708 → 0.4.28-dev.20260710

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 path46 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
- if (exactUnauthPaths.has(path46) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path46)) {
62
+ const path47 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
63
+ if (exactUnauthPaths.has(path47) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path47)) {
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_path42.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
- return import_node_path42.default.resolve(here, "..", "proto");
195
+ const here = import_node_path43.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
196
+ return import_node_path43.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_path42, import_node_crypto2, grpc, protoLoader;
264
+ var import_node_url, import_node_path43, 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_path42 = __toESM(require("path"), 1);
270
+ import_node_path43 = __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);
@@ -360,8 +360,8 @@ function websocketChannelPathOf(attrs) {
360
360
  const v = attrs[key];
361
361
  if (typeof v === "string" && v.length > 0) {
362
362
  const q = v.indexOf("?");
363
- const path46 = q === -1 ? v : v.slice(0, q);
364
- if (path46.length > 0) return path46;
363
+ const path47 = q === -1 ? v : v.slice(0, q);
364
+ if (path47.length > 0) return path47;
365
365
  }
366
366
  }
367
367
  return void 0;
@@ -415,10 +415,10 @@ function parseOtlpRequest(body) {
415
415
  return out;
416
416
  }
417
417
  function loadProtoRoot() {
418
- const here = import_node_path43.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
419
- const protoRoot = import_node_path43.default.resolve(here, "..", "proto");
418
+ const here = import_node_path44.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
419
+ const protoRoot = import_node_path44.default.resolve(here, "..", "proto");
420
420
  const root = new import_protobufjs.default.Root();
421
- root.resolvePath = (_origin, target) => import_node_path43.default.resolve(protoRoot, target);
421
+ root.resolvePath = (_origin, target) => import_node_path44.default.resolve(protoRoot, target);
422
422
  root.loadSync(
423
423
  "opentelemetry/proto/collector/trace/v1/trace_service.proto",
424
424
  { keepCase: true }
@@ -630,12 +630,12 @@ async function buildOtelReceiver(opts) {
630
630
  };
631
631
  return decorated;
632
632
  }
633
- var import_node_path43, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
633
+ var import_node_path44, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
634
634
  var init_otel = __esm({
635
635
  "src/otel.ts"() {
636
636
  "use strict";
637
637
  init_cjs_shims();
638
- import_node_path43 = __toESM(require("path"), 1);
638
+ import_node_path44 = __toESM(require("path"), 1);
639
639
  import_node_url2 = require("url");
640
640
  import_fastify2 = __toESM(require("fastify"), 1);
641
641
  import_protobufjs = __toESM(require("protobufjs"), 1);
@@ -651,7 +651,7 @@ var init_otel = __esm({
651
651
 
652
652
  // src/server.ts
653
653
  init_cjs_shims();
654
- var import_node_path45 = __toESM(require("path"), 1);
654
+ var import_node_path46 = __toESM(require("path"), 1);
655
655
 
656
656
  // src/graph.ts
657
657
  init_cjs_shims();
@@ -675,7 +675,7 @@ function getGraph(project = DEFAULT_PROJECT) {
675
675
  init_cjs_shims();
676
676
  var import_fastify = __toESM(require("fastify"), 1);
677
677
  var import_cors = __toESM(require("@fastify/cors"), 1);
678
- var import_types29 = require("@neat.is/types");
678
+ var import_types30 = require("@neat.is/types");
679
679
 
680
680
  // src/extend/index.ts
681
681
  init_cjs_shims();
@@ -1418,19 +1418,19 @@ function confidenceFromMix(edges, now = Date.now()) {
1418
1418
  function longestIncomingWalk(graph, start, maxDepth) {
1419
1419
  let best = { path: [start], edges: [] };
1420
1420
  const visited = /* @__PURE__ */ new Set([start]);
1421
- function step(node, path46, edges) {
1422
- if (path46.length > best.path.length) {
1423
- best = { path: [...path46], edges: [...edges] };
1421
+ function step(node, path47, edges) {
1422
+ if (path47.length > best.path.length) {
1423
+ best = { path: [...path47], edges: [...edges] };
1424
1424
  }
1425
- if (path46.length - 1 >= maxDepth) return;
1425
+ if (path47.length - 1 >= maxDepth) return;
1426
1426
  const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
1427
1427
  for (const [srcId, edge] of incoming) {
1428
1428
  if (visited.has(srcId)) continue;
1429
1429
  visited.add(srcId);
1430
- path46.push(srcId);
1430
+ path47.push(srcId);
1431
1431
  edges.push(edge);
1432
- step(srcId, path46, edges);
1433
- path46.pop();
1432
+ step(srcId, path47, edges);
1433
+ path47.pop();
1434
1434
  edges.pop();
1435
1435
  visited.delete(srcId);
1436
1436
  }
@@ -1624,26 +1624,26 @@ function dominantFailingCall(graph, serviceId4, visited) {
1624
1624
  return best;
1625
1625
  }
1626
1626
  function followFailingCallChain(graph, originServiceId, maxDepth) {
1627
- const path46 = [originServiceId];
1627
+ const path47 = [originServiceId];
1628
1628
  const edges = [];
1629
1629
  const visited = /* @__PURE__ */ new Set([originServiceId]);
1630
1630
  let current = originServiceId;
1631
1631
  for (let depth = 0; depth < maxDepth; depth++) {
1632
1632
  const hop = dominantFailingCall(graph, current, visited);
1633
1633
  if (!hop) break;
1634
- path46.push(hop.nextService);
1634
+ path47.push(hop.nextService);
1635
1635
  edges.push(hop.edge);
1636
1636
  visited.add(hop.nextService);
1637
1637
  current = hop.nextService;
1638
1638
  }
1639
1639
  if (edges.length === 0) return null;
1640
- return { path: path46, edges, culprit: current };
1640
+ return { path: path47, edges, culprit: current };
1641
1641
  }
1642
1642
  function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1643
1643
  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
1644
1644
  if (!chain) return null;
1645
1645
  const culprit = chain.culprit;
1646
- const path46 = [...chain.path];
1646
+ const path47 = [...chain.path];
1647
1647
  const edgeProvenances = chain.edges.map((e) => e.provenance);
1648
1648
  const baseConfidence = confidenceFromMix(chain.edges);
1649
1649
  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
@@ -1651,14 +1651,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1651
1651
  if (loc) {
1652
1652
  let rootCauseNode = culprit;
1653
1653
  if (loc.fileNode) {
1654
- path46.push(loc.fileNode);
1654
+ path47.push(loc.fileNode);
1655
1655
  edgeProvenances.push(import_types.Provenance.OBSERVED);
1656
1656
  rootCauseNode = loc.fileNode;
1657
1657
  }
1658
1658
  return import_types.RootCauseResultSchema.parse({
1659
1659
  rootCauseNode,
1660
1660
  rootCauseReason: loc.rootCauseReason,
1661
- traversalPath: path46,
1661
+ traversalPath: path47,
1662
1662
  edgeProvenances,
1663
1663
  confidence,
1664
1664
  ...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
@@ -1670,7 +1670,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
1670
1670
  return import_types.RootCauseResultSchema.parse({
1671
1671
  rootCauseNode: culprit,
1672
1672
  rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
1673
- traversalPath: path46,
1673
+ traversalPath: path47,
1674
1674
  edgeProvenances,
1675
1675
  confidence,
1676
1676
  fixRecommendation: `Inspect ${culpritName}'s failing handler`
@@ -5818,10 +5818,10 @@ function fastifyRouteMethods(objNode) {
5818
5818
  }
5819
5819
  return [];
5820
5820
  }
5821
- function serverRoutesFromSource(source, parser, hasExpress, hasFastify) {
5821
+ function serverRoutesFromSource(source, parser, hasExpress, hasFastify, hasHono = false) {
5822
5822
  const tree = parseSource2(parser, source);
5823
5823
  const out = [];
5824
- const framework = hasExpress ? "express" : "fastify";
5824
+ const framework = hasExpress ? "express" : hasFastify ? "fastify" : hasHono ? "hono" : "unknown";
5825
5825
  walk(tree.rootNode, (node) => {
5826
5826
  if (node.type !== "call_expression") return;
5827
5827
  const fn = node.childForFieldName("function");
@@ -5971,8 +5971,9 @@ async function addRoutes(graph, services) {
5971
5971
  };
5972
5972
  const hasExpress = deps["express"] !== void 0;
5973
5973
  const hasFastify = deps["fastify"] !== void 0;
5974
+ const hasHono = deps["hono"] !== void 0;
5974
5975
  const hasNext = deps["next"] !== void 0;
5975
- if (!hasExpress && !hasFastify && !hasNext) continue;
5976
+ if (!hasExpress && !hasFastify && !hasHono && !hasNext) continue;
5976
5977
  const files = await loadSourceFiles(service.dir);
5977
5978
  for (const file of files) {
5978
5979
  if (isTestPath(file.path)) continue;
@@ -5982,8 +5983,8 @@ async function addRoutes(graph, services) {
5982
5983
  try {
5983
5984
  if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
5984
5985
  routes = nextRoutesFromFile(file.content, relFile, jsParser);
5985
- } else if (hasExpress || hasFastify) {
5986
- routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify);
5986
+ } else if (hasExpress || hasFastify || hasHono) {
5987
+ routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
5987
5988
  } else {
5988
5989
  routes = [];
5989
5990
  }
@@ -7307,30 +7308,264 @@ async function addK8sResources(graph, scanPath) {
7307
7308
  return { nodesAdded, edgesAdded: 0 };
7308
7309
  }
7309
7310
 
7311
+ // src/extract/infra/cloudflare.ts
7312
+ init_cjs_shims();
7313
+ var import_node_fs21 = require("fs");
7314
+ var import_node_path37 = __toESM(require("path"), 1);
7315
+ var import_smol_toml2 = require("smol-toml");
7316
+ var import_types26 = require("@neat.is/types");
7317
+ var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
7318
+ async function readWranglerConfig(dir) {
7319
+ for (const filename of WRANGLER_FILENAMES) {
7320
+ const abs = import_node_path37.default.join(dir, filename);
7321
+ if (!await exists2(abs)) continue;
7322
+ const raw = await import_node_fs21.promises.readFile(abs, "utf8");
7323
+ const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
7324
+ return { config, relFile: filename, raw };
7325
+ }
7326
+ return null;
7327
+ }
7328
+ function lineContaining(raw, needle) {
7329
+ if (!needle) return void 0;
7330
+ const idx = raw.indexOf(needle);
7331
+ if (idx === -1) return void 0;
7332
+ let line = 1;
7333
+ for (let i = 0; i < idx; i++) if (raw[i] === "\n") line++;
7334
+ return line;
7335
+ }
7336
+ function normalizeRoutes(config) {
7337
+ const out = [];
7338
+ const pushOne = (r) => {
7339
+ if (typeof r === "string") out.push(r);
7340
+ else if (r && typeof r === "object" && typeof r.pattern === "string") {
7341
+ out.push(r.pattern);
7342
+ }
7343
+ };
7344
+ if (Array.isArray(config.routes)) config.routes.forEach(pushOne);
7345
+ else if (config.route) pushOne(config.route);
7346
+ return out;
7347
+ }
7348
+ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, line) {
7349
+ let nodesAdded = 0;
7350
+ let edgesAdded = 0;
7351
+ const node = makeInfraNode(kind, name, "cloudflare");
7352
+ if (!graph.hasNode(node.id)) {
7353
+ graph.addNode(node.id, node);
7354
+ nodesAdded++;
7355
+ }
7356
+ if (node.id === anchorId) return { nodesAdded, edgesAdded };
7357
+ const edgeId = (0, import_types5.extractedEdgeId)(anchorId, node.id, edgeType);
7358
+ if (!graph.hasEdge(edgeId)) {
7359
+ const edge = {
7360
+ id: edgeId,
7361
+ source: anchorId,
7362
+ target: node.id,
7363
+ type: edgeType,
7364
+ provenance: import_types26.Provenance.EXTRACTED,
7365
+ confidence: (0, import_types26.confidenceForExtracted)("structural"),
7366
+ evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
7367
+ };
7368
+ graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
7369
+ edgesAdded++;
7370
+ }
7371
+ return { nodesAdded, edgesAdded };
7372
+ }
7373
+ async function addCloudflareWorkers(graph, services, scanPath) {
7374
+ let nodesAdded = 0;
7375
+ let edgesAdded = 0;
7376
+ const discovered = [];
7377
+ const workerIndex = /* @__PURE__ */ new Map();
7378
+ for (const service of services) {
7379
+ let read;
7380
+ try {
7381
+ read = await readWranglerConfig(service.dir);
7382
+ } catch (err) {
7383
+ recordExtractionError("infra cloudflare", import_node_path37.default.relative(scanPath, service.dir), err);
7384
+ continue;
7385
+ }
7386
+ if (!read || !read.config.name) continue;
7387
+ const evidenceFile = toPosix2(import_node_path37.default.relative(scanPath, import_node_path37.default.join(service.dir, read.relFile)));
7388
+ discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
7389
+ }
7390
+ for (const worker of discovered) {
7391
+ const { service, config } = worker;
7392
+ const serviceNode = graph.getNodeAttributes(service.node.id);
7393
+ if (serviceNode.platform !== "cloudflare") {
7394
+ const updated = { ...serviceNode, platform: "cloudflare" };
7395
+ graph.replaceNodeAttributes(service.node.id, updated);
7396
+ }
7397
+ let anchorId = service.node.id;
7398
+ if (config.main) {
7399
+ const entryRelPath = toPosix2(import_node_path37.default.normalize(config.main));
7400
+ const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
7401
+ graph,
7402
+ service.pkg.name,
7403
+ service.node.id,
7404
+ entryRelPath
7405
+ );
7406
+ nodesAdded += fn;
7407
+ edgesAdded += fe;
7408
+ const fileNode = graph.getNodeAttributes(fileNodeId);
7409
+ if (fileNode.platform !== "cloudflare" || fileNode.platformName !== config.name) {
7410
+ const updated = { ...fileNode, platform: "cloudflare", platformName: config.name };
7411
+ graph.replaceNodeAttributes(fileNodeId, updated);
7412
+ }
7413
+ anchorId = fileNodeId;
7414
+ }
7415
+ workerIndex.set(config.name, { anchorId });
7416
+ }
7417
+ for (const worker of discovered) {
7418
+ const { config, evidenceFile, raw } = worker;
7419
+ const anchorId = workerIndex.get(config.name).anchorId;
7420
+ const runtimeNode = makeInfraNode("workerd", "cloudflare", "cloudflare");
7421
+ if (!graph.hasNode(runtimeNode.id)) {
7422
+ graph.addNode(runtimeNode.id, runtimeNode);
7423
+ nodesAdded++;
7424
+ }
7425
+ if (runtimeNode.id !== anchorId) {
7426
+ const runsOnId = (0, import_types5.extractedEdgeId)(anchorId, runtimeNode.id, import_types26.EdgeType.RUNS_ON);
7427
+ if (!graph.hasEdge(runsOnId)) {
7428
+ const edge = {
7429
+ id: runsOnId,
7430
+ source: anchorId,
7431
+ target: runtimeNode.id,
7432
+ type: import_types26.EdgeType.RUNS_ON,
7433
+ provenance: import_types26.Provenance.EXTRACTED,
7434
+ confidence: (0, import_types26.confidenceForExtracted)("structural"),
7435
+ evidence: {
7436
+ file: evidenceFile,
7437
+ ...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
7438
+ }
7439
+ };
7440
+ graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge);
7441
+ edgesAdded++;
7442
+ }
7443
+ }
7444
+ for (const route of normalizeRoutes(config)) {
7445
+ const result = addResourceEdge(
7446
+ graph,
7447
+ anchorId,
7448
+ import_types26.EdgeType.CONNECTS_TO,
7449
+ "cloudflare-route",
7450
+ route,
7451
+ evidenceFile,
7452
+ lineContaining(raw, route)
7453
+ );
7454
+ nodesAdded += result.nodesAdded;
7455
+ edgesAdded += result.edgesAdded;
7456
+ }
7457
+ const bindingGroups = [
7458
+ { kind: "cloudflare-kv", entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },
7459
+ { kind: "cloudflare-d1", entries: config.d1_databases ?? [], nameOf: (b) => b.binding },
7460
+ { kind: "cloudflare-r2", entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },
7461
+ { kind: "cloudflare-durable-object", entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },
7462
+ { kind: "cloudflare-queue", entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },
7463
+ { kind: "cloudflare-queue", entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue }
7464
+ ];
7465
+ for (const group of bindingGroups) {
7466
+ for (const entry of group.entries) {
7467
+ const name = group.nameOf(entry);
7468
+ if (!name) continue;
7469
+ const result = addResourceEdge(
7470
+ graph,
7471
+ anchorId,
7472
+ import_types26.EdgeType.DEPENDS_ON,
7473
+ group.kind,
7474
+ name,
7475
+ evidenceFile,
7476
+ lineContaining(raw, name)
7477
+ );
7478
+ nodesAdded += result.nodesAdded;
7479
+ edgesAdded += result.edgesAdded;
7480
+ }
7481
+ }
7482
+ for (const cron of config.triggers?.crons ?? []) {
7483
+ const result = addResourceEdge(
7484
+ graph,
7485
+ anchorId,
7486
+ import_types26.EdgeType.DEPENDS_ON,
7487
+ "cloudflare-cron",
7488
+ cron,
7489
+ evidenceFile,
7490
+ lineContaining(raw, cron)
7491
+ );
7492
+ nodesAdded += result.nodesAdded;
7493
+ edgesAdded += result.edgesAdded;
7494
+ }
7495
+ for (const varName of Object.keys(config.vars ?? {})) {
7496
+ const result = addResourceEdge(
7497
+ graph,
7498
+ anchorId,
7499
+ import_types26.EdgeType.DEPENDS_ON,
7500
+ "cloudflare-env-var",
7501
+ varName,
7502
+ evidenceFile,
7503
+ lineContaining(raw, varName)
7504
+ );
7505
+ nodesAdded += result.nodesAdded;
7506
+ edgesAdded += result.edgesAdded;
7507
+ }
7508
+ for (const svc of config.services ?? []) {
7509
+ if (!svc.service) continue;
7510
+ const target = workerIndex.get(svc.service);
7511
+ if (target && target.anchorId !== anchorId) {
7512
+ const edgeId = (0, import_types5.extractedEdgeId)(anchorId, target.anchorId, import_types26.EdgeType.CALLS);
7513
+ if (!graph.hasEdge(edgeId)) {
7514
+ const edge = {
7515
+ id: edgeId,
7516
+ source: anchorId,
7517
+ target: target.anchorId,
7518
+ type: import_types26.EdgeType.CALLS,
7519
+ provenance: import_types26.Provenance.EXTRACTED,
7520
+ confidence: (0, import_types26.confidenceForExtracted)("structural"),
7521
+ evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) }
7522
+ };
7523
+ graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
7524
+ edgesAdded++;
7525
+ }
7526
+ continue;
7527
+ }
7528
+ const result = addResourceEdge(
7529
+ graph,
7530
+ anchorId,
7531
+ import_types26.EdgeType.DEPENDS_ON,
7532
+ "cloudflare-service-binding",
7533
+ svc.service,
7534
+ evidenceFile,
7535
+ lineContaining(raw, svc.service)
7536
+ );
7537
+ nodesAdded += result.nodesAdded;
7538
+ edgesAdded += result.edgesAdded;
7539
+ }
7540
+ }
7541
+ return { nodesAdded, edgesAdded };
7542
+ }
7543
+
7310
7544
  // src/extract/infra/index.ts
7311
7545
  async function addInfra(graph, scanPath, services) {
7312
7546
  const compose = await addComposeInfra(graph, scanPath, services);
7313
7547
  const dockerfile = await addDockerfileRuntimes(graph, services, scanPath);
7314
7548
  const terraform = await addTerraformResources(graph, scanPath);
7315
7549
  const k8s = await addK8sResources(graph, scanPath);
7550
+ const cloudflare = await addCloudflareWorkers(graph, services, scanPath);
7316
7551
  return {
7317
- nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,
7318
- edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded
7552
+ nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded + cloudflare.nodesAdded,
7553
+ edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded + cloudflare.edgesAdded
7319
7554
  };
7320
7555
  }
7321
7556
 
7322
7557
  // src/extract/index.ts
7323
- var import_node_path38 = __toESM(require("path"), 1);
7558
+ var import_node_path39 = __toESM(require("path"), 1);
7324
7559
 
7325
7560
  // src/extract/retire.ts
7326
7561
  init_cjs_shims();
7327
- var import_node_fs21 = require("fs");
7328
- var import_node_path37 = __toESM(require("path"), 1);
7329
- var import_types26 = require("@neat.is/types");
7562
+ var import_node_fs22 = require("fs");
7563
+ var import_node_path38 = __toESM(require("path"), 1);
7564
+ var import_types27 = require("@neat.is/types");
7330
7565
  function dropOrphanedFileNodes(graph) {
7331
7566
  const orphans = [];
7332
7567
  graph.forEachNode((id, attrs) => {
7333
- if (attrs.type !== import_types26.NodeType.FileNode) return;
7568
+ if (attrs.type !== import_types27.NodeType.FileNode) return;
7334
7569
  if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
7335
7570
  orphans.push(id);
7336
7571
  }
@@ -7343,14 +7578,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
7343
7578
  const bases = [scanPath, ...serviceDirs];
7344
7579
  graph.forEachEdge((id, attrs) => {
7345
7580
  const edge = attrs;
7346
- if (edge.provenance !== import_types26.Provenance.EXTRACTED) return;
7581
+ if (edge.provenance !== import_types27.Provenance.EXTRACTED) return;
7347
7582
  const evidenceFile = edge.evidence?.file;
7348
7583
  if (!evidenceFile) return;
7349
- if (import_node_path37.default.isAbsolute(evidenceFile)) {
7350
- if (!(0, import_node_fs21.existsSync)(evidenceFile)) toDrop.push(id);
7584
+ if (import_node_path38.default.isAbsolute(evidenceFile)) {
7585
+ if (!(0, import_node_fs22.existsSync)(evidenceFile)) toDrop.push(id);
7351
7586
  return;
7352
7587
  }
7353
- const found = bases.some((base) => (0, import_node_fs21.existsSync)(import_node_path37.default.join(base, evidenceFile)));
7588
+ const found = bases.some((base) => (0, import_node_fs22.existsSync)(import_node_path38.default.join(base, evidenceFile)));
7354
7589
  if (!found) toDrop.push(id);
7355
7590
  });
7356
7591
  for (const id of toDrop) graph.dropEdge(id);
@@ -7392,7 +7627,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
7392
7627
  }
7393
7628
  const droppedEntries = drainDroppedExtracted();
7394
7629
  if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
7395
- const rejectedPath = import_node_path38.default.join(import_node_path38.default.dirname(opts.errorsPath), "rejected.ndjson");
7630
+ const rejectedPath = import_node_path39.default.join(import_node_path39.default.dirname(opts.errorsPath), "rejected.ndjson");
7396
7631
  try {
7397
7632
  await writeRejectedExtracted(droppedEntries, rejectedPath);
7398
7633
  } catch (err) {
@@ -7426,7 +7661,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
7426
7661
 
7427
7662
  // src/diff.ts
7428
7663
  init_cjs_shims();
7429
- var import_node_fs22 = require("fs");
7664
+ var import_node_fs23 = require("fs");
7430
7665
  async function loadSnapshotForDiff(target) {
7431
7666
  if (/^https?:\/\//i.test(target)) {
7432
7667
  const res = await fetch(target);
@@ -7435,7 +7670,7 @@ async function loadSnapshotForDiff(target) {
7435
7670
  }
7436
7671
  return await res.json();
7437
7672
  }
7438
- const raw = await import_node_fs22.promises.readFile(target, "utf8");
7673
+ const raw = await import_node_fs23.promises.readFile(target, "utf8");
7439
7674
  return JSON.parse(raw);
7440
7675
  }
7441
7676
  function indexEntries(entries) {
@@ -7503,9 +7738,9 @@ function canonicalJson(value) {
7503
7738
 
7504
7739
  // src/persist.ts
7505
7740
  init_cjs_shims();
7506
- var import_node_fs23 = require("fs");
7507
- var import_node_path39 = __toESM(require("path"), 1);
7508
- var import_types27 = require("@neat.is/types");
7741
+ var import_node_fs24 = require("fs");
7742
+ var import_node_path40 = __toESM(require("path"), 1);
7743
+ var import_types28 = require("@neat.is/types");
7509
7744
  var SCHEMA_VERSION = 4;
7510
7745
  function migrateV1ToV2(payload) {
7511
7746
  const nodes = payload.graph.nodes;
@@ -7527,12 +7762,12 @@ function migrateV2ToV3(payload) {
7527
7762
  for (const edge of edges) {
7528
7763
  const attrs = edge.attributes;
7529
7764
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
7530
- attrs.provenance = import_types27.Provenance.OBSERVED;
7765
+ attrs.provenance = import_types28.Provenance.OBSERVED;
7531
7766
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
7532
7767
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
7533
7768
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
7534
7769
  if (type && source && target) {
7535
- const newId = (0, import_types27.observedEdgeId)(source, target, type);
7770
+ const newId = (0, import_types28.observedEdgeId)(source, target, type);
7536
7771
  attrs.id = newId;
7537
7772
  if (edge.key) edge.key = newId;
7538
7773
  }
@@ -7541,7 +7776,7 @@ function migrateV2ToV3(payload) {
7541
7776
  return { ...payload, schemaVersion: 3 };
7542
7777
  }
7543
7778
  async function ensureDir(filePath) {
7544
- await import_node_fs23.promises.mkdir(import_node_path39.default.dirname(filePath), { recursive: true });
7779
+ await import_node_fs24.promises.mkdir(import_node_path40.default.dirname(filePath), { recursive: true });
7545
7780
  }
7546
7781
  async function saveGraphToDisk(graph, outPath) {
7547
7782
  await ensureDir(outPath);
@@ -7551,13 +7786,13 @@ async function saveGraphToDisk(graph, outPath) {
7551
7786
  graph: graph.export()
7552
7787
  };
7553
7788
  const tmp = `${outPath}.tmp`;
7554
- await import_node_fs23.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
7555
- await import_node_fs23.promises.rename(tmp, outPath);
7789
+ await import_node_fs24.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
7790
+ await import_node_fs24.promises.rename(tmp, outPath);
7556
7791
  }
7557
7792
  async function loadGraphFromDisk(graph, outPath) {
7558
7793
  let raw;
7559
7794
  try {
7560
- raw = await import_node_fs23.promises.readFile(outPath, "utf8");
7795
+ raw = await import_node_fs24.promises.readFile(outPath, "utf8");
7561
7796
  } catch (err) {
7562
7797
  if (err.code === "ENOENT") return;
7563
7798
  throw err;
@@ -7622,23 +7857,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
7622
7857
 
7623
7858
  // src/projects.ts
7624
7859
  init_cjs_shims();
7625
- var import_node_path40 = __toESM(require("path"), 1);
7860
+ var import_node_path41 = __toESM(require("path"), 1);
7626
7861
  function pathsForProject(project, baseDir) {
7627
7862
  if (project === DEFAULT_PROJECT) {
7628
7863
  return {
7629
- snapshotPath: import_node_path40.default.join(baseDir, "graph.json"),
7630
- errorsPath: import_node_path40.default.join(baseDir, "errors.ndjson"),
7631
- staleEventsPath: import_node_path40.default.join(baseDir, "stale-events.ndjson"),
7632
- embeddingsCachePath: import_node_path40.default.join(baseDir, "embeddings.json"),
7633
- policyViolationsPath: import_node_path40.default.join(baseDir, "policy-violations.ndjson")
7864
+ snapshotPath: import_node_path41.default.join(baseDir, "graph.json"),
7865
+ errorsPath: import_node_path41.default.join(baseDir, "errors.ndjson"),
7866
+ staleEventsPath: import_node_path41.default.join(baseDir, "stale-events.ndjson"),
7867
+ embeddingsCachePath: import_node_path41.default.join(baseDir, "embeddings.json"),
7868
+ policyViolationsPath: import_node_path41.default.join(baseDir, "policy-violations.ndjson")
7634
7869
  };
7635
7870
  }
7636
7871
  return {
7637
- snapshotPath: import_node_path40.default.join(baseDir, `${project}.json`),
7638
- errorsPath: import_node_path40.default.join(baseDir, `errors.${project}.ndjson`),
7639
- staleEventsPath: import_node_path40.default.join(baseDir, `stale-events.${project}.ndjson`),
7640
- embeddingsCachePath: import_node_path40.default.join(baseDir, `embeddings.${project}.json`),
7641
- policyViolationsPath: import_node_path40.default.join(baseDir, `policy-violations.${project}.ndjson`)
7872
+ snapshotPath: import_node_path41.default.join(baseDir, `${project}.json`),
7873
+ errorsPath: import_node_path41.default.join(baseDir, `errors.${project}.ndjson`),
7874
+ staleEventsPath: import_node_path41.default.join(baseDir, `stale-events.${project}.ndjson`),
7875
+ embeddingsCachePath: import_node_path41.default.join(baseDir, `embeddings.${project}.json`),
7876
+ policyViolationsPath: import_node_path41.default.join(baseDir, `policy-violations.${project}.ndjson`)
7642
7877
  };
7643
7878
  }
7644
7879
  var Projects = class {
@@ -7678,23 +7913,23 @@ function parseExtraProjects(raw) {
7678
7913
 
7679
7914
  // src/registry.ts
7680
7915
  init_cjs_shims();
7681
- var import_node_fs24 = require("fs");
7916
+ var import_node_fs25 = require("fs");
7682
7917
  var import_node_os3 = __toESM(require("os"), 1);
7683
- var import_node_path41 = __toESM(require("path"), 1);
7684
- var import_types28 = require("@neat.is/types");
7918
+ var import_node_path42 = __toESM(require("path"), 1);
7919
+ var import_types29 = require("@neat.is/types");
7685
7920
  function neatHome() {
7686
7921
  const override = process.env.NEAT_HOME;
7687
- if (override && override.length > 0) return import_node_path41.default.resolve(override);
7688
- return import_node_path41.default.join(import_node_os3.default.homedir(), ".neat");
7922
+ if (override && override.length > 0) return import_node_path42.default.resolve(override);
7923
+ return import_node_path42.default.join(import_node_os3.default.homedir(), ".neat");
7689
7924
  }
7690
7925
  function registryPath() {
7691
- return import_node_path41.default.join(neatHome(), "projects.json");
7926
+ return import_node_path42.default.join(neatHome(), "projects.json");
7692
7927
  }
7693
7928
  async function readRegistry() {
7694
7929
  const file = registryPath();
7695
7930
  let raw;
7696
7931
  try {
7697
- raw = await import_node_fs24.promises.readFile(file, "utf8");
7932
+ raw = await import_node_fs25.promises.readFile(file, "utf8");
7698
7933
  } catch (err) {
7699
7934
  if (err.code === "ENOENT") {
7700
7935
  return { version: 1, projects: [] };
@@ -7702,7 +7937,7 @@ async function readRegistry() {
7702
7937
  throw err;
7703
7938
  }
7704
7939
  const parsed = JSON.parse(raw);
7705
- return import_types28.RegistryFileSchema.parse(parsed);
7940
+ return import_types29.RegistryFileSchema.parse(parsed);
7706
7941
  }
7707
7942
  async function getProject(name) {
7708
7943
  const reg = await readRegistry();
@@ -7923,11 +8158,11 @@ function registerRoutes(scope, ctx) {
7923
8158
  const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
7924
8159
  const parsed = [];
7925
8160
  for (const c of candidates) {
7926
- const r = import_types29.DivergenceTypeSchema.safeParse(c);
8161
+ const r = import_types30.DivergenceTypeSchema.safeParse(c);
7927
8162
  if (!r.success) {
7928
8163
  return reply.code(400).send({
7929
8164
  error: `unknown divergence type "${c}"`,
7930
- allowed: import_types29.DivergenceTypeSchema.options
8165
+ allowed: import_types30.DivergenceTypeSchema.options
7931
8166
  });
7932
8167
  }
7933
8168
  parsed.push(r.data);
@@ -8178,7 +8413,7 @@ function registerRoutes(scope, ctx) {
8178
8413
  const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
8179
8414
  let violations = await log.readAll();
8180
8415
  if (req.query.severity) {
8181
- const sev = import_types29.PolicySeveritySchema.safeParse(req.query.severity);
8416
+ const sev = import_types30.PolicySeveritySchema.safeParse(req.query.severity);
8182
8417
  if (!sev.success) {
8183
8418
  return reply.code(400).send({
8184
8419
  error: "invalid severity",
@@ -8217,7 +8452,7 @@ function registerRoutes(scope, ctx) {
8217
8452
  scope.post("/policies/check", async (req, reply) => {
8218
8453
  const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
8219
8454
  if (!proj) return;
8220
- const parsed = import_types29.PoliciesCheckBodySchema.safeParse(req.body ?? {});
8455
+ const parsed = import_types30.PoliciesCheckBodySchema.safeParse(req.body ?? {});
8221
8456
  if (!parsed.success) {
8222
8457
  return reply.code(400).send({
8223
8458
  error: "invalid /policies/check body",
@@ -8479,8 +8714,8 @@ init_otel_grpc();
8479
8714
 
8480
8715
  // src/search.ts
8481
8716
  init_cjs_shims();
8482
- var import_node_fs25 = require("fs");
8483
- var import_node_path44 = __toESM(require("path"), 1);
8717
+ var import_node_fs26 = require("fs");
8718
+ var import_node_path45 = __toESM(require("path"), 1);
8484
8719
  var import_node_crypto3 = require("crypto");
8485
8720
  var DEFAULT_LIMIT = 10;
8486
8721
  var NOMIC_DIM = 768;
@@ -8634,7 +8869,7 @@ async function pickEmbedder() {
8634
8869
  }
8635
8870
  async function readCache(cachePath) {
8636
8871
  try {
8637
- const raw = await import_node_fs25.promises.readFile(cachePath, "utf8");
8872
+ const raw = await import_node_fs26.promises.readFile(cachePath, "utf8");
8638
8873
  const parsed = JSON.parse(raw);
8639
8874
  if (parsed.version !== 1) return null;
8640
8875
  return parsed;
@@ -8643,8 +8878,8 @@ async function readCache(cachePath) {
8643
8878
  }
8644
8879
  }
8645
8880
  async function writeCache(cachePath, cache) {
8646
- await import_node_fs25.promises.mkdir(import_node_path44.default.dirname(cachePath), { recursive: true });
8647
- await import_node_fs25.promises.writeFile(cachePath, JSON.stringify(cache));
8881
+ await import_node_fs26.promises.mkdir(import_node_path45.default.dirname(cachePath), { recursive: true });
8882
+ await import_node_fs26.promises.writeFile(cachePath, JSON.stringify(cache));
8648
8883
  }
8649
8884
  var VectorIndex = class {
8650
8885
  constructor(embedder, cachePath) {
@@ -8824,14 +9059,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
8824
9059
  async function main() {
8825
9060
  const baseDirEnv = process.env.NEAT_OUT_DIR;
8826
9061
  const legacyOutPath = process.env.NEAT_OUT_PATH;
8827
- const baseDir = baseDirEnv ? import_node_path45.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path45.default.resolve(import_node_path45.default.dirname(legacyOutPath)) : import_node_path45.default.resolve("./neat-out");
8828
- const defaultScanPath = import_node_path45.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
9062
+ const baseDir = baseDirEnv ? import_node_path46.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path46.default.resolve(import_node_path46.default.dirname(legacyOutPath)) : import_node_path46.default.resolve("./neat-out");
9063
+ const defaultScanPath = import_node_path46.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
8829
9064
  const registry = new Projects();
8830
9065
  await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
8831
9066
  for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
8832
9067
  const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
8833
9068
  const projectScan = process.env[envKey];
8834
- await bootProject(registry, name, projectScan ? import_node_path45.default.resolve(projectScan) : void 0, baseDir);
9069
+ await bootProject(registry, name, projectScan ? import_node_path46.default.resolve(projectScan) : void 0, baseDir);
8835
9070
  }
8836
9071
  const host = process.env.HOST ?? "0.0.0.0";
8837
9072
  const port = Number(process.env.PORT ?? 8080);