@neat.is/core 0.4.28-dev.20260708 → 0.4.28-dev.20260709
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/{chunk-O4MRDWD7.js → chunk-5T6J3WKC.js} +369 -121
- package/dist/chunk-5T6J3WKC.js.map +1 -0
- package/dist/{chunk-NY5Q6NE2.js → chunk-UJ6WBLIE.js} +88 -15
- package/dist/chunk-UJ6WBLIE.js.map +1 -0
- package/dist/cli.cjs +712 -409
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +536 -216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +549 -229
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +323 -88
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-NY5Q6NE2.js.map +0 -1
- package/dist/chunk-O4MRDWD7.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -60,8 +60,8 @@ function mountBearerAuth(app, opts) {
|
|
|
60
60
|
]);
|
|
61
61
|
const publicRead = opts.publicRead === true;
|
|
62
62
|
app.addHook("preHandler", (req, reply, done) => {
|
|
63
|
-
const
|
|
64
|
-
if (exactUnauthPaths.has(
|
|
63
|
+
const path48 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
64
|
+
if (exactUnauthPaths.has(path48) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path48)) {
|
|
65
65
|
done();
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
@@ -193,8 +193,8 @@ function reshapeGrpcRequest(req) {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
function resolveProtoRoot() {
|
|
196
|
-
const here =
|
|
197
|
-
return
|
|
196
|
+
const here = import_node_path43.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
197
|
+
return import_node_path43.default.resolve(here, "..", "proto");
|
|
198
198
|
}
|
|
199
199
|
function loadTraceService() {
|
|
200
200
|
const protoRoot = resolveProtoRoot();
|
|
@@ -262,13 +262,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
262
262
|
})
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
var import_node_url,
|
|
265
|
+
var import_node_url, import_node_path43, import_node_crypto2, grpc, protoLoader;
|
|
266
266
|
var init_otel_grpc = __esm({
|
|
267
267
|
"src/otel-grpc.ts"() {
|
|
268
268
|
"use strict";
|
|
269
269
|
init_cjs_shims();
|
|
270
270
|
import_node_url = require("url");
|
|
271
|
-
|
|
271
|
+
import_node_path43 = __toESM(require("path"), 1);
|
|
272
272
|
import_node_crypto2 = require("crypto");
|
|
273
273
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
274
274
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -361,8 +361,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
361
361
|
const v = attrs[key];
|
|
362
362
|
if (typeof v === "string" && v.length > 0) {
|
|
363
363
|
const q = v.indexOf("?");
|
|
364
|
-
const
|
|
365
|
-
if (
|
|
364
|
+
const path48 = q === -1 ? v : v.slice(0, q);
|
|
365
|
+
if (path48.length > 0) return path48;
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
return void 0;
|
|
@@ -416,10 +416,10 @@ function parseOtlpRequest(body) {
|
|
|
416
416
|
return out;
|
|
417
417
|
}
|
|
418
418
|
function loadProtoRoot() {
|
|
419
|
-
const here =
|
|
420
|
-
const protoRoot =
|
|
419
|
+
const here = import_node_path44.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
420
|
+
const protoRoot = import_node_path44.default.resolve(here, "..", "proto");
|
|
421
421
|
const root = new import_protobufjs.default.Root();
|
|
422
|
-
root.resolvePath = (_origin, target) =>
|
|
422
|
+
root.resolvePath = (_origin, target) => import_node_path44.default.resolve(protoRoot, target);
|
|
423
423
|
root.loadSync(
|
|
424
424
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
425
425
|
{ keepCase: true }
|
|
@@ -655,12 +655,12 @@ function logSpanHandler(span) {
|
|
|
655
655
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
656
656
|
);
|
|
657
657
|
}
|
|
658
|
-
var
|
|
658
|
+
var import_node_path44, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
659
659
|
var init_otel = __esm({
|
|
660
660
|
"src/otel.ts"() {
|
|
661
661
|
"use strict";
|
|
662
662
|
init_cjs_shims();
|
|
663
|
-
|
|
663
|
+
import_node_path44 = __toESM(require("path"), 1);
|
|
664
664
|
import_node_url2 = require("url");
|
|
665
665
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
666
666
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -1250,19 +1250,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1250
1250
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1251
1251
|
let best = { path: [start], edges: [] };
|
|
1252
1252
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1253
|
-
function step(node,
|
|
1254
|
-
if (
|
|
1255
|
-
best = { path: [...
|
|
1253
|
+
function step(node, path48, edges) {
|
|
1254
|
+
if (path48.length > best.path.length) {
|
|
1255
|
+
best = { path: [...path48], edges: [...edges] };
|
|
1256
1256
|
}
|
|
1257
|
-
if (
|
|
1257
|
+
if (path48.length - 1 >= maxDepth) return;
|
|
1258
1258
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1259
1259
|
for (const [srcId, edge] of incoming) {
|
|
1260
1260
|
if (visited.has(srcId)) continue;
|
|
1261
1261
|
visited.add(srcId);
|
|
1262
|
-
|
|
1262
|
+
path48.push(srcId);
|
|
1263
1263
|
edges.push(edge);
|
|
1264
|
-
step(srcId,
|
|
1265
|
-
|
|
1264
|
+
step(srcId, path48, edges);
|
|
1265
|
+
path48.pop();
|
|
1266
1266
|
edges.pop();
|
|
1267
1267
|
visited.delete(srcId);
|
|
1268
1268
|
}
|
|
@@ -1456,26 +1456,26 @@ function dominantFailingCall(graph, serviceId5, visited) {
|
|
|
1456
1456
|
return best;
|
|
1457
1457
|
}
|
|
1458
1458
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1459
|
-
const
|
|
1459
|
+
const path48 = [originServiceId];
|
|
1460
1460
|
const edges = [];
|
|
1461
1461
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1462
1462
|
let current = originServiceId;
|
|
1463
1463
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1464
1464
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1465
1465
|
if (!hop) break;
|
|
1466
|
-
|
|
1466
|
+
path48.push(hop.nextService);
|
|
1467
1467
|
edges.push(hop.edge);
|
|
1468
1468
|
visited.add(hop.nextService);
|
|
1469
1469
|
current = hop.nextService;
|
|
1470
1470
|
}
|
|
1471
1471
|
if (edges.length === 0) return null;
|
|
1472
|
-
return { path:
|
|
1472
|
+
return { path: path48, edges, culprit: current };
|
|
1473
1473
|
}
|
|
1474
1474
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1475
1475
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1476
1476
|
if (!chain) return null;
|
|
1477
1477
|
const culprit = chain.culprit;
|
|
1478
|
-
const
|
|
1478
|
+
const path48 = [...chain.path];
|
|
1479
1479
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1480
1480
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1481
1481
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1483,14 +1483,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1483
1483
|
if (loc) {
|
|
1484
1484
|
let rootCauseNode = culprit;
|
|
1485
1485
|
if (loc.fileNode) {
|
|
1486
|
-
|
|
1486
|
+
path48.push(loc.fileNode);
|
|
1487
1487
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1488
1488
|
rootCauseNode = loc.fileNode;
|
|
1489
1489
|
}
|
|
1490
1490
|
return import_types.RootCauseResultSchema.parse({
|
|
1491
1491
|
rootCauseNode,
|
|
1492
1492
|
rootCauseReason: loc.rootCauseReason,
|
|
1493
|
-
traversalPath:
|
|
1493
|
+
traversalPath: path48,
|
|
1494
1494
|
edgeProvenances,
|
|
1495
1495
|
confidence,
|
|
1496
1496
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1502,7 +1502,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1502
1502
|
return import_types.RootCauseResultSchema.parse({
|
|
1503
1503
|
rootCauseNode: culprit,
|
|
1504
1504
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1505
|
-
traversalPath:
|
|
1505
|
+
traversalPath: path48,
|
|
1506
1506
|
edgeProvenances,
|
|
1507
1507
|
confidence,
|
|
1508
1508
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2579,6 +2579,19 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
2579
2579
|
graph.addNode(id, node);
|
|
2580
2580
|
return id;
|
|
2581
2581
|
}
|
|
2582
|
+
function ensureInfraNode(graph, kind, name, provider) {
|
|
2583
|
+
const id = (0, import_types3.infraId)(kind, name);
|
|
2584
|
+
if (graph.hasNode(id)) return id;
|
|
2585
|
+
const node = {
|
|
2586
|
+
id,
|
|
2587
|
+
type: import_types3.NodeType.InfraNode,
|
|
2588
|
+
name,
|
|
2589
|
+
provider,
|
|
2590
|
+
kind
|
|
2591
|
+
};
|
|
2592
|
+
graph.addNode(id, node);
|
|
2593
|
+
return id;
|
|
2594
|
+
}
|
|
2582
2595
|
function ensureDatabaseNode(graph, host, engine) {
|
|
2583
2596
|
const id = (0, import_types3.databaseId)(host);
|
|
2584
2597
|
if (graph.hasNode(id)) return id;
|
|
@@ -5337,10 +5350,10 @@ function fastifyRouteMethods(objNode) {
|
|
|
5337
5350
|
}
|
|
5338
5351
|
return [];
|
|
5339
5352
|
}
|
|
5340
|
-
function serverRoutesFromSource(source, parser, hasExpress, hasFastify) {
|
|
5353
|
+
function serverRoutesFromSource(source, parser, hasExpress, hasFastify, hasHono = false) {
|
|
5341
5354
|
const tree = parseSource2(parser, source);
|
|
5342
5355
|
const out = [];
|
|
5343
|
-
const framework = hasExpress ? "express" : "fastify";
|
|
5356
|
+
const framework = hasExpress ? "express" : hasFastify ? "fastify" : hasHono ? "hono" : "unknown";
|
|
5344
5357
|
walk(tree.rootNode, (node) => {
|
|
5345
5358
|
if (node.type !== "call_expression") return;
|
|
5346
5359
|
const fn = node.childForFieldName("function");
|
|
@@ -5490,8 +5503,9 @@ async function addRoutes(graph, services) {
|
|
|
5490
5503
|
};
|
|
5491
5504
|
const hasExpress = deps["express"] !== void 0;
|
|
5492
5505
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5506
|
+
const hasHono = deps["hono"] !== void 0;
|
|
5493
5507
|
const hasNext = deps["next"] !== void 0;
|
|
5494
|
-
if (!hasExpress && !hasFastify && !hasNext) continue;
|
|
5508
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext) continue;
|
|
5495
5509
|
const files = await loadSourceFiles(service.dir);
|
|
5496
5510
|
for (const file of files) {
|
|
5497
5511
|
if (isTestPath(file.path)) continue;
|
|
@@ -5501,8 +5515,8 @@ async function addRoutes(graph, services) {
|
|
|
5501
5515
|
try {
|
|
5502
5516
|
if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5503
5517
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5504
|
-
} else if (hasExpress || hasFastify) {
|
|
5505
|
-
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify);
|
|
5518
|
+
} else if (hasExpress || hasFastify || hasHono) {
|
|
5519
|
+
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
5506
5520
|
} else {
|
|
5507
5521
|
routes = [];
|
|
5508
5522
|
}
|
|
@@ -6826,30 +6840,264 @@ async function addK8sResources(graph, scanPath) {
|
|
|
6826
6840
|
return { nodesAdded, edgesAdded: 0 };
|
|
6827
6841
|
}
|
|
6828
6842
|
|
|
6843
|
+
// src/extract/infra/cloudflare.ts
|
|
6844
|
+
init_cjs_shims();
|
|
6845
|
+
var import_node_fs19 = require("fs");
|
|
6846
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
6847
|
+
var import_smol_toml2 = require("smol-toml");
|
|
6848
|
+
var import_types25 = require("@neat.is/types");
|
|
6849
|
+
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
6850
|
+
async function readWranglerConfig(dir) {
|
|
6851
|
+
for (const filename of WRANGLER_FILENAMES) {
|
|
6852
|
+
const abs = import_node_path35.default.join(dir, filename);
|
|
6853
|
+
if (!await exists(abs)) continue;
|
|
6854
|
+
const raw = await import_node_fs19.promises.readFile(abs, "utf8");
|
|
6855
|
+
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
6856
|
+
return { config, relFile: filename, raw };
|
|
6857
|
+
}
|
|
6858
|
+
return null;
|
|
6859
|
+
}
|
|
6860
|
+
function lineContaining(raw, needle) {
|
|
6861
|
+
if (!needle) return void 0;
|
|
6862
|
+
const idx = raw.indexOf(needle);
|
|
6863
|
+
if (idx === -1) return void 0;
|
|
6864
|
+
let line = 1;
|
|
6865
|
+
for (let i = 0; i < idx; i++) if (raw[i] === "\n") line++;
|
|
6866
|
+
return line;
|
|
6867
|
+
}
|
|
6868
|
+
function normalizeRoutes(config) {
|
|
6869
|
+
const out = [];
|
|
6870
|
+
const pushOne = (r) => {
|
|
6871
|
+
if (typeof r === "string") out.push(r);
|
|
6872
|
+
else if (r && typeof r === "object" && typeof r.pattern === "string") {
|
|
6873
|
+
out.push(r.pattern);
|
|
6874
|
+
}
|
|
6875
|
+
};
|
|
6876
|
+
if (Array.isArray(config.routes)) config.routes.forEach(pushOne);
|
|
6877
|
+
else if (config.route) pushOne(config.route);
|
|
6878
|
+
return out;
|
|
6879
|
+
}
|
|
6880
|
+
function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, line) {
|
|
6881
|
+
let nodesAdded = 0;
|
|
6882
|
+
let edgesAdded = 0;
|
|
6883
|
+
const node = makeInfraNode(kind, name, "cloudflare");
|
|
6884
|
+
if (!graph.hasNode(node.id)) {
|
|
6885
|
+
graph.addNode(node.id, node);
|
|
6886
|
+
nodesAdded++;
|
|
6887
|
+
}
|
|
6888
|
+
if (node.id === anchorId) return { nodesAdded, edgesAdded };
|
|
6889
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, node.id, edgeType);
|
|
6890
|
+
if (!graph.hasEdge(edgeId)) {
|
|
6891
|
+
const edge = {
|
|
6892
|
+
id: edgeId,
|
|
6893
|
+
source: anchorId,
|
|
6894
|
+
target: node.id,
|
|
6895
|
+
type: edgeType,
|
|
6896
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
6897
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6898
|
+
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
6899
|
+
};
|
|
6900
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
6901
|
+
edgesAdded++;
|
|
6902
|
+
}
|
|
6903
|
+
return { nodesAdded, edgesAdded };
|
|
6904
|
+
}
|
|
6905
|
+
async function addCloudflareWorkers(graph, services, scanPath) {
|
|
6906
|
+
let nodesAdded = 0;
|
|
6907
|
+
let edgesAdded = 0;
|
|
6908
|
+
const discovered = [];
|
|
6909
|
+
const workerIndex = /* @__PURE__ */ new Map();
|
|
6910
|
+
for (const service of services) {
|
|
6911
|
+
let read;
|
|
6912
|
+
try {
|
|
6913
|
+
read = await readWranglerConfig(service.dir);
|
|
6914
|
+
} catch (err) {
|
|
6915
|
+
recordExtractionError("infra cloudflare", import_node_path35.default.relative(scanPath, service.dir), err);
|
|
6916
|
+
continue;
|
|
6917
|
+
}
|
|
6918
|
+
if (!read || !read.config.name) continue;
|
|
6919
|
+
const evidenceFile = toPosix2(import_node_path35.default.relative(scanPath, import_node_path35.default.join(service.dir, read.relFile)));
|
|
6920
|
+
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
6921
|
+
}
|
|
6922
|
+
for (const worker of discovered) {
|
|
6923
|
+
const { service, config } = worker;
|
|
6924
|
+
const serviceNode = graph.getNodeAttributes(service.node.id);
|
|
6925
|
+
if (serviceNode.platform !== "cloudflare") {
|
|
6926
|
+
const updated = { ...serviceNode, platform: "cloudflare" };
|
|
6927
|
+
graph.replaceNodeAttributes(service.node.id, updated);
|
|
6928
|
+
}
|
|
6929
|
+
let anchorId = service.node.id;
|
|
6930
|
+
if (config.main) {
|
|
6931
|
+
const entryRelPath = toPosix2(import_node_path35.default.normalize(config.main));
|
|
6932
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
6933
|
+
graph,
|
|
6934
|
+
service.pkg.name,
|
|
6935
|
+
service.node.id,
|
|
6936
|
+
entryRelPath
|
|
6937
|
+
);
|
|
6938
|
+
nodesAdded += fn;
|
|
6939
|
+
edgesAdded += fe;
|
|
6940
|
+
const fileNode = graph.getNodeAttributes(fileNodeId);
|
|
6941
|
+
if (fileNode.platform !== "cloudflare" || fileNode.platformName !== config.name) {
|
|
6942
|
+
const updated = { ...fileNode, platform: "cloudflare", platformName: config.name };
|
|
6943
|
+
graph.replaceNodeAttributes(fileNodeId, updated);
|
|
6944
|
+
}
|
|
6945
|
+
anchorId = fileNodeId;
|
|
6946
|
+
}
|
|
6947
|
+
workerIndex.set(config.name, { anchorId });
|
|
6948
|
+
}
|
|
6949
|
+
for (const worker of discovered) {
|
|
6950
|
+
const { config, evidenceFile, raw } = worker;
|
|
6951
|
+
const anchorId = workerIndex.get(config.name).anchorId;
|
|
6952
|
+
const runtimeNode = makeInfraNode("workerd", "cloudflare", "cloudflare");
|
|
6953
|
+
if (!graph.hasNode(runtimeNode.id)) {
|
|
6954
|
+
graph.addNode(runtimeNode.id, runtimeNode);
|
|
6955
|
+
nodesAdded++;
|
|
6956
|
+
}
|
|
6957
|
+
if (runtimeNode.id !== anchorId) {
|
|
6958
|
+
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id, import_types25.EdgeType.RUNS_ON);
|
|
6959
|
+
if (!graph.hasEdge(runsOnId)) {
|
|
6960
|
+
const edge = {
|
|
6961
|
+
id: runsOnId,
|
|
6962
|
+
source: anchorId,
|
|
6963
|
+
target: runtimeNode.id,
|
|
6964
|
+
type: import_types25.EdgeType.RUNS_ON,
|
|
6965
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
6966
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6967
|
+
evidence: {
|
|
6968
|
+
file: evidenceFile,
|
|
6969
|
+
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
6970
|
+
}
|
|
6971
|
+
};
|
|
6972
|
+
graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge);
|
|
6973
|
+
edgesAdded++;
|
|
6974
|
+
}
|
|
6975
|
+
}
|
|
6976
|
+
for (const route of normalizeRoutes(config)) {
|
|
6977
|
+
const result = addResourceEdge(
|
|
6978
|
+
graph,
|
|
6979
|
+
anchorId,
|
|
6980
|
+
import_types25.EdgeType.CONNECTS_TO,
|
|
6981
|
+
"cloudflare-route",
|
|
6982
|
+
route,
|
|
6983
|
+
evidenceFile,
|
|
6984
|
+
lineContaining(raw, route)
|
|
6985
|
+
);
|
|
6986
|
+
nodesAdded += result.nodesAdded;
|
|
6987
|
+
edgesAdded += result.edgesAdded;
|
|
6988
|
+
}
|
|
6989
|
+
const bindingGroups = [
|
|
6990
|
+
{ kind: "cloudflare-kv", entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },
|
|
6991
|
+
{ kind: "cloudflare-d1", entries: config.d1_databases ?? [], nameOf: (b) => b.binding },
|
|
6992
|
+
{ kind: "cloudflare-r2", entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },
|
|
6993
|
+
{ kind: "cloudflare-durable-object", entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },
|
|
6994
|
+
{ kind: "cloudflare-queue", entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },
|
|
6995
|
+
{ kind: "cloudflare-queue", entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue }
|
|
6996
|
+
];
|
|
6997
|
+
for (const group of bindingGroups) {
|
|
6998
|
+
for (const entry of group.entries) {
|
|
6999
|
+
const name = group.nameOf(entry);
|
|
7000
|
+
if (!name) continue;
|
|
7001
|
+
const result = addResourceEdge(
|
|
7002
|
+
graph,
|
|
7003
|
+
anchorId,
|
|
7004
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7005
|
+
group.kind,
|
|
7006
|
+
name,
|
|
7007
|
+
evidenceFile,
|
|
7008
|
+
lineContaining(raw, name)
|
|
7009
|
+
);
|
|
7010
|
+
nodesAdded += result.nodesAdded;
|
|
7011
|
+
edgesAdded += result.edgesAdded;
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
for (const cron of config.triggers?.crons ?? []) {
|
|
7015
|
+
const result = addResourceEdge(
|
|
7016
|
+
graph,
|
|
7017
|
+
anchorId,
|
|
7018
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7019
|
+
"cloudflare-cron",
|
|
7020
|
+
cron,
|
|
7021
|
+
evidenceFile,
|
|
7022
|
+
lineContaining(raw, cron)
|
|
7023
|
+
);
|
|
7024
|
+
nodesAdded += result.nodesAdded;
|
|
7025
|
+
edgesAdded += result.edgesAdded;
|
|
7026
|
+
}
|
|
7027
|
+
for (const varName of Object.keys(config.vars ?? {})) {
|
|
7028
|
+
const result = addResourceEdge(
|
|
7029
|
+
graph,
|
|
7030
|
+
anchorId,
|
|
7031
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7032
|
+
"cloudflare-env-var",
|
|
7033
|
+
varName,
|
|
7034
|
+
evidenceFile,
|
|
7035
|
+
lineContaining(raw, varName)
|
|
7036
|
+
);
|
|
7037
|
+
nodesAdded += result.nodesAdded;
|
|
7038
|
+
edgesAdded += result.edgesAdded;
|
|
7039
|
+
}
|
|
7040
|
+
for (const svc of config.services ?? []) {
|
|
7041
|
+
if (!svc.service) continue;
|
|
7042
|
+
const target = workerIndex.get(svc.service);
|
|
7043
|
+
if (target && target.anchorId !== anchorId) {
|
|
7044
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId, import_types25.EdgeType.CALLS);
|
|
7045
|
+
if (!graph.hasEdge(edgeId)) {
|
|
7046
|
+
const edge = {
|
|
7047
|
+
id: edgeId,
|
|
7048
|
+
source: anchorId,
|
|
7049
|
+
target: target.anchorId,
|
|
7050
|
+
type: import_types25.EdgeType.CALLS,
|
|
7051
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7052
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7053
|
+
evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) }
|
|
7054
|
+
};
|
|
7055
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
7056
|
+
edgesAdded++;
|
|
7057
|
+
}
|
|
7058
|
+
continue;
|
|
7059
|
+
}
|
|
7060
|
+
const result = addResourceEdge(
|
|
7061
|
+
graph,
|
|
7062
|
+
anchorId,
|
|
7063
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7064
|
+
"cloudflare-service-binding",
|
|
7065
|
+
svc.service,
|
|
7066
|
+
evidenceFile,
|
|
7067
|
+
lineContaining(raw, svc.service)
|
|
7068
|
+
);
|
|
7069
|
+
nodesAdded += result.nodesAdded;
|
|
7070
|
+
edgesAdded += result.edgesAdded;
|
|
7071
|
+
}
|
|
7072
|
+
}
|
|
7073
|
+
return { nodesAdded, edgesAdded };
|
|
7074
|
+
}
|
|
7075
|
+
|
|
6829
7076
|
// src/extract/infra/index.ts
|
|
6830
7077
|
async function addInfra(graph, scanPath, services) {
|
|
6831
7078
|
const compose = await addComposeInfra(graph, scanPath, services);
|
|
6832
7079
|
const dockerfile = await addDockerfileRuntimes(graph, services, scanPath);
|
|
6833
7080
|
const terraform = await addTerraformResources(graph, scanPath);
|
|
6834
7081
|
const k8s = await addK8sResources(graph, scanPath);
|
|
7082
|
+
const cloudflare = await addCloudflareWorkers(graph, services, scanPath);
|
|
6835
7083
|
return {
|
|
6836
|
-
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,
|
|
6837
|
-
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded
|
|
7084
|
+
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded + cloudflare.nodesAdded,
|
|
7085
|
+
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded + cloudflare.edgesAdded
|
|
6838
7086
|
};
|
|
6839
7087
|
}
|
|
6840
7088
|
|
|
6841
7089
|
// src/extract/index.ts
|
|
6842
|
-
var
|
|
7090
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
6843
7091
|
|
|
6844
7092
|
// src/extract/retire.ts
|
|
6845
7093
|
init_cjs_shims();
|
|
6846
|
-
var
|
|
6847
|
-
var
|
|
6848
|
-
var
|
|
7094
|
+
var import_node_fs20 = require("fs");
|
|
7095
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
7096
|
+
var import_types26 = require("@neat.is/types");
|
|
6849
7097
|
function dropOrphanedFileNodes(graph) {
|
|
6850
7098
|
const orphans = [];
|
|
6851
7099
|
graph.forEachNode((id, attrs) => {
|
|
6852
|
-
if (attrs.type !==
|
|
7100
|
+
if (attrs.type !== import_types26.NodeType.FileNode) return;
|
|
6853
7101
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
6854
7102
|
orphans.push(id);
|
|
6855
7103
|
}
|
|
@@ -6862,14 +7110,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
6862
7110
|
const bases = [scanPath, ...serviceDirs];
|
|
6863
7111
|
graph.forEachEdge((id, attrs) => {
|
|
6864
7112
|
const edge = attrs;
|
|
6865
|
-
if (edge.provenance !==
|
|
7113
|
+
if (edge.provenance !== import_types26.Provenance.EXTRACTED) return;
|
|
6866
7114
|
const evidenceFile = edge.evidence?.file;
|
|
6867
7115
|
if (!evidenceFile) return;
|
|
6868
|
-
if (
|
|
6869
|
-
if (!(0,
|
|
7116
|
+
if (import_node_path36.default.isAbsolute(evidenceFile)) {
|
|
7117
|
+
if (!(0, import_node_fs20.existsSync)(evidenceFile)) toDrop.push(id);
|
|
6870
7118
|
return;
|
|
6871
7119
|
}
|
|
6872
|
-
const found = bases.some((base) => (0,
|
|
7120
|
+
const found = bases.some((base) => (0, import_node_fs20.existsSync)(import_node_path36.default.join(base, evidenceFile)));
|
|
6873
7121
|
if (!found) toDrop.push(id);
|
|
6874
7122
|
});
|
|
6875
7123
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -6911,7 +7159,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6911
7159
|
}
|
|
6912
7160
|
const droppedEntries = drainDroppedExtracted();
|
|
6913
7161
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
6914
|
-
const rejectedPath =
|
|
7162
|
+
const rejectedPath = import_node_path37.default.join(import_node_path37.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
6915
7163
|
try {
|
|
6916
7164
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
6917
7165
|
} catch (err) {
|
|
@@ -6945,9 +7193,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6945
7193
|
|
|
6946
7194
|
// src/persist.ts
|
|
6947
7195
|
init_cjs_shims();
|
|
6948
|
-
var
|
|
6949
|
-
var
|
|
6950
|
-
var
|
|
7196
|
+
var import_node_fs21 = require("fs");
|
|
7197
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7198
|
+
var import_types27 = require("@neat.is/types");
|
|
6951
7199
|
var SCHEMA_VERSION = 4;
|
|
6952
7200
|
function migrateV1ToV2(payload) {
|
|
6953
7201
|
const nodes = payload.graph.nodes;
|
|
@@ -6969,12 +7217,12 @@ function migrateV2ToV3(payload) {
|
|
|
6969
7217
|
for (const edge of edges) {
|
|
6970
7218
|
const attrs = edge.attributes;
|
|
6971
7219
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
6972
|
-
attrs.provenance =
|
|
7220
|
+
attrs.provenance = import_types27.Provenance.OBSERVED;
|
|
6973
7221
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
6974
7222
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
6975
7223
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
6976
7224
|
if (type && source && target) {
|
|
6977
|
-
const newId = (0,
|
|
7225
|
+
const newId = (0, import_types27.observedEdgeId)(source, target, type);
|
|
6978
7226
|
attrs.id = newId;
|
|
6979
7227
|
if (edge.key) edge.key = newId;
|
|
6980
7228
|
}
|
|
@@ -6983,7 +7231,7 @@ function migrateV2ToV3(payload) {
|
|
|
6983
7231
|
return { ...payload, schemaVersion: 3 };
|
|
6984
7232
|
}
|
|
6985
7233
|
async function ensureDir(filePath) {
|
|
6986
|
-
await
|
|
7234
|
+
await import_node_fs21.promises.mkdir(import_node_path38.default.dirname(filePath), { recursive: true });
|
|
6987
7235
|
}
|
|
6988
7236
|
async function saveGraphToDisk(graph, outPath) {
|
|
6989
7237
|
await ensureDir(outPath);
|
|
@@ -6993,13 +7241,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
6993
7241
|
graph: graph.export()
|
|
6994
7242
|
};
|
|
6995
7243
|
const tmp = `${outPath}.tmp`;
|
|
6996
|
-
await
|
|
6997
|
-
await
|
|
7244
|
+
await import_node_fs21.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
7245
|
+
await import_node_fs21.promises.rename(tmp, outPath);
|
|
6998
7246
|
}
|
|
6999
7247
|
async function loadGraphFromDisk(graph, outPath) {
|
|
7000
7248
|
let raw;
|
|
7001
7249
|
try {
|
|
7002
|
-
raw = await
|
|
7250
|
+
raw = await import_node_fs21.promises.readFile(outPath, "utf8");
|
|
7003
7251
|
} catch (err) {
|
|
7004
7252
|
if (err.code === "ENOENT") return;
|
|
7005
7253
|
throw err;
|
|
@@ -7066,19 +7314,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
7066
7314
|
init_cjs_shims();
|
|
7067
7315
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
7068
7316
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
7069
|
-
var
|
|
7317
|
+
var import_types30 = require("@neat.is/types");
|
|
7070
7318
|
|
|
7071
7319
|
// src/extend/index.ts
|
|
7072
7320
|
init_cjs_shims();
|
|
7073
|
-
var
|
|
7074
|
-
var
|
|
7321
|
+
var import_node_fs23 = require("fs");
|
|
7322
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7075
7323
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
7076
7324
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
7077
7325
|
|
|
7078
7326
|
// src/installers/package-manager.ts
|
|
7079
7327
|
init_cjs_shims();
|
|
7080
|
-
var
|
|
7081
|
-
var
|
|
7328
|
+
var import_node_fs22 = require("fs");
|
|
7329
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7082
7330
|
var import_node_child_process = require("child_process");
|
|
7083
7331
|
var LOCKFILE_PRIORITY = [
|
|
7084
7332
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -7093,29 +7341,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
7093
7341
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
7094
7342
|
async function exists2(p) {
|
|
7095
7343
|
try {
|
|
7096
|
-
await
|
|
7344
|
+
await import_node_fs22.promises.access(p);
|
|
7097
7345
|
return true;
|
|
7098
7346
|
} catch {
|
|
7099
7347
|
return false;
|
|
7100
7348
|
}
|
|
7101
7349
|
}
|
|
7102
7350
|
async function detectPackageManager(serviceDir) {
|
|
7103
|
-
let dir =
|
|
7351
|
+
let dir = import_node_path39.default.resolve(serviceDir);
|
|
7104
7352
|
const stops = /* @__PURE__ */ new Set();
|
|
7105
7353
|
for (let i = 0; i < 64; i++) {
|
|
7106
7354
|
if (stops.has(dir)) break;
|
|
7107
7355
|
stops.add(dir);
|
|
7108
7356
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
7109
|
-
const lockPath =
|
|
7357
|
+
const lockPath = import_node_path39.default.join(dir, candidate.lockfile);
|
|
7110
7358
|
if (await exists2(lockPath)) {
|
|
7111
7359
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
7112
7360
|
}
|
|
7113
7361
|
}
|
|
7114
|
-
const parent =
|
|
7362
|
+
const parent = import_node_path39.default.dirname(dir);
|
|
7115
7363
|
if (parent === dir) break;
|
|
7116
7364
|
dir = parent;
|
|
7117
7365
|
}
|
|
7118
|
-
return { pm: "npm", cwd:
|
|
7366
|
+
return { pm: "npm", cwd: import_node_path39.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
7119
7367
|
}
|
|
7120
7368
|
async function runPackageManagerInstall(cmd) {
|
|
7121
7369
|
return new Promise((resolve) => {
|
|
@@ -7157,30 +7405,30 @@ ${err.message}`
|
|
|
7157
7405
|
// src/extend/index.ts
|
|
7158
7406
|
async function fileExists2(p) {
|
|
7159
7407
|
try {
|
|
7160
|
-
await
|
|
7408
|
+
await import_node_fs23.promises.access(p);
|
|
7161
7409
|
return true;
|
|
7162
7410
|
} catch {
|
|
7163
7411
|
return false;
|
|
7164
7412
|
}
|
|
7165
7413
|
}
|
|
7166
7414
|
async function readPackageJson(scanPath) {
|
|
7167
|
-
const pkgPath =
|
|
7168
|
-
const raw = await
|
|
7415
|
+
const pkgPath = import_node_path40.default.join(scanPath, "package.json");
|
|
7416
|
+
const raw = await import_node_fs23.promises.readFile(pkgPath, "utf8");
|
|
7169
7417
|
return JSON.parse(raw);
|
|
7170
7418
|
}
|
|
7171
7419
|
async function findHookFiles(scanPath) {
|
|
7172
|
-
const entries = await
|
|
7420
|
+
const entries = await import_node_fs23.promises.readdir(scanPath);
|
|
7173
7421
|
return entries.filter(
|
|
7174
7422
|
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
7175
7423
|
).sort();
|
|
7176
7424
|
}
|
|
7177
7425
|
function extendLogPath() {
|
|
7178
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
7426
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path40.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
7179
7427
|
}
|
|
7180
7428
|
async function appendExtendLog(entry) {
|
|
7181
7429
|
const logPath = extendLogPath();
|
|
7182
|
-
await
|
|
7183
|
-
await
|
|
7430
|
+
await import_node_fs23.promises.mkdir(import_node_path40.default.dirname(logPath), { recursive: true });
|
|
7431
|
+
await import_node_fs23.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
7184
7432
|
}
|
|
7185
7433
|
function splicedContent(fileContent, snippet2) {
|
|
7186
7434
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -7238,7 +7486,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
7238
7486
|
}
|
|
7239
7487
|
async function describeProjectInstrumentation(ctx) {
|
|
7240
7488
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7241
|
-
const envNeat = await fileExists2(
|
|
7489
|
+
const envNeat = await fileExists2(import_node_path40.default.join(ctx.scanPath, ".env.neat"));
|
|
7242
7490
|
const registryInstrPackages = new Set(
|
|
7243
7491
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
7244
7492
|
);
|
|
@@ -7260,31 +7508,31 @@ async function applyExtension(ctx, args, options) {
|
|
|
7260
7508
|
);
|
|
7261
7509
|
}
|
|
7262
7510
|
for (const file of hookFiles) {
|
|
7263
|
-
const content = await
|
|
7511
|
+
const content = await import_node_fs23.promises.readFile(import_node_path40.default.join(ctx.scanPath, file), "utf8");
|
|
7264
7512
|
if (content.includes(args.registration_snippet)) {
|
|
7265
7513
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
7266
7514
|
}
|
|
7267
7515
|
}
|
|
7268
7516
|
const primaryFile = hookFiles[0];
|
|
7269
|
-
const primaryPath =
|
|
7517
|
+
const primaryPath = import_node_path40.default.join(ctx.scanPath, primaryFile);
|
|
7270
7518
|
const filesTouched = [];
|
|
7271
7519
|
const depsAdded = [];
|
|
7272
|
-
const pkgPath =
|
|
7520
|
+
const pkgPath = import_node_path40.default.join(ctx.scanPath, "package.json");
|
|
7273
7521
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7274
7522
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
7275
7523
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
7276
|
-
await
|
|
7524
|
+
await import_node_fs23.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
7277
7525
|
filesTouched.push("package.json");
|
|
7278
7526
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
7279
7527
|
}
|
|
7280
|
-
const hookContent = await
|
|
7528
|
+
const hookContent = await import_node_fs23.promises.readFile(primaryPath, "utf8");
|
|
7281
7529
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7282
7530
|
if (!patched) {
|
|
7283
7531
|
throw new Error(
|
|
7284
7532
|
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
7285
7533
|
);
|
|
7286
7534
|
}
|
|
7287
|
-
await
|
|
7535
|
+
await import_node_fs23.promises.writeFile(primaryPath, patched, "utf8");
|
|
7288
7536
|
filesTouched.push(primaryFile);
|
|
7289
7537
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
7290
7538
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -7315,7 +7563,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7315
7563
|
};
|
|
7316
7564
|
}
|
|
7317
7565
|
for (const file of hookFiles) {
|
|
7318
|
-
const content = await
|
|
7566
|
+
const content = await import_node_fs23.promises.readFile(import_node_path40.default.join(ctx.scanPath, file), "utf8");
|
|
7319
7567
|
if (content.includes(args.registration_snippet)) {
|
|
7320
7568
|
return {
|
|
7321
7569
|
library: args.library,
|
|
@@ -7337,7 +7585,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7337
7585
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
7338
7586
|
filesTouched.push("package.json");
|
|
7339
7587
|
}
|
|
7340
|
-
const hookContent = await
|
|
7588
|
+
const hookContent = await import_node_fs23.promises.readFile(import_node_path40.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
7341
7589
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7342
7590
|
if (patched) {
|
|
7343
7591
|
filesTouched.push(primaryFile);
|
|
@@ -7352,28 +7600,28 @@ async function rollbackExtension(ctx, args) {
|
|
|
7352
7600
|
if (!await fileExists2(logPath)) {
|
|
7353
7601
|
return { undone: false, message: "no apply found for library" };
|
|
7354
7602
|
}
|
|
7355
|
-
const raw = await
|
|
7603
|
+
const raw = await import_node_fs23.promises.readFile(logPath, "utf8");
|
|
7356
7604
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
7357
7605
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
7358
7606
|
if (!match) {
|
|
7359
7607
|
return { undone: false, message: "no apply found for library" };
|
|
7360
7608
|
}
|
|
7361
|
-
const pkgPath =
|
|
7609
|
+
const pkgPath = import_node_path40.default.join(ctx.scanPath, "package.json");
|
|
7362
7610
|
if (await fileExists2(pkgPath)) {
|
|
7363
7611
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7364
7612
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
7365
7613
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
7366
7614
|
pkg.dependencies = rest;
|
|
7367
|
-
await
|
|
7615
|
+
await import_node_fs23.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
7368
7616
|
}
|
|
7369
7617
|
}
|
|
7370
7618
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7371
7619
|
for (const file of hookFiles) {
|
|
7372
|
-
const filePath =
|
|
7373
|
-
const content = await
|
|
7620
|
+
const filePath = import_node_path40.default.join(ctx.scanPath, file);
|
|
7621
|
+
const content = await import_node_fs23.promises.readFile(filePath, "utf8");
|
|
7374
7622
|
if (content.includes(match.registration_snippet)) {
|
|
7375
7623
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
7376
|
-
await
|
|
7624
|
+
await import_node_fs23.promises.writeFile(filePath, filtered, "utf8");
|
|
7377
7625
|
break;
|
|
7378
7626
|
}
|
|
7379
7627
|
}
|
|
@@ -7385,7 +7633,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
7385
7633
|
|
|
7386
7634
|
// src/divergences.ts
|
|
7387
7635
|
init_cjs_shims();
|
|
7388
|
-
var
|
|
7636
|
+
var import_types28 = require("@neat.is/types");
|
|
7389
7637
|
function bucketKey(source, target, type) {
|
|
7390
7638
|
return `${type}|${source}|${target}`;
|
|
7391
7639
|
}
|
|
@@ -7393,22 +7641,22 @@ function bucketEdges(graph) {
|
|
|
7393
7641
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
7394
7642
|
graph.forEachEdge((id, attrs) => {
|
|
7395
7643
|
const e = attrs;
|
|
7396
|
-
const parsed = (0,
|
|
7644
|
+
const parsed = (0, import_types28.parseEdgeId)(id);
|
|
7397
7645
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
7398
7646
|
const key = bucketKey(e.source, e.target, e.type);
|
|
7399
7647
|
const cur = buckets2.get(key) ?? { source: e.source, target: e.target, type: e.type };
|
|
7400
7648
|
switch (provenance) {
|
|
7401
|
-
case
|
|
7649
|
+
case import_types28.Provenance.EXTRACTED:
|
|
7402
7650
|
cur.extracted = e;
|
|
7403
7651
|
break;
|
|
7404
|
-
case
|
|
7652
|
+
case import_types28.Provenance.OBSERVED:
|
|
7405
7653
|
cur.observed = e;
|
|
7406
7654
|
break;
|
|
7407
|
-
case
|
|
7655
|
+
case import_types28.Provenance.INFERRED:
|
|
7408
7656
|
cur.inferred = e;
|
|
7409
7657
|
break;
|
|
7410
7658
|
default:
|
|
7411
|
-
if (e.provenance ===
|
|
7659
|
+
if (e.provenance === import_types28.Provenance.STALE) cur.stale = e;
|
|
7412
7660
|
}
|
|
7413
7661
|
buckets2.set(key, cur);
|
|
7414
7662
|
});
|
|
@@ -7417,12 +7665,12 @@ function bucketEdges(graph) {
|
|
|
7417
7665
|
function nodeIsFrontier(graph, nodeId) {
|
|
7418
7666
|
if (!graph.hasNode(nodeId)) return false;
|
|
7419
7667
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7420
|
-
return attrs.type ===
|
|
7668
|
+
return attrs.type === import_types28.NodeType.FrontierNode;
|
|
7421
7669
|
}
|
|
7422
7670
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
7423
7671
|
if (!graph.hasNode(nodeId)) return false;
|
|
7424
7672
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7425
|
-
return attrs.type ===
|
|
7673
|
+
return attrs.type === import_types28.NodeType.WebSocketChannelNode;
|
|
7426
7674
|
}
|
|
7427
7675
|
function clampConfidence(n) {
|
|
7428
7676
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -7442,14 +7690,14 @@ function gradedConfidence(edge) {
|
|
|
7442
7690
|
return clampConfidence(confidenceForEdge(edge));
|
|
7443
7691
|
}
|
|
7444
7692
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7693
|
+
import_types28.EdgeType.CALLS,
|
|
7694
|
+
import_types28.EdgeType.CONNECTS_TO,
|
|
7695
|
+
import_types28.EdgeType.PUBLISHES_TO,
|
|
7696
|
+
import_types28.EdgeType.CONSUMES_FROM
|
|
7449
7697
|
]);
|
|
7450
7698
|
function detectMissingDivergences(graph, bucket) {
|
|
7451
7699
|
const out = [];
|
|
7452
|
-
if (bucket.type ===
|
|
7700
|
+
if (bucket.type === import_types28.EdgeType.CONTAINS) return out;
|
|
7453
7701
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
7454
7702
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
7455
7703
|
out.push({
|
|
@@ -7490,7 +7738,7 @@ function declaredHostFor(svc) {
|
|
|
7490
7738
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
7491
7739
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7492
7740
|
const e = graph.getEdgeAttributes(edgeId);
|
|
7493
|
-
if (e.type ===
|
|
7741
|
+
if (e.type === import_types28.EdgeType.CONFIGURED_BY && e.provenance === import_types28.Provenance.EXTRACTED) {
|
|
7494
7742
|
return true;
|
|
7495
7743
|
}
|
|
7496
7744
|
}
|
|
@@ -7503,10 +7751,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
7503
7751
|
const out = [];
|
|
7504
7752
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7505
7753
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
7506
|
-
if (edge.type !==
|
|
7507
|
-
if (edge.provenance !==
|
|
7754
|
+
if (edge.type !== import_types28.EdgeType.CONNECTS_TO) continue;
|
|
7755
|
+
if (edge.provenance !== import_types28.Provenance.OBSERVED) continue;
|
|
7508
7756
|
const target = graph.getNodeAttributes(edge.target);
|
|
7509
|
-
if (target.type !==
|
|
7757
|
+
if (target.type !== import_types28.NodeType.DatabaseNode) continue;
|
|
7510
7758
|
const observedHost = target.host?.trim();
|
|
7511
7759
|
if (!observedHost) continue;
|
|
7512
7760
|
if (observedHost === declaredHost) continue;
|
|
@@ -7528,10 +7776,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
7528
7776
|
const deps = svc.dependencies ?? {};
|
|
7529
7777
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7530
7778
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
7531
|
-
if (edge.type !==
|
|
7532
|
-
if (edge.provenance !==
|
|
7779
|
+
if (edge.type !== import_types28.EdgeType.CONNECTS_TO) continue;
|
|
7780
|
+
if (edge.provenance !== import_types28.Provenance.OBSERVED) continue;
|
|
7533
7781
|
const target = graph.getNodeAttributes(edge.target);
|
|
7534
|
-
if (target.type !==
|
|
7782
|
+
if (target.type !== import_types28.NodeType.DatabaseNode) continue;
|
|
7535
7783
|
for (const pair of compatPairs()) {
|
|
7536
7784
|
if (pair.engine !== target.engine) continue;
|
|
7537
7785
|
const declared = deps[pair.driver];
|
|
@@ -7590,7 +7838,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
7590
7838
|
for (const d of all) {
|
|
7591
7839
|
if (d.type !== "host-mismatch") continue;
|
|
7592
7840
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
7593
|
-
declaredHalf.add((0,
|
|
7841
|
+
declaredHalf.add((0, import_types28.databaseId)(d.extractedHost));
|
|
7594
7842
|
}
|
|
7595
7843
|
if (observedHalf.size === 0) return all;
|
|
7596
7844
|
return all.filter((d) => {
|
|
@@ -7609,7 +7857,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7609
7857
|
}
|
|
7610
7858
|
graph.forEachNode((nodeId, attrs) => {
|
|
7611
7859
|
const n = attrs;
|
|
7612
|
-
if (n.type !==
|
|
7860
|
+
if (n.type !== import_types28.NodeType.ServiceNode) return;
|
|
7613
7861
|
const svc = n;
|
|
7614
7862
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
7615
7863
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -7643,7 +7891,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7643
7891
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
7644
7892
|
return a.target.localeCompare(b.target);
|
|
7645
7893
|
});
|
|
7646
|
-
return
|
|
7894
|
+
return import_types28.DivergenceResultSchema.parse({
|
|
7647
7895
|
divergences: filtered,
|
|
7648
7896
|
totalAffected: filtered.length,
|
|
7649
7897
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7697,7 +7945,7 @@ function queryLogEntries(opts) {
|
|
|
7697
7945
|
|
|
7698
7946
|
// src/diff.ts
|
|
7699
7947
|
init_cjs_shims();
|
|
7700
|
-
var
|
|
7948
|
+
var import_node_fs24 = require("fs");
|
|
7701
7949
|
async function loadSnapshotForDiff(target) {
|
|
7702
7950
|
if (/^https?:\/\//i.test(target)) {
|
|
7703
7951
|
const res = await fetch(target);
|
|
@@ -7706,7 +7954,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
7706
7954
|
}
|
|
7707
7955
|
return await res.json();
|
|
7708
7956
|
}
|
|
7709
|
-
const raw = await
|
|
7957
|
+
const raw = await import_node_fs24.promises.readFile(target, "utf8");
|
|
7710
7958
|
return JSON.parse(raw);
|
|
7711
7959
|
}
|
|
7712
7960
|
function indexEntries(entries) {
|
|
@@ -7774,23 +8022,23 @@ function canonicalJson(value) {
|
|
|
7774
8022
|
|
|
7775
8023
|
// src/projects.ts
|
|
7776
8024
|
init_cjs_shims();
|
|
7777
|
-
var
|
|
8025
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7778
8026
|
function pathsForProject(project, baseDir) {
|
|
7779
8027
|
if (project === DEFAULT_PROJECT) {
|
|
7780
8028
|
return {
|
|
7781
|
-
snapshotPath:
|
|
7782
|
-
errorsPath:
|
|
7783
|
-
staleEventsPath:
|
|
7784
|
-
embeddingsCachePath:
|
|
7785
|
-
policyViolationsPath:
|
|
8029
|
+
snapshotPath: import_node_path41.default.join(baseDir, "graph.json"),
|
|
8030
|
+
errorsPath: import_node_path41.default.join(baseDir, "errors.ndjson"),
|
|
8031
|
+
staleEventsPath: import_node_path41.default.join(baseDir, "stale-events.ndjson"),
|
|
8032
|
+
embeddingsCachePath: import_node_path41.default.join(baseDir, "embeddings.json"),
|
|
8033
|
+
policyViolationsPath: import_node_path41.default.join(baseDir, "policy-violations.ndjson")
|
|
7786
8034
|
};
|
|
7787
8035
|
}
|
|
7788
8036
|
return {
|
|
7789
|
-
snapshotPath:
|
|
7790
|
-
errorsPath:
|
|
7791
|
-
staleEventsPath:
|
|
7792
|
-
embeddingsCachePath:
|
|
7793
|
-
policyViolationsPath:
|
|
8037
|
+
snapshotPath: import_node_path41.default.join(baseDir, `${project}.json`),
|
|
8038
|
+
errorsPath: import_node_path41.default.join(baseDir, `errors.${project}.ndjson`),
|
|
8039
|
+
staleEventsPath: import_node_path41.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
8040
|
+
embeddingsCachePath: import_node_path41.default.join(baseDir, `embeddings.${project}.json`),
|
|
8041
|
+
policyViolationsPath: import_node_path41.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
7794
8042
|
};
|
|
7795
8043
|
}
|
|
7796
8044
|
var Projects = class {
|
|
@@ -7826,25 +8074,25 @@ var Projects = class {
|
|
|
7826
8074
|
|
|
7827
8075
|
// src/registry.ts
|
|
7828
8076
|
init_cjs_shims();
|
|
7829
|
-
var
|
|
8077
|
+
var import_node_fs25 = require("fs");
|
|
7830
8078
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
7831
|
-
var
|
|
7832
|
-
var
|
|
8079
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8080
|
+
var import_types29 = require("@neat.is/types");
|
|
7833
8081
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
7834
8082
|
var LOCK_RETRY_MS = 50;
|
|
7835
8083
|
function neatHome() {
|
|
7836
8084
|
const override = process.env.NEAT_HOME;
|
|
7837
|
-
if (override && override.length > 0) return
|
|
7838
|
-
return
|
|
8085
|
+
if (override && override.length > 0) return import_node_path42.default.resolve(override);
|
|
8086
|
+
return import_node_path42.default.join(import_node_os3.default.homedir(), ".neat");
|
|
7839
8087
|
}
|
|
7840
8088
|
function registryPath() {
|
|
7841
|
-
return
|
|
8089
|
+
return import_node_path42.default.join(neatHome(), "projects.json");
|
|
7842
8090
|
}
|
|
7843
8091
|
function registryLockPath() {
|
|
7844
|
-
return
|
|
8092
|
+
return import_node_path42.default.join(neatHome(), "projects.json.lock");
|
|
7845
8093
|
}
|
|
7846
8094
|
function daemonPidPath() {
|
|
7847
|
-
return
|
|
8095
|
+
return import_node_path42.default.join(neatHome(), "neatd.pid");
|
|
7848
8096
|
}
|
|
7849
8097
|
function isPidAliveDefault(pid) {
|
|
7850
8098
|
try {
|
|
@@ -7856,7 +8104,7 @@ function isPidAliveDefault(pid) {
|
|
|
7856
8104
|
}
|
|
7857
8105
|
async function readPidFile(file) {
|
|
7858
8106
|
try {
|
|
7859
|
-
const raw = await
|
|
8107
|
+
const raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
7860
8108
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
7861
8109
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
7862
8110
|
} catch {
|
|
@@ -7904,32 +8152,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
7904
8152
|
}
|
|
7905
8153
|
}
|
|
7906
8154
|
async function normalizeProjectPath(input) {
|
|
7907
|
-
const resolved =
|
|
8155
|
+
const resolved = import_node_path42.default.resolve(input);
|
|
7908
8156
|
try {
|
|
7909
|
-
return await
|
|
8157
|
+
return await import_node_fs25.promises.realpath(resolved);
|
|
7910
8158
|
} catch {
|
|
7911
8159
|
return resolved;
|
|
7912
8160
|
}
|
|
7913
8161
|
}
|
|
7914
8162
|
async function writeAtomically(target, contents) {
|
|
7915
|
-
await
|
|
8163
|
+
await import_node_fs25.promises.mkdir(import_node_path42.default.dirname(target), { recursive: true });
|
|
7916
8164
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
7917
|
-
const fd = await
|
|
8165
|
+
const fd = await import_node_fs25.promises.open(tmp, "w");
|
|
7918
8166
|
try {
|
|
7919
8167
|
await fd.writeFile(contents, "utf8");
|
|
7920
8168
|
await fd.sync();
|
|
7921
8169
|
} finally {
|
|
7922
8170
|
await fd.close();
|
|
7923
8171
|
}
|
|
7924
|
-
await
|
|
8172
|
+
await import_node_fs25.promises.rename(tmp, target);
|
|
7925
8173
|
}
|
|
7926
8174
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
7927
8175
|
const deadline = Date.now() + timeoutMs;
|
|
7928
|
-
await
|
|
8176
|
+
await import_node_fs25.promises.mkdir(import_node_path42.default.dirname(lockPath), { recursive: true });
|
|
7929
8177
|
let probedHolder = false;
|
|
7930
8178
|
while (true) {
|
|
7931
8179
|
try {
|
|
7932
|
-
const fd = await
|
|
8180
|
+
const fd = await import_node_fs25.promises.open(lockPath, "wx");
|
|
7933
8181
|
try {
|
|
7934
8182
|
await fd.writeFile(`${process.pid}
|
|
7935
8183
|
`, "utf8");
|
|
@@ -7954,7 +8202,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
7954
8202
|
}
|
|
7955
8203
|
}
|
|
7956
8204
|
async function releaseLock(lockPath) {
|
|
7957
|
-
await
|
|
8205
|
+
await import_node_fs25.promises.unlink(lockPath).catch(() => {
|
|
7958
8206
|
});
|
|
7959
8207
|
}
|
|
7960
8208
|
async function withLock(fn) {
|
|
@@ -7970,7 +8218,7 @@ async function readRegistry() {
|
|
|
7970
8218
|
const file = registryPath();
|
|
7971
8219
|
let raw;
|
|
7972
8220
|
try {
|
|
7973
|
-
raw = await
|
|
8221
|
+
raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
7974
8222
|
} catch (err) {
|
|
7975
8223
|
if (err.code === "ENOENT") {
|
|
7976
8224
|
return { version: 1, projects: [] };
|
|
@@ -7978,10 +8226,10 @@ async function readRegistry() {
|
|
|
7978
8226
|
throw err;
|
|
7979
8227
|
}
|
|
7980
8228
|
const parsed = JSON.parse(raw);
|
|
7981
|
-
return
|
|
8229
|
+
return import_types29.RegistryFileSchema.parse(parsed);
|
|
7982
8230
|
}
|
|
7983
8231
|
async function writeRegistry(reg) {
|
|
7984
|
-
const validated =
|
|
8232
|
+
const validated = import_types29.RegistryFileSchema.parse(reg);
|
|
7985
8233
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
7986
8234
|
}
|
|
7987
8235
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -8075,7 +8323,7 @@ function pruneTtlMs() {
|
|
|
8075
8323
|
}
|
|
8076
8324
|
async function statPathStatus(p) {
|
|
8077
8325
|
try {
|
|
8078
|
-
const stat = await
|
|
8326
|
+
const stat = await import_node_fs25.promises.stat(p);
|
|
8079
8327
|
return stat.isDirectory() ? "present" : "unknown";
|
|
8080
8328
|
} catch (err) {
|
|
8081
8329
|
return err.code === "ENOENT" ? "gone" : "unknown";
|
|
@@ -8322,11 +8570,11 @@ function registerRoutes(scope, ctx) {
|
|
|
8322
8570
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
8323
8571
|
const parsed = [];
|
|
8324
8572
|
for (const c of candidates) {
|
|
8325
|
-
const r =
|
|
8573
|
+
const r = import_types30.DivergenceTypeSchema.safeParse(c);
|
|
8326
8574
|
if (!r.success) {
|
|
8327
8575
|
return reply.code(400).send({
|
|
8328
8576
|
error: `unknown divergence type "${c}"`,
|
|
8329
|
-
allowed:
|
|
8577
|
+
allowed: import_types30.DivergenceTypeSchema.options
|
|
8330
8578
|
});
|
|
8331
8579
|
}
|
|
8332
8580
|
parsed.push(r.data);
|
|
@@ -8577,7 +8825,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8577
8825
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
8578
8826
|
let violations = await log.readAll();
|
|
8579
8827
|
if (req.query.severity) {
|
|
8580
|
-
const sev =
|
|
8828
|
+
const sev = import_types30.PolicySeveritySchema.safeParse(req.query.severity);
|
|
8581
8829
|
if (!sev.success) {
|
|
8582
8830
|
return reply.code(400).send({
|
|
8583
8831
|
error: "invalid severity",
|
|
@@ -8616,7 +8864,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8616
8864
|
scope.post("/policies/check", async (req, reply) => {
|
|
8617
8865
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
8618
8866
|
if (!proj) return;
|
|
8619
|
-
const parsed =
|
|
8867
|
+
const parsed = import_types30.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
8620
8868
|
if (!parsed.success) {
|
|
8621
8869
|
return reply.code(400).send({
|
|
8622
8870
|
error: "invalid /policies/check body",
|
|
@@ -8878,8 +9126,8 @@ init_otel_grpc();
|
|
|
8878
9126
|
|
|
8879
9127
|
// src/daemon.ts
|
|
8880
9128
|
init_cjs_shims();
|
|
8881
|
-
var
|
|
8882
|
-
var
|
|
9129
|
+
var import_node_fs28 = require("fs");
|
|
9130
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
8883
9131
|
var import_node_module = require("module");
|
|
8884
9132
|
init_otel();
|
|
8885
9133
|
|
|
@@ -8897,6 +9145,10 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
8897
9145
|
unresolved++;
|
|
8898
9146
|
continue;
|
|
8899
9147
|
}
|
|
9148
|
+
if (resolved.ensureInfraNode) {
|
|
9149
|
+
const { kind, name, provider } = resolved.ensureInfraNode;
|
|
9150
|
+
ensureInfraNode(graph, kind, name, provider);
|
|
9151
|
+
}
|
|
8900
9152
|
const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV);
|
|
8901
9153
|
const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : void 0;
|
|
8902
9154
|
const sourceId = callSite ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite) : serviceNodeId;
|
|
@@ -9298,10 +9550,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
9298
9550
|
// src/connectors/supabase/map.ts
|
|
9299
9551
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
9300
9552
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
9301
|
-
function targetFromRestPath(
|
|
9302
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
9553
|
+
function targetFromRestPath(path48) {
|
|
9554
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path48);
|
|
9303
9555
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
9304
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
9556
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path48);
|
|
9305
9557
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
9306
9558
|
return null;
|
|
9307
9559
|
}
|
|
@@ -9404,19 +9656,19 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
9404
9656
|
|
|
9405
9657
|
// src/connectors/supabase/resolve.ts
|
|
9406
9658
|
init_cjs_shims();
|
|
9407
|
-
var
|
|
9659
|
+
var import_types32 = require("@neat.is/types");
|
|
9408
9660
|
function createSupabaseResolveTarget(graph, config) {
|
|
9409
9661
|
return (signal, _ctx) => {
|
|
9410
9662
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
9411
9663
|
return null;
|
|
9412
9664
|
}
|
|
9413
|
-
const subResourceId = (0,
|
|
9665
|
+
const subResourceId = (0, import_types32.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
9414
9666
|
if (graph.hasNode(subResourceId)) {
|
|
9415
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
9667
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types32.EdgeType.CALLS };
|
|
9416
9668
|
}
|
|
9417
|
-
const projectLevelId = (0,
|
|
9669
|
+
const projectLevelId = (0, import_types32.infraId)("supabase", config.nodeRef);
|
|
9418
9670
|
if (graph.hasNode(projectLevelId)) {
|
|
9419
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
9671
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types32.EdgeType.CALLS };
|
|
9420
9672
|
}
|
|
9421
9673
|
return null;
|
|
9422
9674
|
};
|
|
@@ -9474,7 +9726,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
9474
9726
|
|
|
9475
9727
|
// src/connectors/railway/index.ts
|
|
9476
9728
|
init_cjs_shims();
|
|
9477
|
-
var
|
|
9729
|
+
var import_types36 = require("@neat.is/types");
|
|
9478
9730
|
|
|
9479
9731
|
// src/connectors/railway/client.ts
|
|
9480
9732
|
init_cjs_shims();
|
|
@@ -9619,7 +9871,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
9619
9871
|
const out = [];
|
|
9620
9872
|
graph.forEachNode((_id, attrs) => {
|
|
9621
9873
|
const node = attrs;
|
|
9622
|
-
if (node.type !==
|
|
9874
|
+
if (node.type !== import_types36.NodeType.RouteNode) return;
|
|
9623
9875
|
const route = attrs;
|
|
9624
9876
|
if (route.service !== serviceName) return;
|
|
9625
9877
|
out.push({
|
|
@@ -9715,12 +9967,12 @@ function createRailwayResolveTarget(config) {
|
|
|
9715
9967
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
9716
9968
|
if (!serviceName) return null;
|
|
9717
9969
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
9718
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
9970
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types36.EdgeType.CALLS };
|
|
9719
9971
|
}
|
|
9720
9972
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
9721
9973
|
const peerName = config.serviceNameById[signal.targetName];
|
|
9722
9974
|
if (!peerName) return null;
|
|
9723
|
-
return { targetNodeId: (0,
|
|
9975
|
+
return { targetNodeId: (0, import_types36.serviceId)(peerName), serviceName, edgeType: import_types36.EdgeType.CONNECTS_TO };
|
|
9724
9976
|
}
|
|
9725
9977
|
return null;
|
|
9726
9978
|
};
|
|
@@ -9835,9 +10087,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
9835
10087
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
9836
10088
|
if (secondSep === -1) return null;
|
|
9837
10089
|
const method = rest.slice(0, secondSep);
|
|
9838
|
-
const
|
|
9839
|
-
if (!resourceName || !method || !
|
|
9840
|
-
return { resourceName, method, path:
|
|
10090
|
+
const path48 = rest.slice(secondSep + 1);
|
|
10091
|
+
if (!resourceName || !method || !path48) return null;
|
|
10092
|
+
return { resourceName, method, path: path48 };
|
|
9841
10093
|
}
|
|
9842
10094
|
function resourceNameFor(type, labels) {
|
|
9843
10095
|
if (!labels) return null;
|
|
@@ -9874,14 +10126,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
9874
10126
|
if (!req) return null;
|
|
9875
10127
|
if (!req.requestMethod) return null;
|
|
9876
10128
|
const method = req.requestMethod.toUpperCase();
|
|
9877
|
-
const
|
|
9878
|
-
if (
|
|
10129
|
+
const path48 = pathFromRequestUrl(req.requestUrl);
|
|
10130
|
+
if (path48 === null) return null;
|
|
9879
10131
|
const timestamp = entry.timestamp;
|
|
9880
10132
|
if (!timestamp) return null;
|
|
9881
10133
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
9882
10134
|
return {
|
|
9883
10135
|
targetKind: resourceType,
|
|
9884
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
10136
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path48 }),
|
|
9885
10137
|
callCount: 1,
|
|
9886
10138
|
errorCount: isError ? 1 : 0,
|
|
9887
10139
|
lastObservedIso: timestamp
|
|
@@ -9898,7 +10150,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
9898
10150
|
|
|
9899
10151
|
// src/connectors/firebase/resolve.ts
|
|
9900
10152
|
init_cjs_shims();
|
|
9901
|
-
var
|
|
10153
|
+
var import_types37 = require("@neat.is/types");
|
|
9902
10154
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
9903
10155
|
switch (resourceType) {
|
|
9904
10156
|
case "cloud_function":
|
|
@@ -9913,7 +10165,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
9913
10165
|
const entries = [];
|
|
9914
10166
|
graph.forEachNode((_id, attrs) => {
|
|
9915
10167
|
const node = attrs;
|
|
9916
|
-
if (node.type !==
|
|
10168
|
+
if (node.type !== import_types37.NodeType.RouteNode) return;
|
|
9917
10169
|
const route = attrs;
|
|
9918
10170
|
if (route.service !== serviceName) return;
|
|
9919
10171
|
entries.push({
|
|
@@ -9945,7 +10197,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
9945
10197
|
return {
|
|
9946
10198
|
targetNodeId: match.routeNodeId,
|
|
9947
10199
|
serviceName,
|
|
9948
|
-
edgeType:
|
|
10200
|
+
edgeType: import_types37.EdgeType.CALLS
|
|
9949
10201
|
};
|
|
9950
10202
|
};
|
|
9951
10203
|
}
|
|
@@ -9972,7 +10224,7 @@ init_cjs_shims();
|
|
|
9972
10224
|
|
|
9973
10225
|
// src/connectors/cloudflare/connector.ts
|
|
9974
10226
|
init_cjs_shims();
|
|
9975
|
-
var
|
|
10227
|
+
var import_types39 = require("@neat.is/types");
|
|
9976
10228
|
|
|
9977
10229
|
// src/connectors/cloudflare/client.ts
|
|
9978
10230
|
init_cjs_shims();
|
|
@@ -10022,7 +10274,14 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
|
|
|
10022
10274
|
const message = payload.errors?.map((e) => e.message).join("; ") || "unknown error";
|
|
10023
10275
|
throw new Error(`cloudflare connector: telemetry query returned an error (${message})`);
|
|
10024
10276
|
}
|
|
10025
|
-
|
|
10277
|
+
const events = payload.result?.events?.events;
|
|
10278
|
+
if (events === void 0) {
|
|
10279
|
+
console.warn(
|
|
10280
|
+
"[neat connector] cloudflare: telemetry query returned success:true but no result.events.events array \u2014 the response shape may have changed; treating as zero events this tick"
|
|
10281
|
+
);
|
|
10282
|
+
return [];
|
|
10283
|
+
}
|
|
10284
|
+
return events;
|
|
10026
10285
|
}
|
|
10027
10286
|
|
|
10028
10287
|
// src/connectors/cloudflare/map.ts
|
|
@@ -10053,6 +10312,13 @@ function parseHttpMethodFromTrigger(trigger) {
|
|
|
10053
10312
|
const method = token.toUpperCase();
|
|
10054
10313
|
return HTTP_METHODS.has(method) ? method : null;
|
|
10055
10314
|
}
|
|
10315
|
+
function parsePathFromTrigger(trigger) {
|
|
10316
|
+
const trimmed = trigger.trim();
|
|
10317
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
10318
|
+
if (spaceIdx === -1) return void 0;
|
|
10319
|
+
const rest = trimmed.slice(spaceIdx + 1).trim();
|
|
10320
|
+
return rest.length > 0 ? rest : void 0;
|
|
10321
|
+
}
|
|
10056
10322
|
var ERROR_STATUS_THRESHOLD3 = 500;
|
|
10057
10323
|
function mapEventToSignal(event) {
|
|
10058
10324
|
const metadata = event.$metadata;
|
|
@@ -10065,6 +10331,7 @@ function mapEventToSignal(event) {
|
|
|
10065
10331
|
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return null;
|
|
10066
10332
|
const statusCode = metadata?.statusCode;
|
|
10067
10333
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
10334
|
+
const path48 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
10068
10335
|
return {
|
|
10069
10336
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
10070
10337
|
targetName: scriptName,
|
|
@@ -10072,6 +10339,7 @@ function mapEventToSignal(event) {
|
|
|
10072
10339
|
errorCount: isError ? 1 : 0,
|
|
10073
10340
|
lastObservedIso: new Date(timestampMs).toISOString(),
|
|
10074
10341
|
method,
|
|
10342
|
+
...path48 ? { path: path48 } : {},
|
|
10075
10343
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
10076
10344
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
10077
10345
|
};
|
|
@@ -10106,15 +10374,63 @@ var CloudflareConnector = class {
|
|
|
10106
10374
|
return signals;
|
|
10107
10375
|
}
|
|
10108
10376
|
};
|
|
10109
|
-
function
|
|
10377
|
+
function findTaggedWorkerFileNode(graph, workerName) {
|
|
10378
|
+
let found = null;
|
|
10379
|
+
graph.forEachNode((id, attrs) => {
|
|
10380
|
+
if (found) return;
|
|
10381
|
+
const a = attrs;
|
|
10382
|
+
if (a.type === import_types39.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
10383
|
+
found = id;
|
|
10384
|
+
}
|
|
10385
|
+
});
|
|
10386
|
+
return found;
|
|
10387
|
+
}
|
|
10388
|
+
function findMatchingRouteNode(graph, serviceName, method, path48) {
|
|
10389
|
+
const normalizedPath = normalizePathTemplate(path48);
|
|
10390
|
+
let found = null;
|
|
10391
|
+
graph.forEachNode((id, attrs) => {
|
|
10392
|
+
if (found) return;
|
|
10393
|
+
const a = attrs;
|
|
10394
|
+
if (a.type !== import_types39.NodeType.RouteNode || a.service !== serviceName) return;
|
|
10395
|
+
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
10396
|
+
const routeMethod = (a.method ?? "").toUpperCase();
|
|
10397
|
+
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
10398
|
+
found = id;
|
|
10399
|
+
});
|
|
10400
|
+
return found;
|
|
10401
|
+
}
|
|
10402
|
+
function createCloudflareResolveTarget(config, graph) {
|
|
10110
10403
|
return (signal) => {
|
|
10111
10404
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
10112
|
-
const
|
|
10113
|
-
|
|
10405
|
+
const scriptName = signal.targetName;
|
|
10406
|
+
const { method, path: path48 } = signal;
|
|
10407
|
+
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
10408
|
+
if (!method || !path48) return wholeFileId;
|
|
10409
|
+
return findMatchingRouteNode(graph, serviceName, method, path48) ?? wholeFileId;
|
|
10410
|
+
};
|
|
10411
|
+
const mapping = config.workers?.[scriptName];
|
|
10412
|
+
if (mapping) {
|
|
10413
|
+
const wholeFileId = (0, import_types39.fileId)(mapping.service, mapping.entryFile);
|
|
10414
|
+
return {
|
|
10415
|
+
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
10416
|
+
serviceName: mapping.service,
|
|
10417
|
+
edgeType: import_types39.EdgeType.CALLS
|
|
10418
|
+
};
|
|
10419
|
+
}
|
|
10420
|
+
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
10421
|
+
if (taggedFileId) {
|
|
10422
|
+
const fileNode = graph.getNodeAttributes(taggedFileId);
|
|
10423
|
+
return {
|
|
10424
|
+
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
10425
|
+
serviceName: fileNode.service,
|
|
10426
|
+
edgeType: import_types39.EdgeType.CALLS
|
|
10427
|
+
};
|
|
10428
|
+
}
|
|
10114
10429
|
return {
|
|
10115
|
-
targetNodeId: (0,
|
|
10116
|
-
serviceName:
|
|
10117
|
-
edgeType:
|
|
10430
|
+
targetNodeId: (0, import_types39.infraId)("cloudflare-worker", scriptName),
|
|
10431
|
+
serviceName: scriptName,
|
|
10432
|
+
edgeType: import_types39.EdgeType.CALLS,
|
|
10433
|
+
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
10118
10434
|
};
|
|
10119
10435
|
};
|
|
10120
10436
|
}
|
|
@@ -10122,8 +10438,8 @@ function createCloudflareResolveTarget(config) {
|
|
|
10122
10438
|
// src/connectors-config.ts
|
|
10123
10439
|
init_cjs_shims();
|
|
10124
10440
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10125
|
-
var
|
|
10126
|
-
var
|
|
10441
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
10442
|
+
var import_node_fs26 = require("fs");
|
|
10127
10443
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10128
10444
|
var EnvRefUnsetError = class extends Error {
|
|
10129
10445
|
ref;
|
|
@@ -10137,17 +10453,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10137
10453
|
};
|
|
10138
10454
|
function neatHome2() {
|
|
10139
10455
|
const override = process.env.NEAT_HOME;
|
|
10140
|
-
if (override && override.length > 0) return
|
|
10141
|
-
return
|
|
10456
|
+
if (override && override.length > 0) return import_node_path45.default.resolve(override);
|
|
10457
|
+
return import_node_path45.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10142
10458
|
}
|
|
10143
10459
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10144
|
-
return
|
|
10460
|
+
return import_node_path45.default.join(home, "connectors.json");
|
|
10145
10461
|
}
|
|
10146
10462
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10147
10463
|
async function warnIfModeLooserThan0600(file) {
|
|
10148
10464
|
if (process.platform === "win32") return;
|
|
10149
10465
|
try {
|
|
10150
|
-
const stat = await
|
|
10466
|
+
const stat = await import_node_fs26.promises.stat(file);
|
|
10151
10467
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
10152
10468
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
10153
10469
|
console.warn(
|
|
@@ -10161,7 +10477,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
10161
10477
|
const file = connectorsConfigPath(home);
|
|
10162
10478
|
let raw;
|
|
10163
10479
|
try {
|
|
10164
|
-
raw = await
|
|
10480
|
+
raw = await import_node_fs26.promises.readFile(file, "utf8");
|
|
10165
10481
|
} catch (err) {
|
|
10166
10482
|
if (err.code === "ENOENT") {
|
|
10167
10483
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -10383,12 +10699,16 @@ var PROVIDER_DISPATCH = {
|
|
|
10383
10699
|
provider: "cloudflare",
|
|
10384
10700
|
primaryCredentialKey: "apiToken",
|
|
10385
10701
|
requiredCredentialFields: ["apiToken"],
|
|
10386
|
-
|
|
10387
|
-
|
|
10702
|
+
// `workers` dropped as a required field (ADR-133) — the mapping is now
|
|
10703
|
+
// derived from the extracted graph's platform tag; an `options.workers`
|
|
10704
|
+
// entry still works as an explicit override
|
|
10705
|
+
// (CloudflareConnectorConfig.workers).
|
|
10706
|
+
requiredOptionFields: ["accountId"],
|
|
10707
|
+
build(graph, options) {
|
|
10388
10708
|
const config = options;
|
|
10389
10709
|
return {
|
|
10390
10710
|
connector: new CloudflareConnector(config),
|
|
10391
|
-
resolveTarget: createCloudflareResolveTarget(config)
|
|
10711
|
+
resolveTarget: createCloudflareResolveTarget(config, graph)
|
|
10392
10712
|
};
|
|
10393
10713
|
},
|
|
10394
10714
|
// GET /user/tokens/verify — Cloudflare's own purpose-built "is this API
|
|
@@ -10485,8 +10805,8 @@ init_auth();
|
|
|
10485
10805
|
|
|
10486
10806
|
// src/unrouted.ts
|
|
10487
10807
|
init_cjs_shims();
|
|
10488
|
-
var
|
|
10489
|
-
var
|
|
10808
|
+
var import_node_fs27 = require("fs");
|
|
10809
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
10490
10810
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
10491
10811
|
return {
|
|
10492
10812
|
timestamp: now.toISOString(),
|
|
@@ -10496,34 +10816,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
10496
10816
|
};
|
|
10497
10817
|
}
|
|
10498
10818
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
10499
|
-
const target =
|
|
10500
|
-
await
|
|
10501
|
-
await
|
|
10819
|
+
const target = import_node_path46.default.join(neatHome3, "errors.ndjson");
|
|
10820
|
+
await import_node_fs27.promises.mkdir(neatHome3, { recursive: true });
|
|
10821
|
+
await import_node_fs27.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
10502
10822
|
}
|
|
10503
10823
|
function unroutedErrorsPath(neatHome3) {
|
|
10504
|
-
return
|
|
10824
|
+
return import_node_path46.default.join(neatHome3, "errors.ndjson");
|
|
10505
10825
|
}
|
|
10506
10826
|
|
|
10507
10827
|
// src/daemon.ts
|
|
10508
|
-
var
|
|
10828
|
+
var import_types42 = require("@neat.is/types");
|
|
10509
10829
|
function daemonJsonPath(scanPath) {
|
|
10510
|
-
return
|
|
10830
|
+
return import_node_path47.default.join(scanPath, "neat-out", "daemon.json");
|
|
10511
10831
|
}
|
|
10512
10832
|
function daemonsDiscoveryDir(home) {
|
|
10513
10833
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
10514
|
-
return
|
|
10834
|
+
return import_node_path47.default.join(base, "daemons");
|
|
10515
10835
|
}
|
|
10516
10836
|
function daemonDiscoveryPath(project, home) {
|
|
10517
|
-
return
|
|
10837
|
+
return import_node_path47.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
10518
10838
|
}
|
|
10519
10839
|
function sanitizeDiscoveryName(project) {
|
|
10520
10840
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
10521
10841
|
}
|
|
10522
10842
|
function neatHomeFromEnv() {
|
|
10523
10843
|
const env = process.env.NEAT_HOME;
|
|
10524
|
-
if (env && env.length > 0) return
|
|
10844
|
+
if (env && env.length > 0) return import_node_path47.default.resolve(env);
|
|
10525
10845
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10526
|
-
return
|
|
10846
|
+
return import_node_path47.default.join(home, ".neat");
|
|
10527
10847
|
}
|
|
10528
10848
|
function resolveNeatVersion() {
|
|
10529
10849
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -10555,7 +10875,7 @@ async function clearDaemonRecord(record, home) {
|
|
|
10555
10875
|
} catch {
|
|
10556
10876
|
}
|
|
10557
10877
|
try {
|
|
10558
|
-
await
|
|
10878
|
+
await import_node_fs28.promises.unlink(daemonDiscoveryPath(record.project, home));
|
|
10559
10879
|
} catch {
|
|
10560
10880
|
}
|
|
10561
10881
|
}
|
|
@@ -10578,11 +10898,11 @@ function teardownSlot(slot) {
|
|
|
10578
10898
|
}
|
|
10579
10899
|
}
|
|
10580
10900
|
function neatHomeFor(opts) {
|
|
10581
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
10901
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path47.default.resolve(opts.neatHome);
|
|
10582
10902
|
const env = process.env.NEAT_HOME;
|
|
10583
|
-
if (env && env.length > 0) return
|
|
10903
|
+
if (env && env.length > 0) return import_node_path47.default.resolve(env);
|
|
10584
10904
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10585
|
-
return
|
|
10905
|
+
return import_node_path47.default.join(home, ".neat");
|
|
10586
10906
|
}
|
|
10587
10907
|
function routeSpanToProject(serviceName, projects) {
|
|
10588
10908
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -10626,13 +10946,13 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
10626
10946
|
if (!serviceName) return true;
|
|
10627
10947
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
10628
10948
|
return graph.someNode(
|
|
10629
|
-
(_id, attrs) => attrs.type ===
|
|
10949
|
+
(_id, attrs) => attrs.type === import_types42.NodeType.ServiceNode && attrs.name === serviceName
|
|
10630
10950
|
);
|
|
10631
10951
|
}
|
|
10632
10952
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
10633
|
-
const paths = pathsForProject(entry.name,
|
|
10953
|
+
const paths = pathsForProject(entry.name, import_node_path47.default.join(entry.path, "neat-out"));
|
|
10634
10954
|
try {
|
|
10635
|
-
const stat = await
|
|
10955
|
+
const stat = await import_node_fs28.promises.stat(entry.path);
|
|
10636
10956
|
if (!stat.isDirectory()) {
|
|
10637
10957
|
throw new Error(`registered path ${entry.path} is not a directory`);
|
|
10638
10958
|
}
|
|
@@ -10757,7 +11077,7 @@ async function startDaemon(opts = {}) {
|
|
|
10757
11077
|
const projectArg = typeof opts.project === "string" && opts.project.length > 0 ? opts.project : process.env.NEAT_PROJECT && process.env.NEAT_PROJECT.length > 0 ? process.env.NEAT_PROJECT : null;
|
|
10758
11078
|
const projectPathArg = opts.projectPath && opts.projectPath.length > 0 ? opts.projectPath : process.env.NEAT_PROJECT_PATH && process.env.NEAT_PROJECT_PATH.length > 0 ? process.env.NEAT_PROJECT_PATH : null;
|
|
10759
11079
|
const singleProject = projectArg;
|
|
10760
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
11080
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path47.default.resolve(projectPathArg) : null;
|
|
10761
11081
|
if (singleProject && !singleProjectPath) {
|
|
10762
11082
|
throw new Error(
|
|
10763
11083
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -10765,14 +11085,14 @@ async function startDaemon(opts = {}) {
|
|
|
10765
11085
|
}
|
|
10766
11086
|
if (!singleProject) {
|
|
10767
11087
|
try {
|
|
10768
|
-
await
|
|
11088
|
+
await import_node_fs28.promises.access(regPath);
|
|
10769
11089
|
} catch {
|
|
10770
11090
|
throw new Error(
|
|
10771
11091
|
`neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
|
|
10772
11092
|
);
|
|
10773
11093
|
}
|
|
10774
11094
|
}
|
|
10775
|
-
const pidPath =
|
|
11095
|
+
const pidPath = import_node_path47.default.join(home, "neatd.pid");
|
|
10776
11096
|
await writeAtomically(pidPath, `${process.pid}
|
|
10777
11097
|
`);
|
|
10778
11098
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -10966,7 +11286,7 @@ async function startDaemon(opts = {}) {
|
|
|
10966
11286
|
}
|
|
10967
11287
|
if (restApp) await restApp.close().catch(() => {
|
|
10968
11288
|
});
|
|
10969
|
-
await
|
|
11289
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
10970
11290
|
});
|
|
10971
11291
|
throw new Error(
|
|
10972
11292
|
`neatd: failed to bind REST on port ${restPort} \u2014 ${err.message}`
|
|
@@ -11092,7 +11412,7 @@ async function startDaemon(opts = {}) {
|
|
|
11092
11412
|
});
|
|
11093
11413
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
11094
11414
|
});
|
|
11095
|
-
await
|
|
11415
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
11096
11416
|
});
|
|
11097
11417
|
throw new Error(
|
|
11098
11418
|
`neatd: failed to bind OTLP on port ${otlpPort} \u2014 ${err.message}`
|
|
@@ -11127,7 +11447,7 @@ async function startDaemon(opts = {}) {
|
|
|
11127
11447
|
});
|
|
11128
11448
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
11129
11449
|
});
|
|
11130
|
-
await
|
|
11450
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
11131
11451
|
});
|
|
11132
11452
|
throw new Error(
|
|
11133
11453
|
`neatd: failed to write daemon.json for "${singleProject}" \u2014 ${err.message}`
|
|
@@ -11174,9 +11494,9 @@ async function startDaemon(opts = {}) {
|
|
|
11174
11494
|
let registryWatcher = null;
|
|
11175
11495
|
let reloadTimer = null;
|
|
11176
11496
|
if (!singleProject) try {
|
|
11177
|
-
const regDir =
|
|
11178
|
-
const regBase =
|
|
11179
|
-
registryWatcher = (0,
|
|
11497
|
+
const regDir = import_node_path47.default.dirname(regPath);
|
|
11498
|
+
const regBase = import_node_path47.default.basename(regPath);
|
|
11499
|
+
registryWatcher = (0, import_node_fs28.watch)(regDir, (_eventType, filename) => {
|
|
11180
11500
|
if (filename !== null && filename !== regBase) return;
|
|
11181
11501
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
11182
11502
|
reloadTimer = setTimeout(() => {
|
|
@@ -11225,7 +11545,7 @@ async function startDaemon(opts = {}) {
|
|
|
11225
11545
|
if (daemonRecord) {
|
|
11226
11546
|
await clearDaemonRecord(daemonRecord, home);
|
|
11227
11547
|
}
|
|
11228
|
-
await
|
|
11548
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
11229
11549
|
});
|
|
11230
11550
|
};
|
|
11231
11551
|
return {
|