@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/neatd.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req2, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path50 = (req2.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path50) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path50)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -194,8 +194,8 @@ function reshapeGrpcRequest(req2) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
function resolveProtoRoot() {
|
|
197
|
-
const here =
|
|
198
|
-
return
|
|
197
|
+
const here = import_node_path43.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path43.default.resolve(here, "..", "proto");
|
|
199
199
|
}
|
|
200
200
|
function loadTraceService() {
|
|
201
201
|
const protoRoot = resolveProtoRoot();
|
|
@@ -263,13 +263,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
263
263
|
})
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
|
-
var import_node_url,
|
|
266
|
+
var import_node_url, import_node_path43, import_node_crypto2, grpc, protoLoader;
|
|
267
267
|
var init_otel_grpc = __esm({
|
|
268
268
|
"src/otel-grpc.ts"() {
|
|
269
269
|
"use strict";
|
|
270
270
|
init_cjs_shims();
|
|
271
271
|
import_node_url = require("url");
|
|
272
|
-
|
|
272
|
+
import_node_path43 = __toESM(require("path"), 1);
|
|
273
273
|
import_node_crypto2 = require("crypto");
|
|
274
274
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
275
275
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -362,8 +362,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
362
362
|
const v = attrs[key];
|
|
363
363
|
if (typeof v === "string" && v.length > 0) {
|
|
364
364
|
const q = v.indexOf("?");
|
|
365
|
-
const
|
|
366
|
-
if (
|
|
365
|
+
const path50 = q === -1 ? v : v.slice(0, q);
|
|
366
|
+
if (path50.length > 0) return path50;
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
return void 0;
|
|
@@ -417,10 +417,10 @@ function parseOtlpRequest(body) {
|
|
|
417
417
|
return out;
|
|
418
418
|
}
|
|
419
419
|
function loadProtoRoot() {
|
|
420
|
-
const here =
|
|
421
|
-
const protoRoot =
|
|
420
|
+
const here = import_node_path44.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
421
|
+
const protoRoot = import_node_path44.default.resolve(here, "..", "proto");
|
|
422
422
|
const root = new import_protobufjs.default.Root();
|
|
423
|
-
root.resolvePath = (_origin, target) =>
|
|
423
|
+
root.resolvePath = (_origin, target) => import_node_path44.default.resolve(protoRoot, target);
|
|
424
424
|
root.loadSync(
|
|
425
425
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
426
426
|
{ keepCase: true }
|
|
@@ -648,12 +648,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
648
648
|
}
|
|
649
649
|
}
|
|
650
650
|
}
|
|
651
|
-
var
|
|
651
|
+
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;
|
|
652
652
|
var init_otel = __esm({
|
|
653
653
|
"src/otel.ts"() {
|
|
654
654
|
"use strict";
|
|
655
655
|
init_cjs_shims();
|
|
656
|
-
|
|
656
|
+
import_node_path44 = __toESM(require("path"), 1);
|
|
657
657
|
import_node_url2 = require("url");
|
|
658
658
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
659
659
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -676,14 +676,14 @@ __export(neatd_exports, {
|
|
|
676
676
|
});
|
|
677
677
|
module.exports = __toCommonJS(neatd_exports);
|
|
678
678
|
init_cjs_shims();
|
|
679
|
-
var
|
|
680
|
-
var
|
|
679
|
+
var import_node_fs30 = require("fs");
|
|
680
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
681
681
|
var import_node_module2 = require("module");
|
|
682
682
|
|
|
683
683
|
// src/daemon.ts
|
|
684
684
|
init_cjs_shims();
|
|
685
|
-
var
|
|
686
|
-
var
|
|
685
|
+
var import_node_fs28 = require("fs");
|
|
686
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
687
687
|
var import_node_module = require("module");
|
|
688
688
|
|
|
689
689
|
// src/graph.ts
|
|
@@ -1213,19 +1213,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1213
1213
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1214
1214
|
let best = { path: [start], edges: [] };
|
|
1215
1215
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1216
|
-
function step(node,
|
|
1217
|
-
if (
|
|
1218
|
-
best = { path: [...
|
|
1216
|
+
function step(node, path50, edges) {
|
|
1217
|
+
if (path50.length > best.path.length) {
|
|
1218
|
+
best = { path: [...path50], edges: [...edges] };
|
|
1219
1219
|
}
|
|
1220
|
-
if (
|
|
1220
|
+
if (path50.length - 1 >= maxDepth) return;
|
|
1221
1221
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1222
1222
|
for (const [srcId, edge] of incoming) {
|
|
1223
1223
|
if (visited.has(srcId)) continue;
|
|
1224
1224
|
visited.add(srcId);
|
|
1225
|
-
|
|
1225
|
+
path50.push(srcId);
|
|
1226
1226
|
edges.push(edge);
|
|
1227
|
-
step(srcId,
|
|
1228
|
-
|
|
1227
|
+
step(srcId, path50, edges);
|
|
1228
|
+
path50.pop();
|
|
1229
1229
|
edges.pop();
|
|
1230
1230
|
visited.delete(srcId);
|
|
1231
1231
|
}
|
|
@@ -1419,26 +1419,26 @@ function dominantFailingCall(graph, serviceId5, visited) {
|
|
|
1419
1419
|
return best;
|
|
1420
1420
|
}
|
|
1421
1421
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1422
|
-
const
|
|
1422
|
+
const path50 = [originServiceId];
|
|
1423
1423
|
const edges = [];
|
|
1424
1424
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1425
1425
|
let current = originServiceId;
|
|
1426
1426
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1427
1427
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1428
1428
|
if (!hop) break;
|
|
1429
|
-
|
|
1429
|
+
path50.push(hop.nextService);
|
|
1430
1430
|
edges.push(hop.edge);
|
|
1431
1431
|
visited.add(hop.nextService);
|
|
1432
1432
|
current = hop.nextService;
|
|
1433
1433
|
}
|
|
1434
1434
|
if (edges.length === 0) return null;
|
|
1435
|
-
return { path:
|
|
1435
|
+
return { path: path50, edges, culprit: current };
|
|
1436
1436
|
}
|
|
1437
1437
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1438
1438
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1439
1439
|
if (!chain) return null;
|
|
1440
1440
|
const culprit = chain.culprit;
|
|
1441
|
-
const
|
|
1441
|
+
const path50 = [...chain.path];
|
|
1442
1442
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1443
1443
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1444
1444
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1446,14 +1446,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1446
1446
|
if (loc) {
|
|
1447
1447
|
let rootCauseNode = culprit;
|
|
1448
1448
|
if (loc.fileNode) {
|
|
1449
|
-
|
|
1449
|
+
path50.push(loc.fileNode);
|
|
1450
1450
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1451
1451
|
rootCauseNode = loc.fileNode;
|
|
1452
1452
|
}
|
|
1453
1453
|
return import_types.RootCauseResultSchema.parse({
|
|
1454
1454
|
rootCauseNode,
|
|
1455
1455
|
rootCauseReason: loc.rootCauseReason,
|
|
1456
|
-
traversalPath:
|
|
1456
|
+
traversalPath: path50,
|
|
1457
1457
|
edgeProvenances,
|
|
1458
1458
|
confidence,
|
|
1459
1459
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1465,7 +1465,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1465
1465
|
return import_types.RootCauseResultSchema.parse({
|
|
1466
1466
|
rootCauseNode: culprit,
|
|
1467
1467
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1468
|
-
traversalPath:
|
|
1468
|
+
traversalPath: path50,
|
|
1469
1469
|
edgeProvenances,
|
|
1470
1470
|
confidence,
|
|
1471
1471
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2542,6 +2542,19 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
2542
2542
|
graph.addNode(id, node);
|
|
2543
2543
|
return id;
|
|
2544
2544
|
}
|
|
2545
|
+
function ensureInfraNode(graph, kind, name, provider) {
|
|
2546
|
+
const id = (0, import_types3.infraId)(kind, name);
|
|
2547
|
+
if (graph.hasNode(id)) return id;
|
|
2548
|
+
const node = {
|
|
2549
|
+
id,
|
|
2550
|
+
type: import_types3.NodeType.InfraNode,
|
|
2551
|
+
name,
|
|
2552
|
+
provider,
|
|
2553
|
+
kind
|
|
2554
|
+
};
|
|
2555
|
+
graph.addNode(id, node);
|
|
2556
|
+
return id;
|
|
2557
|
+
}
|
|
2545
2558
|
function ensureDatabaseNode(graph, host, engine) {
|
|
2546
2559
|
const id = (0, import_types3.databaseId)(host);
|
|
2547
2560
|
if (graph.hasNode(id)) return id;
|
|
@@ -5297,10 +5310,10 @@ function fastifyRouteMethods(objNode) {
|
|
|
5297
5310
|
}
|
|
5298
5311
|
return [];
|
|
5299
5312
|
}
|
|
5300
|
-
function serverRoutesFromSource(source, parser, hasExpress, hasFastify) {
|
|
5313
|
+
function serverRoutesFromSource(source, parser, hasExpress, hasFastify, hasHono = false) {
|
|
5301
5314
|
const tree = parseSource2(parser, source);
|
|
5302
5315
|
const out = [];
|
|
5303
|
-
const framework = hasExpress ? "express" : "fastify";
|
|
5316
|
+
const framework = hasExpress ? "express" : hasFastify ? "fastify" : hasHono ? "hono" : "unknown";
|
|
5304
5317
|
walk(tree.rootNode, (node) => {
|
|
5305
5318
|
if (node.type !== "call_expression") return;
|
|
5306
5319
|
const fn = node.childForFieldName("function");
|
|
@@ -5450,8 +5463,9 @@ async function addRoutes(graph, services) {
|
|
|
5450
5463
|
};
|
|
5451
5464
|
const hasExpress = deps["express"] !== void 0;
|
|
5452
5465
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5466
|
+
const hasHono = deps["hono"] !== void 0;
|
|
5453
5467
|
const hasNext = deps["next"] !== void 0;
|
|
5454
|
-
if (!hasExpress && !hasFastify && !hasNext) continue;
|
|
5468
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext) continue;
|
|
5455
5469
|
const files = await loadSourceFiles(service.dir);
|
|
5456
5470
|
for (const file of files) {
|
|
5457
5471
|
if (isTestPath(file.path)) continue;
|
|
@@ -5461,8 +5475,8 @@ async function addRoutes(graph, services) {
|
|
|
5461
5475
|
try {
|
|
5462
5476
|
if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5463
5477
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5464
|
-
} else if (hasExpress || hasFastify) {
|
|
5465
|
-
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify);
|
|
5478
|
+
} else if (hasExpress || hasFastify || hasHono) {
|
|
5479
|
+
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
5466
5480
|
} else {
|
|
5467
5481
|
routes = [];
|
|
5468
5482
|
}
|
|
@@ -6786,30 +6800,264 @@ async function addK8sResources(graph, scanPath) {
|
|
|
6786
6800
|
return { nodesAdded, edgesAdded: 0 };
|
|
6787
6801
|
}
|
|
6788
6802
|
|
|
6803
|
+
// src/extract/infra/cloudflare.ts
|
|
6804
|
+
init_cjs_shims();
|
|
6805
|
+
var import_node_fs19 = require("fs");
|
|
6806
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
6807
|
+
var import_smol_toml2 = require("smol-toml");
|
|
6808
|
+
var import_types25 = require("@neat.is/types");
|
|
6809
|
+
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
6810
|
+
async function readWranglerConfig(dir) {
|
|
6811
|
+
for (const filename of WRANGLER_FILENAMES) {
|
|
6812
|
+
const abs = import_node_path35.default.join(dir, filename);
|
|
6813
|
+
if (!await exists(abs)) continue;
|
|
6814
|
+
const raw = await import_node_fs19.promises.readFile(abs, "utf8");
|
|
6815
|
+
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
6816
|
+
return { config, relFile: filename, raw };
|
|
6817
|
+
}
|
|
6818
|
+
return null;
|
|
6819
|
+
}
|
|
6820
|
+
function lineContaining(raw, needle) {
|
|
6821
|
+
if (!needle) return void 0;
|
|
6822
|
+
const idx = raw.indexOf(needle);
|
|
6823
|
+
if (idx === -1) return void 0;
|
|
6824
|
+
let line = 1;
|
|
6825
|
+
for (let i = 0; i < idx; i++) if (raw[i] === "\n") line++;
|
|
6826
|
+
return line;
|
|
6827
|
+
}
|
|
6828
|
+
function normalizeRoutes(config) {
|
|
6829
|
+
const out = [];
|
|
6830
|
+
const pushOne = (r) => {
|
|
6831
|
+
if (typeof r === "string") out.push(r);
|
|
6832
|
+
else if (r && typeof r === "object" && typeof r.pattern === "string") {
|
|
6833
|
+
out.push(r.pattern);
|
|
6834
|
+
}
|
|
6835
|
+
};
|
|
6836
|
+
if (Array.isArray(config.routes)) config.routes.forEach(pushOne);
|
|
6837
|
+
else if (config.route) pushOne(config.route);
|
|
6838
|
+
return out;
|
|
6839
|
+
}
|
|
6840
|
+
function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, line) {
|
|
6841
|
+
let nodesAdded = 0;
|
|
6842
|
+
let edgesAdded = 0;
|
|
6843
|
+
const node = makeInfraNode(kind, name, "cloudflare");
|
|
6844
|
+
if (!graph.hasNode(node.id)) {
|
|
6845
|
+
graph.addNode(node.id, node);
|
|
6846
|
+
nodesAdded++;
|
|
6847
|
+
}
|
|
6848
|
+
if (node.id === anchorId) return { nodesAdded, edgesAdded };
|
|
6849
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, node.id, edgeType);
|
|
6850
|
+
if (!graph.hasEdge(edgeId)) {
|
|
6851
|
+
const edge = {
|
|
6852
|
+
id: edgeId,
|
|
6853
|
+
source: anchorId,
|
|
6854
|
+
target: node.id,
|
|
6855
|
+
type: edgeType,
|
|
6856
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
6857
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6858
|
+
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
6859
|
+
};
|
|
6860
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
6861
|
+
edgesAdded++;
|
|
6862
|
+
}
|
|
6863
|
+
return { nodesAdded, edgesAdded };
|
|
6864
|
+
}
|
|
6865
|
+
async function addCloudflareWorkers(graph, services, scanPath) {
|
|
6866
|
+
let nodesAdded = 0;
|
|
6867
|
+
let edgesAdded = 0;
|
|
6868
|
+
const discovered = [];
|
|
6869
|
+
const workerIndex = /* @__PURE__ */ new Map();
|
|
6870
|
+
for (const service of services) {
|
|
6871
|
+
let read;
|
|
6872
|
+
try {
|
|
6873
|
+
read = await readWranglerConfig(service.dir);
|
|
6874
|
+
} catch (err) {
|
|
6875
|
+
recordExtractionError("infra cloudflare", import_node_path35.default.relative(scanPath, service.dir), err);
|
|
6876
|
+
continue;
|
|
6877
|
+
}
|
|
6878
|
+
if (!read || !read.config.name) continue;
|
|
6879
|
+
const evidenceFile = toPosix2(import_node_path35.default.relative(scanPath, import_node_path35.default.join(service.dir, read.relFile)));
|
|
6880
|
+
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
6881
|
+
}
|
|
6882
|
+
for (const worker of discovered) {
|
|
6883
|
+
const { service, config } = worker;
|
|
6884
|
+
const serviceNode = graph.getNodeAttributes(service.node.id);
|
|
6885
|
+
if (serviceNode.platform !== "cloudflare") {
|
|
6886
|
+
const updated = { ...serviceNode, platform: "cloudflare" };
|
|
6887
|
+
graph.replaceNodeAttributes(service.node.id, updated);
|
|
6888
|
+
}
|
|
6889
|
+
let anchorId = service.node.id;
|
|
6890
|
+
if (config.main) {
|
|
6891
|
+
const entryRelPath = toPosix2(import_node_path35.default.normalize(config.main));
|
|
6892
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
6893
|
+
graph,
|
|
6894
|
+
service.pkg.name,
|
|
6895
|
+
service.node.id,
|
|
6896
|
+
entryRelPath
|
|
6897
|
+
);
|
|
6898
|
+
nodesAdded += fn;
|
|
6899
|
+
edgesAdded += fe;
|
|
6900
|
+
const fileNode = graph.getNodeAttributes(fileNodeId);
|
|
6901
|
+
if (fileNode.platform !== "cloudflare" || fileNode.platformName !== config.name) {
|
|
6902
|
+
const updated = { ...fileNode, platform: "cloudflare", platformName: config.name };
|
|
6903
|
+
graph.replaceNodeAttributes(fileNodeId, updated);
|
|
6904
|
+
}
|
|
6905
|
+
anchorId = fileNodeId;
|
|
6906
|
+
}
|
|
6907
|
+
workerIndex.set(config.name, { anchorId });
|
|
6908
|
+
}
|
|
6909
|
+
for (const worker of discovered) {
|
|
6910
|
+
const { config, evidenceFile, raw } = worker;
|
|
6911
|
+
const anchorId = workerIndex.get(config.name).anchorId;
|
|
6912
|
+
const runtimeNode = makeInfraNode("workerd", "cloudflare", "cloudflare");
|
|
6913
|
+
if (!graph.hasNode(runtimeNode.id)) {
|
|
6914
|
+
graph.addNode(runtimeNode.id, runtimeNode);
|
|
6915
|
+
nodesAdded++;
|
|
6916
|
+
}
|
|
6917
|
+
if (runtimeNode.id !== anchorId) {
|
|
6918
|
+
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id, import_types25.EdgeType.RUNS_ON);
|
|
6919
|
+
if (!graph.hasEdge(runsOnId)) {
|
|
6920
|
+
const edge = {
|
|
6921
|
+
id: runsOnId,
|
|
6922
|
+
source: anchorId,
|
|
6923
|
+
target: runtimeNode.id,
|
|
6924
|
+
type: import_types25.EdgeType.RUNS_ON,
|
|
6925
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
6926
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6927
|
+
evidence: {
|
|
6928
|
+
file: evidenceFile,
|
|
6929
|
+
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
6930
|
+
}
|
|
6931
|
+
};
|
|
6932
|
+
graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge);
|
|
6933
|
+
edgesAdded++;
|
|
6934
|
+
}
|
|
6935
|
+
}
|
|
6936
|
+
for (const route of normalizeRoutes(config)) {
|
|
6937
|
+
const result = addResourceEdge(
|
|
6938
|
+
graph,
|
|
6939
|
+
anchorId,
|
|
6940
|
+
import_types25.EdgeType.CONNECTS_TO,
|
|
6941
|
+
"cloudflare-route",
|
|
6942
|
+
route,
|
|
6943
|
+
evidenceFile,
|
|
6944
|
+
lineContaining(raw, route)
|
|
6945
|
+
);
|
|
6946
|
+
nodesAdded += result.nodesAdded;
|
|
6947
|
+
edgesAdded += result.edgesAdded;
|
|
6948
|
+
}
|
|
6949
|
+
const bindingGroups = [
|
|
6950
|
+
{ kind: "cloudflare-kv", entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },
|
|
6951
|
+
{ kind: "cloudflare-d1", entries: config.d1_databases ?? [], nameOf: (b) => b.binding },
|
|
6952
|
+
{ kind: "cloudflare-r2", entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },
|
|
6953
|
+
{ kind: "cloudflare-durable-object", entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },
|
|
6954
|
+
{ kind: "cloudflare-queue", entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },
|
|
6955
|
+
{ kind: "cloudflare-queue", entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue }
|
|
6956
|
+
];
|
|
6957
|
+
for (const group of bindingGroups) {
|
|
6958
|
+
for (const entry2 of group.entries) {
|
|
6959
|
+
const name = group.nameOf(entry2);
|
|
6960
|
+
if (!name) continue;
|
|
6961
|
+
const result = addResourceEdge(
|
|
6962
|
+
graph,
|
|
6963
|
+
anchorId,
|
|
6964
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
6965
|
+
group.kind,
|
|
6966
|
+
name,
|
|
6967
|
+
evidenceFile,
|
|
6968
|
+
lineContaining(raw, name)
|
|
6969
|
+
);
|
|
6970
|
+
nodesAdded += result.nodesAdded;
|
|
6971
|
+
edgesAdded += result.edgesAdded;
|
|
6972
|
+
}
|
|
6973
|
+
}
|
|
6974
|
+
for (const cron of config.triggers?.crons ?? []) {
|
|
6975
|
+
const result = addResourceEdge(
|
|
6976
|
+
graph,
|
|
6977
|
+
anchorId,
|
|
6978
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
6979
|
+
"cloudflare-cron",
|
|
6980
|
+
cron,
|
|
6981
|
+
evidenceFile,
|
|
6982
|
+
lineContaining(raw, cron)
|
|
6983
|
+
);
|
|
6984
|
+
nodesAdded += result.nodesAdded;
|
|
6985
|
+
edgesAdded += result.edgesAdded;
|
|
6986
|
+
}
|
|
6987
|
+
for (const varName of Object.keys(config.vars ?? {})) {
|
|
6988
|
+
const result = addResourceEdge(
|
|
6989
|
+
graph,
|
|
6990
|
+
anchorId,
|
|
6991
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
6992
|
+
"cloudflare-env-var",
|
|
6993
|
+
varName,
|
|
6994
|
+
evidenceFile,
|
|
6995
|
+
lineContaining(raw, varName)
|
|
6996
|
+
);
|
|
6997
|
+
nodesAdded += result.nodesAdded;
|
|
6998
|
+
edgesAdded += result.edgesAdded;
|
|
6999
|
+
}
|
|
7000
|
+
for (const svc of config.services ?? []) {
|
|
7001
|
+
if (!svc.service) continue;
|
|
7002
|
+
const target = workerIndex.get(svc.service);
|
|
7003
|
+
if (target && target.anchorId !== anchorId) {
|
|
7004
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId, import_types25.EdgeType.CALLS);
|
|
7005
|
+
if (!graph.hasEdge(edgeId)) {
|
|
7006
|
+
const edge = {
|
|
7007
|
+
id: edgeId,
|
|
7008
|
+
source: anchorId,
|
|
7009
|
+
target: target.anchorId,
|
|
7010
|
+
type: import_types25.EdgeType.CALLS,
|
|
7011
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7012
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7013
|
+
evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) }
|
|
7014
|
+
};
|
|
7015
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
7016
|
+
edgesAdded++;
|
|
7017
|
+
}
|
|
7018
|
+
continue;
|
|
7019
|
+
}
|
|
7020
|
+
const result = addResourceEdge(
|
|
7021
|
+
graph,
|
|
7022
|
+
anchorId,
|
|
7023
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7024
|
+
"cloudflare-service-binding",
|
|
7025
|
+
svc.service,
|
|
7026
|
+
evidenceFile,
|
|
7027
|
+
lineContaining(raw, svc.service)
|
|
7028
|
+
);
|
|
7029
|
+
nodesAdded += result.nodesAdded;
|
|
7030
|
+
edgesAdded += result.edgesAdded;
|
|
7031
|
+
}
|
|
7032
|
+
}
|
|
7033
|
+
return { nodesAdded, edgesAdded };
|
|
7034
|
+
}
|
|
7035
|
+
|
|
6789
7036
|
// src/extract/infra/index.ts
|
|
6790
7037
|
async function addInfra(graph, scanPath, services) {
|
|
6791
7038
|
const compose = await addComposeInfra(graph, scanPath, services);
|
|
6792
7039
|
const dockerfile = await addDockerfileRuntimes(graph, services, scanPath);
|
|
6793
7040
|
const terraform = await addTerraformResources(graph, scanPath);
|
|
6794
7041
|
const k8s = await addK8sResources(graph, scanPath);
|
|
7042
|
+
const cloudflare = await addCloudflareWorkers(graph, services, scanPath);
|
|
6795
7043
|
return {
|
|
6796
|
-
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,
|
|
6797
|
-
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded
|
|
7044
|
+
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded + cloudflare.nodesAdded,
|
|
7045
|
+
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded + cloudflare.edgesAdded
|
|
6798
7046
|
};
|
|
6799
7047
|
}
|
|
6800
7048
|
|
|
6801
7049
|
// src/extract/index.ts
|
|
6802
|
-
var
|
|
7050
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
6803
7051
|
|
|
6804
7052
|
// src/extract/retire.ts
|
|
6805
7053
|
init_cjs_shims();
|
|
6806
|
-
var
|
|
6807
|
-
var
|
|
6808
|
-
var
|
|
7054
|
+
var import_node_fs20 = require("fs");
|
|
7055
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
7056
|
+
var import_types26 = require("@neat.is/types");
|
|
6809
7057
|
function dropOrphanedFileNodes(graph) {
|
|
6810
7058
|
const orphans = [];
|
|
6811
7059
|
graph.forEachNode((id, attrs) => {
|
|
6812
|
-
if (attrs.type !==
|
|
7060
|
+
if (attrs.type !== import_types26.NodeType.FileNode) return;
|
|
6813
7061
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
6814
7062
|
orphans.push(id);
|
|
6815
7063
|
}
|
|
@@ -6822,14 +7070,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
6822
7070
|
const bases = [scanPath, ...serviceDirs];
|
|
6823
7071
|
graph.forEachEdge((id, attrs) => {
|
|
6824
7072
|
const edge = attrs;
|
|
6825
|
-
if (edge.provenance !==
|
|
7073
|
+
if (edge.provenance !== import_types26.Provenance.EXTRACTED) return;
|
|
6826
7074
|
const evidenceFile = edge.evidence?.file;
|
|
6827
7075
|
if (!evidenceFile) return;
|
|
6828
|
-
if (
|
|
6829
|
-
if (!(0,
|
|
7076
|
+
if (import_node_path36.default.isAbsolute(evidenceFile)) {
|
|
7077
|
+
if (!(0, import_node_fs20.existsSync)(evidenceFile)) toDrop.push(id);
|
|
6830
7078
|
return;
|
|
6831
7079
|
}
|
|
6832
|
-
const found = bases.some((base) => (0,
|
|
7080
|
+
const found = bases.some((base) => (0, import_node_fs20.existsSync)(import_node_path36.default.join(base, evidenceFile)));
|
|
6833
7081
|
if (!found) toDrop.push(id);
|
|
6834
7082
|
});
|
|
6835
7083
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -6871,7 +7119,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6871
7119
|
}
|
|
6872
7120
|
const droppedEntries = drainDroppedExtracted();
|
|
6873
7121
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
6874
|
-
const rejectedPath =
|
|
7122
|
+
const rejectedPath = import_node_path37.default.join(import_node_path37.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
6875
7123
|
try {
|
|
6876
7124
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
6877
7125
|
} catch (err) {
|
|
@@ -6905,9 +7153,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6905
7153
|
|
|
6906
7154
|
// src/persist.ts
|
|
6907
7155
|
init_cjs_shims();
|
|
6908
|
-
var
|
|
6909
|
-
var
|
|
6910
|
-
var
|
|
7156
|
+
var import_node_fs21 = require("fs");
|
|
7157
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7158
|
+
var import_types27 = require("@neat.is/types");
|
|
6911
7159
|
var SCHEMA_VERSION = 4;
|
|
6912
7160
|
function migrateV1ToV2(payload) {
|
|
6913
7161
|
const nodes = payload.graph.nodes;
|
|
@@ -6929,12 +7177,12 @@ function migrateV2ToV3(payload) {
|
|
|
6929
7177
|
for (const edge of edges) {
|
|
6930
7178
|
const attrs = edge.attributes;
|
|
6931
7179
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
6932
|
-
attrs.provenance =
|
|
7180
|
+
attrs.provenance = import_types27.Provenance.OBSERVED;
|
|
6933
7181
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
6934
7182
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
6935
7183
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
6936
7184
|
if (type && source && target) {
|
|
6937
|
-
const newId = (0,
|
|
7185
|
+
const newId = (0, import_types27.observedEdgeId)(source, target, type);
|
|
6938
7186
|
attrs.id = newId;
|
|
6939
7187
|
if (edge.key) edge.key = newId;
|
|
6940
7188
|
}
|
|
@@ -6943,7 +7191,7 @@ function migrateV2ToV3(payload) {
|
|
|
6943
7191
|
return { ...payload, schemaVersion: 3 };
|
|
6944
7192
|
}
|
|
6945
7193
|
async function ensureDir(filePath) {
|
|
6946
|
-
await
|
|
7194
|
+
await import_node_fs21.promises.mkdir(import_node_path38.default.dirname(filePath), { recursive: true });
|
|
6947
7195
|
}
|
|
6948
7196
|
async function saveGraphToDisk(graph, outPath) {
|
|
6949
7197
|
await ensureDir(outPath);
|
|
@@ -6953,13 +7201,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
6953
7201
|
graph: graph.export()
|
|
6954
7202
|
};
|
|
6955
7203
|
const tmp = `${outPath}.tmp`;
|
|
6956
|
-
await
|
|
6957
|
-
await
|
|
7204
|
+
await import_node_fs21.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
7205
|
+
await import_node_fs21.promises.rename(tmp, outPath);
|
|
6958
7206
|
}
|
|
6959
7207
|
async function loadGraphFromDisk(graph, outPath) {
|
|
6960
7208
|
let raw;
|
|
6961
7209
|
try {
|
|
6962
|
-
raw = await
|
|
7210
|
+
raw = await import_node_fs21.promises.readFile(outPath, "utf8");
|
|
6963
7211
|
} catch (err) {
|
|
6964
7212
|
if (err.code === "ENOENT") return;
|
|
6965
7213
|
throw err;
|
|
@@ -7024,23 +7272,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
7024
7272
|
|
|
7025
7273
|
// src/projects.ts
|
|
7026
7274
|
init_cjs_shims();
|
|
7027
|
-
var
|
|
7275
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7028
7276
|
function pathsForProject(project, baseDir) {
|
|
7029
7277
|
if (project === DEFAULT_PROJECT) {
|
|
7030
7278
|
return {
|
|
7031
|
-
snapshotPath:
|
|
7032
|
-
errorsPath:
|
|
7033
|
-
staleEventsPath:
|
|
7034
|
-
embeddingsCachePath:
|
|
7035
|
-
policyViolationsPath:
|
|
7279
|
+
snapshotPath: import_node_path39.default.join(baseDir, "graph.json"),
|
|
7280
|
+
errorsPath: import_node_path39.default.join(baseDir, "errors.ndjson"),
|
|
7281
|
+
staleEventsPath: import_node_path39.default.join(baseDir, "stale-events.ndjson"),
|
|
7282
|
+
embeddingsCachePath: import_node_path39.default.join(baseDir, "embeddings.json"),
|
|
7283
|
+
policyViolationsPath: import_node_path39.default.join(baseDir, "policy-violations.ndjson")
|
|
7036
7284
|
};
|
|
7037
7285
|
}
|
|
7038
7286
|
return {
|
|
7039
|
-
snapshotPath:
|
|
7040
|
-
errorsPath:
|
|
7041
|
-
staleEventsPath:
|
|
7042
|
-
embeddingsCachePath:
|
|
7043
|
-
policyViolationsPath:
|
|
7287
|
+
snapshotPath: import_node_path39.default.join(baseDir, `${project}.json`),
|
|
7288
|
+
errorsPath: import_node_path39.default.join(baseDir, `errors.${project}.ndjson`),
|
|
7289
|
+
staleEventsPath: import_node_path39.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
7290
|
+
embeddingsCachePath: import_node_path39.default.join(baseDir, `embeddings.${project}.json`),
|
|
7291
|
+
policyViolationsPath: import_node_path39.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
7044
7292
|
};
|
|
7045
7293
|
}
|
|
7046
7294
|
var Projects = class {
|
|
@@ -7078,19 +7326,19 @@ var Projects = class {
|
|
|
7078
7326
|
init_cjs_shims();
|
|
7079
7327
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
7080
7328
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
7081
|
-
var
|
|
7329
|
+
var import_types30 = require("@neat.is/types");
|
|
7082
7330
|
|
|
7083
7331
|
// src/extend/index.ts
|
|
7084
7332
|
init_cjs_shims();
|
|
7085
|
-
var
|
|
7086
|
-
var
|
|
7333
|
+
var import_node_fs23 = require("fs");
|
|
7334
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7087
7335
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
7088
7336
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
7089
7337
|
|
|
7090
7338
|
// src/installers/package-manager.ts
|
|
7091
7339
|
init_cjs_shims();
|
|
7092
|
-
var
|
|
7093
|
-
var
|
|
7340
|
+
var import_node_fs22 = require("fs");
|
|
7341
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7094
7342
|
var import_node_child_process = require("child_process");
|
|
7095
7343
|
var LOCKFILE_PRIORITY = [
|
|
7096
7344
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -7105,29 +7353,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
7105
7353
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
7106
7354
|
async function exists2(p) {
|
|
7107
7355
|
try {
|
|
7108
|
-
await
|
|
7356
|
+
await import_node_fs22.promises.access(p);
|
|
7109
7357
|
return true;
|
|
7110
7358
|
} catch {
|
|
7111
7359
|
return false;
|
|
7112
7360
|
}
|
|
7113
7361
|
}
|
|
7114
7362
|
async function detectPackageManager(serviceDir) {
|
|
7115
|
-
let dir =
|
|
7363
|
+
let dir = import_node_path40.default.resolve(serviceDir);
|
|
7116
7364
|
const stops = /* @__PURE__ */ new Set();
|
|
7117
7365
|
for (let i = 0; i < 64; i++) {
|
|
7118
7366
|
if (stops.has(dir)) break;
|
|
7119
7367
|
stops.add(dir);
|
|
7120
7368
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
7121
|
-
const lockPath =
|
|
7369
|
+
const lockPath = import_node_path40.default.join(dir, candidate.lockfile);
|
|
7122
7370
|
if (await exists2(lockPath)) {
|
|
7123
7371
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
7124
7372
|
}
|
|
7125
7373
|
}
|
|
7126
|
-
const parent =
|
|
7374
|
+
const parent = import_node_path40.default.dirname(dir);
|
|
7127
7375
|
if (parent === dir) break;
|
|
7128
7376
|
dir = parent;
|
|
7129
7377
|
}
|
|
7130
|
-
return { pm: "npm", cwd:
|
|
7378
|
+
return { pm: "npm", cwd: import_node_path40.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
7131
7379
|
}
|
|
7132
7380
|
async function runPackageManagerInstall(cmd) {
|
|
7133
7381
|
return new Promise((resolve) => {
|
|
@@ -7169,30 +7417,30 @@ ${err.message}`
|
|
|
7169
7417
|
// src/extend/index.ts
|
|
7170
7418
|
async function fileExists2(p) {
|
|
7171
7419
|
try {
|
|
7172
|
-
await
|
|
7420
|
+
await import_node_fs23.promises.access(p);
|
|
7173
7421
|
return true;
|
|
7174
7422
|
} catch {
|
|
7175
7423
|
return false;
|
|
7176
7424
|
}
|
|
7177
7425
|
}
|
|
7178
7426
|
async function readPackageJson(scanPath) {
|
|
7179
|
-
const pkgPath =
|
|
7180
|
-
const raw = await
|
|
7427
|
+
const pkgPath = import_node_path41.default.join(scanPath, "package.json");
|
|
7428
|
+
const raw = await import_node_fs23.promises.readFile(pkgPath, "utf8");
|
|
7181
7429
|
return JSON.parse(raw);
|
|
7182
7430
|
}
|
|
7183
7431
|
async function findHookFiles(scanPath) {
|
|
7184
|
-
const entries = await
|
|
7432
|
+
const entries = await import_node_fs23.promises.readdir(scanPath);
|
|
7185
7433
|
return entries.filter(
|
|
7186
7434
|
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
7187
7435
|
).sort();
|
|
7188
7436
|
}
|
|
7189
7437
|
function extendLogPath() {
|
|
7190
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
7438
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path41.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
7191
7439
|
}
|
|
7192
7440
|
async function appendExtendLog(entry2) {
|
|
7193
7441
|
const logPath = extendLogPath();
|
|
7194
|
-
await
|
|
7195
|
-
await
|
|
7442
|
+
await import_node_fs23.promises.mkdir(import_node_path41.default.dirname(logPath), { recursive: true });
|
|
7443
|
+
await import_node_fs23.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
7196
7444
|
}
|
|
7197
7445
|
function splicedContent(fileContent, snippet2) {
|
|
7198
7446
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -7250,7 +7498,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
7250
7498
|
}
|
|
7251
7499
|
async function describeProjectInstrumentation(ctx) {
|
|
7252
7500
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7253
|
-
const envNeat = await fileExists2(
|
|
7501
|
+
const envNeat = await fileExists2(import_node_path41.default.join(ctx.scanPath, ".env.neat"));
|
|
7254
7502
|
const registryInstrPackages = new Set(
|
|
7255
7503
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
7256
7504
|
);
|
|
@@ -7272,31 +7520,31 @@ async function applyExtension(ctx, args, options) {
|
|
|
7272
7520
|
);
|
|
7273
7521
|
}
|
|
7274
7522
|
for (const file of hookFiles) {
|
|
7275
|
-
const content = await
|
|
7523
|
+
const content = await import_node_fs23.promises.readFile(import_node_path41.default.join(ctx.scanPath, file), "utf8");
|
|
7276
7524
|
if (content.includes(args.registration_snippet)) {
|
|
7277
7525
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
7278
7526
|
}
|
|
7279
7527
|
}
|
|
7280
7528
|
const primaryFile = hookFiles[0];
|
|
7281
|
-
const primaryPath =
|
|
7529
|
+
const primaryPath = import_node_path41.default.join(ctx.scanPath, primaryFile);
|
|
7282
7530
|
const filesTouched = [];
|
|
7283
7531
|
const depsAdded = [];
|
|
7284
|
-
const pkgPath =
|
|
7532
|
+
const pkgPath = import_node_path41.default.join(ctx.scanPath, "package.json");
|
|
7285
7533
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7286
7534
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
7287
7535
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
7288
|
-
await
|
|
7536
|
+
await import_node_fs23.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
7289
7537
|
filesTouched.push("package.json");
|
|
7290
7538
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
7291
7539
|
}
|
|
7292
|
-
const hookContent = await
|
|
7540
|
+
const hookContent = await import_node_fs23.promises.readFile(primaryPath, "utf8");
|
|
7293
7541
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7294
7542
|
if (!patched) {
|
|
7295
7543
|
throw new Error(
|
|
7296
7544
|
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
7297
7545
|
);
|
|
7298
7546
|
}
|
|
7299
|
-
await
|
|
7547
|
+
await import_node_fs23.promises.writeFile(primaryPath, patched, "utf8");
|
|
7300
7548
|
filesTouched.push(primaryFile);
|
|
7301
7549
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
7302
7550
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -7327,7 +7575,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7327
7575
|
};
|
|
7328
7576
|
}
|
|
7329
7577
|
for (const file of hookFiles) {
|
|
7330
|
-
const content = await
|
|
7578
|
+
const content = await import_node_fs23.promises.readFile(import_node_path41.default.join(ctx.scanPath, file), "utf8");
|
|
7331
7579
|
if (content.includes(args.registration_snippet)) {
|
|
7332
7580
|
return {
|
|
7333
7581
|
library: args.library,
|
|
@@ -7349,7 +7597,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7349
7597
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
7350
7598
|
filesTouched.push("package.json");
|
|
7351
7599
|
}
|
|
7352
|
-
const hookContent = await
|
|
7600
|
+
const hookContent = await import_node_fs23.promises.readFile(import_node_path41.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
7353
7601
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7354
7602
|
if (patched) {
|
|
7355
7603
|
filesTouched.push(primaryFile);
|
|
@@ -7364,28 +7612,28 @@ async function rollbackExtension(ctx, args) {
|
|
|
7364
7612
|
if (!await fileExists2(logPath)) {
|
|
7365
7613
|
return { undone: false, message: "no apply found for library" };
|
|
7366
7614
|
}
|
|
7367
|
-
const raw = await
|
|
7615
|
+
const raw = await import_node_fs23.promises.readFile(logPath, "utf8");
|
|
7368
7616
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
7369
7617
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
7370
7618
|
if (!match) {
|
|
7371
7619
|
return { undone: false, message: "no apply found for library" };
|
|
7372
7620
|
}
|
|
7373
|
-
const pkgPath =
|
|
7621
|
+
const pkgPath = import_node_path41.default.join(ctx.scanPath, "package.json");
|
|
7374
7622
|
if (await fileExists2(pkgPath)) {
|
|
7375
7623
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7376
7624
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
7377
7625
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
7378
7626
|
pkg.dependencies = rest;
|
|
7379
|
-
await
|
|
7627
|
+
await import_node_fs23.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
7380
7628
|
}
|
|
7381
7629
|
}
|
|
7382
7630
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7383
7631
|
for (const file of hookFiles) {
|
|
7384
|
-
const filePath =
|
|
7385
|
-
const content = await
|
|
7632
|
+
const filePath = import_node_path41.default.join(ctx.scanPath, file);
|
|
7633
|
+
const content = await import_node_fs23.promises.readFile(filePath, "utf8");
|
|
7386
7634
|
if (content.includes(match.registration_snippet)) {
|
|
7387
7635
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
7388
|
-
await
|
|
7636
|
+
await import_node_fs23.promises.writeFile(filePath, filtered, "utf8");
|
|
7389
7637
|
break;
|
|
7390
7638
|
}
|
|
7391
7639
|
}
|
|
@@ -7397,7 +7645,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
7397
7645
|
|
|
7398
7646
|
// src/divergences.ts
|
|
7399
7647
|
init_cjs_shims();
|
|
7400
|
-
var
|
|
7648
|
+
var import_types28 = require("@neat.is/types");
|
|
7401
7649
|
function bucketKey(source, target, type) {
|
|
7402
7650
|
return `${type}|${source}|${target}`;
|
|
7403
7651
|
}
|
|
@@ -7405,22 +7653,22 @@ function bucketEdges(graph) {
|
|
|
7405
7653
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
7406
7654
|
graph.forEachEdge((id, attrs) => {
|
|
7407
7655
|
const e = attrs;
|
|
7408
|
-
const parsed = (0,
|
|
7656
|
+
const parsed = (0, import_types28.parseEdgeId)(id);
|
|
7409
7657
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
7410
7658
|
const key = bucketKey(e.source, e.target, e.type);
|
|
7411
7659
|
const cur = buckets2.get(key) ?? { source: e.source, target: e.target, type: e.type };
|
|
7412
7660
|
switch (provenance) {
|
|
7413
|
-
case
|
|
7661
|
+
case import_types28.Provenance.EXTRACTED:
|
|
7414
7662
|
cur.extracted = e;
|
|
7415
7663
|
break;
|
|
7416
|
-
case
|
|
7664
|
+
case import_types28.Provenance.OBSERVED:
|
|
7417
7665
|
cur.observed = e;
|
|
7418
7666
|
break;
|
|
7419
|
-
case
|
|
7667
|
+
case import_types28.Provenance.INFERRED:
|
|
7420
7668
|
cur.inferred = e;
|
|
7421
7669
|
break;
|
|
7422
7670
|
default:
|
|
7423
|
-
if (e.provenance ===
|
|
7671
|
+
if (e.provenance === import_types28.Provenance.STALE) cur.stale = e;
|
|
7424
7672
|
}
|
|
7425
7673
|
buckets2.set(key, cur);
|
|
7426
7674
|
});
|
|
@@ -7429,12 +7677,12 @@ function bucketEdges(graph) {
|
|
|
7429
7677
|
function nodeIsFrontier(graph, nodeId) {
|
|
7430
7678
|
if (!graph.hasNode(nodeId)) return false;
|
|
7431
7679
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7432
|
-
return attrs.type ===
|
|
7680
|
+
return attrs.type === import_types28.NodeType.FrontierNode;
|
|
7433
7681
|
}
|
|
7434
7682
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
7435
7683
|
if (!graph.hasNode(nodeId)) return false;
|
|
7436
7684
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7437
|
-
return attrs.type ===
|
|
7685
|
+
return attrs.type === import_types28.NodeType.WebSocketChannelNode;
|
|
7438
7686
|
}
|
|
7439
7687
|
function clampConfidence(n) {
|
|
7440
7688
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -7454,14 +7702,14 @@ function gradedConfidence(edge) {
|
|
|
7454
7702
|
return clampConfidence(confidenceForEdge(edge));
|
|
7455
7703
|
}
|
|
7456
7704
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7705
|
+
import_types28.EdgeType.CALLS,
|
|
7706
|
+
import_types28.EdgeType.CONNECTS_TO,
|
|
7707
|
+
import_types28.EdgeType.PUBLISHES_TO,
|
|
7708
|
+
import_types28.EdgeType.CONSUMES_FROM
|
|
7461
7709
|
]);
|
|
7462
7710
|
function detectMissingDivergences(graph, bucket) {
|
|
7463
7711
|
const out = [];
|
|
7464
|
-
if (bucket.type ===
|
|
7712
|
+
if (bucket.type === import_types28.EdgeType.CONTAINS) return out;
|
|
7465
7713
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
7466
7714
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
7467
7715
|
out.push({
|
|
@@ -7502,7 +7750,7 @@ function declaredHostFor(svc) {
|
|
|
7502
7750
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
7503
7751
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7504
7752
|
const e = graph.getEdgeAttributes(edgeId);
|
|
7505
|
-
if (e.type ===
|
|
7753
|
+
if (e.type === import_types28.EdgeType.CONFIGURED_BY && e.provenance === import_types28.Provenance.EXTRACTED) {
|
|
7506
7754
|
return true;
|
|
7507
7755
|
}
|
|
7508
7756
|
}
|
|
@@ -7515,10 +7763,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
7515
7763
|
const out = [];
|
|
7516
7764
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7517
7765
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
7518
|
-
if (edge.type !==
|
|
7519
|
-
if (edge.provenance !==
|
|
7766
|
+
if (edge.type !== import_types28.EdgeType.CONNECTS_TO) continue;
|
|
7767
|
+
if (edge.provenance !== import_types28.Provenance.OBSERVED) continue;
|
|
7520
7768
|
const target = graph.getNodeAttributes(edge.target);
|
|
7521
|
-
if (target.type !==
|
|
7769
|
+
if (target.type !== import_types28.NodeType.DatabaseNode) continue;
|
|
7522
7770
|
const observedHost = target.host?.trim();
|
|
7523
7771
|
if (!observedHost) continue;
|
|
7524
7772
|
if (observedHost === declaredHost) continue;
|
|
@@ -7540,10 +7788,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
7540
7788
|
const deps = svc.dependencies ?? {};
|
|
7541
7789
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7542
7790
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
7543
|
-
if (edge.type !==
|
|
7544
|
-
if (edge.provenance !==
|
|
7791
|
+
if (edge.type !== import_types28.EdgeType.CONNECTS_TO) continue;
|
|
7792
|
+
if (edge.provenance !== import_types28.Provenance.OBSERVED) continue;
|
|
7545
7793
|
const target = graph.getNodeAttributes(edge.target);
|
|
7546
|
-
if (target.type !==
|
|
7794
|
+
if (target.type !== import_types28.NodeType.DatabaseNode) continue;
|
|
7547
7795
|
for (const pair of compatPairs()) {
|
|
7548
7796
|
if (pair.engine !== target.engine) continue;
|
|
7549
7797
|
const declared = deps[pair.driver];
|
|
@@ -7602,7 +7850,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
7602
7850
|
for (const d of all) {
|
|
7603
7851
|
if (d.type !== "host-mismatch") continue;
|
|
7604
7852
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
7605
|
-
declaredHalf.add((0,
|
|
7853
|
+
declaredHalf.add((0, import_types28.databaseId)(d.extractedHost));
|
|
7606
7854
|
}
|
|
7607
7855
|
if (observedHalf.size === 0) return all;
|
|
7608
7856
|
return all.filter((d) => {
|
|
@@ -7621,7 +7869,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7621
7869
|
}
|
|
7622
7870
|
graph.forEachNode((nodeId, attrs) => {
|
|
7623
7871
|
const n = attrs;
|
|
7624
|
-
if (n.type !==
|
|
7872
|
+
if (n.type !== import_types28.NodeType.ServiceNode) return;
|
|
7625
7873
|
const svc = n;
|
|
7626
7874
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
7627
7875
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -7655,7 +7903,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7655
7903
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
7656
7904
|
return a.target.localeCompare(b.target);
|
|
7657
7905
|
});
|
|
7658
|
-
return
|
|
7906
|
+
return import_types28.DivergenceResultSchema.parse({
|
|
7659
7907
|
divergences: filtered,
|
|
7660
7908
|
totalAffected: filtered.length,
|
|
7661
7909
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7709,7 +7957,7 @@ function queryLogEntries(opts) {
|
|
|
7709
7957
|
|
|
7710
7958
|
// src/diff.ts
|
|
7711
7959
|
init_cjs_shims();
|
|
7712
|
-
var
|
|
7960
|
+
var import_node_fs24 = require("fs");
|
|
7713
7961
|
async function loadSnapshotForDiff(target) {
|
|
7714
7962
|
if (/^https?:\/\//i.test(target)) {
|
|
7715
7963
|
const res = await fetch(target);
|
|
@@ -7718,7 +7966,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
7718
7966
|
}
|
|
7719
7967
|
return await res.json();
|
|
7720
7968
|
}
|
|
7721
|
-
const raw = await
|
|
7969
|
+
const raw = await import_node_fs24.promises.readFile(target, "utf8");
|
|
7722
7970
|
return JSON.parse(raw);
|
|
7723
7971
|
}
|
|
7724
7972
|
function indexEntries(entries) {
|
|
@@ -7786,25 +8034,25 @@ function canonicalJson(value) {
|
|
|
7786
8034
|
|
|
7787
8035
|
// src/registry.ts
|
|
7788
8036
|
init_cjs_shims();
|
|
7789
|
-
var
|
|
8037
|
+
var import_node_fs25 = require("fs");
|
|
7790
8038
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
7791
|
-
var
|
|
7792
|
-
var
|
|
8039
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8040
|
+
var import_types29 = require("@neat.is/types");
|
|
7793
8041
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
7794
8042
|
var LOCK_RETRY_MS = 50;
|
|
7795
8043
|
function neatHome() {
|
|
7796
8044
|
const override = process.env.NEAT_HOME;
|
|
7797
|
-
if (override && override.length > 0) return
|
|
7798
|
-
return
|
|
8045
|
+
if (override && override.length > 0) return import_node_path42.default.resolve(override);
|
|
8046
|
+
return import_node_path42.default.join(import_node_os3.default.homedir(), ".neat");
|
|
7799
8047
|
}
|
|
7800
8048
|
function registryPath() {
|
|
7801
|
-
return
|
|
8049
|
+
return import_node_path42.default.join(neatHome(), "projects.json");
|
|
7802
8050
|
}
|
|
7803
8051
|
function registryLockPath() {
|
|
7804
|
-
return
|
|
8052
|
+
return import_node_path42.default.join(neatHome(), "projects.json.lock");
|
|
7805
8053
|
}
|
|
7806
8054
|
function daemonPidPath() {
|
|
7807
|
-
return
|
|
8055
|
+
return import_node_path42.default.join(neatHome(), "neatd.pid");
|
|
7808
8056
|
}
|
|
7809
8057
|
function isPidAliveDefault(pid) {
|
|
7810
8058
|
try {
|
|
@@ -7816,7 +8064,7 @@ function isPidAliveDefault(pid) {
|
|
|
7816
8064
|
}
|
|
7817
8065
|
async function readPidFile(file) {
|
|
7818
8066
|
try {
|
|
7819
|
-
const raw = await
|
|
8067
|
+
const raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
7820
8068
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
7821
8069
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
7822
8070
|
} catch {
|
|
@@ -7864,24 +8112,24 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
7864
8112
|
}
|
|
7865
8113
|
}
|
|
7866
8114
|
async function writeAtomically(target, contents) {
|
|
7867
|
-
await
|
|
8115
|
+
await import_node_fs25.promises.mkdir(import_node_path42.default.dirname(target), { recursive: true });
|
|
7868
8116
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
7869
|
-
const fd = await
|
|
8117
|
+
const fd = await import_node_fs25.promises.open(tmp, "w");
|
|
7870
8118
|
try {
|
|
7871
8119
|
await fd.writeFile(contents, "utf8");
|
|
7872
8120
|
await fd.sync();
|
|
7873
8121
|
} finally {
|
|
7874
8122
|
await fd.close();
|
|
7875
8123
|
}
|
|
7876
|
-
await
|
|
8124
|
+
await import_node_fs25.promises.rename(tmp, target);
|
|
7877
8125
|
}
|
|
7878
8126
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
7879
8127
|
const deadline = Date.now() + timeoutMs;
|
|
7880
|
-
await
|
|
8128
|
+
await import_node_fs25.promises.mkdir(import_node_path42.default.dirname(lockPath), { recursive: true });
|
|
7881
8129
|
let probedHolder = false;
|
|
7882
8130
|
while (true) {
|
|
7883
8131
|
try {
|
|
7884
|
-
const fd = await
|
|
8132
|
+
const fd = await import_node_fs25.promises.open(lockPath, "wx");
|
|
7885
8133
|
try {
|
|
7886
8134
|
await fd.writeFile(`${process.pid}
|
|
7887
8135
|
`, "utf8");
|
|
@@ -7906,7 +8154,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
7906
8154
|
}
|
|
7907
8155
|
}
|
|
7908
8156
|
async function releaseLock(lockPath) {
|
|
7909
|
-
await
|
|
8157
|
+
await import_node_fs25.promises.unlink(lockPath).catch(() => {
|
|
7910
8158
|
});
|
|
7911
8159
|
}
|
|
7912
8160
|
async function withLock(fn) {
|
|
@@ -7922,7 +8170,7 @@ async function readRegistry() {
|
|
|
7922
8170
|
const file = registryPath();
|
|
7923
8171
|
let raw;
|
|
7924
8172
|
try {
|
|
7925
|
-
raw = await
|
|
8173
|
+
raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
7926
8174
|
} catch (err) {
|
|
7927
8175
|
if (err.code === "ENOENT") {
|
|
7928
8176
|
return { version: 1, projects: [] };
|
|
@@ -7930,10 +8178,10 @@ async function readRegistry() {
|
|
|
7930
8178
|
throw err;
|
|
7931
8179
|
}
|
|
7932
8180
|
const parsed = JSON.parse(raw);
|
|
7933
|
-
return
|
|
8181
|
+
return import_types29.RegistryFileSchema.parse(parsed);
|
|
7934
8182
|
}
|
|
7935
8183
|
async function writeRegistry(reg) {
|
|
7936
|
-
const validated =
|
|
8184
|
+
const validated = import_types29.RegistryFileSchema.parse(reg);
|
|
7937
8185
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
7938
8186
|
}
|
|
7939
8187
|
async function getProject(name) {
|
|
@@ -7977,7 +8225,7 @@ function pruneTtlMs() {
|
|
|
7977
8225
|
}
|
|
7978
8226
|
async function statPathStatus(p) {
|
|
7979
8227
|
try {
|
|
7980
|
-
const stat = await
|
|
8228
|
+
const stat = await import_node_fs25.promises.stat(p);
|
|
7981
8229
|
return stat.isDirectory() ? "present" : "unknown";
|
|
7982
8230
|
} catch (err) {
|
|
7983
8231
|
return err.code === "ENOENT" ? "gone" : "unknown";
|
|
@@ -8224,11 +8472,11 @@ function registerRoutes(scope, ctx) {
|
|
|
8224
8472
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
8225
8473
|
const parsed = [];
|
|
8226
8474
|
for (const c of candidates) {
|
|
8227
|
-
const r =
|
|
8475
|
+
const r = import_types30.DivergenceTypeSchema.safeParse(c);
|
|
8228
8476
|
if (!r.success) {
|
|
8229
8477
|
return reply.code(400).send({
|
|
8230
8478
|
error: `unknown divergence type "${c}"`,
|
|
8231
|
-
allowed:
|
|
8479
|
+
allowed: import_types30.DivergenceTypeSchema.options
|
|
8232
8480
|
});
|
|
8233
8481
|
}
|
|
8234
8482
|
parsed.push(r.data);
|
|
@@ -8479,7 +8727,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8479
8727
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
8480
8728
|
let violations = await log.readAll();
|
|
8481
8729
|
if (req2.query.severity) {
|
|
8482
|
-
const sev =
|
|
8730
|
+
const sev = import_types30.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
8483
8731
|
if (!sev.success) {
|
|
8484
8732
|
return reply.code(400).send({
|
|
8485
8733
|
error: "invalid severity",
|
|
@@ -8518,7 +8766,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8518
8766
|
scope.post("/policies/check", async (req2, reply) => {
|
|
8519
8767
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
8520
8768
|
if (!proj) return;
|
|
8521
|
-
const parsed =
|
|
8769
|
+
const parsed = import_types30.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
8522
8770
|
if (!parsed.success) {
|
|
8523
8771
|
return reply.code(400).send({
|
|
8524
8772
|
error: "invalid /policies/check body",
|
|
@@ -8791,6 +9039,10 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
8791
9039
|
unresolved++;
|
|
8792
9040
|
continue;
|
|
8793
9041
|
}
|
|
9042
|
+
if (resolved.ensureInfraNode) {
|
|
9043
|
+
const { kind, name, provider } = resolved.ensureInfraNode;
|
|
9044
|
+
ensureInfraNode(graph, kind, name, provider);
|
|
9045
|
+
}
|
|
8794
9046
|
const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV);
|
|
8795
9047
|
const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : void 0;
|
|
8796
9048
|
const sourceId = callSite ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite) : serviceNodeId;
|
|
@@ -9192,10 +9444,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
9192
9444
|
// src/connectors/supabase/map.ts
|
|
9193
9445
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
9194
9446
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
9195
|
-
function targetFromRestPath(
|
|
9196
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
9447
|
+
function targetFromRestPath(path50) {
|
|
9448
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path50);
|
|
9197
9449
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
9198
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
9450
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path50);
|
|
9199
9451
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
9200
9452
|
return null;
|
|
9201
9453
|
}
|
|
@@ -9298,19 +9550,19 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
9298
9550
|
|
|
9299
9551
|
// src/connectors/supabase/resolve.ts
|
|
9300
9552
|
init_cjs_shims();
|
|
9301
|
-
var
|
|
9553
|
+
var import_types32 = require("@neat.is/types");
|
|
9302
9554
|
function createSupabaseResolveTarget(graph, config) {
|
|
9303
9555
|
return (signal, _ctx) => {
|
|
9304
9556
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
9305
9557
|
return null;
|
|
9306
9558
|
}
|
|
9307
|
-
const subResourceId = (0,
|
|
9559
|
+
const subResourceId = (0, import_types32.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
9308
9560
|
if (graph.hasNode(subResourceId)) {
|
|
9309
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
9561
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types32.EdgeType.CALLS };
|
|
9310
9562
|
}
|
|
9311
|
-
const projectLevelId = (0,
|
|
9563
|
+
const projectLevelId = (0, import_types32.infraId)("supabase", config.nodeRef);
|
|
9312
9564
|
if (graph.hasNode(projectLevelId)) {
|
|
9313
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
9565
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types32.EdgeType.CALLS };
|
|
9314
9566
|
}
|
|
9315
9567
|
return null;
|
|
9316
9568
|
};
|
|
@@ -9368,7 +9620,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
9368
9620
|
|
|
9369
9621
|
// src/connectors/railway/index.ts
|
|
9370
9622
|
init_cjs_shims();
|
|
9371
|
-
var
|
|
9623
|
+
var import_types36 = require("@neat.is/types");
|
|
9372
9624
|
|
|
9373
9625
|
// src/connectors/railway/client.ts
|
|
9374
9626
|
init_cjs_shims();
|
|
@@ -9513,7 +9765,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
9513
9765
|
const out = [];
|
|
9514
9766
|
graph.forEachNode((_id, attrs) => {
|
|
9515
9767
|
const node = attrs;
|
|
9516
|
-
if (node.type !==
|
|
9768
|
+
if (node.type !== import_types36.NodeType.RouteNode) return;
|
|
9517
9769
|
const route = attrs;
|
|
9518
9770
|
if (route.service !== serviceName) return;
|
|
9519
9771
|
out.push({
|
|
@@ -9609,12 +9861,12 @@ function createRailwayResolveTarget(config) {
|
|
|
9609
9861
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
9610
9862
|
if (!serviceName) return null;
|
|
9611
9863
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
9612
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
9864
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types36.EdgeType.CALLS };
|
|
9613
9865
|
}
|
|
9614
9866
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
9615
9867
|
const peerName = config.serviceNameById[signal.targetName];
|
|
9616
9868
|
if (!peerName) return null;
|
|
9617
|
-
return { targetNodeId: (0,
|
|
9869
|
+
return { targetNodeId: (0, import_types36.serviceId)(peerName), serviceName, edgeType: import_types36.EdgeType.CONNECTS_TO };
|
|
9618
9870
|
}
|
|
9619
9871
|
return null;
|
|
9620
9872
|
};
|
|
@@ -9729,9 +9981,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
9729
9981
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
9730
9982
|
if (secondSep === -1) return null;
|
|
9731
9983
|
const method = rest.slice(0, secondSep);
|
|
9732
|
-
const
|
|
9733
|
-
if (!resourceName || !method || !
|
|
9734
|
-
return { resourceName, method, path:
|
|
9984
|
+
const path50 = rest.slice(secondSep + 1);
|
|
9985
|
+
if (!resourceName || !method || !path50) return null;
|
|
9986
|
+
return { resourceName, method, path: path50 };
|
|
9735
9987
|
}
|
|
9736
9988
|
function resourceNameFor(type, labels) {
|
|
9737
9989
|
if (!labels) return null;
|
|
@@ -9768,14 +10020,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
9768
10020
|
if (!req2) return null;
|
|
9769
10021
|
if (!req2.requestMethod) return null;
|
|
9770
10022
|
const method = req2.requestMethod.toUpperCase();
|
|
9771
|
-
const
|
|
9772
|
-
if (
|
|
10023
|
+
const path50 = pathFromRequestUrl(req2.requestUrl);
|
|
10024
|
+
if (path50 === null) return null;
|
|
9773
10025
|
const timestamp = entry2.timestamp;
|
|
9774
10026
|
if (!timestamp) return null;
|
|
9775
10027
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD2;
|
|
9776
10028
|
return {
|
|
9777
10029
|
targetKind: resourceType,
|
|
9778
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
10030
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path50 }),
|
|
9779
10031
|
callCount: 1,
|
|
9780
10032
|
errorCount: isError ? 1 : 0,
|
|
9781
10033
|
lastObservedIso: timestamp
|
|
@@ -9792,7 +10044,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
9792
10044
|
|
|
9793
10045
|
// src/connectors/firebase/resolve.ts
|
|
9794
10046
|
init_cjs_shims();
|
|
9795
|
-
var
|
|
10047
|
+
var import_types37 = require("@neat.is/types");
|
|
9796
10048
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
9797
10049
|
switch (resourceType) {
|
|
9798
10050
|
case "cloud_function":
|
|
@@ -9807,7 +10059,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
9807
10059
|
const entries = [];
|
|
9808
10060
|
graph.forEachNode((_id, attrs) => {
|
|
9809
10061
|
const node = attrs;
|
|
9810
|
-
if (node.type !==
|
|
10062
|
+
if (node.type !== import_types37.NodeType.RouteNode) return;
|
|
9811
10063
|
const route = attrs;
|
|
9812
10064
|
if (route.service !== serviceName) return;
|
|
9813
10065
|
entries.push({
|
|
@@ -9839,7 +10091,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
9839
10091
|
return {
|
|
9840
10092
|
targetNodeId: match.routeNodeId,
|
|
9841
10093
|
serviceName,
|
|
9842
|
-
edgeType:
|
|
10094
|
+
edgeType: import_types37.EdgeType.CALLS
|
|
9843
10095
|
};
|
|
9844
10096
|
};
|
|
9845
10097
|
}
|
|
@@ -9866,7 +10118,7 @@ init_cjs_shims();
|
|
|
9866
10118
|
|
|
9867
10119
|
// src/connectors/cloudflare/connector.ts
|
|
9868
10120
|
init_cjs_shims();
|
|
9869
|
-
var
|
|
10121
|
+
var import_types39 = require("@neat.is/types");
|
|
9870
10122
|
|
|
9871
10123
|
// src/connectors/cloudflare/client.ts
|
|
9872
10124
|
init_cjs_shims();
|
|
@@ -9916,7 +10168,14 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
|
|
|
9916
10168
|
const message = payload.errors?.map((e) => e.message).join("; ") || "unknown error";
|
|
9917
10169
|
throw new Error(`cloudflare connector: telemetry query returned an error (${message})`);
|
|
9918
10170
|
}
|
|
9919
|
-
|
|
10171
|
+
const events = payload.result?.events?.events;
|
|
10172
|
+
if (events === void 0) {
|
|
10173
|
+
console.warn(
|
|
10174
|
+
"[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"
|
|
10175
|
+
);
|
|
10176
|
+
return [];
|
|
10177
|
+
}
|
|
10178
|
+
return events;
|
|
9920
10179
|
}
|
|
9921
10180
|
|
|
9922
10181
|
// src/connectors/cloudflare/map.ts
|
|
@@ -9947,6 +10206,13 @@ function parseHttpMethodFromTrigger(trigger) {
|
|
|
9947
10206
|
const method = token.toUpperCase();
|
|
9948
10207
|
return HTTP_METHODS.has(method) ? method : null;
|
|
9949
10208
|
}
|
|
10209
|
+
function parsePathFromTrigger(trigger) {
|
|
10210
|
+
const trimmed = trigger.trim();
|
|
10211
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
10212
|
+
if (spaceIdx === -1) return void 0;
|
|
10213
|
+
const rest = trimmed.slice(spaceIdx + 1).trim();
|
|
10214
|
+
return rest.length > 0 ? rest : void 0;
|
|
10215
|
+
}
|
|
9950
10216
|
var ERROR_STATUS_THRESHOLD3 = 500;
|
|
9951
10217
|
function mapEventToSignal(event) {
|
|
9952
10218
|
const metadata = event.$metadata;
|
|
@@ -9959,6 +10225,7 @@ function mapEventToSignal(event) {
|
|
|
9959
10225
|
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return null;
|
|
9960
10226
|
const statusCode = metadata?.statusCode;
|
|
9961
10227
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
10228
|
+
const path50 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
9962
10229
|
return {
|
|
9963
10230
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
9964
10231
|
targetName: scriptName,
|
|
@@ -9966,6 +10233,7 @@ function mapEventToSignal(event) {
|
|
|
9966
10233
|
errorCount: isError ? 1 : 0,
|
|
9967
10234
|
lastObservedIso: new Date(timestampMs).toISOString(),
|
|
9968
10235
|
method,
|
|
10236
|
+
...path50 ? { path: path50 } : {},
|
|
9969
10237
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
9970
10238
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
9971
10239
|
};
|
|
@@ -10000,15 +10268,63 @@ var CloudflareConnector = class {
|
|
|
10000
10268
|
return signals;
|
|
10001
10269
|
}
|
|
10002
10270
|
};
|
|
10003
|
-
function
|
|
10271
|
+
function findTaggedWorkerFileNode(graph, workerName) {
|
|
10272
|
+
let found = null;
|
|
10273
|
+
graph.forEachNode((id, attrs) => {
|
|
10274
|
+
if (found) return;
|
|
10275
|
+
const a = attrs;
|
|
10276
|
+
if (a.type === import_types39.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
10277
|
+
found = id;
|
|
10278
|
+
}
|
|
10279
|
+
});
|
|
10280
|
+
return found;
|
|
10281
|
+
}
|
|
10282
|
+
function findMatchingRouteNode(graph, serviceName, method, path50) {
|
|
10283
|
+
const normalizedPath = normalizePathTemplate(path50);
|
|
10284
|
+
let found = null;
|
|
10285
|
+
graph.forEachNode((id, attrs) => {
|
|
10286
|
+
if (found) return;
|
|
10287
|
+
const a = attrs;
|
|
10288
|
+
if (a.type !== import_types39.NodeType.RouteNode || a.service !== serviceName) return;
|
|
10289
|
+
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
10290
|
+
const routeMethod = (a.method ?? "").toUpperCase();
|
|
10291
|
+
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
10292
|
+
found = id;
|
|
10293
|
+
});
|
|
10294
|
+
return found;
|
|
10295
|
+
}
|
|
10296
|
+
function createCloudflareResolveTarget(config, graph) {
|
|
10004
10297
|
return (signal) => {
|
|
10005
10298
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
10006
|
-
const
|
|
10007
|
-
|
|
10299
|
+
const scriptName = signal.targetName;
|
|
10300
|
+
const { method, path: path50 } = signal;
|
|
10301
|
+
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
10302
|
+
if (!method || !path50) return wholeFileId;
|
|
10303
|
+
return findMatchingRouteNode(graph, serviceName, method, path50) ?? wholeFileId;
|
|
10304
|
+
};
|
|
10305
|
+
const mapping = config.workers?.[scriptName];
|
|
10306
|
+
if (mapping) {
|
|
10307
|
+
const wholeFileId = (0, import_types39.fileId)(mapping.service, mapping.entryFile);
|
|
10308
|
+
return {
|
|
10309
|
+
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
10310
|
+
serviceName: mapping.service,
|
|
10311
|
+
edgeType: import_types39.EdgeType.CALLS
|
|
10312
|
+
};
|
|
10313
|
+
}
|
|
10314
|
+
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
10315
|
+
if (taggedFileId) {
|
|
10316
|
+
const fileNode = graph.getNodeAttributes(taggedFileId);
|
|
10317
|
+
return {
|
|
10318
|
+
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
10319
|
+
serviceName: fileNode.service,
|
|
10320
|
+
edgeType: import_types39.EdgeType.CALLS
|
|
10321
|
+
};
|
|
10322
|
+
}
|
|
10008
10323
|
return {
|
|
10009
|
-
targetNodeId: (0,
|
|
10010
|
-
serviceName:
|
|
10011
|
-
edgeType:
|
|
10324
|
+
targetNodeId: (0, import_types39.infraId)("cloudflare-worker", scriptName),
|
|
10325
|
+
serviceName: scriptName,
|
|
10326
|
+
edgeType: import_types39.EdgeType.CALLS,
|
|
10327
|
+
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
10012
10328
|
};
|
|
10013
10329
|
};
|
|
10014
10330
|
}
|
|
@@ -10016,8 +10332,8 @@ function createCloudflareResolveTarget(config) {
|
|
|
10016
10332
|
// src/connectors-config.ts
|
|
10017
10333
|
init_cjs_shims();
|
|
10018
10334
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10019
|
-
var
|
|
10020
|
-
var
|
|
10335
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
10336
|
+
var import_node_fs26 = require("fs");
|
|
10021
10337
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10022
10338
|
var EnvRefUnsetError = class extends Error {
|
|
10023
10339
|
ref;
|
|
@@ -10031,17 +10347,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10031
10347
|
};
|
|
10032
10348
|
function neatHome2() {
|
|
10033
10349
|
const override = process.env.NEAT_HOME;
|
|
10034
|
-
if (override && override.length > 0) return
|
|
10035
|
-
return
|
|
10350
|
+
if (override && override.length > 0) return import_node_path45.default.resolve(override);
|
|
10351
|
+
return import_node_path45.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10036
10352
|
}
|
|
10037
10353
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10038
|
-
return
|
|
10354
|
+
return import_node_path45.default.join(home, "connectors.json");
|
|
10039
10355
|
}
|
|
10040
10356
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10041
10357
|
async function warnIfModeLooserThan0600(file) {
|
|
10042
10358
|
if (process.platform === "win32") return;
|
|
10043
10359
|
try {
|
|
10044
|
-
const stat = await
|
|
10360
|
+
const stat = await import_node_fs26.promises.stat(file);
|
|
10045
10361
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
10046
10362
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
10047
10363
|
console.warn(
|
|
@@ -10055,7 +10371,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
10055
10371
|
const file = connectorsConfigPath(home);
|
|
10056
10372
|
let raw;
|
|
10057
10373
|
try {
|
|
10058
|
-
raw = await
|
|
10374
|
+
raw = await import_node_fs26.promises.readFile(file, "utf8");
|
|
10059
10375
|
} catch (err) {
|
|
10060
10376
|
if (err.code === "ENOENT") {
|
|
10061
10377
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -10277,12 +10593,16 @@ var PROVIDER_DISPATCH = {
|
|
|
10277
10593
|
provider: "cloudflare",
|
|
10278
10594
|
primaryCredentialKey: "apiToken",
|
|
10279
10595
|
requiredCredentialFields: ["apiToken"],
|
|
10280
|
-
|
|
10281
|
-
|
|
10596
|
+
// `workers` dropped as a required field (ADR-133) — the mapping is now
|
|
10597
|
+
// derived from the extracted graph's platform tag; an `options.workers`
|
|
10598
|
+
// entry still works as an explicit override
|
|
10599
|
+
// (CloudflareConnectorConfig.workers).
|
|
10600
|
+
requiredOptionFields: ["accountId"],
|
|
10601
|
+
build(graph, options) {
|
|
10282
10602
|
const config = options;
|
|
10283
10603
|
return {
|
|
10284
10604
|
connector: new CloudflareConnector(config),
|
|
10285
|
-
resolveTarget: createCloudflareResolveTarget(config)
|
|
10605
|
+
resolveTarget: createCloudflareResolveTarget(config, graph)
|
|
10286
10606
|
};
|
|
10287
10607
|
},
|
|
10288
10608
|
// GET /user/tokens/verify — Cloudflare's own purpose-built "is this API
|
|
@@ -10379,8 +10699,8 @@ init_auth();
|
|
|
10379
10699
|
|
|
10380
10700
|
// src/unrouted.ts
|
|
10381
10701
|
init_cjs_shims();
|
|
10382
|
-
var
|
|
10383
|
-
var
|
|
10702
|
+
var import_node_fs27 = require("fs");
|
|
10703
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
10384
10704
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
10385
10705
|
return {
|
|
10386
10706
|
timestamp: now.toISOString(),
|
|
@@ -10390,34 +10710,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
10390
10710
|
};
|
|
10391
10711
|
}
|
|
10392
10712
|
async function appendUnroutedSpan(neatHome4, record) {
|
|
10393
|
-
const target =
|
|
10394
|
-
await
|
|
10395
|
-
await
|
|
10713
|
+
const target = import_node_path46.default.join(neatHome4, "errors.ndjson");
|
|
10714
|
+
await import_node_fs27.promises.mkdir(neatHome4, { recursive: true });
|
|
10715
|
+
await import_node_fs27.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
10396
10716
|
}
|
|
10397
10717
|
function unroutedErrorsPath(neatHome4) {
|
|
10398
|
-
return
|
|
10718
|
+
return import_node_path46.default.join(neatHome4, "errors.ndjson");
|
|
10399
10719
|
}
|
|
10400
10720
|
|
|
10401
10721
|
// src/daemon.ts
|
|
10402
|
-
var
|
|
10722
|
+
var import_types42 = require("@neat.is/types");
|
|
10403
10723
|
function daemonJsonPath(scanPath) {
|
|
10404
|
-
return
|
|
10724
|
+
return import_node_path47.default.join(scanPath, "neat-out", "daemon.json");
|
|
10405
10725
|
}
|
|
10406
10726
|
function daemonsDiscoveryDir(home) {
|
|
10407
10727
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
10408
|
-
return
|
|
10728
|
+
return import_node_path47.default.join(base, "daemons");
|
|
10409
10729
|
}
|
|
10410
10730
|
function daemonDiscoveryPath(project, home) {
|
|
10411
|
-
return
|
|
10731
|
+
return import_node_path47.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
10412
10732
|
}
|
|
10413
10733
|
function sanitizeDiscoveryName(project) {
|
|
10414
10734
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
10415
10735
|
}
|
|
10416
10736
|
function neatHomeFromEnv() {
|
|
10417
10737
|
const env = process.env.NEAT_HOME;
|
|
10418
|
-
if (env && env.length > 0) return
|
|
10738
|
+
if (env && env.length > 0) return import_node_path47.default.resolve(env);
|
|
10419
10739
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10420
|
-
return
|
|
10740
|
+
return import_node_path47.default.join(home, ".neat");
|
|
10421
10741
|
}
|
|
10422
10742
|
function resolveNeatVersion() {
|
|
10423
10743
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -10449,7 +10769,7 @@ async function clearDaemonRecord(record, home) {
|
|
|
10449
10769
|
} catch {
|
|
10450
10770
|
}
|
|
10451
10771
|
try {
|
|
10452
|
-
await
|
|
10772
|
+
await import_node_fs28.promises.unlink(daemonDiscoveryPath(record.project, home));
|
|
10453
10773
|
} catch {
|
|
10454
10774
|
}
|
|
10455
10775
|
}
|
|
@@ -10458,12 +10778,12 @@ function reconcileDaemonRecordSync(record, home) {
|
|
|
10458
10778
|
const stopped = { ...record, status: "stopped" };
|
|
10459
10779
|
const target = daemonJsonPath(record.projectPath);
|
|
10460
10780
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
10461
|
-
(0,
|
|
10462
|
-
(0,
|
|
10781
|
+
(0, import_node_fs28.writeFileSync)(tmp, JSON.stringify(stopped, null, 2) + "\n");
|
|
10782
|
+
(0, import_node_fs28.renameSync)(tmp, target);
|
|
10463
10783
|
} catch {
|
|
10464
10784
|
}
|
|
10465
10785
|
try {
|
|
10466
|
-
(0,
|
|
10786
|
+
(0, import_node_fs28.unlinkSync)(daemonDiscoveryPath(record.project, home));
|
|
10467
10787
|
} catch {
|
|
10468
10788
|
}
|
|
10469
10789
|
}
|
|
@@ -10486,11 +10806,11 @@ function teardownSlot(slot) {
|
|
|
10486
10806
|
}
|
|
10487
10807
|
}
|
|
10488
10808
|
function neatHomeFor(opts) {
|
|
10489
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
10809
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path47.default.resolve(opts.neatHome);
|
|
10490
10810
|
const env = process.env.NEAT_HOME;
|
|
10491
|
-
if (env && env.length > 0) return
|
|
10811
|
+
if (env && env.length > 0) return import_node_path47.default.resolve(env);
|
|
10492
10812
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10493
|
-
return
|
|
10813
|
+
return import_node_path47.default.join(home, ".neat");
|
|
10494
10814
|
}
|
|
10495
10815
|
function routeSpanToProject(serviceName, projects) {
|
|
10496
10816
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -10534,13 +10854,13 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
10534
10854
|
if (!serviceName) return true;
|
|
10535
10855
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
10536
10856
|
return graph.someNode(
|
|
10537
|
-
(_id, attrs) => attrs.type ===
|
|
10857
|
+
(_id, attrs) => attrs.type === import_types42.NodeType.ServiceNode && attrs.name === serviceName
|
|
10538
10858
|
);
|
|
10539
10859
|
}
|
|
10540
10860
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
10541
|
-
const paths = pathsForProject(entry2.name,
|
|
10861
|
+
const paths = pathsForProject(entry2.name, import_node_path47.default.join(entry2.path, "neat-out"));
|
|
10542
10862
|
try {
|
|
10543
|
-
const stat = await
|
|
10863
|
+
const stat = await import_node_fs28.promises.stat(entry2.path);
|
|
10544
10864
|
if (!stat.isDirectory()) {
|
|
10545
10865
|
throw new Error(`registered path ${entry2.path} is not a directory`);
|
|
10546
10866
|
}
|
|
@@ -10665,7 +10985,7 @@ async function startDaemon(opts = {}) {
|
|
|
10665
10985
|
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;
|
|
10666
10986
|
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;
|
|
10667
10987
|
const singleProject = projectArg;
|
|
10668
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
10988
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path47.default.resolve(projectPathArg) : null;
|
|
10669
10989
|
if (singleProject && !singleProjectPath) {
|
|
10670
10990
|
throw new Error(
|
|
10671
10991
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -10673,14 +10993,14 @@ async function startDaemon(opts = {}) {
|
|
|
10673
10993
|
}
|
|
10674
10994
|
if (!singleProject) {
|
|
10675
10995
|
try {
|
|
10676
|
-
await
|
|
10996
|
+
await import_node_fs28.promises.access(regPath);
|
|
10677
10997
|
} catch {
|
|
10678
10998
|
throw new Error(
|
|
10679
10999
|
`neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
|
|
10680
11000
|
);
|
|
10681
11001
|
}
|
|
10682
11002
|
}
|
|
10683
|
-
const pidPath =
|
|
11003
|
+
const pidPath = import_node_path47.default.join(home, "neatd.pid");
|
|
10684
11004
|
await writeAtomically(pidPath, `${process.pid}
|
|
10685
11005
|
`);
|
|
10686
11006
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -10874,7 +11194,7 @@ async function startDaemon(opts = {}) {
|
|
|
10874
11194
|
}
|
|
10875
11195
|
if (restApp) await restApp.close().catch(() => {
|
|
10876
11196
|
});
|
|
10877
|
-
await
|
|
11197
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
10878
11198
|
});
|
|
10879
11199
|
throw new Error(
|
|
10880
11200
|
`neatd: failed to bind REST on port ${restPort} \u2014 ${err.message}`
|
|
@@ -11000,7 +11320,7 @@ async function startDaemon(opts = {}) {
|
|
|
11000
11320
|
});
|
|
11001
11321
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
11002
11322
|
});
|
|
11003
|
-
await
|
|
11323
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
11004
11324
|
});
|
|
11005
11325
|
throw new Error(
|
|
11006
11326
|
`neatd: failed to bind OTLP on port ${otlpPort} \u2014 ${err.message}`
|
|
@@ -11035,7 +11355,7 @@ async function startDaemon(opts = {}) {
|
|
|
11035
11355
|
});
|
|
11036
11356
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
11037
11357
|
});
|
|
11038
|
-
await
|
|
11358
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
11039
11359
|
});
|
|
11040
11360
|
throw new Error(
|
|
11041
11361
|
`neatd: failed to write daemon.json for "${singleProject}" \u2014 ${err.message}`
|
|
@@ -11082,9 +11402,9 @@ async function startDaemon(opts = {}) {
|
|
|
11082
11402
|
let registryWatcher = null;
|
|
11083
11403
|
let reloadTimer = null;
|
|
11084
11404
|
if (!singleProject) try {
|
|
11085
|
-
const regDir =
|
|
11086
|
-
const regBase =
|
|
11087
|
-
registryWatcher = (0,
|
|
11405
|
+
const regDir = import_node_path47.default.dirname(regPath);
|
|
11406
|
+
const regBase = import_node_path47.default.basename(regPath);
|
|
11407
|
+
registryWatcher = (0, import_node_fs28.watch)(regDir, (_eventType, filename) => {
|
|
11088
11408
|
if (filename !== null && filename !== regBase) return;
|
|
11089
11409
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
11090
11410
|
reloadTimer = setTimeout(() => {
|
|
@@ -11133,7 +11453,7 @@ async function startDaemon(opts = {}) {
|
|
|
11133
11453
|
if (daemonRecord) {
|
|
11134
11454
|
await clearDaemonRecord(daemonRecord, home);
|
|
11135
11455
|
}
|
|
11136
|
-
await
|
|
11456
|
+
await import_node_fs28.promises.unlink(pidPath).catch(() => {
|
|
11137
11457
|
});
|
|
11138
11458
|
};
|
|
11139
11459
|
return {
|
|
@@ -11156,9 +11476,9 @@ init_auth();
|
|
|
11156
11476
|
// src/web-spawn.ts
|
|
11157
11477
|
init_cjs_shims();
|
|
11158
11478
|
var import_node_child_process2 = require("child_process");
|
|
11159
|
-
var
|
|
11479
|
+
var import_node_fs29 = require("fs");
|
|
11160
11480
|
var import_node_net = __toESM(require("net"), 1);
|
|
11161
|
-
var
|
|
11481
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11162
11482
|
var DEFAULT_WEB_PORT = 6328;
|
|
11163
11483
|
var DEFAULT_REST_PORT = 8080;
|
|
11164
11484
|
function asValidPort(value) {
|
|
@@ -11167,11 +11487,11 @@ function asValidPort(value) {
|
|
|
11167
11487
|
}
|
|
11168
11488
|
function projectRoot() {
|
|
11169
11489
|
const fromEnv = process.env.NEAT_SCAN_PATH;
|
|
11170
|
-
return
|
|
11490
|
+
return import_node_path48.default.resolve(fromEnv && fromEnv.length > 0 ? fromEnv : process.cwd());
|
|
11171
11491
|
}
|
|
11172
11492
|
async function readDaemonPorts(root) {
|
|
11173
11493
|
try {
|
|
11174
|
-
const raw = await
|
|
11494
|
+
const raw = await import_node_fs29.promises.readFile(import_node_path48.default.join(root, "neat-out", "daemon.json"), "utf8");
|
|
11175
11495
|
const parsed = JSON.parse(raw);
|
|
11176
11496
|
const ports = parsed?.ports ?? {};
|
|
11177
11497
|
return { web: asValidPort(ports.web), rest: asValidPort(ports.rest) };
|
|
@@ -11216,10 +11536,10 @@ function resolveWebPackageDir() {
|
|
|
11216
11536
|
eval("require")
|
|
11217
11537
|
);
|
|
11218
11538
|
const pkgJsonPath = req.resolve("@neat.is/web/package.json");
|
|
11219
|
-
return
|
|
11539
|
+
return import_node_path48.default.dirname(pkgJsonPath);
|
|
11220
11540
|
}
|
|
11221
11541
|
function resolveStandaloneServerEntry(webDir) {
|
|
11222
|
-
return
|
|
11542
|
+
return import_node_path48.default.join(webDir, ".next/standalone/packages/web/server.js");
|
|
11223
11543
|
}
|
|
11224
11544
|
async function pickInternalPort() {
|
|
11225
11545
|
return new Promise((resolve, reject) => {
|
|
@@ -11272,7 +11592,7 @@ async function spawnWebUI(restPort, opts = {}) {
|
|
|
11272
11592
|
NEAT_API_URL: apiUrl
|
|
11273
11593
|
};
|
|
11274
11594
|
child = (0, import_node_child_process2.spawn)(process.execPath, [serverEntry], {
|
|
11275
|
-
cwd:
|
|
11595
|
+
cwd: import_node_path48.default.dirname(serverEntry),
|
|
11276
11596
|
env,
|
|
11277
11597
|
stdio: ["ignore", "inherit", "inherit"],
|
|
11278
11598
|
detached: false
|
|
@@ -11448,14 +11768,14 @@ function localVersion() {
|
|
|
11448
11768
|
}
|
|
11449
11769
|
function neatHome3() {
|
|
11450
11770
|
if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {
|
|
11451
|
-
return
|
|
11771
|
+
return import_node_path49.default.resolve(process.env.NEAT_HOME);
|
|
11452
11772
|
}
|
|
11453
11773
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
11454
|
-
return
|
|
11774
|
+
return import_node_path49.default.join(home, ".neat");
|
|
11455
11775
|
}
|
|
11456
11776
|
async function readPid() {
|
|
11457
11777
|
try {
|
|
11458
|
-
const raw = await
|
|
11778
|
+
const raw = await import_node_fs30.promises.readFile(import_node_path49.default.join(neatHome3(), "neatd.pid"), "utf8");
|
|
11459
11779
|
const n = Number.parseInt(raw.trim(), 10);
|
|
11460
11780
|
return Number.isFinite(n) ? n : null;
|
|
11461
11781
|
} catch {
|