@neat.is/core 0.9.0 → 0.9.1
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-RDLDSIEY.js → chunk-UN7VFA4H.js} +1112 -382
- package/dist/chunk-UN7VFA4H.js.map +1 -0
- package/dist/{chunk-WMYVJXUF.js → chunk-YKQB622D.js} +2 -2
- package/dist/cli.cjs +1648 -916
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1311 -579
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +1327 -595
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +1214 -482
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-RDLDSIEY.js.map +0 -1
- /package/dist/{chunk-WMYVJXUF.js.map → chunk-YKQB622D.js.map} +0 -0
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 path78 = (req2.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path78) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path78)) {
|
|
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_path52.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path52.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_path52, 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_path52 = __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);
|
|
@@ -415,8 +415,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
415
415
|
const v = attrs[key];
|
|
416
416
|
if (typeof v === "string" && v.length > 0) {
|
|
417
417
|
const q = v.indexOf("?");
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
418
|
+
const path78 = q === -1 ? v : v.slice(0, q);
|
|
419
|
+
if (path78.length > 0) return path78;
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
return void 0;
|
|
@@ -478,10 +478,10 @@ function parseOtlpRequest(body) {
|
|
|
478
478
|
return out;
|
|
479
479
|
}
|
|
480
480
|
function loadProtoRoot() {
|
|
481
|
-
const here =
|
|
482
|
-
const protoRoot =
|
|
481
|
+
const here = import_node_path53.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
482
|
+
const protoRoot = import_node_path53.default.resolve(here, "..", "proto");
|
|
483
483
|
const root = new import_protobufjs.default.Root();
|
|
484
|
-
root.resolvePath = (_origin, target) =>
|
|
484
|
+
root.resolvePath = (_origin, target) => import_node_path53.default.resolve(protoRoot, target);
|
|
485
485
|
root.loadSync(
|
|
486
486
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
487
487
|
{ keepCase: true }
|
|
@@ -728,12 +728,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
728
728
|
}
|
|
729
729
|
}
|
|
730
730
|
}
|
|
731
|
-
var
|
|
731
|
+
var import_node_path53, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
732
732
|
var init_otel = __esm({
|
|
733
733
|
"src/otel.ts"() {
|
|
734
734
|
"use strict";
|
|
735
735
|
init_cjs_shims();
|
|
736
|
-
|
|
736
|
+
import_node_path53 = __toESM(require("path"), 1);
|
|
737
737
|
import_node_url2 = require("url");
|
|
738
738
|
import_fastify = __toESM(require("fastify"), 1);
|
|
739
739
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -756,14 +756,14 @@ __export(neatd_exports, {
|
|
|
756
756
|
});
|
|
757
757
|
module.exports = __toCommonJS(neatd_exports);
|
|
758
758
|
init_cjs_shims();
|
|
759
|
-
var
|
|
760
|
-
var
|
|
759
|
+
var import_node_fs42 = require("fs");
|
|
760
|
+
var import_node_path77 = __toESM(require("path"), 1);
|
|
761
761
|
var import_node_module2 = require("module");
|
|
762
762
|
|
|
763
763
|
// src/daemon.ts
|
|
764
764
|
init_cjs_shims();
|
|
765
|
-
var
|
|
766
|
-
var
|
|
765
|
+
var import_node_fs40 = require("fs");
|
|
766
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
767
767
|
var import_node_module = require("module");
|
|
768
768
|
|
|
769
769
|
// src/graph.ts
|
|
@@ -1296,19 +1296,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1296
1296
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1297
1297
|
let best = { path: [start], edges: [] };
|
|
1298
1298
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1299
|
-
function step(node,
|
|
1300
|
-
if (
|
|
1301
|
-
best = { path: [...
|
|
1299
|
+
function step(node, path78, edges) {
|
|
1300
|
+
if (path78.length > best.path.length) {
|
|
1301
|
+
best = { path: [...path78], edges: [...edges] };
|
|
1302
1302
|
}
|
|
1303
|
-
if (
|
|
1303
|
+
if (path78.length - 1 >= maxDepth) return;
|
|
1304
1304
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1305
1305
|
for (const [srcId, edge] of incoming) {
|
|
1306
1306
|
if (visited.has(srcId)) continue;
|
|
1307
1307
|
visited.add(srcId);
|
|
1308
|
-
|
|
1308
|
+
path78.push(srcId);
|
|
1309
1309
|
edges.push(edge);
|
|
1310
|
-
step(srcId,
|
|
1311
|
-
|
|
1310
|
+
step(srcId, path78, edges);
|
|
1311
|
+
path78.pop();
|
|
1312
1312
|
edges.pop();
|
|
1313
1313
|
visited.delete(srcId);
|
|
1314
1314
|
}
|
|
@@ -1316,11 +1316,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1316
1316
|
step(start, [start], []);
|
|
1317
1317
|
return best;
|
|
1318
1318
|
}
|
|
1319
|
-
function databaseRootCauseShape(graph, origin,
|
|
1319
|
+
function databaseRootCauseShape(graph, origin, walk10) {
|
|
1320
1320
|
const targetDb = origin;
|
|
1321
1321
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1322
1322
|
if (candidatePairs.length === 0) return null;
|
|
1323
|
-
for (const id of
|
|
1323
|
+
for (const id of walk10.path) {
|
|
1324
1324
|
const owner = resolveOwningService(graph, id);
|
|
1325
1325
|
if (!owner) continue;
|
|
1326
1326
|
const { id: serviceId15, svc } = owner;
|
|
@@ -1347,8 +1347,8 @@ function databaseRootCauseShape(graph, origin, walk9) {
|
|
|
1347
1347
|
}
|
|
1348
1348
|
return null;
|
|
1349
1349
|
}
|
|
1350
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1351
|
-
for (const id of
|
|
1350
|
+
function serviceRootCauseShape(graph, _origin, walk10) {
|
|
1351
|
+
for (const id of walk10.path) {
|
|
1352
1352
|
const owner = resolveOwningService(graph, id);
|
|
1353
1353
|
if (!owner) continue;
|
|
1354
1354
|
const { id: serviceId15, svc } = owner;
|
|
@@ -1384,15 +1384,15 @@ function serviceRootCauseShape(graph, _origin, walk9) {
|
|
|
1384
1384
|
}
|
|
1385
1385
|
return null;
|
|
1386
1386
|
}
|
|
1387
|
-
function fileRootCauseShape(graph, origin,
|
|
1387
|
+
function fileRootCauseShape(graph, origin, walk10) {
|
|
1388
1388
|
const owner = resolveOwningService(graph, origin.id);
|
|
1389
1389
|
if (!owner) return null;
|
|
1390
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1390
|
+
return serviceRootCauseShape(graph, owner.svc, walk10);
|
|
1391
1391
|
}
|
|
1392
|
-
function symbolRootCauseShape(graph, origin,
|
|
1392
|
+
function symbolRootCauseShape(graph, origin, walk10) {
|
|
1393
1393
|
const owner = resolveOwningService(graph, origin.id);
|
|
1394
1394
|
if (!owner) return null;
|
|
1395
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1395
|
+
return serviceRootCauseShape(graph, owner.svc, walk10);
|
|
1396
1396
|
}
|
|
1397
1397
|
var rootCauseShapes = {
|
|
1398
1398
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1405,25 +1405,29 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1405
1405
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1406
1406
|
const shape = rootCauseShapes[origin.type];
|
|
1407
1407
|
if (shape) {
|
|
1408
|
-
const
|
|
1409
|
-
const match = shape(graph, origin,
|
|
1408
|
+
const walk10 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1409
|
+
const match = shape(graph, origin, walk10);
|
|
1410
1410
|
if (match) {
|
|
1411
1411
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1412
|
-
return
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1412
|
+
return {
|
|
1413
|
+
source: "compat",
|
|
1414
|
+
result: import_types.RootCauseResultSchema.parse({
|
|
1415
|
+
rootCauseNode: match.rootCauseNode,
|
|
1416
|
+
rootCauseReason: reason,
|
|
1417
|
+
traversalPath: walk10.path,
|
|
1418
|
+
edgeProvenances: walk10.edges.map((e) => e.provenance),
|
|
1419
|
+
confidence: confidenceFromMix(walk10.edges),
|
|
1420
|
+
fixRecommendation: match.fixRecommendation
|
|
1421
|
+
})
|
|
1422
|
+
};
|
|
1420
1423
|
}
|
|
1421
1424
|
}
|
|
1422
1425
|
if (origin.type === import_types.NodeType.ServiceNode) {
|
|
1423
1426
|
const crossService = crossServiceRootCause(graph, errorNodeId, incidents, errorEvent);
|
|
1424
|
-
if (crossService) return crossService;
|
|
1427
|
+
if (crossService) return { result: crossService, source: "cross-service" };
|
|
1425
1428
|
}
|
|
1426
|
-
|
|
1429
|
+
const incident = rootCauseFromIncidents(errorNodeId, incidents, errorEvent);
|
|
1430
|
+
return incident ? { result: incident, source: "incident" } : null;
|
|
1427
1431
|
}
|
|
1428
1432
|
var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
|
|
1429
1433
|
function incidentMatchesNode(ev, nodeId) {
|
|
@@ -1519,26 +1523,75 @@ function dominantFailingCall(graph, serviceId15, visited) {
|
|
|
1519
1523
|
return best;
|
|
1520
1524
|
}
|
|
1521
1525
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1522
|
-
const
|
|
1526
|
+
const path78 = [originServiceId];
|
|
1523
1527
|
const edges = [];
|
|
1524
1528
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1525
1529
|
let current = originServiceId;
|
|
1526
1530
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1527
1531
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1528
1532
|
if (!hop) break;
|
|
1529
|
-
|
|
1533
|
+
path78.push(hop.nextService);
|
|
1530
1534
|
edges.push(hop.edge);
|
|
1531
1535
|
visited.add(hop.nextService);
|
|
1532
1536
|
current = hop.nextService;
|
|
1533
1537
|
}
|
|
1534
1538
|
if (edges.length === 0) return null;
|
|
1535
|
-
return { path:
|
|
1539
|
+
return { path: path78, edges, culprit: current };
|
|
1540
|
+
}
|
|
1541
|
+
function isStaleCallEdge(e) {
|
|
1542
|
+
return e.type === import_types.EdgeType.CALLS && e.provenance === import_types.Provenance.STALE;
|
|
1543
|
+
}
|
|
1544
|
+
function staleCallDominates(e, id, curEdge, curId) {
|
|
1545
|
+
const ev = e.signal?.spanCount ?? e.callCount ?? 0;
|
|
1546
|
+
const cv = curEdge.signal?.spanCount ?? curEdge.callCount ?? 0;
|
|
1547
|
+
if (ev !== cv) return ev > cv;
|
|
1548
|
+
return id < curId;
|
|
1549
|
+
}
|
|
1550
|
+
function dominantStaleCall(graph, serviceId15, visited) {
|
|
1551
|
+
const bestByCallee = /* @__PURE__ */ new Map();
|
|
1552
|
+
for (const src of callSourcesForService(graph, serviceId15)) {
|
|
1553
|
+
for (const edgeId of graph.outboundEdges(src)) {
|
|
1554
|
+
const e = graph.getEdgeAttributes(edgeId);
|
|
1555
|
+
if (e.type !== import_types.EdgeType.CALLS) continue;
|
|
1556
|
+
if (isFrontierNode(graph, e.target)) continue;
|
|
1557
|
+
const owner = resolveOwningService(graph, e.target);
|
|
1558
|
+
if (!owner || visited.has(owner.id)) continue;
|
|
1559
|
+
const cur = bestByCallee.get(owner.id);
|
|
1560
|
+
if (!cur || import_types.PROV_RANK[e.provenance] > import_types.PROV_RANK[cur.provenance]) {
|
|
1561
|
+
bestByCallee.set(owner.id, e);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
let best = null;
|
|
1566
|
+
for (const [id, edge] of bestByCallee) {
|
|
1567
|
+
if (!isStaleCallEdge(edge)) continue;
|
|
1568
|
+
if (!best || staleCallDominates(edge, id, best.edge, best.nextService)) {
|
|
1569
|
+
best = { nextService: id, edge };
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
return best;
|
|
1573
|
+
}
|
|
1574
|
+
function followStaleCallChain(graph, originServiceId, maxDepth) {
|
|
1575
|
+
const path78 = [originServiceId];
|
|
1576
|
+
const edges = [];
|
|
1577
|
+
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1578
|
+
let current = originServiceId;
|
|
1579
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1580
|
+
const hop = dominantStaleCall(graph, current, visited);
|
|
1581
|
+
if (!hop) break;
|
|
1582
|
+
path78.push(hop.nextService);
|
|
1583
|
+
edges.push(hop.edge);
|
|
1584
|
+
visited.add(hop.nextService);
|
|
1585
|
+
current = hop.nextService;
|
|
1586
|
+
}
|
|
1587
|
+
if (edges.length === 0) return null;
|
|
1588
|
+
return { path: path78, edges, culprit: current };
|
|
1536
1589
|
}
|
|
1537
1590
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1538
1591
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1539
1592
|
if (!chain) return null;
|
|
1540
1593
|
const culprit = chain.culprit;
|
|
1541
|
-
const
|
|
1594
|
+
const path78 = [...chain.path];
|
|
1542
1595
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1543
1596
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1544
1597
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1546,14 +1599,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1546
1599
|
if (loc) {
|
|
1547
1600
|
let rootCauseNode = culprit;
|
|
1548
1601
|
if (loc.fileNode) {
|
|
1549
|
-
|
|
1602
|
+
path78.push(loc.fileNode);
|
|
1550
1603
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1551
1604
|
rootCauseNode = loc.fileNode;
|
|
1552
1605
|
}
|
|
1553
1606
|
return import_types.RootCauseResultSchema.parse({
|
|
1554
1607
|
rootCauseNode,
|
|
1555
1608
|
rootCauseReason: loc.rootCauseReason,
|
|
1556
|
-
traversalPath:
|
|
1609
|
+
traversalPath: path78,
|
|
1557
1610
|
edgeProvenances,
|
|
1558
1611
|
confidence,
|
|
1559
1612
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1565,7 +1618,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1565
1618
|
return import_types.RootCauseResultSchema.parse({
|
|
1566
1619
|
rootCauseNode: culprit,
|
|
1567
1620
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1568
|
-
traversalPath:
|
|
1621
|
+
traversalPath: path78,
|
|
1569
1622
|
edgeProvenances,
|
|
1570
1623
|
confidence,
|
|
1571
1624
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -1952,17 +2005,20 @@ function displayNameOf(nodeId) {
|
|
|
1952
2005
|
return nodeId.replace(/^[a-z]+:/, "");
|
|
1953
2006
|
}
|
|
1954
2007
|
function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
|
|
1955
|
-
const
|
|
1956
|
-
if (!
|
|
2008
|
+
const tagged = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
|
|
2009
|
+
if (!tagged) return null;
|
|
1957
2010
|
const navigation = opts?.navigation ?? process.env.NEAT_RCA_NAVIGATION !== "0";
|
|
1958
|
-
if (!navigation) return
|
|
1959
|
-
return enrichWithNavigation(graph, errorNodeId,
|
|
2011
|
+
if (!navigation) return tagged.result;
|
|
2012
|
+
return enrichWithNavigation(graph, errorNodeId, tagged, incidents, opts?.now ?? Date.now());
|
|
1960
2013
|
}
|
|
1961
|
-
function enrichWithNavigation(graph, errorNodeId,
|
|
2014
|
+
function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
2015
|
+
const legacy = tagged.result;
|
|
1962
2016
|
const seedNode = legacy.rootCauseNode;
|
|
1963
2017
|
const seedCtx = graph.hasNode(seedNode) ? nodeContext(graph, seedNode, incidents, now) : null;
|
|
1964
2018
|
const lastProv = legacy.edgeProvenances[legacy.edgeProvenances.length - 1];
|
|
1965
2019
|
const candidates = [];
|
|
2020
|
+
const deadEndOnSymptom = tagged.source === "incident" && seedNode === errorNodeId && legacy.traversalPath.length === 1;
|
|
2021
|
+
const staleChain = deadEndOnSymptom && !(seedCtx && isVictimSeed(seedCtx)) ? followStaleCallChain(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH) : null;
|
|
1966
2022
|
if (seedCtx && isVictimSeed(seedCtx)) {
|
|
1967
2023
|
const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
|
|
1968
2024
|
const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
|
|
@@ -1987,6 +2043,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
1987
2043
|
confidence: Math.min(legacy.confidence, 0.4),
|
|
1988
2044
|
...lastProv ? { provenance: lastProv } : {}
|
|
1989
2045
|
});
|
|
2046
|
+
} else if (staleChain) {
|
|
2047
|
+
const culprit = staleChain.culprit;
|
|
2048
|
+
const culpritName = displayNameOf(culprit);
|
|
2049
|
+
const seedName = displayNameOf(seedNode);
|
|
2050
|
+
const staleConfidence = confidenceFromMix(staleChain.edges, now);
|
|
2051
|
+
candidates.push({
|
|
2052
|
+
node: culprit,
|
|
2053
|
+
classification: "primary-failure",
|
|
2054
|
+
reason: `${culpritName} is the stale-derived root cause (low confidence): live telemetry for this subgraph has gone quiet, but the last-observed topology traces the failure surfacing at ${seedName} downstream through a STALE call chain to ${culpritName}. Provenance is STALE, so confidence is capped low \u2014 restore instrumentation and re-run to confirm before acting.`,
|
|
2055
|
+
context: nodeContext(graph, culprit, incidents, now),
|
|
2056
|
+
confidence: staleConfidence,
|
|
2057
|
+
provenance: import_types.Provenance.STALE
|
|
2058
|
+
});
|
|
2059
|
+
candidates.push({
|
|
2060
|
+
node: seedNode,
|
|
2061
|
+
classification: "symptom-only",
|
|
2062
|
+
reason: `The failure surfaced here, but the only causal chain the graph still holds is STALE and runs downstream \u2014 ${seedName} is the surface of a stale-traced failure, not a proven origin.`,
|
|
2063
|
+
context: seedCtx ?? EMPTY_CONTEXT,
|
|
2064
|
+
confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.STALE),
|
|
2065
|
+
...lastProv ? { provenance: lastProv } : {}
|
|
2066
|
+
});
|
|
1990
2067
|
} else {
|
|
1991
2068
|
candidates.push({
|
|
1992
2069
|
node: seedNode,
|
|
@@ -2000,11 +2077,14 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
2000
2077
|
const top = candidates[0];
|
|
2001
2078
|
let traversalPath = legacy.traversalPath;
|
|
2002
2079
|
let edgeProvenances = legacy.edgeProvenances;
|
|
2003
|
-
if (top.node
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2080
|
+
if (staleChain && top.node === staleChain.culprit) {
|
|
2081
|
+
traversalPath = staleChain.path;
|
|
2082
|
+
edgeProvenances = staleChain.edges.map((e) => e.provenance);
|
|
2083
|
+
} else if (top.node !== seedNode) {
|
|
2084
|
+
const path78 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
|
|
2085
|
+
if (path78) {
|
|
2086
|
+
traversalPath = path78.nodes;
|
|
2087
|
+
edgeProvenances = path78.edges.map((e) => e.provenance);
|
|
2008
2088
|
} else {
|
|
2009
2089
|
traversalPath = [errorNodeId, top.node];
|
|
2010
2090
|
edgeProvenances = [top.provenance ?? import_types.Provenance.OBSERVED];
|
|
@@ -2026,6 +2106,9 @@ function fixRecommendationForTop(top, seedNode, legacy) {
|
|
|
2026
2106
|
return legacy.fixRecommendation;
|
|
2027
2107
|
}
|
|
2028
2108
|
const name = top.node.replace(/^service:/, "");
|
|
2109
|
+
if (top.provenance === import_types.Provenance.STALE) {
|
|
2110
|
+
return `Live telemetry for this path has gone quiet; the last-observed topology traces the failure downstream to ${name}. Restore instrumentation (or re-run with live traces) to confirm, then inspect ${name}.`;
|
|
2111
|
+
}
|
|
2029
2112
|
if (top.classification === "primary-failure") {
|
|
2030
2113
|
return `Reduce or throttle the load from ${name} (or scale the saturated downstream capacity it drives) \u2014 the failure originates at this overloading source, not the starved callee.`;
|
|
2031
2114
|
}
|
|
@@ -2544,6 +2627,7 @@ var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
|
2544
2627
|
var import_tree_sitter_go2 = __toESM(require("tree-sitter-go"), 1);
|
|
2545
2628
|
var import_tree_sitter_ruby = __toESM(require("tree-sitter-ruby"), 1);
|
|
2546
2629
|
var import_tree_sitter_php = __toESM(require("tree-sitter-php"), 1);
|
|
2630
|
+
var import_tree_sitter_rust = __toESM(require("tree-sitter-rust"), 1);
|
|
2547
2631
|
var import_types6 = require("@neat.is/types");
|
|
2548
2632
|
|
|
2549
2633
|
// src/extract/shared.ts
|
|
@@ -2824,7 +2908,7 @@ function buildServiceHostIndex(services) {
|
|
|
2824
2908
|
async function walkSourceFiles(dir, excludeDirs = []) {
|
|
2825
2909
|
const excluded = new Set(excludeDirs.map((d) => import_node_path5.default.resolve(d)));
|
|
2826
2910
|
const out = [];
|
|
2827
|
-
async function
|
|
2911
|
+
async function walk10(current) {
|
|
2828
2912
|
const entries = await import_node_fs5.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2829
2913
|
for (const entry2 of entries) {
|
|
2830
2914
|
const full = import_node_path5.default.join(current, entry2.name);
|
|
@@ -2832,7 +2916,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
2832
2916
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
2833
2917
|
if (excluded.has(import_node_path5.default.resolve(full))) continue;
|
|
2834
2918
|
if (await isPythonVenvDir(full)) continue;
|
|
2835
|
-
await
|
|
2919
|
+
await walk10(full);
|
|
2836
2920
|
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path5.default.extname(entry2.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
2837
2921
|
// would attribute our instrumentation imports to the user's service.
|
|
2838
2922
|
!isNeatAuthoredSourceFile(entry2.name)) {
|
|
@@ -2840,7 +2924,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
2840
2924
|
}
|
|
2841
2925
|
}
|
|
2842
2926
|
}
|
|
2843
|
-
await
|
|
2927
|
+
await walk10(dir);
|
|
2844
2928
|
return out;
|
|
2845
2929
|
}
|
|
2846
2930
|
async function loadSourceFiles(dir, excludeDirs = []) {
|
|
@@ -3360,6 +3444,11 @@ function makePhpParser() {
|
|
|
3360
3444
|
p.setLanguage(import_tree_sitter_php.default.php_only);
|
|
3361
3445
|
return p;
|
|
3362
3446
|
}
|
|
3447
|
+
function makeRustParser() {
|
|
3448
|
+
const p = new import_tree_sitter2.default();
|
|
3449
|
+
p.setLanguage(import_tree_sitter_rust.default);
|
|
3450
|
+
return p;
|
|
3451
|
+
}
|
|
3363
3452
|
var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
3364
3453
|
"get",
|
|
3365
3454
|
"post",
|
|
@@ -3431,8 +3520,8 @@ function chiRoutesFromSource(source, parser) {
|
|
|
3431
3520
|
chiWalk(tree.rootNode, "", out);
|
|
3432
3521
|
return out;
|
|
3433
3522
|
}
|
|
3434
|
-
function stripChiRegex(
|
|
3435
|
-
return
|
|
3523
|
+
function stripChiRegex(path78) {
|
|
3524
|
+
return path78.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
3436
3525
|
}
|
|
3437
3526
|
function chiWalk(node, prefix, out) {
|
|
3438
3527
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -4104,9 +4193,9 @@ function rubyRocketRoute(args) {
|
|
|
4104
4193
|
if (!pair || pair.type !== "pair") continue;
|
|
4105
4194
|
const k = pair.childForFieldName("key");
|
|
4106
4195
|
if (k?.type !== "string") continue;
|
|
4107
|
-
const
|
|
4108
|
-
if (
|
|
4109
|
-
return { path:
|
|
4196
|
+
const path78 = rubyLiteral(k);
|
|
4197
|
+
if (path78 === null) continue;
|
|
4198
|
+
return { path: path78, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
4110
4199
|
}
|
|
4111
4200
|
return null;
|
|
4112
4201
|
}
|
|
@@ -4276,6 +4365,48 @@ function railsRoutesFromSource(source, parser) {
|
|
|
4276
4365
|
});
|
|
4277
4366
|
return out;
|
|
4278
4367
|
}
|
|
4368
|
+
var SINATRA_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head"]);
|
|
4369
|
+
function sinatraRoutesFromSource(source, parser) {
|
|
4370
|
+
const tree = parseSource2(parser, source);
|
|
4371
|
+
if (!fileReferencesSinatra(tree.rootNode)) return [];
|
|
4372
|
+
const out = [];
|
|
4373
|
+
walk(tree.rootNode, (node) => {
|
|
4374
|
+
if (node.type !== "call") return;
|
|
4375
|
+
if (node.childForFieldName("receiver")) return;
|
|
4376
|
+
const method = node.childForFieldName("method")?.text;
|
|
4377
|
+
if (!method || !SINATRA_VERBS.has(method)) return;
|
|
4378
|
+
if (!node.childForFieldName("block")) return;
|
|
4379
|
+
const first = node.childForFieldName("arguments")?.namedChild(0);
|
|
4380
|
+
if (first?.type !== "string") return;
|
|
4381
|
+
const p = rubyLiteral(first);
|
|
4382
|
+
if (p === null || !p.startsWith("/")) return;
|
|
4383
|
+
out.push({
|
|
4384
|
+
method: method.toUpperCase(),
|
|
4385
|
+
pathTemplate: canonicalizeTemplate(p),
|
|
4386
|
+
line: node.startPosition.row + 1,
|
|
4387
|
+
framework: "sinatra"
|
|
4388
|
+
});
|
|
4389
|
+
});
|
|
4390
|
+
return out;
|
|
4391
|
+
}
|
|
4392
|
+
function fileReferencesSinatra(root) {
|
|
4393
|
+
let found = false;
|
|
4394
|
+
walk(root, (node) => {
|
|
4395
|
+
if (found) return;
|
|
4396
|
+
if (node.type === "call") {
|
|
4397
|
+
const m = node.childForFieldName("method")?.text;
|
|
4398
|
+
if (m === "require" || m === "require_relative") {
|
|
4399
|
+
const s = rubyLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
4400
|
+
if (s !== null && /^sinatra\b/.test(s)) found = true;
|
|
4401
|
+
}
|
|
4402
|
+
return;
|
|
4403
|
+
}
|
|
4404
|
+
if (node.type === "constant" && node.text === "Sinatra" || node.type === "scope_resolution" && node.text.startsWith("Sinatra")) {
|
|
4405
|
+
found = true;
|
|
4406
|
+
}
|
|
4407
|
+
});
|
|
4408
|
+
return found;
|
|
4409
|
+
}
|
|
4279
4410
|
var LARAVEL_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options"]);
|
|
4280
4411
|
var LARAVEL_RESOURCE_ROWS = [
|
|
4281
4412
|
{ action: "index", methods: ["GET"], suffix: "" },
|
|
@@ -4451,6 +4582,223 @@ function laravelRoutesFromSource(source, parser, basePrefix = "") {
|
|
|
4451
4582
|
}
|
|
4452
4583
|
return out;
|
|
4453
4584
|
}
|
|
4585
|
+
var SLIM_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head"]);
|
|
4586
|
+
function isSlimAppCtor(node) {
|
|
4587
|
+
if (!node) return false;
|
|
4588
|
+
if (node.type === "scoped_call_expression") {
|
|
4589
|
+
const scope = node.childForFieldName("scope")?.text ?? "";
|
|
4590
|
+
const name = node.childForFieldName("name")?.text;
|
|
4591
|
+
return name === "create" && (scope === "AppFactory" || scope.endsWith("\\AppFactory"));
|
|
4592
|
+
}
|
|
4593
|
+
if (node.type === "object_creation_expression") {
|
|
4594
|
+
const cls = node.namedChild(0)?.text ?? "";
|
|
4595
|
+
return cls === "App" || cls.endsWith("\\App") || cls.includes("Slim");
|
|
4596
|
+
}
|
|
4597
|
+
return false;
|
|
4598
|
+
}
|
|
4599
|
+
function isSlimAppType(node) {
|
|
4600
|
+
if (!node || node.type !== "named_type") return false;
|
|
4601
|
+
const text = node.text;
|
|
4602
|
+
return text === "App" || text.endsWith("\\App");
|
|
4603
|
+
}
|
|
4604
|
+
function collectSlimAppVars(root) {
|
|
4605
|
+
const vars = /* @__PURE__ */ new Set();
|
|
4606
|
+
walk(root, (node) => {
|
|
4607
|
+
if (node.type === "assignment_expression") {
|
|
4608
|
+
const left = node.childForFieldName("left");
|
|
4609
|
+
if (left?.type === "variable_name" && isSlimAppCtor(node.childForFieldName("right"))) {
|
|
4610
|
+
vars.add(left.text);
|
|
4611
|
+
}
|
|
4612
|
+
return;
|
|
4613
|
+
}
|
|
4614
|
+
if (node.type === "simple_parameter" && isSlimAppType(node.childForFieldName("type"))) {
|
|
4615
|
+
const name = node.childForFieldName("name");
|
|
4616
|
+
if (name?.type === "variable_name") vars.add(name.text);
|
|
4617
|
+
}
|
|
4618
|
+
});
|
|
4619
|
+
return vars;
|
|
4620
|
+
}
|
|
4621
|
+
function slimClosureParamVars(closure) {
|
|
4622
|
+
const out = ["$this"];
|
|
4623
|
+
for (let i = 0; i < closure.namedChildCount; i++) {
|
|
4624
|
+
const params = closure.namedChild(i);
|
|
4625
|
+
if (params?.type !== "formal_parameters") continue;
|
|
4626
|
+
for (let j = 0; j < params.namedChildCount; j++) {
|
|
4627
|
+
const param = params.namedChild(j);
|
|
4628
|
+
if (param?.type !== "simple_parameter") continue;
|
|
4629
|
+
for (let k = 0; k < param.namedChildCount; k++) {
|
|
4630
|
+
const v = param.namedChild(k);
|
|
4631
|
+
if (v?.type === "variable_name") {
|
|
4632
|
+
out.push(v.text);
|
|
4633
|
+
break;
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
return out;
|
|
4639
|
+
}
|
|
4640
|
+
function phpStringArray(node) {
|
|
4641
|
+
const out = [];
|
|
4642
|
+
if (node?.type !== "array_creation_expression") return out;
|
|
4643
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4644
|
+
const el = node.namedChild(i);
|
|
4645
|
+
if (el?.type !== "array_element_initializer") continue;
|
|
4646
|
+
const s = phpStaticString(el.namedChild(0));
|
|
4647
|
+
if (s !== null) out.push(s);
|
|
4648
|
+
}
|
|
4649
|
+
return out;
|
|
4650
|
+
}
|
|
4651
|
+
function slimRoutesFromSource(source, parser) {
|
|
4652
|
+
const tree = parseSource2(parser, source);
|
|
4653
|
+
const appVars = collectSlimAppVars(tree.rootNode);
|
|
4654
|
+
if (appVars.size === 0) return [];
|
|
4655
|
+
const out = [];
|
|
4656
|
+
slimWalk(tree.rootNode, "", appVars, out);
|
|
4657
|
+
return out;
|
|
4658
|
+
}
|
|
4659
|
+
function slimWalk(node, prefix, appVars, out) {
|
|
4660
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4661
|
+
const child = node.namedChild(i);
|
|
4662
|
+
if (child) slimHandle(child, prefix, appVars, out);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
function slimHandle(node, prefix, appVars, out) {
|
|
4666
|
+
if (node.type === "member_call_expression") {
|
|
4667
|
+
const obj = node.childForFieldName("object");
|
|
4668
|
+
const method = node.childForFieldName("name")?.text;
|
|
4669
|
+
const args = node.childForFieldName("arguments");
|
|
4670
|
+
if (obj?.type === "variable_name" && method && appVars.has(obj.text)) {
|
|
4671
|
+
const line = node.startPosition.row + 1;
|
|
4672
|
+
if (method === "group") {
|
|
4673
|
+
const groupPrefix = phpFirstString(args);
|
|
4674
|
+
const closure = laravelGroupClosure(args);
|
|
4675
|
+
if (groupPrefix !== null && closure) {
|
|
4676
|
+
const inner = new Set(appVars);
|
|
4677
|
+
for (const v of slimClosureParamVars(closure)) inner.add(v);
|
|
4678
|
+
const body = closure.childForFieldName("body");
|
|
4679
|
+
if (body) slimWalk(body, laravelJoinPath(prefix, groupPrefix), inner, out);
|
|
4680
|
+
}
|
|
4681
|
+
return;
|
|
4682
|
+
}
|
|
4683
|
+
if (SLIM_VERBS.has(method)) {
|
|
4684
|
+
const p = phpFirstString(args);
|
|
4685
|
+
if (p !== null) {
|
|
4686
|
+
out.push({
|
|
4687
|
+
method: method.toUpperCase(),
|
|
4688
|
+
pathTemplate: laravelJoinPath(prefix, p),
|
|
4689
|
+
line,
|
|
4690
|
+
framework: "slim"
|
|
4691
|
+
});
|
|
4692
|
+
}
|
|
4693
|
+
return;
|
|
4694
|
+
}
|
|
4695
|
+
if (method === "any") {
|
|
4696
|
+
const p = phpFirstString(args);
|
|
4697
|
+
if (p !== null) {
|
|
4698
|
+
out.push({ method: "ALL", pathTemplate: laravelJoinPath(prefix, p), line, framework: "slim" });
|
|
4699
|
+
}
|
|
4700
|
+
return;
|
|
4701
|
+
}
|
|
4702
|
+
if (method === "map") {
|
|
4703
|
+
const vals = phpArgumentValues(args);
|
|
4704
|
+
const methods = phpStringArray(vals[0]);
|
|
4705
|
+
const p = vals.length > 1 ? phpStaticString(vals[1]) : null;
|
|
4706
|
+
if (p !== null) {
|
|
4707
|
+
for (const m of methods) {
|
|
4708
|
+
out.push({
|
|
4709
|
+
method: m.toUpperCase(),
|
|
4710
|
+
pathTemplate: laravelJoinPath(prefix, p),
|
|
4711
|
+
line,
|
|
4712
|
+
framework: "slim"
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
return;
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
slimWalk(node, prefix, appVars, out);
|
|
4721
|
+
}
|
|
4722
|
+
var ACTIX_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "head", "options", "trace"]);
|
|
4723
|
+
function rustStringContent(node) {
|
|
4724
|
+
if (!node || node.type !== "string_literal") return null;
|
|
4725
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4726
|
+
if (node.namedChild(i)?.type === "string_content") return node.namedChild(i).text;
|
|
4727
|
+
}
|
|
4728
|
+
return "";
|
|
4729
|
+
}
|
|
4730
|
+
function actixRoutesFromSource(source, parser) {
|
|
4731
|
+
const tree = parseSource2(parser, source);
|
|
4732
|
+
const out = [];
|
|
4733
|
+
walk(tree.rootNode, (node) => {
|
|
4734
|
+
if (node.type === "attribute_item") {
|
|
4735
|
+
actixAttributeRoute(node, out);
|
|
4736
|
+
return;
|
|
4737
|
+
}
|
|
4738
|
+
if (node.type === "call_expression") {
|
|
4739
|
+
actixBuilderRoute(node, out);
|
|
4740
|
+
}
|
|
4741
|
+
});
|
|
4742
|
+
return out;
|
|
4743
|
+
}
|
|
4744
|
+
function actixAttributeRoute(attrItem, out) {
|
|
4745
|
+
const attr = attrItem.namedChild(0);
|
|
4746
|
+
if (!attr || attr.type !== "attribute") return;
|
|
4747
|
+
const nameNode = attr.namedChild(0);
|
|
4748
|
+
if (!nameNode) return;
|
|
4749
|
+
const macro = nameNode.type === "identifier" ? nameNode.text : nameNode.type === "scoped_identifier" ? nameNode.childForFieldName("name")?.text ?? null : null;
|
|
4750
|
+
if (!macro) return;
|
|
4751
|
+
const tokens = attr.childForFieldName("arguments");
|
|
4752
|
+
if (!tokens || tokens.type !== "token_tree") return;
|
|
4753
|
+
const strings = [];
|
|
4754
|
+
for (let i = 0; i < tokens.namedChildCount; i++) {
|
|
4755
|
+
const s = rustStringContent(tokens.namedChild(i));
|
|
4756
|
+
if (s !== null) strings.push(s);
|
|
4757
|
+
}
|
|
4758
|
+
const pathStr = strings[0];
|
|
4759
|
+
if (pathStr === void 0 || !pathStr.startsWith("/")) return;
|
|
4760
|
+
const line = attrItem.startPosition.row + 1;
|
|
4761
|
+
const template = canonicalizeTemplate(pathStr);
|
|
4762
|
+
if (ACTIX_METHODS.has(macro)) {
|
|
4763
|
+
out.push({ method: macro.toUpperCase(), pathTemplate: template, line, framework: "actix-web" });
|
|
4764
|
+
return;
|
|
4765
|
+
}
|
|
4766
|
+
if (macro === "route") {
|
|
4767
|
+
const methods = strings.slice(1).filter((m) => ACTIX_METHODS.has(m.toLowerCase()));
|
|
4768
|
+
const list = methods.length > 0 ? methods.map((m) => m.toUpperCase()) : ["ALL"];
|
|
4769
|
+
for (const m of list) {
|
|
4770
|
+
out.push({ method: m, pathTemplate: template, line, framework: "actix-web" });
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
function actixBuilderRoute(call, out) {
|
|
4775
|
+
const fn = call.childForFieldName("function");
|
|
4776
|
+
if (fn?.type !== "field_expression") return;
|
|
4777
|
+
if (fn.childForFieldName("field")?.text !== "route") return;
|
|
4778
|
+
const args = call.childForFieldName("arguments");
|
|
4779
|
+
const pathStr = rustStringContent(args?.namedChild(0));
|
|
4780
|
+
if (pathStr === null || !pathStr.startsWith("/")) return;
|
|
4781
|
+
const second = args?.namedChild(1);
|
|
4782
|
+
if (!second) return;
|
|
4783
|
+
const method = actixBuilderMethod(second);
|
|
4784
|
+
if (!method) return;
|
|
4785
|
+
out.push({
|
|
4786
|
+
method,
|
|
4787
|
+
pathTemplate: canonicalizeTemplate(pathStr),
|
|
4788
|
+
line: call.startPosition.row + 1,
|
|
4789
|
+
framework: "actix-web"
|
|
4790
|
+
});
|
|
4791
|
+
}
|
|
4792
|
+
function actixBuilderMethod(node) {
|
|
4793
|
+
let method = null;
|
|
4794
|
+
walk(node, (n) => {
|
|
4795
|
+
if (method || n.type !== "scoped_identifier") return;
|
|
4796
|
+
const verb = n.childForFieldName("name")?.text;
|
|
4797
|
+
const scopeLeaf = n.childForFieldName("path")?.text?.split("::").pop();
|
|
4798
|
+
if (scopeLeaf === "web" && verb && ACTIX_METHODS.has(verb)) method = verb.toUpperCase();
|
|
4799
|
+
});
|
|
4800
|
+
return method;
|
|
4801
|
+
}
|
|
4454
4802
|
function namedArgs(argsNode) {
|
|
4455
4803
|
const out = [];
|
|
4456
4804
|
if (!argsNode) return out;
|
|
@@ -4767,6 +5115,7 @@ async function addRoutes(graph, services) {
|
|
|
4767
5115
|
const goParser = makeGoParser2();
|
|
4768
5116
|
const rubyParser = makeRubyParser();
|
|
4769
5117
|
const phpParser = makePhpParser();
|
|
5118
|
+
const rustParser = makeRustParser();
|
|
4770
5119
|
let nodesAdded = 0;
|
|
4771
5120
|
let edgesAdded = 0;
|
|
4772
5121
|
for (const service of services) {
|
|
@@ -4789,7 +5138,10 @@ async function addRoutes(graph, services) {
|
|
|
4789
5138
|
const isGoService = service.node.language === "go";
|
|
4790
5139
|
const hasRails = deps["rails"] !== void 0;
|
|
4791
5140
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4792
|
-
|
|
5141
|
+
const hasSlim = deps["slim/slim"] !== void 0;
|
|
5142
|
+
const hasSinatra = deps["sinatra"] !== void 0;
|
|
5143
|
+
const hasActix = deps["actix-web"] !== void 0;
|
|
5144
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel && !hasSlim && !hasSinatra && !hasActix)
|
|
4793
5145
|
continue;
|
|
4794
5146
|
const files = await loadSourceFiles(service.dir, service.excludeDirs);
|
|
4795
5147
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4800,7 +5152,8 @@ async function addRoutes(graph, services) {
|
|
|
4800
5152
|
const isGo = ext === ".go";
|
|
4801
5153
|
const isRb = ext === ".rb";
|
|
4802
5154
|
const isPhp = ext === ".php";
|
|
4803
|
-
|
|
5155
|
+
const isRs = ext === ".rs";
|
|
5156
|
+
if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy && !isGo && !isRb && !isPhp && !isRs) continue;
|
|
4804
5157
|
const relFile = toPosix(import_node_path7.default.relative(service.dir, file.path));
|
|
4805
5158
|
let routes;
|
|
4806
5159
|
try {
|
|
@@ -4810,8 +5163,12 @@ async function addRoutes(graph, services) {
|
|
|
4810
5163
|
phpParser,
|
|
4811
5164
|
relFile === "routes/api.php" ? "/api" : ""
|
|
4812
5165
|
) : [];
|
|
5166
|
+
if (hasSlim) routes = routes.concat(slimRoutesFromSource(file.content, phpParser));
|
|
4813
5167
|
} else if (isRb) {
|
|
4814
5168
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
5169
|
+
if (hasSinatra) routes = routes.concat(sinatraRoutesFromSource(file.content, rubyParser));
|
|
5170
|
+
} else if (isRs) {
|
|
5171
|
+
routes = hasActix ? actixRoutesFromSource(file.content, rustParser) : [];
|
|
4815
5172
|
} else if (isGo) {
|
|
4816
5173
|
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4817
5174
|
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
@@ -5046,6 +5403,37 @@ function loadIncidentThresholdsFromEnv() {
|
|
|
5046
5403
|
return DEFAULT_INCIDENT_THRESHOLDS;
|
|
5047
5404
|
}
|
|
5048
5405
|
}
|
|
5406
|
+
var DEFAULT_LATENCY_STREAM_CEILING_MS = 6e4;
|
|
5407
|
+
function latencyStreamCeilingMs() {
|
|
5408
|
+
const raw = process.env.NEAT_LATENCY_STREAM_CEILING_MS;
|
|
5409
|
+
if (!raw) return DEFAULT_LATENCY_STREAM_CEILING_MS;
|
|
5410
|
+
const n = Number(raw);
|
|
5411
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
5412
|
+
console.warn(
|
|
5413
|
+
`[neat] NEAT_LATENCY_STREAM_CEILING_MS could not be parsed (${raw}); using default`
|
|
5414
|
+
);
|
|
5415
|
+
return DEFAULT_LATENCY_STREAM_CEILING_MS;
|
|
5416
|
+
}
|
|
5417
|
+
function spanServesEventStream(attrs) {
|
|
5418
|
+
for (const key of [
|
|
5419
|
+
"http.response.header.content-type",
|
|
5420
|
+
"http.response.header.content_type"
|
|
5421
|
+
]) {
|
|
5422
|
+
const v = attrs[key];
|
|
5423
|
+
const values = Array.isArray(v) ? v : v !== void 0 && v !== null ? [v] : [];
|
|
5424
|
+
for (const item of values) {
|
|
5425
|
+
if (typeof item === "string" && item.toLowerCase().includes("text/event-stream")) {
|
|
5426
|
+
return true;
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
}
|
|
5430
|
+
return false;
|
|
5431
|
+
}
|
|
5432
|
+
function spanIsStreaming(span, ceilingMs = latencyStreamCeilingMs()) {
|
|
5433
|
+
if (span.websocketChannel !== void 0) return true;
|
|
5434
|
+
if (spanServesEventStream(span.attributes)) return true;
|
|
5435
|
+
return span.durationNanos > BigInt(Math.round(ceilingMs)) * 1000000n;
|
|
5436
|
+
}
|
|
5049
5437
|
function httpResponseStatusFromAttrs(attrs) {
|
|
5050
5438
|
for (const key of ["http.response.status_code", "http.status_code"]) {
|
|
5051
5439
|
const v = attrs[key];
|
|
@@ -5938,6 +6326,12 @@ async function advance4xxBurst(ctx, span, affectedNode, ts, nowMs, status2) {
|
|
|
5938
6326
|
);
|
|
5939
6327
|
ctx.burstState.delete(key);
|
|
5940
6328
|
}
|
|
6329
|
+
var NEXT_API_ROUTE_SPAN_NAME = /^executing api route \((?:pages|app)\) (\/\S*)$/;
|
|
6330
|
+
function nextApiRouteTemplate(span) {
|
|
6331
|
+
const raw = pickAttr(span, "next.span_name") ?? span.name;
|
|
6332
|
+
const match = raw ? NEXT_API_ROUTE_SPAN_NAME.exec(raw) : null;
|
|
6333
|
+
return match ? match[1] : void 0;
|
|
6334
|
+
}
|
|
5941
6335
|
function findRouteNodeByHttpRoute(graph, serviceName, method, httpRoute) {
|
|
5942
6336
|
const target = normalizePathTemplate(httpRoute);
|
|
5943
6337
|
const m = method?.toUpperCase();
|
|
@@ -5960,7 +6354,7 @@ async function handleSpan(ctx, span) {
|
|
|
5960
6354
|
}
|
|
5961
6355
|
const sourceId = ensureServiceNode(ctx.graph, span.service, env);
|
|
5962
6356
|
const isError = span.statusCode === 2;
|
|
5963
|
-
const durationMs = span.durationNanos > 0n ? Number(span.durationNanos) / 1e6 : void 0;
|
|
6357
|
+
const durationMs = span.durationNanos > 0n && !spanIsStreaming(span) ? Number(span.durationNanos) / 1e6 : void 0;
|
|
5964
6358
|
const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId);
|
|
5965
6359
|
const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath);
|
|
5966
6360
|
cacheSpanService(span, nowMs, callSite);
|
|
@@ -6157,12 +6551,13 @@ async function handleSpan(ctx, span) {
|
|
|
6157
6551
|
}
|
|
6158
6552
|
}
|
|
6159
6553
|
}
|
|
6160
|
-
|
|
6554
|
+
const fusionRoute = nextApiRouteTemplate(span) ?? span.httpRoute;
|
|
6555
|
+
if (fusionRoute && (span.kind === 2 || span.kind === 1 || span.kind === 0 || span.kind === void 0)) {
|
|
6161
6556
|
const routeNodeId = findRouteNodeByHttpRoute(
|
|
6162
6557
|
ctx.graph,
|
|
6163
6558
|
span.service,
|
|
6164
6559
|
span.httpMethod,
|
|
6165
|
-
|
|
6560
|
+
fusionRoute
|
|
6166
6561
|
);
|
|
6167
6562
|
if (routeNodeId) {
|
|
6168
6563
|
const routeSvc = ctx.graph.getNodeAttributes(routeNodeId).service;
|
|
@@ -7550,7 +7945,7 @@ var import_tree_sitter_php2 = __toESM(require("tree-sitter-php"), 1);
|
|
|
7550
7945
|
var import_tree_sitter_c_sharp = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
7551
7946
|
var import_tree_sitter_java = __toESM(require("tree-sitter-java"), 1);
|
|
7552
7947
|
var import_tree_sitter_kotlin = __toESM(require("tree-sitter-kotlin"), 1);
|
|
7553
|
-
var
|
|
7948
|
+
var import_tree_sitter_rust2 = __toESM(require("tree-sitter-rust"), 1);
|
|
7554
7949
|
var import_tree_sitter_cpp = __toESM(require("tree-sitter-cpp"), 1);
|
|
7555
7950
|
var import_types20 = require("@neat.is/types");
|
|
7556
7951
|
var PARSE_CHUNK3 = 16384;
|
|
@@ -7571,7 +7966,7 @@ var SYMBOL_GRAMMAR_BY_EXT = {
|
|
|
7571
7966
|
".cs": import_tree_sitter_c_sharp.default,
|
|
7572
7967
|
".java": import_tree_sitter_java.default,
|
|
7573
7968
|
".kt": import_tree_sitter_kotlin.default,
|
|
7574
|
-
".rs":
|
|
7969
|
+
".rs": import_tree_sitter_rust2.default,
|
|
7575
7970
|
// C++ (ADR-202) — only the UNAMBIGUOUS extensions. `.cpp` / `.cc` / `.cxx` /
|
|
7576
7971
|
// `.c++` are implementation files; `.hpp` / `.hh` / `.hxx` / `.h++` are C++-only
|
|
7577
7972
|
// headers. `.h` and `.c` are deliberately absent: they are shared with C (a
|
|
@@ -8011,15 +8406,15 @@ function collectKotlinSymbolDefs(root) {
|
|
|
8011
8406
|
});
|
|
8012
8407
|
};
|
|
8013
8408
|
const join = (prefix, name) => prefix ? `${prefix}.${name}` : name;
|
|
8014
|
-
const
|
|
8409
|
+
const firstChildOfType2 = (node, types) => {
|
|
8015
8410
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8016
8411
|
const child = node.namedChild(i);
|
|
8017
8412
|
if (child && types.includes(child.type)) return child;
|
|
8018
8413
|
}
|
|
8019
8414
|
return void 0;
|
|
8020
8415
|
};
|
|
8021
|
-
const nameOf = (node, ...types) =>
|
|
8022
|
-
const bodyOf = (node) =>
|
|
8416
|
+
const nameOf = (node, ...types) => firstChildOfType2(node, types)?.text;
|
|
8417
|
+
const bodyOf = (node) => firstChildOfType2(node, ["class_body", "enum_class_body"]);
|
|
8023
8418
|
let pkg;
|
|
8024
8419
|
for (let i = 0; i < root.namedChildCount; i++) {
|
|
8025
8420
|
const child = root.namedChild(i);
|
|
@@ -8520,7 +8915,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
8520
8915
|
return best;
|
|
8521
8916
|
};
|
|
8522
8917
|
const requests = [];
|
|
8523
|
-
const
|
|
8918
|
+
const walk10 = (node) => {
|
|
8524
8919
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
8525
8920
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
8526
8921
|
if (self && self.kind === "class") {
|
|
@@ -8566,10 +8961,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
8566
8961
|
}
|
|
8567
8962
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8568
8963
|
const child = node.namedChild(i);
|
|
8569
|
-
if (child)
|
|
8964
|
+
if (child) walk10(child);
|
|
8570
8965
|
}
|
|
8571
8966
|
};
|
|
8572
|
-
|
|
8967
|
+
walk10(root);
|
|
8573
8968
|
for (const req2 of requests) {
|
|
8574
8969
|
const targetSid = resolveTarget(req2.targetName, req2.wantKind);
|
|
8575
8970
|
if (!targetSid) continue;
|
|
@@ -8865,7 +9260,7 @@ async function addServerActions(graph, services) {
|
|
|
8865
9260
|
|
|
8866
9261
|
// src/extract/databases/index.ts
|
|
8867
9262
|
init_cjs_shims();
|
|
8868
|
-
var
|
|
9263
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
8869
9264
|
var import_types23 = require("@neat.is/types");
|
|
8870
9265
|
|
|
8871
9266
|
// src/extract/databases/db-config-yaml.ts
|
|
@@ -9300,9 +9695,163 @@ async function parse8(serviceDir) {
|
|
|
9300
9695
|
}
|
|
9301
9696
|
var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
9302
9697
|
|
|
9303
|
-
// src/extract/databases/
|
|
9698
|
+
// src/extract/databases/csharp.ts
|
|
9304
9699
|
init_cjs_shims();
|
|
9700
|
+
var import_node_fs22 = require("fs");
|
|
9305
9701
|
var import_node_path32 = __toESM(require("path"), 1);
|
|
9702
|
+
var CS_EXT = ".cs";
|
|
9703
|
+
var NPGSQL_GATE = /\bUseNpgsql\b|\bNpgsql\b/;
|
|
9704
|
+
var REDIS_GATE = /\bConnectionMultiplexer\b|\bStackExchange\.Redis\b|\bConfigurationOptions\.Parse\b|\bAddStackExchangeRedisCache\b/;
|
|
9705
|
+
var ENV_READ_RE = /(?:GetEnvironmentVariable|GetConnectionString)\(\s*"([^"]+)"\s*\)|Configuration\s*\[\s*"([^"]+)"\s*\]/g;
|
|
9706
|
+
var STRING_LITERAL_RE = /@?"([^"\\]*(?:\\.[^"\\]*)*)"/g;
|
|
9707
|
+
function hostIsUnresolved(host) {
|
|
9708
|
+
return host === "" || /[${}]/.test(host);
|
|
9709
|
+
}
|
|
9710
|
+
function looksLikePostgres(s) {
|
|
9711
|
+
return /(?:^|;)\s*(?:host|server|data\s*source)\s*=/i.test(s) || /^postgres(?:ql)?:\/\//i.test(s);
|
|
9712
|
+
}
|
|
9713
|
+
function looksLikeRedis(s) {
|
|
9714
|
+
return /^rediss?:\/\//i.test(s) || /^[A-Za-z0-9_.-]+:\d+(?:$|,)/.test(s) || /,\s*(?:ssl|abortconnect|allowadmin|connecttimeout|password|user)\s*=/i.test(s);
|
|
9715
|
+
}
|
|
9716
|
+
function parsePostgresConnection(raw) {
|
|
9717
|
+
const s = raw.trim();
|
|
9718
|
+
if (/^postgres(?:ql)?:\/\//i.test(s)) return parseConnectionString(s);
|
|
9719
|
+
const fields = /* @__PURE__ */ new Map();
|
|
9720
|
+
for (const part of s.split(";")) {
|
|
9721
|
+
const eq = part.indexOf("=");
|
|
9722
|
+
if (eq < 0) continue;
|
|
9723
|
+
const key = part.slice(0, eq).trim().toLowerCase().replace(/\s+/g, " ");
|
|
9724
|
+
const value = part.slice(eq + 1).trim();
|
|
9725
|
+
if (value && !fields.has(key)) fields.set(key, value);
|
|
9726
|
+
}
|
|
9727
|
+
const hostRaw = fields.get("host") ?? fields.get("server") ?? fields.get("data source");
|
|
9728
|
+
if (!hostRaw) return null;
|
|
9729
|
+
const host = hostRaw.split(",")[0].trim();
|
|
9730
|
+
if (hostIsUnresolved(host)) return null;
|
|
9731
|
+
const portRaw = fields.get("port");
|
|
9732
|
+
const port = portRaw && /^\d+$/.test(portRaw) ? Number(portRaw) : void 0;
|
|
9733
|
+
const database = fields.get("database") ?? fields.get("db") ?? "";
|
|
9734
|
+
return { host, port, database, engine: "postgresql", engineVersion: "unknown" };
|
|
9735
|
+
}
|
|
9736
|
+
function parseRedisEndpoint(raw) {
|
|
9737
|
+
const s = raw.trim();
|
|
9738
|
+
if (/^rediss?:\/\//i.test(s)) return parseConnectionString(s);
|
|
9739
|
+
const first = s.split(",")[0].trim();
|
|
9740
|
+
const m = first.match(/^([A-Za-z0-9_.-]+)(?::(\d+))?$/);
|
|
9741
|
+
if (!m) return null;
|
|
9742
|
+
const host = m[1];
|
|
9743
|
+
if (hostIsUnresolved(host) || host.includes("=")) return null;
|
|
9744
|
+
const port = m[2] ? Number(m[2]) : void 0;
|
|
9745
|
+
return { host, port, database: "", engine: "redis", engineVersion: "unknown" };
|
|
9746
|
+
}
|
|
9747
|
+
async function resolveEnvUpTree(startDir, name) {
|
|
9748
|
+
let dir = import_node_path32.default.resolve(startDir);
|
|
9749
|
+
for (let depth = 0; depth < 12; depth++) {
|
|
9750
|
+
const value = await resolveEnvVar(dir, name);
|
|
9751
|
+
if (value !== null) return value;
|
|
9752
|
+
const atRepoRoot = await import_node_fs22.promises.access(import_node_path32.default.join(dir, ".git")).then(() => true).catch(() => false);
|
|
9753
|
+
const parent = import_node_path32.default.dirname(dir);
|
|
9754
|
+
if (atRepoRoot || parent === dir) break;
|
|
9755
|
+
dir = parent;
|
|
9756
|
+
}
|
|
9757
|
+
return null;
|
|
9758
|
+
}
|
|
9759
|
+
async function interpolateEnvRefs(value, dir) {
|
|
9760
|
+
const refs = /* @__PURE__ */ new Set();
|
|
9761
|
+
for (const m of value.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
9762
|
+
refs.add(m[1] ?? m[2]);
|
|
9763
|
+
}
|
|
9764
|
+
let out = value;
|
|
9765
|
+
for (const name of refs) {
|
|
9766
|
+
const resolved = await resolveEnvUpTree(dir, name);
|
|
9767
|
+
if (resolved === null) continue;
|
|
9768
|
+
out = out.split(`\${${name}}`).join(resolved).replace(new RegExp(`\\$${name}\\b`, "g"), resolved);
|
|
9769
|
+
}
|
|
9770
|
+
return out;
|
|
9771
|
+
}
|
|
9772
|
+
function stringLiterals(masked) {
|
|
9773
|
+
const out = [];
|
|
9774
|
+
STRING_LITERAL_RE.lastIndex = 0;
|
|
9775
|
+
let m;
|
|
9776
|
+
while ((m = STRING_LITERAL_RE.exec(masked)) !== null) out.push(m[1]);
|
|
9777
|
+
return out;
|
|
9778
|
+
}
|
|
9779
|
+
function envKeys(masked) {
|
|
9780
|
+
const out = [];
|
|
9781
|
+
ENV_READ_RE.lastIndex = 0;
|
|
9782
|
+
let m;
|
|
9783
|
+
while ((m = ENV_READ_RE.exec(masked)) !== null) {
|
|
9784
|
+
const key = m[1] ?? m[2];
|
|
9785
|
+
if (key) out.push(key);
|
|
9786
|
+
}
|
|
9787
|
+
return out;
|
|
9788
|
+
}
|
|
9789
|
+
async function resolveConfigs(literals, keys, serviceDir, looksLike, parse11) {
|
|
9790
|
+
const out = [];
|
|
9791
|
+
for (const key of keys) {
|
|
9792
|
+
const raw = await resolveEnvUpTree(serviceDir, key);
|
|
9793
|
+
if (raw === null) continue;
|
|
9794
|
+
const value = await interpolateEnvRefs(raw, serviceDir);
|
|
9795
|
+
if (!looksLike(value)) continue;
|
|
9796
|
+
const parsed = parse11(value);
|
|
9797
|
+
if (parsed) out.push(parsed);
|
|
9798
|
+
}
|
|
9799
|
+
for (const lit of literals) {
|
|
9800
|
+
if (!looksLike(lit)) continue;
|
|
9801
|
+
const parsed = parse11(lit);
|
|
9802
|
+
if (parsed) out.push(parsed);
|
|
9803
|
+
}
|
|
9804
|
+
return out;
|
|
9805
|
+
}
|
|
9806
|
+
async function parse9(serviceDir) {
|
|
9807
|
+
const files = (await walkSourceFiles(serviceDir).catch(() => [])).filter(
|
|
9808
|
+
(f) => import_node_path32.default.extname(f) === CS_EXT
|
|
9809
|
+
);
|
|
9810
|
+
if (files.length === 0) return [];
|
|
9811
|
+
const sources = [];
|
|
9812
|
+
for (const file of files) {
|
|
9813
|
+
const content = await import_node_fs22.promises.readFile(file, "utf8").catch(() => null);
|
|
9814
|
+
if (content !== null) sources.push({ file, content });
|
|
9815
|
+
}
|
|
9816
|
+
let pgGateFile = null;
|
|
9817
|
+
let redisGateFile = null;
|
|
9818
|
+
for (const { file, content } of sources) {
|
|
9819
|
+
if (pgGateFile === null && NPGSQL_GATE.test(content)) pgGateFile = file;
|
|
9820
|
+
if (redisGateFile === null && REDIS_GATE.test(content)) redisGateFile = file;
|
|
9821
|
+
}
|
|
9822
|
+
if (!pgGateFile && !redisGateFile) return [];
|
|
9823
|
+
const literals = [];
|
|
9824
|
+
const keys = [];
|
|
9825
|
+
for (const { content } of sources) {
|
|
9826
|
+
const masked = maskCommentsInSource(content);
|
|
9827
|
+
literals.push(...stringLiterals(masked));
|
|
9828
|
+
keys.push(...envKeys(masked));
|
|
9829
|
+
}
|
|
9830
|
+
const out = [];
|
|
9831
|
+
const seenHosts = /* @__PURE__ */ new Set();
|
|
9832
|
+
const push = (config, sourceFile) => {
|
|
9833
|
+
const dedupe = `${config.engine}:${config.host}`;
|
|
9834
|
+
if (seenHosts.has(dedupe)) return;
|
|
9835
|
+
seenHosts.add(dedupe);
|
|
9836
|
+
out.push({ ...config, sourceFile });
|
|
9837
|
+
};
|
|
9838
|
+
if (pgGateFile) {
|
|
9839
|
+
for (const pg3 of await resolveConfigs(literals, keys, serviceDir, looksLikePostgres, parsePostgresConnection)) {
|
|
9840
|
+
push(pg3, pgGateFile);
|
|
9841
|
+
}
|
|
9842
|
+
}
|
|
9843
|
+
if (redisGateFile) {
|
|
9844
|
+
for (const redis of await resolveConfigs(literals, keys, serviceDir, looksLikeRedis, parseRedisEndpoint)) {
|
|
9845
|
+
push(redis, redisGateFile);
|
|
9846
|
+
}
|
|
9847
|
+
}
|
|
9848
|
+
return out;
|
|
9849
|
+
}
|
|
9850
|
+
var csharpParser = { name: "csharp", parse: parse9 };
|
|
9851
|
+
|
|
9852
|
+
// src/extract/databases/docker-compose.ts
|
|
9853
|
+
init_cjs_shims();
|
|
9854
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
9306
9855
|
function portFromService(svc) {
|
|
9307
9856
|
for (const raw of svc.ports ?? []) {
|
|
9308
9857
|
const str = String(raw);
|
|
@@ -9327,9 +9876,9 @@ function databaseFromEnv(svc) {
|
|
|
9327
9876
|
};
|
|
9328
9877
|
return get("POSTGRES_DB") ?? get("MYSQL_DATABASE") ?? get("MONGO_INITDB_DATABASE") ?? "";
|
|
9329
9878
|
}
|
|
9330
|
-
async function
|
|
9879
|
+
async function parse10(serviceDir) {
|
|
9331
9880
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
9332
|
-
const abs =
|
|
9881
|
+
const abs = import_node_path33.default.join(serviceDir, name);
|
|
9333
9882
|
if (!await exists(abs)) continue;
|
|
9334
9883
|
const raw = await readYaml(abs);
|
|
9335
9884
|
if (!raw?.services) return [];
|
|
@@ -9351,7 +9900,7 @@ async function parse9(serviceDir) {
|
|
|
9351
9900
|
}
|
|
9352
9901
|
return [];
|
|
9353
9902
|
}
|
|
9354
|
-
var dockerComposeParser = { name: "docker-compose", parse:
|
|
9903
|
+
var dockerComposeParser = { name: "docker-compose", parse: parse10 };
|
|
9355
9904
|
|
|
9356
9905
|
// src/extract/databases/index.ts
|
|
9357
9906
|
var DB_PARSERS = [
|
|
@@ -9363,6 +9912,7 @@ var DB_PARSERS = [
|
|
|
9363
9912
|
ormconfigParser,
|
|
9364
9913
|
typeormParser,
|
|
9365
9914
|
sequelizeParser,
|
|
9915
|
+
csharpParser,
|
|
9366
9916
|
dockerComposeParser
|
|
9367
9917
|
];
|
|
9368
9918
|
function compatibleDriversFor(engine) {
|
|
@@ -9501,7 +10051,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
9501
10051
|
discoveredVia: mergedDiscoveredVia
|
|
9502
10052
|
});
|
|
9503
10053
|
}
|
|
9504
|
-
const relConfigFile = toPosix(
|
|
10054
|
+
const relConfigFile = toPosix(import_node_path34.default.relative(service.dir, config.sourceFile));
|
|
9505
10055
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
9506
10056
|
graph,
|
|
9507
10057
|
service.pkg.name,
|
|
@@ -9510,7 +10060,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
9510
10060
|
);
|
|
9511
10061
|
nodesAdded += fn;
|
|
9512
10062
|
edgesAdded += fe;
|
|
9513
|
-
const evidenceFile = toPosix(
|
|
10063
|
+
const evidenceFile = toPosix(import_node_path34.default.relative(scanPath, config.sourceFile));
|
|
9514
10064
|
const edge = {
|
|
9515
10065
|
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types23.EdgeType.CONNECTS_TO),
|
|
9516
10066
|
source: fileNodeId,
|
|
@@ -9528,15 +10078,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
9528
10078
|
if (allConfigs.length === 1) {
|
|
9529
10079
|
const primary = allConfigs[0];
|
|
9530
10080
|
service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
|
|
9531
|
-
const relPath =
|
|
10081
|
+
const relPath = import_node_path34.default.relative(scanPath, primary.sourceFile);
|
|
9532
10082
|
const cfgId = (0, import_types23.configId)(relPath);
|
|
9533
10083
|
if (!graph.hasNode(cfgId)) {
|
|
9534
10084
|
const cfgNode = {
|
|
9535
10085
|
id: cfgId,
|
|
9536
10086
|
type: import_types23.NodeType.ConfigNode,
|
|
9537
|
-
name:
|
|
10087
|
+
name: import_node_path34.default.basename(primary.sourceFile),
|
|
9538
10088
|
path: relPath,
|
|
9539
|
-
fileType: isConfigFile(
|
|
10089
|
+
fileType: isConfigFile(import_node_path34.default.basename(primary.sourceFile)).fileType || "config"
|
|
9540
10090
|
};
|
|
9541
10091
|
graph.addNode(cfgId, cfgNode);
|
|
9542
10092
|
nodesAdded++;
|
|
@@ -9577,27 +10127,27 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
9577
10127
|
|
|
9578
10128
|
// src/extract/configs.ts
|
|
9579
10129
|
init_cjs_shims();
|
|
9580
|
-
var
|
|
9581
|
-
var
|
|
10130
|
+
var import_node_fs23 = require("fs");
|
|
10131
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
9582
10132
|
var import_types24 = require("@neat.is/types");
|
|
9583
10133
|
async function walkConfigFiles(dir, excludeDirs = []) {
|
|
9584
|
-
const excluded = new Set(excludeDirs.map((d) =>
|
|
10134
|
+
const excluded = new Set(excludeDirs.map((d) => import_node_path35.default.resolve(d)));
|
|
9585
10135
|
const out = [];
|
|
9586
|
-
async function
|
|
9587
|
-
const entries = await
|
|
10136
|
+
async function walk10(current) {
|
|
10137
|
+
const entries = await import_node_fs23.promises.readdir(current, { withFileTypes: true });
|
|
9588
10138
|
for (const entry2 of entries) {
|
|
9589
|
-
const full =
|
|
10139
|
+
const full = import_node_path35.default.join(current, entry2.name);
|
|
9590
10140
|
if (entry2.isDirectory()) {
|
|
9591
10141
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
9592
|
-
if (excluded.has(
|
|
10142
|
+
if (excluded.has(import_node_path35.default.resolve(full))) continue;
|
|
9593
10143
|
if (await isPythonVenvDir(full)) continue;
|
|
9594
|
-
await
|
|
10144
|
+
await walk10(full);
|
|
9595
10145
|
} else if (entry2.isFile() && isConfigFile(entry2.name).match) {
|
|
9596
10146
|
out.push(full);
|
|
9597
10147
|
}
|
|
9598
10148
|
}
|
|
9599
10149
|
}
|
|
9600
|
-
await
|
|
10150
|
+
await walk10(dir);
|
|
9601
10151
|
return out;
|
|
9602
10152
|
}
|
|
9603
10153
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -9606,19 +10156,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
9606
10156
|
for (const service of services) {
|
|
9607
10157
|
const configFiles = await walkConfigFiles(service.dir, service.excludeDirs);
|
|
9608
10158
|
for (const file of configFiles) {
|
|
9609
|
-
const relPath =
|
|
10159
|
+
const relPath = import_node_path35.default.relative(scanPath, file);
|
|
9610
10160
|
const node = {
|
|
9611
10161
|
id: (0, import_types24.configId)(relPath),
|
|
9612
10162
|
type: import_types24.NodeType.ConfigNode,
|
|
9613
|
-
name:
|
|
10163
|
+
name: import_node_path35.default.basename(file),
|
|
9614
10164
|
path: relPath,
|
|
9615
|
-
fileType: isConfigFile(
|
|
10165
|
+
fileType: isConfigFile(import_node_path35.default.basename(file)).fileType
|
|
9616
10166
|
};
|
|
9617
10167
|
if (!graph.hasNode(node.id)) {
|
|
9618
10168
|
graph.addNode(node.id, node);
|
|
9619
10169
|
nodesAdded++;
|
|
9620
10170
|
}
|
|
9621
|
-
const relToService = toPosix(
|
|
10171
|
+
const relToService = toPosix(import_node_path35.default.relative(service.dir, file));
|
|
9622
10172
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
9623
10173
|
graph,
|
|
9624
10174
|
service.pkg.name,
|
|
@@ -9634,7 +10184,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
9634
10184
|
type: import_types24.EdgeType.CONFIGURED_BY,
|
|
9635
10185
|
provenance: import_types24.Provenance.EXTRACTED,
|
|
9636
10186
|
confidence: (0, import_types24.confidenceForExtracted)("structural"),
|
|
9637
|
-
evidence: { file: relPath.split(
|
|
10187
|
+
evidence: { file: relPath.split(import_node_path35.default.sep).join("/") }
|
|
9638
10188
|
};
|
|
9639
10189
|
if (!graph.hasEdge(edge.id)) {
|
|
9640
10190
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -9647,8 +10197,8 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
9647
10197
|
|
|
9648
10198
|
// src/extract/proto.ts
|
|
9649
10199
|
init_cjs_shims();
|
|
9650
|
-
var
|
|
9651
|
-
var
|
|
10200
|
+
var import_node_fs24 = require("fs");
|
|
10201
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
9652
10202
|
var import_types25 = require("@neat.is/types");
|
|
9653
10203
|
var PROTO_EXTENSION = ".proto";
|
|
9654
10204
|
function packageOf(content) {
|
|
@@ -9686,23 +10236,23 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
9686
10236
|
return out;
|
|
9687
10237
|
}
|
|
9688
10238
|
async function walkProtoFiles(dir, excludeDirs = []) {
|
|
9689
|
-
const excluded = new Set(excludeDirs.map((d) =>
|
|
10239
|
+
const excluded = new Set(excludeDirs.map((d) => import_node_path36.default.resolve(d)));
|
|
9690
10240
|
const out = [];
|
|
9691
|
-
async function
|
|
9692
|
-
const entries = await
|
|
10241
|
+
async function walk10(current) {
|
|
10242
|
+
const entries = await import_node_fs24.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
9693
10243
|
for (const entry2 of entries) {
|
|
9694
|
-
const full =
|
|
10244
|
+
const full = import_node_path36.default.join(current, entry2.name);
|
|
9695
10245
|
if (entry2.isDirectory()) {
|
|
9696
10246
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
9697
|
-
if (excluded.has(
|
|
10247
|
+
if (excluded.has(import_node_path36.default.resolve(full))) continue;
|
|
9698
10248
|
if (await isPythonVenvDir(full)) continue;
|
|
9699
|
-
await
|
|
9700
|
-
} else if (entry2.isFile() &&
|
|
10249
|
+
await walk10(full);
|
|
10250
|
+
} else if (entry2.isFile() && import_node_path36.default.extname(entry2.name) === PROTO_EXTENSION) {
|
|
9701
10251
|
out.push(full);
|
|
9702
10252
|
}
|
|
9703
10253
|
}
|
|
9704
10254
|
}
|
|
9705
|
-
await
|
|
10255
|
+
await walk10(dir);
|
|
9706
10256
|
return out;
|
|
9707
10257
|
}
|
|
9708
10258
|
async function addGrpcMethods(graph, services) {
|
|
@@ -9712,10 +10262,10 @@ async function addGrpcMethods(graph, services) {
|
|
|
9712
10262
|
const protoPaths = await walkProtoFiles(service.dir, service.excludeDirs);
|
|
9713
10263
|
for (const protoPath of protoPaths) {
|
|
9714
10264
|
if (isTestPath(protoPath)) continue;
|
|
9715
|
-
const relFile = toPosix(
|
|
10265
|
+
const relFile = toPosix(import_node_path36.default.relative(service.dir, protoPath));
|
|
9716
10266
|
let content;
|
|
9717
10267
|
try {
|
|
9718
|
-
content = await
|
|
10268
|
+
content = await import_node_fs24.promises.readFile(protoPath, "utf8");
|
|
9719
10269
|
} catch (err) {
|
|
9720
10270
|
recordExtractionError("proto extraction", protoPath, err);
|
|
9721
10271
|
continue;
|
|
@@ -9770,11 +10320,11 @@ async function addGrpcMethods(graph, services) {
|
|
|
9770
10320
|
|
|
9771
10321
|
// src/extract/calls/index.ts
|
|
9772
10322
|
init_cjs_shims();
|
|
9773
|
-
var
|
|
10323
|
+
var import_types44 = require("@neat.is/types");
|
|
9774
10324
|
|
|
9775
10325
|
// src/extract/calls/http.ts
|
|
9776
10326
|
init_cjs_shims();
|
|
9777
|
-
var
|
|
10327
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
9778
10328
|
var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
|
|
9779
10329
|
var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
|
|
9780
10330
|
var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
|
|
@@ -9857,7 +10407,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
9857
10407
|
const seen = /* @__PURE__ */ new Set();
|
|
9858
10408
|
for (const file of files) {
|
|
9859
10409
|
if (isTestPath(file.path)) continue;
|
|
9860
|
-
const parser = parserForExt(
|
|
10410
|
+
const parser = parserForExt(import_node_path37.default.extname(file.path), parserCache);
|
|
9861
10411
|
let sites;
|
|
9862
10412
|
try {
|
|
9863
10413
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -9866,7 +10416,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
9866
10416
|
continue;
|
|
9867
10417
|
}
|
|
9868
10418
|
if (sites.length === 0) continue;
|
|
9869
|
-
const relFile = toPosix(
|
|
10419
|
+
const relFile = toPosix(import_node_path37.default.relative(service.dir, file.path));
|
|
9870
10420
|
for (const site of sites) {
|
|
9871
10421
|
const targetId = hostToNodeId.get(site.host);
|
|
9872
10422
|
if (!targetId || targetId === service.node.id) continue;
|
|
@@ -9920,7 +10470,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
9920
10470
|
|
|
9921
10471
|
// src/extract/calls/route-match.ts
|
|
9922
10472
|
init_cjs_shims();
|
|
9923
|
-
var
|
|
10473
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
9924
10474
|
var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
|
|
9925
10475
|
var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
|
|
9926
10476
|
var import_types27 = require("@neat.is/types");
|
|
@@ -10119,7 +10669,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10119
10669
|
const seen = /* @__PURE__ */ new Set();
|
|
10120
10670
|
for (const file of files) {
|
|
10121
10671
|
if (isTestPath(file.path)) continue;
|
|
10122
|
-
if (!JS_CLIENT_EXTENSIONS.has(
|
|
10672
|
+
if (!JS_CLIENT_EXTENSIONS.has(import_node_path38.default.extname(file.path))) continue;
|
|
10123
10673
|
let sites;
|
|
10124
10674
|
try {
|
|
10125
10675
|
sites = clientCallSitesFromSource(file.content, jsParser, knownHosts);
|
|
@@ -10128,7 +10678,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10128
10678
|
continue;
|
|
10129
10679
|
}
|
|
10130
10680
|
if (sites.length === 0) continue;
|
|
10131
|
-
const relFile = toPosix(
|
|
10681
|
+
const relFile = toPosix(import_node_path38.default.relative(service.dir, file.path));
|
|
10132
10682
|
for (const site of sites) {
|
|
10133
10683
|
const serverServiceId = hostToNodeId.get(site.host);
|
|
10134
10684
|
if (!serverServiceId || serverServiceId === service.node.id) continue;
|
|
@@ -10189,10 +10739,15 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10189
10739
|
|
|
10190
10740
|
// src/extract/calls/kafka.ts
|
|
10191
10741
|
init_cjs_shims();
|
|
10192
|
-
var
|
|
10742
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
10193
10743
|
var import_types28 = require("@neat.is/types");
|
|
10194
10744
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10195
10745
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
10746
|
+
var SARAMA_IMPORT_RE = /"[^"]*\/sarama"/;
|
|
10747
|
+
var GO_PRODUCER_RE = /ProducerMessage\s*\{[\s\S]{0,300}?\bTopic\s*:\s*(?:"([^"]+)"|`([^`]+)`|([A-Za-z_]\w*))/g;
|
|
10748
|
+
var GO_CONSUMER_RE = /\.Consume\s*\([\s\S]{0,120}?\[\]string\s*\{([^}]*)\}/g;
|
|
10749
|
+
var GO_STRING_LITERAL_RE = /"([^"]+)"|`([^`]+)`/g;
|
|
10750
|
+
var GO_IDENT_RE = /[A-Za-z_]\w*/g;
|
|
10196
10751
|
function findAll(re, text) {
|
|
10197
10752
|
re.lastIndex = 0;
|
|
10198
10753
|
const out = [];
|
|
@@ -10202,38 +10757,94 @@ function findAll(re, text) {
|
|
|
10202
10757
|
}
|
|
10203
10758
|
return out;
|
|
10204
10759
|
}
|
|
10760
|
+
function resolveGoLiteral(ident, text) {
|
|
10761
|
+
const esc = ident.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10762
|
+
const re = new RegExp(
|
|
10763
|
+
`\\b${esc}(?:\\s+\\w[\\w.\\[\\]*]*)?\\s*(?::=|=)\\s*(?:"([^"]+)"|\`([^\`]+)\`)`
|
|
10764
|
+
);
|
|
10765
|
+
const m = re.exec(text);
|
|
10766
|
+
if (!m) return void 0;
|
|
10767
|
+
return m[1] ?? m[2];
|
|
10768
|
+
}
|
|
10769
|
+
function producerTopicAnchor(match) {
|
|
10770
|
+
const [full] = match;
|
|
10771
|
+
const tokenLen = match[1] ? match[1].length + 2 : match[2] ? match[2].length + 2 : match[3]?.length ?? 0;
|
|
10772
|
+
return match.index + full.length - tokenLen;
|
|
10773
|
+
}
|
|
10774
|
+
function goSaramaEndpoints(text, emit) {
|
|
10775
|
+
if (!SARAMA_IMPORT_RE.test(text)) return;
|
|
10776
|
+
GO_PRODUCER_RE.lastIndex = 0;
|
|
10777
|
+
let m;
|
|
10778
|
+
while ((m = GO_PRODUCER_RE.exec(text)) !== null) {
|
|
10779
|
+
const literal = m[1] ?? m[2];
|
|
10780
|
+
const anchor = producerTopicAnchor(m);
|
|
10781
|
+
if (literal) {
|
|
10782
|
+
emit(literal, "PUBLISHES_TO", anchor);
|
|
10783
|
+
} else if (m[3]) {
|
|
10784
|
+
const resolved = resolveGoLiteral(m[3], text);
|
|
10785
|
+
if (resolved) emit(resolved, "PUBLISHES_TO", anchor);
|
|
10786
|
+
}
|
|
10787
|
+
}
|
|
10788
|
+
GO_CONSUMER_RE.lastIndex = 0;
|
|
10789
|
+
while ((m = GO_CONSUMER_RE.exec(text)) !== null) {
|
|
10790
|
+
const inside = m[1] ?? "";
|
|
10791
|
+
const anchor = m.index + Math.max(0, m[0].indexOf("[]string"));
|
|
10792
|
+
let sawLiteral = false;
|
|
10793
|
+
GO_STRING_LITERAL_RE.lastIndex = 0;
|
|
10794
|
+
let s;
|
|
10795
|
+
while ((s = GO_STRING_LITERAL_RE.exec(inside)) !== null) {
|
|
10796
|
+
const topic = s[1] ?? s[2];
|
|
10797
|
+
if (topic) {
|
|
10798
|
+
emit(topic, "CONSUMES_FROM", anchor);
|
|
10799
|
+
sawLiteral = true;
|
|
10800
|
+
}
|
|
10801
|
+
}
|
|
10802
|
+
if (sawLiteral) continue;
|
|
10803
|
+
GO_IDENT_RE.lastIndex = 0;
|
|
10804
|
+
let id;
|
|
10805
|
+
while ((id = GO_IDENT_RE.exec(inside)) !== null) {
|
|
10806
|
+
const resolved = resolveGoLiteral(id[0], text);
|
|
10807
|
+
if (resolved) emit(resolved, "CONSUMES_FROM", anchor);
|
|
10808
|
+
}
|
|
10809
|
+
}
|
|
10810
|
+
}
|
|
10205
10811
|
function kafkaEndpointsFromFile(file, serviceDir) {
|
|
10206
10812
|
const out = [];
|
|
10207
10813
|
const seen = /* @__PURE__ */ new Set();
|
|
10208
|
-
const make = (topic, edgeType) => {
|
|
10814
|
+
const make = (topic, edgeType, anchor) => {
|
|
10209
10815
|
const key = `${edgeType}|${topic}`;
|
|
10210
10816
|
if (seen.has(key)) return;
|
|
10211
10817
|
seen.add(key);
|
|
10212
|
-
const line = lineOf(file.content, topic);
|
|
10818
|
+
const line = anchor !== void 0 ? file.content.slice(0, anchor).split("\n").length : lineOf(file.content, topic);
|
|
10213
10819
|
out.push({
|
|
10214
10820
|
infraId: (0, import_types28.infraId)("kafka-topic", topic),
|
|
10215
10821
|
name: topic,
|
|
10216
10822
|
kind: "kafka-topic",
|
|
10217
10823
|
edgeType,
|
|
10218
|
-
// `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})`
|
|
10219
|
-
//
|
|
10220
|
-
//
|
|
10824
|
+
// JS: `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})`
|
|
10825
|
+
// (kafkajs / node-rdkafka). Go: `sarama.ProducerMessage{Topic: 'x'}` /
|
|
10826
|
+
// `consumerGroup.Consume(ctx, []string{'x'}, …)`. Both are framework-aware
|
|
10827
|
+
// call sites — verified-call-site tier (ADR-066).
|
|
10221
10828
|
confidenceKind: "verified-call-site",
|
|
10222
10829
|
evidence: {
|
|
10223
|
-
file:
|
|
10830
|
+
file: import_node_path39.default.relative(serviceDir, file.path),
|
|
10224
10831
|
line,
|
|
10225
10832
|
snippet: snippet(file.content, line)
|
|
10226
10833
|
}
|
|
10227
10834
|
});
|
|
10228
10835
|
};
|
|
10229
|
-
|
|
10230
|
-
|
|
10836
|
+
if (import_node_path39.default.extname(file.path) === ".go") {
|
|
10837
|
+
goSaramaEndpoints(file.content, make);
|
|
10838
|
+
} else {
|
|
10839
|
+
for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, "PUBLISHES_TO");
|
|
10840
|
+
for (const { topic } of findAll(CONSUMER_TOPIC_RE, file.content)) make(topic, "CONSUMES_FROM");
|
|
10841
|
+
}
|
|
10231
10842
|
return out;
|
|
10232
10843
|
}
|
|
10233
10844
|
|
|
10234
10845
|
// src/extract/calls/redis.ts
|
|
10235
10846
|
init_cjs_shims();
|
|
10236
|
-
var
|
|
10847
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
10237
10848
|
var import_types29 = require("@neat.is/types");
|
|
10238
10849
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
10239
10850
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
@@ -10256,7 +10867,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10256
10867
|
// support tier (ADR-066).
|
|
10257
10868
|
confidenceKind: "url-with-structural-support",
|
|
10258
10869
|
evidence: {
|
|
10259
|
-
file:
|
|
10870
|
+
file: import_node_path40.default.relative(serviceDir, file.path),
|
|
10260
10871
|
line,
|
|
10261
10872
|
snippet: snippet(file.content, line)
|
|
10262
10873
|
}
|
|
@@ -10267,7 +10878,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10267
10878
|
|
|
10268
10879
|
// src/extract/calls/aws.ts
|
|
10269
10880
|
init_cjs_shims();
|
|
10270
|
-
var
|
|
10881
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
10271
10882
|
var import_types30 = require("@neat.is/types");
|
|
10272
10883
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10273
10884
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
@@ -10301,7 +10912,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
10301
10912
|
// (ADR-066).
|
|
10302
10913
|
confidenceKind: "verified-call-site",
|
|
10303
10914
|
evidence: {
|
|
10304
|
-
file:
|
|
10915
|
+
file: import_node_path41.default.relative(serviceDir, file.path),
|
|
10305
10916
|
line,
|
|
10306
10917
|
snippet: snippet(file.content, line)
|
|
10307
10918
|
}
|
|
@@ -10326,7 +10937,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
10326
10937
|
|
|
10327
10938
|
// src/extract/calls/grpc.ts
|
|
10328
10939
|
init_cjs_shims();
|
|
10329
|
-
var
|
|
10940
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
10330
10941
|
var import_types31 = require("@neat.is/types");
|
|
10331
10942
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
10332
10943
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
@@ -10385,7 +10996,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
10385
10996
|
// tier (ADR-066).
|
|
10386
10997
|
confidenceKind: "verified-call-site",
|
|
10387
10998
|
evidence: {
|
|
10388
|
-
file:
|
|
10999
|
+
file: import_node_path42.default.relative(serviceDir, file.path),
|
|
10389
11000
|
line,
|
|
10390
11001
|
snippet: snippet(file.content, line)
|
|
10391
11002
|
}
|
|
@@ -10396,7 +11007,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
10396
11007
|
|
|
10397
11008
|
// src/extract/calls/supabase.ts
|
|
10398
11009
|
init_cjs_shims();
|
|
10399
|
-
var
|
|
11010
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
10400
11011
|
var import_types32 = require("@neat.is/types");
|
|
10401
11012
|
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
10402
11013
|
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
@@ -10455,7 +11066,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
10455
11066
|
// tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
|
|
10456
11067
|
confidenceKind: "verified-call-site",
|
|
10457
11068
|
evidence: {
|
|
10458
|
-
file:
|
|
11069
|
+
file: import_node_path43.default.relative(serviceDir, file.path),
|
|
10459
11070
|
line,
|
|
10460
11071
|
snippet: snippet(file.content, line)
|
|
10461
11072
|
}
|
|
@@ -10482,7 +11093,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
10482
11093
|
edgeType: "CALLS",
|
|
10483
11094
|
confidenceKind: "verified-call-site",
|
|
10484
11095
|
evidence: {
|
|
10485
|
-
file:
|
|
11096
|
+
file: import_node_path43.default.relative(serviceDir, file.path),
|
|
10486
11097
|
line,
|
|
10487
11098
|
snippet: snippet(file.content, line)
|
|
10488
11099
|
}
|
|
@@ -10494,7 +11105,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
10494
11105
|
|
|
10495
11106
|
// src/extract/calls/firestore.ts
|
|
10496
11107
|
init_cjs_shims();
|
|
10497
|
-
var
|
|
11108
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
10498
11109
|
var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
|
|
10499
11110
|
var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
|
|
10500
11111
|
var import_types33 = require("@neat.is/types");
|
|
@@ -10533,7 +11144,7 @@ function isFirestoreClientFactory(node) {
|
|
|
10533
11144
|
}
|
|
10534
11145
|
function firestoreClientVars(root) {
|
|
10535
11146
|
const vars = /* @__PURE__ */ new Set();
|
|
10536
|
-
const
|
|
11147
|
+
const walk10 = (node) => {
|
|
10537
11148
|
if (node.type === "variable_declarator") {
|
|
10538
11149
|
const name = node.childForFieldName("name");
|
|
10539
11150
|
let value = node.childForFieldName("value");
|
|
@@ -10542,9 +11153,9 @@ function firestoreClientVars(root) {
|
|
|
10542
11153
|
vars.add(name.text);
|
|
10543
11154
|
}
|
|
10544
11155
|
}
|
|
10545
|
-
for (const c of namedChildren(node))
|
|
11156
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
10546
11157
|
};
|
|
10547
|
-
|
|
11158
|
+
walk10(root);
|
|
10548
11159
|
return vars;
|
|
10549
11160
|
}
|
|
10550
11161
|
function isClientExpr(node, clientVars) {
|
|
@@ -10665,7 +11276,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
10665
11276
|
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
|
|
10666
11277
|
if (!hasClient && !hasAdmin) return [];
|
|
10667
11278
|
const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
10668
|
-
const tree = parseSource3(parserForExt2(
|
|
11279
|
+
const tree = parseSource3(parserForExt2(import_node_path44.default.extname(file.path)), file.content);
|
|
10669
11280
|
const clientVars = firestoreClientVars(tree.rootNode);
|
|
10670
11281
|
const collLine = /* @__PURE__ */ new Map();
|
|
10671
11282
|
const writes = /* @__PURE__ */ new Map();
|
|
@@ -10699,7 +11310,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
10699
11310
|
}
|
|
10700
11311
|
s.add(field);
|
|
10701
11312
|
};
|
|
10702
|
-
const
|
|
11313
|
+
const walk10 = (node) => {
|
|
10703
11314
|
if (node.type === "call_expression") {
|
|
10704
11315
|
const fn = node.childForFieldName("function");
|
|
10705
11316
|
const line = node.startPosition.row + 1;
|
|
@@ -10739,9 +11350,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
10739
11350
|
}
|
|
10740
11351
|
}
|
|
10741
11352
|
}
|
|
10742
|
-
for (const c of namedChildren(node))
|
|
11353
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
10743
11354
|
};
|
|
10744
|
-
|
|
11355
|
+
walk10(tree.rootNode);
|
|
10745
11356
|
const out = [];
|
|
10746
11357
|
for (const [collPath, line] of collLine) {
|
|
10747
11358
|
const byField = writes.get(collPath);
|
|
@@ -10769,7 +11380,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
10769
11380
|
...columnSet.size > 0 ? { columns: [...columnSet] } : {},
|
|
10770
11381
|
...sdkWrites ? { sdkWrites } : {},
|
|
10771
11382
|
evidence: {
|
|
10772
|
-
file:
|
|
11383
|
+
file: import_node_path44.default.relative(serviceDir, file.path),
|
|
10773
11384
|
line,
|
|
10774
11385
|
snippet: snippet(file.content, line)
|
|
10775
11386
|
}
|
|
@@ -10780,7 +11391,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
10780
11391
|
|
|
10781
11392
|
// src/extract/calls/mongoose.ts
|
|
10782
11393
|
init_cjs_shims();
|
|
10783
|
-
var
|
|
11394
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
10784
11395
|
var import_types34 = require("@neat.is/types");
|
|
10785
11396
|
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
10786
11397
|
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
@@ -10931,7 +11542,7 @@ function endpoint(r, file, serviceDir, matchText) {
|
|
|
10931
11542
|
kind: r.kind,
|
|
10932
11543
|
edgeType: "CALLS",
|
|
10933
11544
|
confidenceKind: "verified-call-site",
|
|
10934
|
-
evidence: { file:
|
|
11545
|
+
evidence: { file: import_node_path45.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
10935
11546
|
};
|
|
10936
11547
|
}
|
|
10937
11548
|
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
@@ -11021,7 +11632,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11021
11632
|
const registry = /* @__PURE__ */ new Map();
|
|
11022
11633
|
for (const f of mongooseFiles) {
|
|
11023
11634
|
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
11024
|
-
if (fx) registry.set(toPosix(
|
|
11635
|
+
if (fx) registry.set(toPosix(import_node_path45.default.relative(serviceDir, f.path)), fx);
|
|
11025
11636
|
}
|
|
11026
11637
|
if (registry.size === 0) return [];
|
|
11027
11638
|
const out = [];
|
|
@@ -11032,7 +11643,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11032
11643
|
const directColl = /* @__PURE__ */ new Map();
|
|
11033
11644
|
const nsExports = /* @__PURE__ */ new Map();
|
|
11034
11645
|
for (const b of bindings) {
|
|
11035
|
-
const resolvedRel = await resolveJsImport(b.specifier,
|
|
11646
|
+
const resolvedRel = await resolveJsImport(b.specifier, import_node_path45.default.dirname(f.path), serviceDir, null);
|
|
11036
11647
|
if (!resolvedRel) continue;
|
|
11037
11648
|
const fx = registry.get(resolvedRel);
|
|
11038
11649
|
if (!fx) continue;
|
|
@@ -11076,7 +11687,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11076
11687
|
|
|
11077
11688
|
// src/extract/calls/sqlalchemy.ts
|
|
11078
11689
|
init_cjs_shims();
|
|
11079
|
-
var
|
|
11690
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
11080
11691
|
var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
|
|
11081
11692
|
var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
11082
11693
|
var import_types35 = require("@neat.is/types");
|
|
@@ -11215,7 +11826,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
|
|
|
11215
11826
|
childTable,
|
|
11216
11827
|
parentTable,
|
|
11217
11828
|
evidence: {
|
|
11218
|
-
file:
|
|
11829
|
+
file: import_node_path46.default.relative(serviceDir, file.path),
|
|
11219
11830
|
line,
|
|
11220
11831
|
snippet: snippet(file.content, line)
|
|
11221
11832
|
}
|
|
@@ -11240,7 +11851,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
11240
11851
|
confidenceKind: "verified-call-site",
|
|
11241
11852
|
...columns && columns.length > 0 ? { columns } : {},
|
|
11242
11853
|
evidence: {
|
|
11243
|
-
file:
|
|
11854
|
+
file: import_node_path46.default.relative(serviceDir, file.path),
|
|
11244
11855
|
line,
|
|
11245
11856
|
snippet: snippet(file.content, line)
|
|
11246
11857
|
}
|
|
@@ -11347,7 +11958,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
11347
11958
|
edgeType: "CALLS",
|
|
11348
11959
|
confidenceKind: "verified-call-site",
|
|
11349
11960
|
evidence: {
|
|
11350
|
-
file:
|
|
11961
|
+
file: import_node_path46.default.relative(serviceDir, file.path),
|
|
11351
11962
|
line,
|
|
11352
11963
|
snippet: snippet(file.content, line)
|
|
11353
11964
|
}
|
|
@@ -11359,7 +11970,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
11359
11970
|
|
|
11360
11971
|
// src/extract/calls/django-orm.ts
|
|
11361
11972
|
init_cjs_shims();
|
|
11362
|
-
var
|
|
11973
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
11363
11974
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
11364
11975
|
var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
|
|
11365
11976
|
var import_types36 = require("@neat.is/types");
|
|
@@ -11429,7 +12040,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
11429
12040
|
const tree = parseSource7(makePyParser4(), file.content);
|
|
11430
12041
|
const out = [];
|
|
11431
12042
|
const seen = /* @__PURE__ */ new Set();
|
|
11432
|
-
const defaultAppLabel =
|
|
12043
|
+
const defaultAppLabel = import_node_path47.default.basename(import_node_path47.default.dirname(file.path));
|
|
11433
12044
|
walk4(tree.rootNode, (node) => {
|
|
11434
12045
|
if (node.type !== "class_definition") return;
|
|
11435
12046
|
if (!extendsDjangoModel(node)) return;
|
|
@@ -11447,7 +12058,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
11447
12058
|
kind: "sql-table",
|
|
11448
12059
|
edgeType: "CALLS",
|
|
11449
12060
|
confidenceKind: "verified-call-site",
|
|
11450
|
-
evidence: { file:
|
|
12061
|
+
evidence: { file: import_node_path47.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
11451
12062
|
});
|
|
11452
12063
|
});
|
|
11453
12064
|
return out;
|
|
@@ -11455,7 +12066,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
11455
12066
|
|
|
11456
12067
|
// src/extract/calls/drizzle.ts
|
|
11457
12068
|
init_cjs_shims();
|
|
11458
|
-
var
|
|
12069
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11459
12070
|
var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
|
|
11460
12071
|
var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
|
|
11461
12072
|
var import_types37 = require("@neat.is/types");
|
|
@@ -11533,10 +12144,10 @@ function columnsFromObject(obj) {
|
|
|
11533
12144
|
}
|
|
11534
12145
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
11535
12146
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
11536
|
-
const tree = parseSource3(parserForExt3(
|
|
12147
|
+
const tree = parseSource3(parserForExt3(import_node_path48.default.extname(file.path)), file.content);
|
|
11537
12148
|
const out = [];
|
|
11538
12149
|
const seen = /* @__PURE__ */ new Set();
|
|
11539
|
-
const
|
|
12150
|
+
const walk10 = (node) => {
|
|
11540
12151
|
if (node.type === "call_expression") {
|
|
11541
12152
|
const fn = node.childForFieldName("function");
|
|
11542
12153
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -11556,7 +12167,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
11556
12167
|
confidenceKind: "structural",
|
|
11557
12168
|
columns,
|
|
11558
12169
|
evidence: {
|
|
11559
|
-
file:
|
|
12170
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11560
12171
|
line,
|
|
11561
12172
|
snippet: snippet(file.content, line)
|
|
11562
12173
|
}
|
|
@@ -11564,9 +12175,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
11564
12175
|
}
|
|
11565
12176
|
}
|
|
11566
12177
|
}
|
|
11567
|
-
for (const c of namedChildren4(node))
|
|
12178
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
11568
12179
|
};
|
|
11569
|
-
|
|
12180
|
+
walk10(tree.rootNode);
|
|
11570
12181
|
return out;
|
|
11571
12182
|
}
|
|
11572
12183
|
function enclosingVarName(call) {
|
|
@@ -11588,7 +12199,7 @@ function enclosingVarName(call) {
|
|
|
11588
12199
|
function collectDrizzleTables(root) {
|
|
11589
12200
|
const tables = [];
|
|
11590
12201
|
const varToTable = /* @__PURE__ */ new Map();
|
|
11591
|
-
const
|
|
12202
|
+
const walk10 = (node) => {
|
|
11592
12203
|
if (node.type === "call_expression") {
|
|
11593
12204
|
const fn = node.childForFieldName("function");
|
|
11594
12205
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -11603,9 +12214,9 @@ function collectDrizzleTables(root) {
|
|
|
11603
12214
|
}
|
|
11604
12215
|
}
|
|
11605
12216
|
}
|
|
11606
|
-
for (const c of namedChildren4(node))
|
|
12217
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
11607
12218
|
};
|
|
11608
|
-
|
|
12219
|
+
walk10(root);
|
|
11609
12220
|
return { tables, varToTable };
|
|
11610
12221
|
}
|
|
11611
12222
|
function referencesTargetVar(call) {
|
|
@@ -11622,13 +12233,13 @@ function referencesTargetVar(call) {
|
|
|
11622
12233
|
}
|
|
11623
12234
|
function drizzleForeignKeys(file, serviceDir) {
|
|
11624
12235
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
11625
|
-
const tree = parseSource3(parserForExt3(
|
|
12236
|
+
const tree = parseSource3(parserForExt3(import_node_path48.default.extname(file.path)), file.content);
|
|
11626
12237
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
11627
12238
|
const out = [];
|
|
11628
12239
|
const seen = /* @__PURE__ */ new Set();
|
|
11629
12240
|
for (const table of tables) {
|
|
11630
12241
|
if (!table.object) continue;
|
|
11631
|
-
const
|
|
12242
|
+
const walk10 = (node) => {
|
|
11632
12243
|
if (node.type === "call_expression") {
|
|
11633
12244
|
const targetVar = referencesTargetVar(node);
|
|
11634
12245
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -11641,7 +12252,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
11641
12252
|
childTable: table.tableName,
|
|
11642
12253
|
parentTable,
|
|
11643
12254
|
evidence: {
|
|
11644
|
-
file:
|
|
12255
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11645
12256
|
line,
|
|
11646
12257
|
snippet: snippet(file.content, line)
|
|
11647
12258
|
}
|
|
@@ -11649,16 +12260,16 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
11649
12260
|
}
|
|
11650
12261
|
}
|
|
11651
12262
|
}
|
|
11652
|
-
for (const c of namedChildren4(node))
|
|
12263
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
11653
12264
|
};
|
|
11654
|
-
|
|
12265
|
+
walk10(table.object);
|
|
11655
12266
|
}
|
|
11656
12267
|
return out;
|
|
11657
12268
|
}
|
|
11658
12269
|
|
|
11659
12270
|
// src/extract/calls/prisma.ts
|
|
11660
12271
|
init_cjs_shims();
|
|
11661
|
-
var
|
|
12272
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11662
12273
|
var import_types38 = require("@neat.is/types");
|
|
11663
12274
|
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
11664
12275
|
"Int",
|
|
@@ -11714,7 +12325,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
11714
12325
|
confidenceKind: "structural",
|
|
11715
12326
|
columns: b.columns,
|
|
11716
12327
|
evidence: {
|
|
11717
|
-
file:
|
|
12328
|
+
file: import_node_path49.default.relative(serviceDir, file.path),
|
|
11718
12329
|
line: b.startLine,
|
|
11719
12330
|
snippet: snippet(content, b.startLine)
|
|
11720
12331
|
}
|
|
@@ -11775,7 +12386,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
11775
12386
|
}
|
|
11776
12387
|
async function prismaColumnEndpoints(serviceDir) {
|
|
11777
12388
|
const schemaPath = await findFirst(serviceDir, [
|
|
11778
|
-
|
|
12389
|
+
import_node_path49.default.join("prisma", "schema.prisma"),
|
|
11779
12390
|
"schema.prisma"
|
|
11780
12391
|
]);
|
|
11781
12392
|
if (!schemaPath) return [];
|
|
@@ -11850,7 +12461,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
11850
12461
|
childTable: current.table,
|
|
11851
12462
|
parentTable,
|
|
11852
12463
|
evidence: {
|
|
11853
|
-
file:
|
|
12464
|
+
file: import_node_path49.default.relative(serviceDir, file.path),
|
|
11854
12465
|
line: lineNo,
|
|
11855
12466
|
snippet: snippet(content, lineNo)
|
|
11856
12467
|
}
|
|
@@ -11865,7 +12476,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
11865
12476
|
}
|
|
11866
12477
|
async function prismaForeignKeys(serviceDir) {
|
|
11867
12478
|
const schemaPath = await findFirst(serviceDir, [
|
|
11868
|
-
|
|
12479
|
+
import_node_path49.default.join("prisma", "schema.prisma"),
|
|
11869
12480
|
"schema.prisma"
|
|
11870
12481
|
]);
|
|
11871
12482
|
if (!schemaPath) return [];
|
|
@@ -11876,7 +12487,7 @@ async function prismaForeignKeys(serviceDir) {
|
|
|
11876
12487
|
|
|
11877
12488
|
// src/extract/calls/activerecord.ts
|
|
11878
12489
|
init_cjs_shims();
|
|
11879
|
-
var
|
|
12490
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11880
12491
|
var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
|
|
11881
12492
|
var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
|
|
11882
12493
|
var import_types39 = require("@neat.is/types");
|
|
@@ -12084,7 +12695,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
|
12084
12695
|
confidenceKind: "structural",
|
|
12085
12696
|
...table.columns.length > 0 ? { columns: table.columns } : {},
|
|
12086
12697
|
evidence: {
|
|
12087
|
-
file:
|
|
12698
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12088
12699
|
line: table.line,
|
|
12089
12700
|
snippet: snippet(file.content, table.line)
|
|
12090
12701
|
}
|
|
@@ -12106,7 +12717,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
|
|
|
12106
12717
|
childTable,
|
|
12107
12718
|
parentTable,
|
|
12108
12719
|
evidence: {
|
|
12109
|
-
file:
|
|
12720
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12110
12721
|
line,
|
|
12111
12722
|
snippet: snippet(file.content, line)
|
|
12112
12723
|
}
|
|
@@ -12189,7 +12800,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
|
|
|
12189
12800
|
edgeType: "CALLS",
|
|
12190
12801
|
confidenceKind: "verified-call-site",
|
|
12191
12802
|
evidence: {
|
|
12192
|
-
file:
|
|
12803
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12193
12804
|
line,
|
|
12194
12805
|
snippet: snippet(file.content, line)
|
|
12195
12806
|
}
|
|
@@ -12226,7 +12837,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12226
12837
|
childTable,
|
|
12227
12838
|
parentTable,
|
|
12228
12839
|
evidence: {
|
|
12229
|
-
file:
|
|
12840
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12230
12841
|
line,
|
|
12231
12842
|
snippet: snippet(file.content, line)
|
|
12232
12843
|
}
|
|
@@ -12238,7 +12849,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12238
12849
|
|
|
12239
12850
|
// src/extract/calls/eloquent.ts
|
|
12240
12851
|
init_cjs_shims();
|
|
12241
|
-
var
|
|
12852
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12242
12853
|
var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
|
|
12243
12854
|
var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
|
|
12244
12855
|
var import_types40 = require("@neat.is/types");
|
|
@@ -12495,7 +13106,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
12495
13106
|
confidenceKind: "structural",
|
|
12496
13107
|
...columns.length > 0 ? { columns } : {},
|
|
12497
13108
|
evidence: {
|
|
12498
|
-
file:
|
|
13109
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12499
13110
|
line: bp.line,
|
|
12500
13111
|
snippet: snippet(file.content, bp.line)
|
|
12501
13112
|
}
|
|
@@ -12517,7 +13128,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
|
|
|
12517
13128
|
childTable,
|
|
12518
13129
|
parentTable,
|
|
12519
13130
|
evidence: {
|
|
12520
|
-
file:
|
|
13131
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12521
13132
|
line,
|
|
12522
13133
|
snippet: snippet(file.content, line)
|
|
12523
13134
|
}
|
|
@@ -12637,7 +13248,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
|
12637
13248
|
edgeType: "CALLS",
|
|
12638
13249
|
confidenceKind: "verified-call-site",
|
|
12639
13250
|
evidence: {
|
|
12640
|
-
file:
|
|
13251
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12641
13252
|
line,
|
|
12642
13253
|
snippet: snippet(file.content, line)
|
|
12643
13254
|
}
|
|
@@ -12673,7 +13284,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
12673
13284
|
childTable,
|
|
12674
13285
|
parentTable,
|
|
12675
13286
|
evidence: {
|
|
12676
|
-
file:
|
|
13287
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12677
13288
|
line,
|
|
12678
13289
|
snippet: snippet(file.content, line)
|
|
12679
13290
|
}
|
|
@@ -12685,7 +13296,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
12685
13296
|
|
|
12686
13297
|
// src/extract/calls/go.ts
|
|
12687
13298
|
init_cjs_shims();
|
|
12688
|
-
var
|
|
13299
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
12689
13300
|
var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
|
|
12690
13301
|
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
12691
13302
|
var import_types41 = require("@neat.is/types");
|
|
@@ -12760,7 +13371,7 @@ function firstStringLiteralArg(argsNode) {
|
|
|
12760
13371
|
return null;
|
|
12761
13372
|
}
|
|
12762
13373
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
12763
|
-
if (
|
|
13374
|
+
if (import_node_path54.default.extname(file.path) !== ".go") return [];
|
|
12764
13375
|
if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
|
|
12765
13376
|
const tree = parseSource10(makeGoParser3(), file.content);
|
|
12766
13377
|
const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
|
|
@@ -12789,7 +13400,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
12789
13400
|
confidenceKind: "verified-call-site",
|
|
12790
13401
|
...columns.length > 0 ? { columns } : {},
|
|
12791
13402
|
evidence: {
|
|
12792
|
-
file: toPosix(
|
|
13403
|
+
file: toPosix(import_node_path54.default.relative(serviceDir, file.path)),
|
|
12793
13404
|
line,
|
|
12794
13405
|
snippet: snippet(file.content, line)
|
|
12795
13406
|
}
|
|
@@ -12800,7 +13411,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
12800
13411
|
|
|
12801
13412
|
// src/extract/calls/gorm.ts
|
|
12802
13413
|
init_cjs_shims();
|
|
12803
|
-
var
|
|
13414
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
12804
13415
|
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
12805
13416
|
var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
|
|
12806
13417
|
var import_types42 = require("@neat.is/types");
|
|
@@ -13233,7 +13844,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
|
13233
13844
|
seen.delete(struct.name);
|
|
13234
13845
|
}
|
|
13235
13846
|
function gormEndpointsFromFile(file, serviceDir) {
|
|
13236
|
-
if (
|
|
13847
|
+
if (import_node_path55.default.extname(file.path) !== ".go") return [];
|
|
13237
13848
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13238
13849
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13239
13850
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13255,7 +13866,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13255
13866
|
confidenceKind: "structural",
|
|
13256
13867
|
...columns.length > 0 ? { columns } : {},
|
|
13257
13868
|
evidence: {
|
|
13258
|
-
file: toPosix(
|
|
13869
|
+
file: toPosix(import_node_path55.default.relative(serviceDir, file.path)),
|
|
13259
13870
|
line: struct.line,
|
|
13260
13871
|
snippet: snippet(file.content, struct.line)
|
|
13261
13872
|
}
|
|
@@ -13264,7 +13875,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13264
13875
|
return out;
|
|
13265
13876
|
}
|
|
13266
13877
|
function gormForeignKeys(file, serviceDir) {
|
|
13267
|
-
if (
|
|
13878
|
+
if (import_node_path55.default.extname(file.path) !== ".go") return [];
|
|
13268
13879
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13269
13880
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13270
13881
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13279,7 +13890,7 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13279
13890
|
childTable,
|
|
13280
13891
|
parentTable,
|
|
13281
13892
|
evidence: {
|
|
13282
|
-
file: toPosix(
|
|
13893
|
+
file: toPosix(import_node_path55.default.relative(serviceDir, file.path)),
|
|
13283
13894
|
line,
|
|
13284
13895
|
snippet: snippet(file.content, line)
|
|
13285
13896
|
}
|
|
@@ -13314,15 +13925,131 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13314
13925
|
return out;
|
|
13315
13926
|
}
|
|
13316
13927
|
|
|
13928
|
+
// src/extract/calls/efcore.ts
|
|
13929
|
+
init_cjs_shims();
|
|
13930
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
13931
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
13932
|
+
var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
13933
|
+
var import_types43 = require("@neat.is/types");
|
|
13934
|
+
var EFCORE_GATE = /Microsoft\.EntityFrameworkCore|DataAnnotations\.Schema|\bDbContext\b|\bDbSet\s*</;
|
|
13935
|
+
var PARSE_CHUNK12 = 16384;
|
|
13936
|
+
function makeCsParser() {
|
|
13937
|
+
const p = new import_tree_sitter16.default();
|
|
13938
|
+
p.setLanguage(import_tree_sitter_c_sharp2.default);
|
|
13939
|
+
return p;
|
|
13940
|
+
}
|
|
13941
|
+
function parseSource12(parser, source) {
|
|
13942
|
+
return parser.parse(
|
|
13943
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK12)
|
|
13944
|
+
);
|
|
13945
|
+
}
|
|
13946
|
+
function walk9(node, visit) {
|
|
13947
|
+
visit(node);
|
|
13948
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13949
|
+
const c = node.namedChild(i);
|
|
13950
|
+
if (c) walk9(c, visit);
|
|
13951
|
+
}
|
|
13952
|
+
}
|
|
13953
|
+
function firstChildOfType(node, type) {
|
|
13954
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13955
|
+
const c = node.namedChild(i);
|
|
13956
|
+
if (c?.type === type) return c;
|
|
13957
|
+
}
|
|
13958
|
+
return null;
|
|
13959
|
+
}
|
|
13960
|
+
function csStringLiteral(node) {
|
|
13961
|
+
if (node.type === "string_literal") {
|
|
13962
|
+
let out = "";
|
|
13963
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13964
|
+
const c = node.namedChild(i);
|
|
13965
|
+
if (c?.type === "string_literal_content") out += c.text;
|
|
13966
|
+
}
|
|
13967
|
+
return out;
|
|
13968
|
+
}
|
|
13969
|
+
if (node.type === "verbatim_string_literal") {
|
|
13970
|
+
const t = node.text;
|
|
13971
|
+
return t.length >= 3 ? t.slice(2, -1).replace(/""/g, '"') : "";
|
|
13972
|
+
}
|
|
13973
|
+
return null;
|
|
13974
|
+
}
|
|
13975
|
+
function attributeName(attr) {
|
|
13976
|
+
const nameNode = attr.childForFieldName("name") ?? attr.namedChild(0);
|
|
13977
|
+
if (!nameNode) return null;
|
|
13978
|
+
const text = nameNode.text;
|
|
13979
|
+
const base = text.includes(".") ? text.slice(text.lastIndexOf(".") + 1) : text;
|
|
13980
|
+
return base.endsWith("Attribute") ? base.slice(0, -"Attribute".length) : base;
|
|
13981
|
+
}
|
|
13982
|
+
function tableFromAttribute(attr) {
|
|
13983
|
+
if (attributeName(attr) !== "Table") return null;
|
|
13984
|
+
const args = attr.childForFieldName("arguments") ?? firstChildOfType(attr, "attribute_argument_list");
|
|
13985
|
+
if (!args) return null;
|
|
13986
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
13987
|
+
const arg = args.namedChild(i);
|
|
13988
|
+
if (arg?.type !== "attribute_argument") continue;
|
|
13989
|
+
const first = arg.namedChild(0);
|
|
13990
|
+
if (!first) continue;
|
|
13991
|
+
const value = csStringLiteral(first);
|
|
13992
|
+
if (value !== null) return value;
|
|
13993
|
+
return null;
|
|
13994
|
+
}
|
|
13995
|
+
return null;
|
|
13996
|
+
}
|
|
13997
|
+
function tableFromToTable(call) {
|
|
13998
|
+
const fn = call.childForFieldName("function");
|
|
13999
|
+
if (fn?.type !== "member_access_expression") return null;
|
|
14000
|
+
const method = fn.childForFieldName("name") ?? fn.namedChild(fn.namedChildCount - 1);
|
|
14001
|
+
if (method?.text !== "ToTable") return null;
|
|
14002
|
+
const args = call.childForFieldName("arguments");
|
|
14003
|
+
const firstArg2 = args?.namedChild(0);
|
|
14004
|
+
if (firstArg2?.type !== "argument") return null;
|
|
14005
|
+
const value = firstArg2.namedChild(0);
|
|
14006
|
+
return value ? csStringLiteral(value) : null;
|
|
14007
|
+
}
|
|
14008
|
+
function efcoreEndpointsFromFile(file, serviceDir) {
|
|
14009
|
+
if (import_node_path56.default.extname(file.path) !== ".cs") return [];
|
|
14010
|
+
if (!EFCORE_GATE.test(file.content)) return [];
|
|
14011
|
+
const tree = parseSource12(makeCsParser(), file.content);
|
|
14012
|
+
const out = [];
|
|
14013
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14014
|
+
const push = (name, line) => {
|
|
14015
|
+
if (!name || seen.has(name)) return;
|
|
14016
|
+
seen.add(name);
|
|
14017
|
+
out.push({
|
|
14018
|
+
infraId: (0, import_types43.infraId)("sql-table", name),
|
|
14019
|
+
name,
|
|
14020
|
+
kind: "sql-table",
|
|
14021
|
+
edgeType: "CALLS",
|
|
14022
|
+
confidenceKind: "structural",
|
|
14023
|
+
evidence: {
|
|
14024
|
+
file: toPosix(import_node_path56.default.relative(serviceDir, file.path)),
|
|
14025
|
+
line,
|
|
14026
|
+
snippet: snippet(file.content, line)
|
|
14027
|
+
}
|
|
14028
|
+
});
|
|
14029
|
+
};
|
|
14030
|
+
walk9(tree.rootNode, (node) => {
|
|
14031
|
+
if (node.type === "attribute") {
|
|
14032
|
+
const table = tableFromAttribute(node);
|
|
14033
|
+
if (table) push(table, node.startPosition.row + 1);
|
|
14034
|
+
return;
|
|
14035
|
+
}
|
|
14036
|
+
if (node.type === "invocation_expression") {
|
|
14037
|
+
const table = tableFromToTable(node);
|
|
14038
|
+
if (table) push(table, node.startPosition.row + 1);
|
|
14039
|
+
}
|
|
14040
|
+
});
|
|
14041
|
+
return out;
|
|
14042
|
+
}
|
|
14043
|
+
|
|
13317
14044
|
// src/extract/calls/index.ts
|
|
13318
14045
|
function edgeTypeFromEndpoint(ep) {
|
|
13319
14046
|
switch (ep.edgeType) {
|
|
13320
14047
|
case "PUBLISHES_TO":
|
|
13321
|
-
return
|
|
14048
|
+
return import_types44.EdgeType.PUBLISHES_TO;
|
|
13322
14049
|
case "CONSUMES_FROM":
|
|
13323
|
-
return
|
|
14050
|
+
return import_types44.EdgeType.CONSUMES_FROM;
|
|
13324
14051
|
default:
|
|
13325
|
-
return
|
|
14052
|
+
return import_types44.EdgeType.CALLS;
|
|
13326
14053
|
}
|
|
13327
14054
|
}
|
|
13328
14055
|
function isAwsKind(kind) {
|
|
@@ -13372,6 +14099,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13372
14099
|
} catch (err) {
|
|
13373
14100
|
recordExtractionError("laravel eloquent extraction", file.path, err);
|
|
13374
14101
|
}
|
|
14102
|
+
try {
|
|
14103
|
+
endpoints.push(...efcoreEndpointsFromFile(file, service.dir));
|
|
14104
|
+
} catch (err) {
|
|
14105
|
+
recordExtractionError("efcore data-axis extraction", file.path, err);
|
|
14106
|
+
}
|
|
13375
14107
|
}
|
|
13376
14108
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
13377
14109
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
@@ -13382,7 +14114,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13382
14114
|
if (!graph.hasNode(ep.infraId)) {
|
|
13383
14115
|
const node = {
|
|
13384
14116
|
id: ep.infraId,
|
|
13385
|
-
type:
|
|
14117
|
+
type: import_types44.NodeType.InfraNode,
|
|
13386
14118
|
name: ep.name,
|
|
13387
14119
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
13388
14120
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -13395,21 +14127,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13395
14127
|
}
|
|
13396
14128
|
if (ep.columns && ep.columns.length > 0) {
|
|
13397
14129
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
13398
|
-
if (node.type ===
|
|
14130
|
+
if (node.type === import_types44.NodeType.InfraNode) {
|
|
13399
14131
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
13400
14132
|
...node,
|
|
13401
14133
|
columns: foldColumns(
|
|
13402
14134
|
node.columns,
|
|
13403
14135
|
ep.columns,
|
|
13404
|
-
|
|
13405
|
-
(0,
|
|
14136
|
+
import_types44.Provenance.EXTRACTED,
|
|
14137
|
+
(0, import_types44.confidenceForExtracted)(ep.confidenceKind)
|
|
13406
14138
|
)
|
|
13407
14139
|
});
|
|
13408
14140
|
}
|
|
13409
14141
|
}
|
|
13410
14142
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
13411
14143
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
13412
|
-
if (node.type ===
|
|
14144
|
+
if (node.type === import_types44.NodeType.InfraNode) {
|
|
13413
14145
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
13414
14146
|
...node,
|
|
13415
14147
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -13417,7 +14149,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13417
14149
|
}
|
|
13418
14150
|
}
|
|
13419
14151
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
13420
|
-
const confidence = (0,
|
|
14152
|
+
const confidence = (0, import_types44.confidenceForExtracted)(ep.confidenceKind);
|
|
13421
14153
|
const relFile = toPosix(ep.evidence.file);
|
|
13422
14154
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
13423
14155
|
graph,
|
|
@@ -13427,7 +14159,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13427
14159
|
);
|
|
13428
14160
|
nodesAdded += n;
|
|
13429
14161
|
edgesAdded += e;
|
|
13430
|
-
if (!(0,
|
|
14162
|
+
if (!(0, import_types44.passesExtractedFloor)(confidence)) {
|
|
13431
14163
|
noteExtractedDropped({
|
|
13432
14164
|
source: fileNodeId,
|
|
13433
14165
|
target: ep.infraId,
|
|
@@ -13447,7 +14179,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13447
14179
|
source: fileNodeId,
|
|
13448
14180
|
target: ep.infraId,
|
|
13449
14181
|
type: edgeType,
|
|
13450
|
-
provenance:
|
|
14182
|
+
provenance: import_types44.Provenance.EXTRACTED,
|
|
13451
14183
|
confidence,
|
|
13452
14184
|
evidence: ep.evidence
|
|
13453
14185
|
};
|
|
@@ -13470,7 +14202,7 @@ async function addCallEdges(graph, services) {
|
|
|
13470
14202
|
|
|
13471
14203
|
// src/extract/table-edges.ts
|
|
13472
14204
|
init_cjs_shims();
|
|
13473
|
-
var
|
|
14205
|
+
var import_types45 = require("@neat.is/types");
|
|
13474
14206
|
async function addTableEdges(graph, services) {
|
|
13475
14207
|
let nodesAdded = 0;
|
|
13476
14208
|
let edgesAdded = 0;
|
|
@@ -13498,20 +14230,20 @@ async function addTableEdges(graph, services) {
|
|
|
13498
14230
|
}
|
|
13499
14231
|
refs.push(...modelRefs);
|
|
13500
14232
|
for (const ref of refs) {
|
|
13501
|
-
const childId = (0,
|
|
13502
|
-
const parentId = (0,
|
|
14233
|
+
const childId = (0, import_types45.infraId)("sql-table", ref.childTable);
|
|
14234
|
+
const parentId = (0, import_types45.infraId)("sql-table", ref.parentTable);
|
|
13503
14235
|
if (childId === parentId) continue;
|
|
13504
14236
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
13505
14237
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
13506
|
-
const edgeId = (0,
|
|
14238
|
+
const edgeId = (0, import_types45.extractedEdgeId)(childId, parentId, import_types45.EdgeType.REFERENCES);
|
|
13507
14239
|
if (graph.hasEdge(edgeId)) continue;
|
|
13508
14240
|
const edge = {
|
|
13509
14241
|
id: edgeId,
|
|
13510
14242
|
source: childId,
|
|
13511
14243
|
target: parentId,
|
|
13512
|
-
type:
|
|
13513
|
-
provenance:
|
|
13514
|
-
confidence: (0,
|
|
14244
|
+
type: import_types45.EdgeType.REFERENCES,
|
|
14245
|
+
provenance: import_types45.Provenance.EXTRACTED,
|
|
14246
|
+
confidence: (0, import_types45.confidenceForExtracted)("structural"),
|
|
13515
14247
|
evidence: ref.evidence
|
|
13516
14248
|
};
|
|
13517
14249
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -13524,7 +14256,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
13524
14256
|
if (graph.hasNode(id)) return 0;
|
|
13525
14257
|
const node = {
|
|
13526
14258
|
id,
|
|
13527
|
-
type:
|
|
14259
|
+
type: import_types45.NodeType.InfraNode,
|
|
13528
14260
|
name,
|
|
13529
14261
|
provider: "self",
|
|
13530
14262
|
kind: "sql-table"
|
|
@@ -13538,16 +14270,16 @@ init_cjs_shims();
|
|
|
13538
14270
|
|
|
13539
14271
|
// src/extract/infra/docker-compose.ts
|
|
13540
14272
|
init_cjs_shims();
|
|
13541
|
-
var
|
|
13542
|
-
var
|
|
14273
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
14274
|
+
var import_types47 = require("@neat.is/types");
|
|
13543
14275
|
|
|
13544
14276
|
// src/extract/infra/shared.ts
|
|
13545
14277
|
init_cjs_shims();
|
|
13546
|
-
var
|
|
14278
|
+
var import_types46 = require("@neat.is/types");
|
|
13547
14279
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
13548
14280
|
return {
|
|
13549
|
-
id: (0,
|
|
13550
|
-
type:
|
|
14281
|
+
id: (0, import_types46.infraId)(kind, name),
|
|
14282
|
+
type: import_types46.NodeType.InfraNode,
|
|
13551
14283
|
name,
|
|
13552
14284
|
provider,
|
|
13553
14285
|
kind,
|
|
@@ -13591,8 +14323,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
13591
14323
|
source: anchorId,
|
|
13592
14324
|
target: node.id,
|
|
13593
14325
|
type: edgeType,
|
|
13594
|
-
provenance:
|
|
13595
|
-
confidence: (0,
|
|
14326
|
+
provenance: import_types46.Provenance.EXTRACTED,
|
|
14327
|
+
confidence: (0, import_types46.confidenceForExtracted)("structural"),
|
|
13596
14328
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
13597
14329
|
};
|
|
13598
14330
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -13609,7 +14341,7 @@ function dependsOnList(value) {
|
|
|
13609
14341
|
}
|
|
13610
14342
|
function serviceNameToServiceNode(name, services) {
|
|
13611
14343
|
for (const s of services) {
|
|
13612
|
-
if (s.node.name === name ||
|
|
14344
|
+
if (s.node.name === name || import_node_path57.default.basename(s.dir) === name) return s.node.id;
|
|
13613
14345
|
}
|
|
13614
14346
|
return null;
|
|
13615
14347
|
}
|
|
@@ -13618,7 +14350,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
13618
14350
|
let edgesAdded = 0;
|
|
13619
14351
|
let composePath = null;
|
|
13620
14352
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
13621
|
-
const abs =
|
|
14353
|
+
const abs = import_node_path57.default.join(scanPath, name);
|
|
13622
14354
|
if (await exists(abs)) {
|
|
13623
14355
|
composePath = abs;
|
|
13624
14356
|
break;
|
|
@@ -13631,13 +14363,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
13631
14363
|
} catch (err) {
|
|
13632
14364
|
recordExtractionError(
|
|
13633
14365
|
"infra docker-compose",
|
|
13634
|
-
|
|
14366
|
+
import_node_path57.default.relative(scanPath, composePath),
|
|
13635
14367
|
err
|
|
13636
14368
|
);
|
|
13637
14369
|
return { nodesAdded, edgesAdded };
|
|
13638
14370
|
}
|
|
13639
14371
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
13640
|
-
const evidenceFile =
|
|
14372
|
+
const evidenceFile = import_node_path57.default.relative(scanPath, composePath).split(import_node_path57.default.sep).join("/");
|
|
13641
14373
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
13642
14374
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
13643
14375
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -13659,15 +14391,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
13659
14391
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
13660
14392
|
const targetId = composeNameToNodeId.get(dep);
|
|
13661
14393
|
if (!targetId) continue;
|
|
13662
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
14394
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types47.EdgeType.DEPENDS_ON);
|
|
13663
14395
|
if (graph.hasEdge(edgeId)) continue;
|
|
13664
14396
|
const edge = {
|
|
13665
14397
|
id: edgeId,
|
|
13666
14398
|
source: sourceId,
|
|
13667
14399
|
target: targetId,
|
|
13668
|
-
type:
|
|
13669
|
-
provenance:
|
|
13670
|
-
confidence: (0,
|
|
14400
|
+
type: import_types47.EdgeType.DEPENDS_ON,
|
|
14401
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
14402
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
13671
14403
|
evidence: { file: evidenceFile }
|
|
13672
14404
|
};
|
|
13673
14405
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -13679,9 +14411,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
13679
14411
|
|
|
13680
14412
|
// src/extract/infra/dockerfile.ts
|
|
13681
14413
|
init_cjs_shims();
|
|
13682
|
-
var
|
|
13683
|
-
var
|
|
13684
|
-
var
|
|
14414
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
14415
|
+
var import_node_fs25 = require("fs");
|
|
14416
|
+
var import_types48 = require("@neat.is/types");
|
|
13685
14417
|
function readDockerfile(content) {
|
|
13686
14418
|
let image = null;
|
|
13687
14419
|
const ports = [];
|
|
@@ -13710,15 +14442,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
13710
14442
|
let nodesAdded = 0;
|
|
13711
14443
|
let edgesAdded = 0;
|
|
13712
14444
|
for (const service of services) {
|
|
13713
|
-
const dockerfilePath =
|
|
14445
|
+
const dockerfilePath = import_node_path58.default.join(service.dir, "Dockerfile");
|
|
13714
14446
|
if (!await exists(dockerfilePath)) continue;
|
|
13715
14447
|
let content;
|
|
13716
14448
|
try {
|
|
13717
|
-
content = await
|
|
14449
|
+
content = await import_node_fs25.promises.readFile(dockerfilePath, "utf8");
|
|
13718
14450
|
} catch (err) {
|
|
13719
14451
|
recordExtractionError(
|
|
13720
14452
|
"infra dockerfile",
|
|
13721
|
-
|
|
14453
|
+
import_node_path58.default.relative(scanPath, dockerfilePath),
|
|
13722
14454
|
err
|
|
13723
14455
|
);
|
|
13724
14456
|
continue;
|
|
@@ -13730,8 +14462,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
13730
14462
|
graph.addNode(node.id, node);
|
|
13731
14463
|
nodesAdded++;
|
|
13732
14464
|
}
|
|
13733
|
-
const relDockerfile = toPosix(
|
|
13734
|
-
const evidenceFile = toPosix(
|
|
14465
|
+
const relDockerfile = toPosix(import_node_path58.default.relative(service.dir, dockerfilePath));
|
|
14466
|
+
const evidenceFile = toPosix(import_node_path58.default.relative(scanPath, dockerfilePath));
|
|
13735
14467
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
13736
14468
|
graph,
|
|
13737
14469
|
service.pkg.name,
|
|
@@ -13740,15 +14472,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
13740
14472
|
);
|
|
13741
14473
|
nodesAdded += fn;
|
|
13742
14474
|
edgesAdded += fe;
|
|
13743
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
14475
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types48.EdgeType.RUNS_ON);
|
|
13744
14476
|
if (!graph.hasEdge(edgeId)) {
|
|
13745
14477
|
const edge = {
|
|
13746
14478
|
id: edgeId,
|
|
13747
14479
|
source: fileNodeId,
|
|
13748
14480
|
target: node.id,
|
|
13749
|
-
type:
|
|
13750
|
-
provenance:
|
|
13751
|
-
confidence: (0,
|
|
14481
|
+
type: import_types48.EdgeType.RUNS_ON,
|
|
14482
|
+
provenance: import_types48.Provenance.EXTRACTED,
|
|
14483
|
+
confidence: (0, import_types48.confidenceForExtracted)("structural"),
|
|
13752
14484
|
evidence: {
|
|
13753
14485
|
file: evidenceFile,
|
|
13754
14486
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -13763,15 +14495,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
13763
14495
|
graph.addNode(portNode.id, portNode);
|
|
13764
14496
|
nodesAdded++;
|
|
13765
14497
|
}
|
|
13766
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
14498
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types48.EdgeType.CONNECTS_TO);
|
|
13767
14499
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
13768
14500
|
const portEdge = {
|
|
13769
14501
|
id: portEdgeId,
|
|
13770
14502
|
source: fileNodeId,
|
|
13771
14503
|
target: portNode.id,
|
|
13772
|
-
type:
|
|
13773
|
-
provenance:
|
|
13774
|
-
confidence: (0,
|
|
14504
|
+
type: import_types48.EdgeType.CONNECTS_TO,
|
|
14505
|
+
provenance: import_types48.Provenance.EXTRACTED,
|
|
14506
|
+
confidence: (0, import_types48.confidenceForExtracted)("structural"),
|
|
13775
14507
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
13776
14508
|
};
|
|
13777
14509
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -13783,23 +14515,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
13783
14515
|
|
|
13784
14516
|
// src/extract/infra/terraform.ts
|
|
13785
14517
|
init_cjs_shims();
|
|
13786
|
-
var
|
|
13787
|
-
var
|
|
13788
|
-
var
|
|
14518
|
+
var import_node_fs26 = require("fs");
|
|
14519
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14520
|
+
var import_types49 = require("@neat.is/types");
|
|
13789
14521
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
13790
14522
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
13791
14523
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
13792
14524
|
if (depth > max) return [];
|
|
13793
14525
|
const out = [];
|
|
13794
|
-
const entries = await
|
|
14526
|
+
const entries = await import_node_fs26.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
13795
14527
|
for (const entry2 of entries) {
|
|
13796
14528
|
if (entry2.isDirectory()) {
|
|
13797
14529
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
13798
|
-
const child =
|
|
14530
|
+
const child = import_node_path59.default.join(start, entry2.name);
|
|
13799
14531
|
if (await isPythonVenvDir(child)) continue;
|
|
13800
14532
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
13801
14533
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
13802
|
-
out.push(
|
|
14534
|
+
out.push(import_node_path59.default.join(start, entry2.name));
|
|
13803
14535
|
}
|
|
13804
14536
|
}
|
|
13805
14537
|
return out;
|
|
@@ -13830,8 +14562,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
13830
14562
|
let edgesAdded = 0;
|
|
13831
14563
|
const files = await walkTfFiles(scanPath);
|
|
13832
14564
|
for (const file of files) {
|
|
13833
|
-
const content = await
|
|
13834
|
-
const evidenceFile = toPosix(
|
|
14565
|
+
const content = await import_node_fs26.promises.readFile(file, "utf8");
|
|
14566
|
+
const evidenceFile = toPosix(import_node_path59.default.relative(scanPath, file));
|
|
13835
14567
|
const resources = [];
|
|
13836
14568
|
const byKey = /* @__PURE__ */ new Map();
|
|
13837
14569
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -13866,16 +14598,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
13866
14598
|
if (!target) continue;
|
|
13867
14599
|
if (seen.has(target.nodeId)) continue;
|
|
13868
14600
|
seen.add(target.nodeId);
|
|
13869
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
14601
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types49.EdgeType.DEPENDS_ON);
|
|
13870
14602
|
if (graph.hasEdge(edgeId)) continue;
|
|
13871
14603
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
13872
14604
|
const edge = {
|
|
13873
14605
|
id: edgeId,
|
|
13874
14606
|
source: resource.nodeId,
|
|
13875
14607
|
target: target.nodeId,
|
|
13876
|
-
type:
|
|
13877
|
-
provenance:
|
|
13878
|
-
confidence: (0,
|
|
14608
|
+
type: import_types49.EdgeType.DEPENDS_ON,
|
|
14609
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
14610
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
13879
14611
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
13880
14612
|
};
|
|
13881
14613
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -13888,8 +14620,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
13888
14620
|
|
|
13889
14621
|
// src/extract/infra/k8s.ts
|
|
13890
14622
|
init_cjs_shims();
|
|
13891
|
-
var
|
|
13892
|
-
var
|
|
14623
|
+
var import_node_fs27 = require("fs");
|
|
14624
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
13893
14625
|
var import_yaml3 = require("yaml");
|
|
13894
14626
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
13895
14627
|
Service: "k8s-service",
|
|
@@ -13903,15 +14635,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
13903
14635
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
13904
14636
|
if (depth > max) return [];
|
|
13905
14637
|
const out = [];
|
|
13906
|
-
const entries = await
|
|
14638
|
+
const entries = await import_node_fs27.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
13907
14639
|
for (const entry2 of entries) {
|
|
13908
14640
|
if (entry2.isDirectory()) {
|
|
13909
14641
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
13910
|
-
const child =
|
|
14642
|
+
const child = import_node_path60.default.join(start, entry2.name);
|
|
13911
14643
|
if (await isPythonVenvDir(child)) continue;
|
|
13912
14644
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
13913
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
13914
|
-
out.push(
|
|
14645
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path60.default.extname(entry2.name))) {
|
|
14646
|
+
out.push(import_node_path60.default.join(start, entry2.name));
|
|
13915
14647
|
}
|
|
13916
14648
|
}
|
|
13917
14649
|
return out;
|
|
@@ -13920,7 +14652,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
13920
14652
|
let nodesAdded = 0;
|
|
13921
14653
|
const files = await walkYamlFiles2(scanPath);
|
|
13922
14654
|
for (const file of files) {
|
|
13923
|
-
const content = await
|
|
14655
|
+
const content = await import_node_fs27.promises.readFile(file, "utf8");
|
|
13924
14656
|
let docs;
|
|
13925
14657
|
try {
|
|
13926
14658
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -13944,16 +14676,16 @@ async function addK8sResources(graph, scanPath) {
|
|
|
13944
14676
|
|
|
13945
14677
|
// src/extract/infra/cloudflare.ts
|
|
13946
14678
|
init_cjs_shims();
|
|
13947
|
-
var
|
|
13948
|
-
var
|
|
14679
|
+
var import_node_fs28 = require("fs");
|
|
14680
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
13949
14681
|
var import_smol_toml3 = require("smol-toml");
|
|
13950
|
-
var
|
|
14682
|
+
var import_types50 = require("@neat.is/types");
|
|
13951
14683
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
13952
14684
|
async function readWranglerConfig(dir) {
|
|
13953
14685
|
for (const filename of WRANGLER_FILENAMES) {
|
|
13954
|
-
const abs =
|
|
14686
|
+
const abs = import_node_path61.default.join(dir, filename);
|
|
13955
14687
|
if (!await exists(abs)) continue;
|
|
13956
|
-
const raw = await
|
|
14688
|
+
const raw = await import_node_fs28.promises.readFile(abs, "utf8");
|
|
13957
14689
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
13958
14690
|
return { config, relFile: filename, raw };
|
|
13959
14691
|
}
|
|
@@ -13995,8 +14727,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
13995
14727
|
source: anchorId,
|
|
13996
14728
|
target: node.id,
|
|
13997
14729
|
type: edgeType,
|
|
13998
|
-
provenance:
|
|
13999
|
-
confidence: (0,
|
|
14730
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
14731
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
14000
14732
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14001
14733
|
};
|
|
14002
14734
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14014,11 +14746,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14014
14746
|
try {
|
|
14015
14747
|
read = await readWranglerConfig(service.dir);
|
|
14016
14748
|
} catch (err) {
|
|
14017
|
-
recordExtractionError("infra cloudflare",
|
|
14749
|
+
recordExtractionError("infra cloudflare", import_node_path61.default.relative(scanPath, service.dir), err);
|
|
14018
14750
|
continue;
|
|
14019
14751
|
}
|
|
14020
14752
|
if (!read || !read.config.name) continue;
|
|
14021
|
-
const evidenceFile = toPosix(
|
|
14753
|
+
const evidenceFile = toPosix(import_node_path61.default.relative(scanPath, import_node_path61.default.join(service.dir, read.relFile)));
|
|
14022
14754
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
14023
14755
|
}
|
|
14024
14756
|
for (const worker of discovered) {
|
|
@@ -14030,7 +14762,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14030
14762
|
}
|
|
14031
14763
|
let anchorId = service.node.id;
|
|
14032
14764
|
if (config.main) {
|
|
14033
|
-
const entryRelPath = toPosix(
|
|
14765
|
+
const entryRelPath = toPosix(import_node_path61.default.normalize(config.main));
|
|
14034
14766
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14035
14767
|
graph,
|
|
14036
14768
|
service.pkg.name,
|
|
@@ -14057,15 +14789,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14057
14789
|
nodesAdded++;
|
|
14058
14790
|
}
|
|
14059
14791
|
if (runtimeNode.id !== anchorId) {
|
|
14060
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
14792
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types50.EdgeType.RUNS_ON);
|
|
14061
14793
|
if (!graph.hasEdge(runsOnId)) {
|
|
14062
14794
|
const edge = {
|
|
14063
14795
|
id: runsOnId,
|
|
14064
14796
|
source: anchorId,
|
|
14065
14797
|
target: runtimeNode.id,
|
|
14066
|
-
type:
|
|
14067
|
-
provenance:
|
|
14068
|
-
confidence: (0,
|
|
14798
|
+
type: import_types50.EdgeType.RUNS_ON,
|
|
14799
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
14800
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
14069
14801
|
evidence: {
|
|
14070
14802
|
file: evidenceFile,
|
|
14071
14803
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -14079,7 +14811,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14079
14811
|
const result = addResourceEdge(
|
|
14080
14812
|
graph,
|
|
14081
14813
|
anchorId,
|
|
14082
|
-
|
|
14814
|
+
import_types50.EdgeType.CONNECTS_TO,
|
|
14083
14815
|
"cloudflare-route",
|
|
14084
14816
|
route,
|
|
14085
14817
|
evidenceFile,
|
|
@@ -14103,7 +14835,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14103
14835
|
const result = addResourceEdge(
|
|
14104
14836
|
graph,
|
|
14105
14837
|
anchorId,
|
|
14106
|
-
|
|
14838
|
+
import_types50.EdgeType.DEPENDS_ON,
|
|
14107
14839
|
group.kind,
|
|
14108
14840
|
name,
|
|
14109
14841
|
evidenceFile,
|
|
@@ -14117,7 +14849,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14117
14849
|
const result = addResourceEdge(
|
|
14118
14850
|
graph,
|
|
14119
14851
|
anchorId,
|
|
14120
|
-
|
|
14852
|
+
import_types50.EdgeType.DEPENDS_ON,
|
|
14121
14853
|
"cloudflare-cron",
|
|
14122
14854
|
cron,
|
|
14123
14855
|
evidenceFile,
|
|
@@ -14130,7 +14862,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14130
14862
|
const result = addResourceEdge(
|
|
14131
14863
|
graph,
|
|
14132
14864
|
anchorId,
|
|
14133
|
-
|
|
14865
|
+
import_types50.EdgeType.DEPENDS_ON,
|
|
14134
14866
|
"cloudflare-env-var",
|
|
14135
14867
|
varName,
|
|
14136
14868
|
evidenceFile,
|
|
@@ -14143,15 +14875,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14143
14875
|
if (!svc.service) continue;
|
|
14144
14876
|
const target = workerIndex.get(svc.service);
|
|
14145
14877
|
if (target && target.anchorId !== anchorId) {
|
|
14146
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
14878
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types50.EdgeType.CALLS);
|
|
14147
14879
|
if (!graph.hasEdge(edgeId)) {
|
|
14148
14880
|
const edge = {
|
|
14149
14881
|
id: edgeId,
|
|
14150
14882
|
source: anchorId,
|
|
14151
14883
|
target: target.anchorId,
|
|
14152
|
-
type:
|
|
14153
|
-
provenance:
|
|
14154
|
-
confidence: (0,
|
|
14884
|
+
type: import_types50.EdgeType.CALLS,
|
|
14885
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
14886
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
14155
14887
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
14156
14888
|
};
|
|
14157
14889
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14162,7 +14894,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14162
14894
|
const result = addResourceEdge(
|
|
14163
14895
|
graph,
|
|
14164
14896
|
anchorId,
|
|
14165
|
-
|
|
14897
|
+
import_types50.EdgeType.DEPENDS_ON,
|
|
14166
14898
|
"cloudflare-service-binding",
|
|
14167
14899
|
svc.service,
|
|
14168
14900
|
evidenceFile,
|
|
@@ -14177,24 +14909,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14177
14909
|
|
|
14178
14910
|
// src/extract/infra/vercel.ts
|
|
14179
14911
|
init_cjs_shims();
|
|
14180
|
-
var
|
|
14181
|
-
var
|
|
14182
|
-
var
|
|
14912
|
+
var import_node_fs29 = require("fs");
|
|
14913
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
14914
|
+
var import_types51 = require("@neat.is/types");
|
|
14183
14915
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
14184
14916
|
async function readVercelConfig(dir) {
|
|
14185
14917
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
14186
|
-
const abs =
|
|
14918
|
+
const abs = import_node_path62.default.join(dir, filename);
|
|
14187
14919
|
if (!await exists(abs)) continue;
|
|
14188
|
-
const raw = await
|
|
14920
|
+
const raw = await import_node_fs29.promises.readFile(abs, "utf8");
|
|
14189
14921
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
14190
14922
|
return { config, relFile: filename, raw };
|
|
14191
14923
|
}
|
|
14192
14924
|
return null;
|
|
14193
14925
|
}
|
|
14194
14926
|
async function readLinkedProjectName(dir) {
|
|
14195
|
-
const abs =
|
|
14927
|
+
const abs = import_node_path62.default.join(dir, ".vercel", "project.json");
|
|
14196
14928
|
if (!await exists(abs)) return void 0;
|
|
14197
|
-
const parsed = JSON.parse(await
|
|
14929
|
+
const parsed = JSON.parse(await import_node_fs29.promises.readFile(abs, "utf8"));
|
|
14198
14930
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
14199
14931
|
}
|
|
14200
14932
|
function routeSource(route) {
|
|
@@ -14210,7 +14942,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14210
14942
|
read = await readVercelConfig(service.dir);
|
|
14211
14943
|
projectName = await readLinkedProjectName(service.dir);
|
|
14212
14944
|
} catch (err) {
|
|
14213
|
-
recordExtractionError("infra vercel",
|
|
14945
|
+
recordExtractionError("infra vercel", import_node_path62.default.relative(scanPath, service.dir), err);
|
|
14214
14946
|
continue;
|
|
14215
14947
|
}
|
|
14216
14948
|
if (!read && !projectName) continue;
|
|
@@ -14226,7 +14958,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14226
14958
|
const anchorId = service.node.id;
|
|
14227
14959
|
if (!read) continue;
|
|
14228
14960
|
const { config, relFile, raw } = read;
|
|
14229
|
-
const evidenceFile = toPosix(
|
|
14961
|
+
const evidenceFile = toPosix(import_node_path62.default.relative(scanPath, import_node_path62.default.join(service.dir, relFile)));
|
|
14230
14962
|
const add = (edgeType, kind, name) => {
|
|
14231
14963
|
if (!name) return;
|
|
14232
14964
|
const result = emitPlatformResourceEdge(
|
|
@@ -14242,12 +14974,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14242
14974
|
nodesAdded += result.nodesAdded;
|
|
14243
14975
|
edgesAdded += result.edgesAdded;
|
|
14244
14976
|
};
|
|
14245
|
-
add(
|
|
14246
|
-
for (const cron of config.crons ?? []) add(
|
|
14247
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
14248
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
14977
|
+
add(import_types51.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
14978
|
+
for (const cron of config.crons ?? []) add(import_types51.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
14979
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types51.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
14980
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types51.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
14249
14981
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
14250
|
-
add(
|
|
14982
|
+
add(import_types51.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
14251
14983
|
}
|
|
14252
14984
|
}
|
|
14253
14985
|
return { nodesAdded, edgesAdded };
|
|
@@ -14255,16 +14987,16 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14255
14987
|
|
|
14256
14988
|
// src/extract/infra/railway.ts
|
|
14257
14989
|
init_cjs_shims();
|
|
14258
|
-
var
|
|
14259
|
-
var
|
|
14990
|
+
var import_node_fs30 = require("fs");
|
|
14991
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
14260
14992
|
var import_smol_toml4 = require("smol-toml");
|
|
14261
|
-
var
|
|
14993
|
+
var import_types52 = require("@neat.is/types");
|
|
14262
14994
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
14263
14995
|
async function readRailwayConfig(dir) {
|
|
14264
14996
|
for (const filename of RAILWAY_FILENAMES) {
|
|
14265
|
-
const abs =
|
|
14997
|
+
const abs = import_node_path63.default.join(dir, filename);
|
|
14266
14998
|
if (!await exists(abs)) continue;
|
|
14267
|
-
const raw = await
|
|
14999
|
+
const raw = await import_node_fs30.promises.readFile(abs, "utf8");
|
|
14268
15000
|
const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14269
15001
|
return { config, relFile: filename, raw };
|
|
14270
15002
|
}
|
|
@@ -14278,7 +15010,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14278
15010
|
try {
|
|
14279
15011
|
read = await readRailwayConfig(service.dir);
|
|
14280
15012
|
} catch (err) {
|
|
14281
|
-
recordExtractionError("infra railway",
|
|
15013
|
+
recordExtractionError("infra railway", import_node_path63.default.relative(scanPath, service.dir), err);
|
|
14282
15014
|
continue;
|
|
14283
15015
|
}
|
|
14284
15016
|
if (!read) continue;
|
|
@@ -14288,7 +15020,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14288
15020
|
}
|
|
14289
15021
|
const anchorId = service.node.id;
|
|
14290
15022
|
const { config, relFile, raw } = read;
|
|
14291
|
-
const evidenceFile = toPosix(
|
|
15023
|
+
const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, import_node_path63.default.join(service.dir, relFile)));
|
|
14292
15024
|
const add = (edgeType, kind, name) => {
|
|
14293
15025
|
if (!name) return;
|
|
14294
15026
|
const result = emitPlatformResourceEdge(
|
|
@@ -14304,24 +15036,24 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14304
15036
|
nodesAdded += result.nodesAdded;
|
|
14305
15037
|
edgesAdded += result.edgesAdded;
|
|
14306
15038
|
};
|
|
14307
|
-
add(
|
|
14308
|
-
add(
|
|
14309
|
-
add(
|
|
15039
|
+
add(import_types52.EdgeType.RUNS_ON, "railway", "railway");
|
|
15040
|
+
add(import_types52.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
15041
|
+
add(import_types52.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
14310
15042
|
}
|
|
14311
15043
|
return { nodesAdded, edgesAdded };
|
|
14312
15044
|
}
|
|
14313
15045
|
|
|
14314
15046
|
// src/extract/infra/supabase.ts
|
|
14315
15047
|
init_cjs_shims();
|
|
14316
|
-
var
|
|
14317
|
-
var
|
|
15048
|
+
var import_node_fs31 = require("fs");
|
|
15049
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
14318
15050
|
var import_smol_toml5 = require("smol-toml");
|
|
14319
|
-
var
|
|
15051
|
+
var import_types53 = require("@neat.is/types");
|
|
14320
15052
|
async function readSupabaseConfig(dir) {
|
|
14321
|
-
const relFile =
|
|
14322
|
-
const abs =
|
|
15053
|
+
const relFile = import_node_path64.default.join("supabase", "config.toml");
|
|
15054
|
+
const abs = import_node_path64.default.join(dir, relFile);
|
|
14323
15055
|
if (!await exists(abs)) return null;
|
|
14324
|
-
const raw = await
|
|
15056
|
+
const raw = await import_node_fs31.promises.readFile(abs, "utf8");
|
|
14325
15057
|
const config = (0, import_smol_toml5.parse)(raw);
|
|
14326
15058
|
return { config, relFile, raw };
|
|
14327
15059
|
}
|
|
@@ -14333,7 +15065,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14333
15065
|
try {
|
|
14334
15066
|
read = await readSupabaseConfig(service.dir);
|
|
14335
15067
|
} catch (err) {
|
|
14336
|
-
recordExtractionError("infra supabase",
|
|
15068
|
+
recordExtractionError("infra supabase", import_node_path64.default.relative(scanPath, service.dir), err);
|
|
14337
15069
|
continue;
|
|
14338
15070
|
}
|
|
14339
15071
|
if (!read) continue;
|
|
@@ -14348,7 +15080,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14348
15080
|
});
|
|
14349
15081
|
}
|
|
14350
15082
|
const anchorId = service.node.id;
|
|
14351
|
-
const evidenceFile = toPosix(
|
|
15083
|
+
const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, import_node_path64.default.join(service.dir, relFile)));
|
|
14352
15084
|
const add = (edgeType, kind, name) => {
|
|
14353
15085
|
if (!name) return;
|
|
14354
15086
|
const result = emitPlatformResourceEdge(
|
|
@@ -14364,10 +15096,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14364
15096
|
nodesAdded += result.nodesAdded;
|
|
14365
15097
|
edgesAdded += result.edgesAdded;
|
|
14366
15098
|
};
|
|
14367
|
-
add(
|
|
14368
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
14369
|
-
if (config.storage) add(
|
|
14370
|
-
if (config.auth) add(
|
|
15099
|
+
add(import_types53.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
15100
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types53.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
15101
|
+
if (config.storage) add(import_types53.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
15102
|
+
if (config.auth) add(import_types53.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
14371
15103
|
}
|
|
14372
15104
|
return { nodesAdded, edgesAdded };
|
|
14373
15105
|
}
|
|
@@ -14390,14 +15122,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
14390
15122
|
|
|
14391
15123
|
// src/extract/zod-shapes.ts
|
|
14392
15124
|
init_cjs_shims();
|
|
14393
|
-
var
|
|
14394
|
-
var
|
|
15125
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
15126
|
+
var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
|
|
14395
15127
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
14396
|
-
var
|
|
15128
|
+
var import_types54 = require("@neat.is/types");
|
|
14397
15129
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
14398
15130
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
14399
15131
|
function parserForExt4(ext) {
|
|
14400
|
-
const p = new
|
|
15132
|
+
const p = new import_tree_sitter17.default();
|
|
14401
15133
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
14402
15134
|
return p;
|
|
14403
15135
|
}
|
|
@@ -14485,7 +15217,7 @@ function topLevelSchemas(root) {
|
|
|
14485
15217
|
}
|
|
14486
15218
|
function zodShapesFromFile(file, serviceDir) {
|
|
14487
15219
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
14488
|
-
const tree = parseSource3(parserForExt4(
|
|
15220
|
+
const tree = parseSource3(parserForExt4(import_node_path65.default.extname(file.path)), file.content);
|
|
14489
15221
|
const out = [];
|
|
14490
15222
|
const seen = /* @__PURE__ */ new Set();
|
|
14491
15223
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -14499,11 +15231,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
14499
15231
|
seen.add(name);
|
|
14500
15232
|
const line = call.startPosition.row + 1;
|
|
14501
15233
|
out.push({
|
|
14502
|
-
infraId: (0,
|
|
15234
|
+
infraId: (0, import_types54.infraId)("zod-schema", name),
|
|
14503
15235
|
name,
|
|
14504
15236
|
fields,
|
|
14505
15237
|
evidence: {
|
|
14506
|
-
file:
|
|
15238
|
+
file: import_node_path65.default.relative(serviceDir, file.path),
|
|
14507
15239
|
line,
|
|
14508
15240
|
snippet: snippet(file.content, line)
|
|
14509
15241
|
}
|
|
@@ -14534,7 +15266,7 @@ async function addZodShapes(graph, services) {
|
|
|
14534
15266
|
if (!graph.hasNode(shape.infraId)) {
|
|
14535
15267
|
const node = {
|
|
14536
15268
|
id: shape.infraId,
|
|
14537
|
-
type:
|
|
15269
|
+
type: import_types54.NodeType.InfraNode,
|
|
14538
15270
|
name: shape.name,
|
|
14539
15271
|
provider: "self",
|
|
14540
15272
|
kind: "zod-schema"
|
|
@@ -14544,14 +15276,14 @@ async function addZodShapes(graph, services) {
|
|
|
14544
15276
|
}
|
|
14545
15277
|
if (shape.fields.length > 0) {
|
|
14546
15278
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
14547
|
-
if (node.type ===
|
|
15279
|
+
if (node.type === import_types54.NodeType.InfraNode) {
|
|
14548
15280
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
14549
15281
|
...node,
|
|
14550
15282
|
columns: foldColumns(
|
|
14551
15283
|
node.columns,
|
|
14552
15284
|
shape.fields,
|
|
14553
|
-
|
|
14554
|
-
(0,
|
|
15285
|
+
import_types54.Provenance.EXTRACTED,
|
|
15286
|
+
(0, import_types54.confidenceForExtracted)("structural")
|
|
14555
15287
|
)
|
|
14556
15288
|
});
|
|
14557
15289
|
}
|
|
@@ -14565,15 +15297,15 @@ async function addZodShapes(graph, services) {
|
|
|
14565
15297
|
);
|
|
14566
15298
|
nodesAdded += n;
|
|
14567
15299
|
edgesAdded += e;
|
|
14568
|
-
const edgeId = (0,
|
|
15300
|
+
const edgeId = (0, import_types54.extractedEdgeId)(fileNodeId, shape.infraId, import_types54.EdgeType.CONTAINS);
|
|
14569
15301
|
if (!graph.hasEdge(edgeId)) {
|
|
14570
15302
|
const edge = {
|
|
14571
15303
|
id: edgeId,
|
|
14572
15304
|
source: fileNodeId,
|
|
14573
15305
|
target: shape.infraId,
|
|
14574
|
-
type:
|
|
14575
|
-
provenance:
|
|
14576
|
-
confidence: (0,
|
|
15306
|
+
type: import_types54.EdgeType.CONTAINS,
|
|
15307
|
+
provenance: import_types54.Provenance.EXTRACTED,
|
|
15308
|
+
confidence: (0, import_types54.confidenceForExtracted)("structural"),
|
|
14577
15309
|
evidence: shape.evidence
|
|
14578
15310
|
};
|
|
14579
15311
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -14587,7 +15319,7 @@ async function addZodShapes(graph, services) {
|
|
|
14587
15319
|
|
|
14588
15320
|
// src/extract/firestore-rules.ts
|
|
14589
15321
|
init_cjs_shims();
|
|
14590
|
-
var
|
|
15322
|
+
var import_types55 = require("@neat.is/types");
|
|
14591
15323
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
14592
15324
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
14593
15325
|
function stripComments(src) {
|
|
@@ -14727,7 +15459,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
14727
15459
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
14728
15460
|
graph.forEachNode((id, attrs) => {
|
|
14729
15461
|
const node = attrs;
|
|
14730
|
-
if (node.type !==
|
|
15462
|
+
if (node.type !== import_types55.NodeType.InfraNode) return;
|
|
14731
15463
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
14732
15464
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
14733
15465
|
if (!fields || fields.size === 0) return;
|
|
@@ -14740,17 +15472,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
14740
15472
|
}
|
|
14741
15473
|
|
|
14742
15474
|
// src/extract/index.ts
|
|
14743
|
-
var
|
|
15475
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
14744
15476
|
|
|
14745
15477
|
// src/extract/retire.ts
|
|
14746
15478
|
init_cjs_shims();
|
|
14747
|
-
var
|
|
14748
|
-
var
|
|
14749
|
-
var
|
|
15479
|
+
var import_node_fs32 = require("fs");
|
|
15480
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
15481
|
+
var import_types56 = require("@neat.is/types");
|
|
14750
15482
|
function dropOrphanedFileNodes(graph) {
|
|
14751
15483
|
const orphans = [];
|
|
14752
15484
|
graph.forEachNode((id, attrs) => {
|
|
14753
|
-
if (attrs.type !==
|
|
15485
|
+
if (attrs.type !== import_types56.NodeType.FileNode) return;
|
|
14754
15486
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
14755
15487
|
orphans.push(id);
|
|
14756
15488
|
}
|
|
@@ -14763,14 +15495,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
14763
15495
|
const bases = [scanPath, ...serviceDirs];
|
|
14764
15496
|
graph.forEachEdge((id, attrs) => {
|
|
14765
15497
|
const edge = attrs;
|
|
14766
|
-
if (edge.provenance !==
|
|
15498
|
+
if (edge.provenance !== import_types56.Provenance.EXTRACTED) return;
|
|
14767
15499
|
const evidenceFile = edge.evidence?.file;
|
|
14768
15500
|
if (!evidenceFile) return;
|
|
14769
|
-
if (
|
|
14770
|
-
if (!(0,
|
|
15501
|
+
if (import_node_path66.default.isAbsolute(evidenceFile)) {
|
|
15502
|
+
if (!(0, import_node_fs32.existsSync)(evidenceFile)) toDrop.push(id);
|
|
14771
15503
|
return;
|
|
14772
15504
|
}
|
|
14773
|
-
const found = bases.some((base) => (0,
|
|
15505
|
+
const found = bases.some((base) => (0, import_node_fs32.existsSync)(import_node_path66.default.join(base, evidenceFile)));
|
|
14774
15506
|
if (!found) toDrop.push(id);
|
|
14775
15507
|
});
|
|
14776
15508
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -14827,7 +15559,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
14827
15559
|
}
|
|
14828
15560
|
const droppedEntries = drainDroppedExtracted();
|
|
14829
15561
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
14830
|
-
const rejectedPath =
|
|
15562
|
+
const rejectedPath = import_node_path67.default.join(import_node_path67.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
14831
15563
|
try {
|
|
14832
15564
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
14833
15565
|
} catch (err) {
|
|
@@ -14861,9 +15593,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
14861
15593
|
|
|
14862
15594
|
// src/persist.ts
|
|
14863
15595
|
init_cjs_shims();
|
|
14864
|
-
var
|
|
14865
|
-
var
|
|
14866
|
-
var
|
|
15596
|
+
var import_node_fs33 = require("fs");
|
|
15597
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
15598
|
+
var import_types57 = require("@neat.is/types");
|
|
14867
15599
|
var SCHEMA_VERSION = 7;
|
|
14868
15600
|
function migrateV1ToV2(payload) {
|
|
14869
15601
|
const nodes = payload.graph.nodes;
|
|
@@ -14887,7 +15619,7 @@ function migrateV5ToV6(payload) {
|
|
|
14887
15619
|
if (Array.isArray(nodes)) {
|
|
14888
15620
|
for (const node of nodes) {
|
|
14889
15621
|
const attrs = node.attributes;
|
|
14890
|
-
if (!attrs || attrs.type !==
|
|
15622
|
+
if (!attrs || attrs.type !== import_types57.NodeType.InfraNode) continue;
|
|
14891
15623
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
14892
15624
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
14893
15625
|
}
|
|
@@ -14903,12 +15635,12 @@ function migrateV2ToV3(payload) {
|
|
|
14903
15635
|
for (const edge of edges) {
|
|
14904
15636
|
const attrs = edge.attributes;
|
|
14905
15637
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
14906
|
-
attrs.provenance =
|
|
15638
|
+
attrs.provenance = import_types57.Provenance.OBSERVED;
|
|
14907
15639
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
14908
15640
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
14909
15641
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
14910
15642
|
if (type && source && target) {
|
|
14911
|
-
const newId = (0,
|
|
15643
|
+
const newId = (0, import_types57.observedEdgeId)(source, target, type);
|
|
14912
15644
|
attrs.id = newId;
|
|
14913
15645
|
if (edge.key) edge.key = newId;
|
|
14914
15646
|
}
|
|
@@ -14917,7 +15649,7 @@ function migrateV2ToV3(payload) {
|
|
|
14917
15649
|
return { ...payload, schemaVersion: 3 };
|
|
14918
15650
|
}
|
|
14919
15651
|
async function ensureDir(filePath) {
|
|
14920
|
-
await
|
|
15652
|
+
await import_node_fs33.promises.mkdir(import_node_path68.default.dirname(filePath), { recursive: true });
|
|
14921
15653
|
}
|
|
14922
15654
|
async function saveGraphToDisk(graph, outPath) {
|
|
14923
15655
|
await ensureDir(outPath);
|
|
@@ -14927,13 +15659,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
14927
15659
|
graph: graph.export()
|
|
14928
15660
|
};
|
|
14929
15661
|
const tmp = `${outPath}.tmp`;
|
|
14930
|
-
await
|
|
14931
|
-
await
|
|
15662
|
+
await import_node_fs33.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
15663
|
+
await import_node_fs33.promises.rename(tmp, outPath);
|
|
14932
15664
|
}
|
|
14933
15665
|
async function loadGraphFromDisk(graph, outPath) {
|
|
14934
15666
|
let raw;
|
|
14935
15667
|
try {
|
|
14936
|
-
raw = await
|
|
15668
|
+
raw = await import_node_fs33.promises.readFile(outPath, "utf8");
|
|
14937
15669
|
} catch (err) {
|
|
14938
15670
|
if (err.code === "ENOENT") return;
|
|
14939
15671
|
throw err;
|
|
@@ -15007,23 +15739,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
15007
15739
|
|
|
15008
15740
|
// src/projects.ts
|
|
15009
15741
|
init_cjs_shims();
|
|
15010
|
-
var
|
|
15742
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
15011
15743
|
function pathsForProject(project, baseDir) {
|
|
15012
15744
|
if (project === DEFAULT_PROJECT) {
|
|
15013
15745
|
return {
|
|
15014
|
-
snapshotPath:
|
|
15015
|
-
errorsPath:
|
|
15016
|
-
staleEventsPath:
|
|
15017
|
-
embeddingsCachePath:
|
|
15018
|
-
policyViolationsPath:
|
|
15746
|
+
snapshotPath: import_node_path69.default.join(baseDir, "graph.json"),
|
|
15747
|
+
errorsPath: import_node_path69.default.join(baseDir, "errors.ndjson"),
|
|
15748
|
+
staleEventsPath: import_node_path69.default.join(baseDir, "stale-events.ndjson"),
|
|
15749
|
+
embeddingsCachePath: import_node_path69.default.join(baseDir, "embeddings.json"),
|
|
15750
|
+
policyViolationsPath: import_node_path69.default.join(baseDir, "policy-violations.ndjson")
|
|
15019
15751
|
};
|
|
15020
15752
|
}
|
|
15021
15753
|
return {
|
|
15022
|
-
snapshotPath:
|
|
15023
|
-
errorsPath:
|
|
15024
|
-
staleEventsPath:
|
|
15025
|
-
embeddingsCachePath:
|
|
15026
|
-
policyViolationsPath:
|
|
15754
|
+
snapshotPath: import_node_path69.default.join(baseDir, `${project}.json`),
|
|
15755
|
+
errorsPath: import_node_path69.default.join(baseDir, `errors.${project}.ndjson`),
|
|
15756
|
+
staleEventsPath: import_node_path69.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
15757
|
+
embeddingsCachePath: import_node_path69.default.join(baseDir, `embeddings.${project}.json`),
|
|
15758
|
+
policyViolationsPath: import_node_path69.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
15027
15759
|
};
|
|
15028
15760
|
}
|
|
15029
15761
|
var Projects = class {
|
|
@@ -15061,19 +15793,19 @@ var Projects = class {
|
|
|
15061
15793
|
init_cjs_shims();
|
|
15062
15794
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
15063
15795
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
15064
|
-
var
|
|
15796
|
+
var import_types92 = require("@neat.is/types");
|
|
15065
15797
|
|
|
15066
15798
|
// src/extend/index.ts
|
|
15067
15799
|
init_cjs_shims();
|
|
15068
|
-
var
|
|
15069
|
-
var
|
|
15800
|
+
var import_node_fs35 = require("fs");
|
|
15801
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
15070
15802
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
15071
15803
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
15072
15804
|
|
|
15073
15805
|
// src/installers/package-manager.ts
|
|
15074
15806
|
init_cjs_shims();
|
|
15075
|
-
var
|
|
15076
|
-
var
|
|
15807
|
+
var import_node_fs34 = require("fs");
|
|
15808
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
15077
15809
|
var import_node_child_process = require("child_process");
|
|
15078
15810
|
var LOCKFILE_PRIORITY = [
|
|
15079
15811
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -15088,29 +15820,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
15088
15820
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
15089
15821
|
async function exists2(p) {
|
|
15090
15822
|
try {
|
|
15091
|
-
await
|
|
15823
|
+
await import_node_fs34.promises.access(p);
|
|
15092
15824
|
return true;
|
|
15093
15825
|
} catch {
|
|
15094
15826
|
return false;
|
|
15095
15827
|
}
|
|
15096
15828
|
}
|
|
15097
15829
|
async function detectPackageManager(serviceDir) {
|
|
15098
|
-
let dir =
|
|
15830
|
+
let dir = import_node_path70.default.resolve(serviceDir);
|
|
15099
15831
|
const stops = /* @__PURE__ */ new Set();
|
|
15100
15832
|
for (let i = 0; i < 64; i++) {
|
|
15101
15833
|
if (stops.has(dir)) break;
|
|
15102
15834
|
stops.add(dir);
|
|
15103
15835
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
15104
|
-
const lockPath =
|
|
15836
|
+
const lockPath = import_node_path70.default.join(dir, candidate.lockfile);
|
|
15105
15837
|
if (await exists2(lockPath)) {
|
|
15106
15838
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
15107
15839
|
}
|
|
15108
15840
|
}
|
|
15109
|
-
const parent =
|
|
15841
|
+
const parent = import_node_path70.default.dirname(dir);
|
|
15110
15842
|
if (parent === dir) break;
|
|
15111
15843
|
dir = parent;
|
|
15112
15844
|
}
|
|
15113
|
-
return { pm: "npm", cwd:
|
|
15845
|
+
return { pm: "npm", cwd: import_node_path70.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
15114
15846
|
}
|
|
15115
15847
|
async function runPackageManagerInstall(cmd) {
|
|
15116
15848
|
return new Promise((resolve) => {
|
|
@@ -15152,15 +15884,15 @@ ${err.message}`
|
|
|
15152
15884
|
// src/extend/index.ts
|
|
15153
15885
|
async function fileExists2(p) {
|
|
15154
15886
|
try {
|
|
15155
|
-
await
|
|
15887
|
+
await import_node_fs35.promises.access(p);
|
|
15156
15888
|
return true;
|
|
15157
15889
|
} catch {
|
|
15158
15890
|
return false;
|
|
15159
15891
|
}
|
|
15160
15892
|
}
|
|
15161
15893
|
async function readPackageJson(scanPath) {
|
|
15162
|
-
const pkgPath =
|
|
15163
|
-
const raw = await
|
|
15894
|
+
const pkgPath = import_node_path71.default.join(scanPath, "package.json");
|
|
15895
|
+
const raw = await import_node_fs35.promises.readFile(pkgPath, "utf8");
|
|
15164
15896
|
return JSON.parse(raw);
|
|
15165
15897
|
}
|
|
15166
15898
|
var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
@@ -15173,27 +15905,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
15173
15905
|
]);
|
|
15174
15906
|
async function findHookFiles(scanPath) {
|
|
15175
15907
|
const found = [];
|
|
15176
|
-
const
|
|
15177
|
-
const entries = await
|
|
15908
|
+
const walk10 = async (dir) => {
|
|
15909
|
+
const entries = await import_node_fs35.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
15178
15910
|
for (const entry2 of entries) {
|
|
15179
15911
|
if (entry2.isDirectory()) {
|
|
15180
15912
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
15181
|
-
await
|
|
15913
|
+
await walk10(import_node_path71.default.join(dir, entry2.name));
|
|
15182
15914
|
} else if (entry2.isFile()) {
|
|
15183
15915
|
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
15184
|
-
const rel =
|
|
15185
|
-
found.push(rel.split(
|
|
15916
|
+
const rel = import_node_path71.default.relative(scanPath, import_node_path71.default.join(dir, entry2.name));
|
|
15917
|
+
found.push(rel.split(import_node_path71.default.sep).join("/"));
|
|
15186
15918
|
}
|
|
15187
15919
|
}
|
|
15188
15920
|
}
|
|
15189
15921
|
};
|
|
15190
|
-
await
|
|
15922
|
+
await walk10(scanPath);
|
|
15191
15923
|
return found.sort();
|
|
15192
15924
|
}
|
|
15193
15925
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
15194
15926
|
let fallback = null;
|
|
15195
15927
|
for (const file of hookFiles) {
|
|
15196
|
-
const content = await
|
|
15928
|
+
const content = await import_node_fs35.promises.readFile(import_node_path71.default.join(scanPath, file), "utf8");
|
|
15197
15929
|
const patched = splicedContent(content, snippet2);
|
|
15198
15930
|
if (patched !== null) return { file, content, patched };
|
|
15199
15931
|
if (fallback === null) fallback = { file, content };
|
|
@@ -15201,12 +15933,12 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
15201
15933
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
15202
15934
|
}
|
|
15203
15935
|
function extendLogPath() {
|
|
15204
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
15936
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path71.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
15205
15937
|
}
|
|
15206
15938
|
async function appendExtendLog(entry2) {
|
|
15207
15939
|
const logPath = extendLogPath();
|
|
15208
|
-
await
|
|
15209
|
-
await
|
|
15940
|
+
await import_node_fs35.promises.mkdir(import_node_path71.default.dirname(logPath), { recursive: true });
|
|
15941
|
+
await import_node_fs35.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
15210
15942
|
}
|
|
15211
15943
|
function splicedContent(fileContent, snippet2) {
|
|
15212
15944
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -15264,7 +15996,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
15264
15996
|
}
|
|
15265
15997
|
async function describeProjectInstrumentation(ctx) {
|
|
15266
15998
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
15267
|
-
const envNeat = await fileExists2(
|
|
15999
|
+
const envNeat = await fileExists2(import_node_path71.default.join(ctx.scanPath, ".env.neat"));
|
|
15268
16000
|
const registryInstrPackages = new Set(
|
|
15269
16001
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
15270
16002
|
);
|
|
@@ -15286,7 +16018,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
15286
16018
|
);
|
|
15287
16019
|
}
|
|
15288
16020
|
for (const file of hookFiles) {
|
|
15289
|
-
const content = await
|
|
16021
|
+
const content = await import_node_fs35.promises.readFile(import_node_path71.default.join(ctx.scanPath, file), "utf8");
|
|
15290
16022
|
if (content.includes(args.registration_snippet)) {
|
|
15291
16023
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
15292
16024
|
}
|
|
@@ -15298,18 +16030,18 @@ async function applyExtension(ctx, args, options) {
|
|
|
15298
16030
|
);
|
|
15299
16031
|
}
|
|
15300
16032
|
const primaryFile = primary.file;
|
|
15301
|
-
const primaryPath =
|
|
16033
|
+
const primaryPath = import_node_path71.default.join(ctx.scanPath, primaryFile);
|
|
15302
16034
|
const filesTouched = [];
|
|
15303
16035
|
const depsAdded = [];
|
|
15304
|
-
const pkgPath =
|
|
16036
|
+
const pkgPath = import_node_path71.default.join(ctx.scanPath, "package.json");
|
|
15305
16037
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
15306
16038
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
15307
16039
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
15308
|
-
await
|
|
16040
|
+
await import_node_fs35.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
15309
16041
|
filesTouched.push("package.json");
|
|
15310
16042
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
15311
16043
|
}
|
|
15312
|
-
await
|
|
16044
|
+
await import_node_fs35.promises.writeFile(primaryPath, primary.patched, "utf8");
|
|
15313
16045
|
filesTouched.push(primaryFile);
|
|
15314
16046
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
15315
16047
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -15340,7 +16072,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
15340
16072
|
};
|
|
15341
16073
|
}
|
|
15342
16074
|
for (const file of hookFiles) {
|
|
15343
|
-
const content = await
|
|
16075
|
+
const content = await import_node_fs35.promises.readFile(import_node_path71.default.join(ctx.scanPath, file), "utf8");
|
|
15344
16076
|
if (content.includes(args.registration_snippet)) {
|
|
15345
16077
|
return {
|
|
15346
16078
|
library: args.library,
|
|
@@ -15375,28 +16107,28 @@ async function rollbackExtension(ctx, args) {
|
|
|
15375
16107
|
if (!await fileExists2(logPath)) {
|
|
15376
16108
|
return { undone: false, message: "no apply found for library" };
|
|
15377
16109
|
}
|
|
15378
|
-
const raw = await
|
|
16110
|
+
const raw = await import_node_fs35.promises.readFile(logPath, "utf8");
|
|
15379
16111
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
15380
16112
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
15381
16113
|
if (!match) {
|
|
15382
16114
|
return { undone: false, message: "no apply found for library" };
|
|
15383
16115
|
}
|
|
15384
|
-
const pkgPath =
|
|
16116
|
+
const pkgPath = import_node_path71.default.join(ctx.scanPath, "package.json");
|
|
15385
16117
|
if (await fileExists2(pkgPath)) {
|
|
15386
16118
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
15387
16119
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
15388
16120
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
15389
16121
|
pkg.dependencies = rest;
|
|
15390
|
-
await
|
|
16122
|
+
await import_node_fs35.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
15391
16123
|
}
|
|
15392
16124
|
}
|
|
15393
16125
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
15394
16126
|
for (const file of hookFiles) {
|
|
15395
|
-
const filePath =
|
|
15396
|
-
const content = await
|
|
16127
|
+
const filePath = import_node_path71.default.join(ctx.scanPath, file);
|
|
16128
|
+
const content = await import_node_fs35.promises.readFile(filePath, "utf8");
|
|
15397
16129
|
if (content.includes(match.registration_snippet)) {
|
|
15398
16130
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
15399
|
-
await
|
|
16131
|
+
await import_node_fs35.promises.writeFile(filePath, filtered, "utf8");
|
|
15400
16132
|
break;
|
|
15401
16133
|
}
|
|
15402
16134
|
}
|
|
@@ -15408,39 +16140,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
15408
16140
|
|
|
15409
16141
|
// src/divergences.ts
|
|
15410
16142
|
init_cjs_shims();
|
|
15411
|
-
var
|
|
16143
|
+
var import_types58 = require("@neat.is/types");
|
|
15412
16144
|
function bucketKey(source, target, type) {
|
|
15413
16145
|
return `${type}|${source}|${target}`;
|
|
15414
16146
|
}
|
|
15415
16147
|
function bucketSourceFor(graph, edge) {
|
|
15416
|
-
if (edge.type !==
|
|
15417
|
-
const parsed = (0,
|
|
16148
|
+
if (edge.type !== import_types58.EdgeType.CONNECTS_TO) return edge.source;
|
|
16149
|
+
const parsed = (0, import_types58.parseFileId)(edge.source);
|
|
15418
16150
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
15419
16151
|
const target = graph.getNodeAttributes(edge.target);
|
|
15420
|
-
if (target.type !==
|
|
15421
|
-
return (0,
|
|
16152
|
+
if (target.type !== import_types58.NodeType.DatabaseNode) return edge.source;
|
|
16153
|
+
return (0, import_types58.serviceId)(parsed.service);
|
|
15422
16154
|
}
|
|
15423
16155
|
function bucketEdges(graph) {
|
|
15424
16156
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
15425
16157
|
graph.forEachEdge((id, attrs) => {
|
|
15426
16158
|
const e = attrs;
|
|
15427
|
-
const parsed = (0,
|
|
16159
|
+
const parsed = (0, import_types58.parseEdgeId)(id);
|
|
15428
16160
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
15429
16161
|
const source = bucketSourceFor(graph, e);
|
|
15430
16162
|
const key = bucketKey(source, e.target, e.type);
|
|
15431
16163
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
15432
16164
|
switch (provenance) {
|
|
15433
|
-
case
|
|
16165
|
+
case import_types58.Provenance.EXTRACTED:
|
|
15434
16166
|
cur.extracted = e;
|
|
15435
16167
|
break;
|
|
15436
|
-
case
|
|
16168
|
+
case import_types58.Provenance.OBSERVED:
|
|
15437
16169
|
cur.observed = e;
|
|
15438
16170
|
break;
|
|
15439
|
-
case
|
|
16171
|
+
case import_types58.Provenance.INFERRED:
|
|
15440
16172
|
cur.inferred = e;
|
|
15441
16173
|
break;
|
|
15442
16174
|
default:
|
|
15443
|
-
if (e.provenance ===
|
|
16175
|
+
if (e.provenance === import_types58.Provenance.STALE) cur.stale = e;
|
|
15444
16176
|
}
|
|
15445
16177
|
buckets2.set(key, cur);
|
|
15446
16178
|
});
|
|
@@ -15449,22 +16181,22 @@ function bucketEdges(graph) {
|
|
|
15449
16181
|
function nodeIsFrontier(graph, nodeId) {
|
|
15450
16182
|
if (!graph.hasNode(nodeId)) return false;
|
|
15451
16183
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
15452
|
-
return attrs.type ===
|
|
16184
|
+
return attrs.type === import_types58.NodeType.FrontierNode;
|
|
15453
16185
|
}
|
|
15454
16186
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
15455
16187
|
if (!graph.hasNode(nodeId)) return false;
|
|
15456
16188
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
15457
|
-
return attrs.type ===
|
|
16189
|
+
return attrs.type === import_types58.NodeType.WebSocketChannelNode;
|
|
15458
16190
|
}
|
|
15459
16191
|
function nodeIsServerAction(graph, nodeId) {
|
|
15460
16192
|
if (!graph.hasNode(nodeId)) return false;
|
|
15461
16193
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
15462
|
-
return attrs.type ===
|
|
16194
|
+
return attrs.type === import_types58.NodeType.ServerActionNode;
|
|
15463
16195
|
}
|
|
15464
16196
|
function nodeIsSymbol(graph, nodeId) {
|
|
15465
16197
|
if (!graph.hasNode(nodeId)) return false;
|
|
15466
16198
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
15467
|
-
return attrs.type ===
|
|
16199
|
+
return attrs.type === import_types58.NodeType.SymbolNode;
|
|
15468
16200
|
}
|
|
15469
16201
|
function clampConfidence(n) {
|
|
15470
16202
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -15484,14 +16216,14 @@ function gradedConfidence(edge) {
|
|
|
15484
16216
|
return clampConfidence(confidenceForEdge(edge));
|
|
15485
16217
|
}
|
|
15486
16218
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
16219
|
+
import_types58.EdgeType.CALLS,
|
|
16220
|
+
import_types58.EdgeType.CONNECTS_TO,
|
|
16221
|
+
import_types58.EdgeType.PUBLISHES_TO,
|
|
16222
|
+
import_types58.EdgeType.CONSUMES_FROM
|
|
15491
16223
|
]);
|
|
15492
16224
|
function detectMissingDivergences(graph, bucket) {
|
|
15493
16225
|
const out = [];
|
|
15494
|
-
if (bucket.type ===
|
|
16226
|
+
if (bucket.type === import_types58.EdgeType.CONTAINS) return out;
|
|
15495
16227
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
15496
16228
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
15497
16229
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -15533,7 +16265,7 @@ function declaredHostFor(svc) {
|
|
|
15533
16265
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
15534
16266
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
15535
16267
|
const e = graph.getEdgeAttributes(edgeId);
|
|
15536
|
-
if (e.type ===
|
|
16268
|
+
if (e.type === import_types58.EdgeType.CONFIGURED_BY && e.provenance === import_types58.Provenance.EXTRACTED) {
|
|
15537
16269
|
return true;
|
|
15538
16270
|
}
|
|
15539
16271
|
}
|
|
@@ -15546,10 +16278,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
15546
16278
|
const out = [];
|
|
15547
16279
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
15548
16280
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
15549
|
-
if (edge.type !==
|
|
15550
|
-
if (edge.provenance !==
|
|
16281
|
+
if (edge.type !== import_types58.EdgeType.CONNECTS_TO) continue;
|
|
16282
|
+
if (edge.provenance !== import_types58.Provenance.OBSERVED) continue;
|
|
15551
16283
|
const target = graph.getNodeAttributes(edge.target);
|
|
15552
|
-
if (target.type !==
|
|
16284
|
+
if (target.type !== import_types58.NodeType.DatabaseNode) continue;
|
|
15553
16285
|
const observedHost = target.host?.trim();
|
|
15554
16286
|
if (!observedHost) continue;
|
|
15555
16287
|
if (observedHost === declaredHost) continue;
|
|
@@ -15571,10 +16303,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
15571
16303
|
const deps = svc.dependencies ?? {};
|
|
15572
16304
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
15573
16305
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
15574
|
-
if (edge.type !==
|
|
15575
|
-
if (edge.provenance !==
|
|
16306
|
+
if (edge.type !== import_types58.EdgeType.CONNECTS_TO) continue;
|
|
16307
|
+
if (edge.provenance !== import_types58.Provenance.OBSERVED) continue;
|
|
15576
16308
|
const target = graph.getNodeAttributes(edge.target);
|
|
15577
|
-
if (target.type !==
|
|
16309
|
+
if (target.type !== import_types58.NodeType.DatabaseNode) continue;
|
|
15578
16310
|
for (const pair of compatPairs()) {
|
|
15579
16311
|
if (pair.engine !== target.engine) continue;
|
|
15580
16312
|
const declared = deps[pair.driver];
|
|
@@ -15671,7 +16403,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
15671
16403
|
for (const d of all) {
|
|
15672
16404
|
if (d.type !== "host-mismatch") continue;
|
|
15673
16405
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
15674
|
-
declaredHalf.add((0,
|
|
16406
|
+
declaredHalf.add((0, import_types58.databaseId)(d.extractedHost));
|
|
15675
16407
|
}
|
|
15676
16408
|
if (observedHalf.size === 0) return all;
|
|
15677
16409
|
return all.filter((d) => {
|
|
@@ -15690,13 +16422,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
15690
16422
|
}
|
|
15691
16423
|
graph.forEachNode((nodeId, attrs) => {
|
|
15692
16424
|
const n = attrs;
|
|
15693
|
-
if (n.type ===
|
|
16425
|
+
if (n.type === import_types58.NodeType.ServiceNode) {
|
|
15694
16426
|
const svc = n;
|
|
15695
16427
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
15696
16428
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
15697
16429
|
return;
|
|
15698
16430
|
}
|
|
15699
|
-
if (n.type ===
|
|
16431
|
+
if (n.type === import_types58.NodeType.InfraNode && n.kind === "sql-table") {
|
|
15700
16432
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
15701
16433
|
}
|
|
15702
16434
|
});
|
|
@@ -15732,7 +16464,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
15732
16464
|
const bc = "column" in b && b.column ? b.column : "";
|
|
15733
16465
|
return ac.localeCompare(bc);
|
|
15734
16466
|
});
|
|
15735
|
-
return
|
|
16467
|
+
return import_types58.DivergenceResultSchema.parse({
|
|
15736
16468
|
divergences: filtered,
|
|
15737
16469
|
totalAffected: filtered.length,
|
|
15738
16470
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -15786,7 +16518,7 @@ function queryLogEntries(opts) {
|
|
|
15786
16518
|
|
|
15787
16519
|
// src/diff.ts
|
|
15788
16520
|
init_cjs_shims();
|
|
15789
|
-
var
|
|
16521
|
+
var import_node_fs36 = require("fs");
|
|
15790
16522
|
async function loadSnapshotForDiff(target) {
|
|
15791
16523
|
if (/^https?:\/\//i.test(target)) {
|
|
15792
16524
|
const res = await fetch(target);
|
|
@@ -15795,7 +16527,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
15795
16527
|
}
|
|
15796
16528
|
return await res.json();
|
|
15797
16529
|
}
|
|
15798
|
-
const raw = await
|
|
16530
|
+
const raw = await import_node_fs36.promises.readFile(target, "utf8");
|
|
15799
16531
|
return JSON.parse(raw);
|
|
15800
16532
|
}
|
|
15801
16533
|
function indexEntries(entries) {
|
|
@@ -15863,28 +16595,28 @@ function canonicalJson(value) {
|
|
|
15863
16595
|
|
|
15864
16596
|
// src/registry.ts
|
|
15865
16597
|
init_cjs_shims();
|
|
15866
|
-
var
|
|
16598
|
+
var import_node_fs37 = require("fs");
|
|
15867
16599
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
15868
|
-
var
|
|
15869
|
-
var
|
|
16600
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
16601
|
+
var import_types59 = require("@neat.is/types");
|
|
15870
16602
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
15871
16603
|
var LOCK_RETRY_MS = 50;
|
|
15872
16604
|
function neatHome() {
|
|
15873
16605
|
const override = process.env.NEAT_HOME;
|
|
15874
|
-
if (override && override.length > 0) return
|
|
15875
|
-
return
|
|
16606
|
+
if (override && override.length > 0) return import_node_path72.default.resolve(override);
|
|
16607
|
+
return import_node_path72.default.join(import_node_os3.default.homedir(), ".neat");
|
|
15876
16608
|
}
|
|
15877
16609
|
function registryPath() {
|
|
15878
|
-
return
|
|
16610
|
+
return import_node_path72.default.join(neatHome(), "projects.json");
|
|
15879
16611
|
}
|
|
15880
16612
|
function registryLockPath() {
|
|
15881
|
-
return
|
|
16613
|
+
return import_node_path72.default.join(neatHome(), "projects.json.lock");
|
|
15882
16614
|
}
|
|
15883
16615
|
function daemonPidPath() {
|
|
15884
|
-
return
|
|
16616
|
+
return import_node_path72.default.join(neatHome(), "neatd.pid");
|
|
15885
16617
|
}
|
|
15886
16618
|
function daemonsDir() {
|
|
15887
|
-
return
|
|
16619
|
+
return import_node_path72.default.join(neatHome(), "daemons");
|
|
15888
16620
|
}
|
|
15889
16621
|
function isFiniteInt(v) {
|
|
15890
16622
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -15917,7 +16649,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15917
16649
|
const dir = daemonsDir();
|
|
15918
16650
|
let names;
|
|
15919
16651
|
try {
|
|
15920
|
-
names = await
|
|
16652
|
+
names = await import_node_fs37.promises.readdir(dir);
|
|
15921
16653
|
} catch (err) {
|
|
15922
16654
|
if (err.code === "ENOENT") return [];
|
|
15923
16655
|
throw err;
|
|
@@ -15925,10 +16657,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15925
16657
|
const out = [];
|
|
15926
16658
|
for (const name of names) {
|
|
15927
16659
|
if (!name.endsWith(".json")) continue;
|
|
15928
|
-
const file =
|
|
16660
|
+
const file = import_node_path72.default.join(dir, name);
|
|
15929
16661
|
let raw;
|
|
15930
16662
|
try {
|
|
15931
|
-
raw = await
|
|
16663
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15932
16664
|
} catch {
|
|
15933
16665
|
continue;
|
|
15934
16666
|
}
|
|
@@ -15954,7 +16686,7 @@ function isPidAliveDefault(pid) {
|
|
|
15954
16686
|
}
|
|
15955
16687
|
async function readPidFile(file) {
|
|
15956
16688
|
try {
|
|
15957
|
-
const raw = await
|
|
16689
|
+
const raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15958
16690
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
15959
16691
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
15960
16692
|
} catch {
|
|
@@ -16002,24 +16734,24 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
16002
16734
|
}
|
|
16003
16735
|
}
|
|
16004
16736
|
async function writeAtomically(target, contents) {
|
|
16005
|
-
await
|
|
16737
|
+
await import_node_fs37.promises.mkdir(import_node_path72.default.dirname(target), { recursive: true });
|
|
16006
16738
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
16007
|
-
const fd = await
|
|
16739
|
+
const fd = await import_node_fs37.promises.open(tmp, "w");
|
|
16008
16740
|
try {
|
|
16009
16741
|
await fd.writeFile(contents, "utf8");
|
|
16010
16742
|
await fd.sync();
|
|
16011
16743
|
} finally {
|
|
16012
16744
|
await fd.close();
|
|
16013
16745
|
}
|
|
16014
|
-
await
|
|
16746
|
+
await import_node_fs37.promises.rename(tmp, target);
|
|
16015
16747
|
}
|
|
16016
16748
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
16017
16749
|
const deadline = Date.now() + timeoutMs;
|
|
16018
|
-
await
|
|
16750
|
+
await import_node_fs37.promises.mkdir(import_node_path72.default.dirname(lockPath), { recursive: true });
|
|
16019
16751
|
let probedHolder = false;
|
|
16020
16752
|
while (true) {
|
|
16021
16753
|
try {
|
|
16022
|
-
const fd = await
|
|
16754
|
+
const fd = await import_node_fs37.promises.open(lockPath, "wx");
|
|
16023
16755
|
try {
|
|
16024
16756
|
await fd.writeFile(`${process.pid}
|
|
16025
16757
|
`, "utf8");
|
|
@@ -16044,7 +16776,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
16044
16776
|
}
|
|
16045
16777
|
}
|
|
16046
16778
|
async function releaseLock(lockPath) {
|
|
16047
|
-
await
|
|
16779
|
+
await import_node_fs37.promises.unlink(lockPath).catch(() => {
|
|
16048
16780
|
});
|
|
16049
16781
|
}
|
|
16050
16782
|
async function withLock(fn) {
|
|
@@ -16060,7 +16792,7 @@ async function readRegistry() {
|
|
|
16060
16792
|
const file = registryPath();
|
|
16061
16793
|
let raw;
|
|
16062
16794
|
try {
|
|
16063
|
-
raw = await
|
|
16795
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
16064
16796
|
} catch (err) {
|
|
16065
16797
|
if (err.code === "ENOENT") {
|
|
16066
16798
|
return { version: 1, projects: [] };
|
|
@@ -16068,10 +16800,10 @@ async function readRegistry() {
|
|
|
16068
16800
|
throw err;
|
|
16069
16801
|
}
|
|
16070
16802
|
const parsed = JSON.parse(raw);
|
|
16071
|
-
return
|
|
16803
|
+
return import_types59.RegistryFileSchema.parse(parsed);
|
|
16072
16804
|
}
|
|
16073
16805
|
async function writeRegistry(reg) {
|
|
16074
|
-
const validated =
|
|
16806
|
+
const validated = import_types59.RegistryFileSchema.parse(reg);
|
|
16075
16807
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
16076
16808
|
}
|
|
16077
16809
|
async function getProject(name) {
|
|
@@ -16115,7 +16847,7 @@ function pruneTtlMs() {
|
|
|
16115
16847
|
}
|
|
16116
16848
|
async function statPathStatus(p) {
|
|
16117
16849
|
try {
|
|
16118
|
-
const stat = await
|
|
16850
|
+
const stat = await import_node_fs37.promises.stat(p);
|
|
16119
16851
|
return stat.isDirectory() ? "present" : "unknown";
|
|
16120
16852
|
} catch (err) {
|
|
16121
16853
|
return err.code === "ENOENT" ? "gone" : "unknown";
|
|
@@ -16216,8 +16948,8 @@ init_auth();
|
|
|
16216
16948
|
// src/connectors-config.ts
|
|
16217
16949
|
init_cjs_shims();
|
|
16218
16950
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
16219
|
-
var
|
|
16220
|
-
var
|
|
16951
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
16952
|
+
var import_node_fs38 = require("fs");
|
|
16221
16953
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
16222
16954
|
var EnvRefUnsetError = class extends Error {
|
|
16223
16955
|
ref;
|
|
@@ -16231,17 +16963,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
16231
16963
|
};
|
|
16232
16964
|
function neatHome2() {
|
|
16233
16965
|
const override = process.env.NEAT_HOME;
|
|
16234
|
-
if (override && override.length > 0) return
|
|
16235
|
-
return
|
|
16966
|
+
if (override && override.length > 0) return import_node_path73.default.resolve(override);
|
|
16967
|
+
return import_node_path73.default.join(import_node_os4.default.homedir(), ".neat");
|
|
16236
16968
|
}
|
|
16237
16969
|
function connectorsConfigPath(home = neatHome2()) {
|
|
16238
|
-
return
|
|
16970
|
+
return import_node_path73.default.join(home, "connectors.json");
|
|
16239
16971
|
}
|
|
16240
16972
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
16241
16973
|
async function warnIfModeLooserThan0600(file) {
|
|
16242
16974
|
if (process.platform === "win32") return;
|
|
16243
16975
|
try {
|
|
16244
|
-
const stat = await
|
|
16976
|
+
const stat = await import_node_fs38.promises.stat(file);
|
|
16245
16977
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
16246
16978
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
16247
16979
|
console.warn(
|
|
@@ -16255,7 +16987,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
16255
16987
|
const file = connectorsConfigPath(home);
|
|
16256
16988
|
let raw;
|
|
16257
16989
|
try {
|
|
16258
|
-
raw = await
|
|
16990
|
+
raw = await import_node_fs38.promises.readFile(file, "utf8");
|
|
16259
16991
|
} catch (err) {
|
|
16260
16992
|
if (err.code === "ENOENT") {
|
|
16261
16993
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -16422,15 +17154,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
16422
17154
|
|
|
16423
17155
|
// src/connectors/index.ts
|
|
16424
17156
|
init_cjs_shims();
|
|
16425
|
-
var
|
|
17157
|
+
var import_types60 = require("@neat.is/types");
|
|
16426
17158
|
var NO_ENV = "unknown";
|
|
16427
17159
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
16428
17160
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16429
17161
|
const sites = [];
|
|
16430
17162
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
16431
17163
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
16432
|
-
if (edge.provenance !==
|
|
16433
|
-
const parsed = (0,
|
|
17164
|
+
if (edge.provenance !== import_types60.Provenance.EXTRACTED) continue;
|
|
17165
|
+
const parsed = (0, import_types60.parseFileId)(edge.source);
|
|
16434
17166
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
16435
17167
|
const site = { relPath: edge.evidence.file };
|
|
16436
17168
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -16441,7 +17173,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
16441
17173
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
16442
17174
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16443
17175
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
16444
|
-
if (attrs.type !==
|
|
17176
|
+
if (attrs.type !== import_types60.NodeType.RouteNode || !attrs.path) return void 0;
|
|
16445
17177
|
const site = { relPath: attrs.path };
|
|
16446
17178
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
16447
17179
|
return site;
|
|
@@ -16939,10 +17671,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
16939
17671
|
// src/connectors/supabase/map.ts
|
|
16940
17672
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
16941
17673
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
16942
|
-
function targetFromRestPath(
|
|
16943
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
17674
|
+
function targetFromRestPath(path78) {
|
|
17675
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path78);
|
|
16944
17676
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
16945
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
17677
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path78);
|
|
16946
17678
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
16947
17679
|
return null;
|
|
16948
17680
|
}
|
|
@@ -17053,23 +17785,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
17053
17785
|
|
|
17054
17786
|
// src/connectors/supabase/resolve.ts
|
|
17055
17787
|
init_cjs_shims();
|
|
17056
|
-
var
|
|
17788
|
+
var import_types62 = require("@neat.is/types");
|
|
17057
17789
|
function createSupabaseResolveTarget(graph, config) {
|
|
17058
17790
|
return (signal, _ctx) => {
|
|
17059
17791
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
17060
17792
|
return null;
|
|
17061
17793
|
}
|
|
17062
|
-
const subResourceId = (0,
|
|
17794
|
+
const subResourceId = (0, import_types62.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
17063
17795
|
if (graph.hasNode(subResourceId)) {
|
|
17064
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
17796
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
17065
17797
|
}
|
|
17066
|
-
const bareResourceId = (0,
|
|
17798
|
+
const bareResourceId = (0, import_types62.infraId)(signal.targetKind, signal.targetName);
|
|
17067
17799
|
if (graph.hasNode(bareResourceId)) {
|
|
17068
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
17800
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
17069
17801
|
}
|
|
17070
|
-
const projectLevelId = (0,
|
|
17802
|
+
const projectLevelId = (0, import_types62.infraId)("supabase", config.nodeRef);
|
|
17071
17803
|
if (graph.hasNode(projectLevelId)) {
|
|
17072
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
17804
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
17073
17805
|
}
|
|
17074
17806
|
return null;
|
|
17075
17807
|
};
|
|
@@ -17162,7 +17894,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
17162
17894
|
|
|
17163
17895
|
// src/connectors/railway/index.ts
|
|
17164
17896
|
init_cjs_shims();
|
|
17165
|
-
var
|
|
17897
|
+
var import_types66 = require("@neat.is/types");
|
|
17166
17898
|
|
|
17167
17899
|
// src/connectors/railway/client.ts
|
|
17168
17900
|
init_cjs_shims();
|
|
@@ -17313,7 +18045,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
17313
18045
|
const out = [];
|
|
17314
18046
|
graph.forEachNode((_id, attrs) => {
|
|
17315
18047
|
const node = attrs;
|
|
17316
|
-
if (node.type !==
|
|
18048
|
+
if (node.type !== import_types66.NodeType.RouteNode) return;
|
|
17317
18049
|
const route = attrs;
|
|
17318
18050
|
if (route.service !== serviceName) return;
|
|
17319
18051
|
out.push({
|
|
@@ -17417,12 +18149,12 @@ function createRailwayResolveTarget(config) {
|
|
|
17417
18149
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
17418
18150
|
if (!serviceName) return null;
|
|
17419
18151
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
17420
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
18152
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
17421
18153
|
}
|
|
17422
18154
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
17423
18155
|
const peerName = config.serviceNameById[signal.targetName];
|
|
17424
18156
|
if (!peerName) return null;
|
|
17425
|
-
return { targetNodeId: (0,
|
|
18157
|
+
return { targetNodeId: (0, import_types66.serviceId)(peerName), serviceName, edgeType: import_types66.EdgeType.CONNECTS_TO };
|
|
17426
18158
|
}
|
|
17427
18159
|
return null;
|
|
17428
18160
|
};
|
|
@@ -17546,9 +18278,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
17546
18278
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
17547
18279
|
if (secondSep === -1) return null;
|
|
17548
18280
|
const method = rest.slice(0, secondSep);
|
|
17549
|
-
const
|
|
17550
|
-
if (!resourceName || !method || !
|
|
17551
|
-
return { resourceName, method, path:
|
|
18281
|
+
const path78 = rest.slice(secondSep + 1);
|
|
18282
|
+
if (!resourceName || !method || !path78) return null;
|
|
18283
|
+
return { resourceName, method, path: path78 };
|
|
17552
18284
|
}
|
|
17553
18285
|
function resourceNameFor(type, labels) {
|
|
17554
18286
|
if (!labels) return null;
|
|
@@ -17586,14 +18318,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
17586
18318
|
if (!req2) return null;
|
|
17587
18319
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
17588
18320
|
const method = req2.requestMethod.toUpperCase();
|
|
17589
|
-
const
|
|
17590
|
-
if (
|
|
18321
|
+
const path78 = pathFromRequestUrl(req2.requestUrl);
|
|
18322
|
+
if (path78 === null) return null;
|
|
17591
18323
|
const timestamp = entry2.timestamp;
|
|
17592
18324
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17593
18325
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD2;
|
|
17594
18326
|
return {
|
|
17595
18327
|
targetKind: resourceType,
|
|
17596
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
18328
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path78 }),
|
|
17597
18329
|
callCount: 1,
|
|
17598
18330
|
errorCount: isError ? 1 : 0,
|
|
17599
18331
|
lastObservedIso: timestamp
|
|
@@ -17610,7 +18342,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
17610
18342
|
|
|
17611
18343
|
// src/connectors/firebase/resolve.ts
|
|
17612
18344
|
init_cjs_shims();
|
|
17613
|
-
var
|
|
18345
|
+
var import_types67 = require("@neat.is/types");
|
|
17614
18346
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
17615
18347
|
switch (resourceType) {
|
|
17616
18348
|
case "cloud_function":
|
|
@@ -17625,7 +18357,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
17625
18357
|
const entries = [];
|
|
17626
18358
|
graph.forEachNode((_id, attrs) => {
|
|
17627
18359
|
const node = attrs;
|
|
17628
|
-
if (node.type !==
|
|
18360
|
+
if (node.type !== import_types67.NodeType.RouteNode) return;
|
|
17629
18361
|
const route = attrs;
|
|
17630
18362
|
if (route.service !== serviceName) return;
|
|
17631
18363
|
entries.push({
|
|
@@ -17657,7 +18389,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
17657
18389
|
return {
|
|
17658
18390
|
targetNodeId: match.routeNodeId,
|
|
17659
18391
|
serviceName,
|
|
17660
|
-
edgeType:
|
|
18392
|
+
edgeType: import_types67.EdgeType.CALLS
|
|
17661
18393
|
};
|
|
17662
18394
|
};
|
|
17663
18395
|
}
|
|
@@ -17684,7 +18416,7 @@ init_cjs_shims();
|
|
|
17684
18416
|
|
|
17685
18417
|
// src/connectors/cloudflare/connector.ts
|
|
17686
18418
|
init_cjs_shims();
|
|
17687
|
-
var
|
|
18419
|
+
var import_types69 = require("@neat.is/types");
|
|
17688
18420
|
|
|
17689
18421
|
// src/connectors/cloudflare/client.ts
|
|
17690
18422
|
init_cjs_shims();
|
|
@@ -17800,7 +18532,7 @@ function mapEventToSignal(event) {
|
|
|
17800
18532
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
17801
18533
|
const statusCode = metadata?.statusCode;
|
|
17802
18534
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
17803
|
-
const
|
|
18535
|
+
const path78 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
17804
18536
|
return {
|
|
17805
18537
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
17806
18538
|
targetName: scriptName,
|
|
@@ -17808,7 +18540,7 @@ function mapEventToSignal(event) {
|
|
|
17808
18540
|
errorCount: isError ? 1 : 0,
|
|
17809
18541
|
lastObservedIso: observedAt.toISOString(),
|
|
17810
18542
|
method,
|
|
17811
|
-
...
|
|
18543
|
+
...path78 ? { path: path78 } : {},
|
|
17812
18544
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
17813
18545
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
17814
18546
|
};
|
|
@@ -17848,19 +18580,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
17848
18580
|
graph.forEachNode((id, attrs) => {
|
|
17849
18581
|
if (found) return;
|
|
17850
18582
|
const a = attrs;
|
|
17851
|
-
if (a.type ===
|
|
18583
|
+
if (a.type === import_types69.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
17852
18584
|
found = id;
|
|
17853
18585
|
}
|
|
17854
18586
|
});
|
|
17855
18587
|
return found;
|
|
17856
18588
|
}
|
|
17857
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
17858
|
-
const normalizedPath = normalizePathTemplate(
|
|
18589
|
+
function findMatchingRouteNode(graph, serviceName, method, path78) {
|
|
18590
|
+
const normalizedPath = normalizePathTemplate(path78);
|
|
17859
18591
|
let found = null;
|
|
17860
18592
|
graph.forEachNode((id, attrs) => {
|
|
17861
18593
|
if (found) return;
|
|
17862
18594
|
const a = attrs;
|
|
17863
|
-
if (a.type !==
|
|
18595
|
+
if (a.type !== import_types69.NodeType.RouteNode || a.service !== serviceName) return;
|
|
17864
18596
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
17865
18597
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
17866
18598
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -17872,18 +18604,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17872
18604
|
return (signal) => {
|
|
17873
18605
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
17874
18606
|
const scriptName = signal.targetName;
|
|
17875
|
-
const { method, path:
|
|
18607
|
+
const { method, path: path78 } = signal;
|
|
17876
18608
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
17877
|
-
if (!method || !
|
|
17878
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
18609
|
+
if (!method || !path78) return wholeFileId;
|
|
18610
|
+
return findMatchingRouteNode(graph, serviceName, method, path78) ?? wholeFileId;
|
|
17879
18611
|
};
|
|
17880
18612
|
const mapping = config.workers?.[scriptName];
|
|
17881
18613
|
if (mapping) {
|
|
17882
|
-
const wholeFileId = (0,
|
|
18614
|
+
const wholeFileId = (0, import_types69.fileId)(mapping.service, mapping.entryFile);
|
|
17883
18615
|
return {
|
|
17884
18616
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
17885
18617
|
serviceName: mapping.service,
|
|
17886
|
-
edgeType:
|
|
18618
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17887
18619
|
};
|
|
17888
18620
|
}
|
|
17889
18621
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -17892,13 +18624,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17892
18624
|
return {
|
|
17893
18625
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
17894
18626
|
serviceName: fileNode.service,
|
|
17895
|
-
edgeType:
|
|
18627
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17896
18628
|
};
|
|
17897
18629
|
}
|
|
17898
18630
|
return {
|
|
17899
|
-
targetNodeId: (0,
|
|
18631
|
+
targetNodeId: (0, import_types69.infraId)("cloudflare-worker", scriptName),
|
|
17900
18632
|
serviceName: scriptName,
|
|
17901
|
-
edgeType:
|
|
18633
|
+
edgeType: import_types69.EdgeType.CALLS,
|
|
17902
18634
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
17903
18635
|
};
|
|
17904
18636
|
};
|
|
@@ -18094,14 +18826,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
18094
18826
|
|
|
18095
18827
|
// src/connectors/neon/resolve.ts
|
|
18096
18828
|
init_cjs_shims();
|
|
18097
|
-
var
|
|
18829
|
+
var import_types73 = require("@neat.is/types");
|
|
18098
18830
|
function createNeonResolveTarget(config) {
|
|
18099
18831
|
return (signal) => {
|
|
18100
18832
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
18101
18833
|
return {
|
|
18102
|
-
targetNodeId: (0,
|
|
18834
|
+
targetNodeId: (0, import_types73.infraId)("sql-table", signal.targetName),
|
|
18103
18835
|
serviceName: config.serviceName,
|
|
18104
|
-
edgeType:
|
|
18836
|
+
edgeType: import_types73.EdgeType.CALLS,
|
|
18105
18837
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
18106
18838
|
};
|
|
18107
18839
|
};
|
|
@@ -18227,9 +18959,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
18227
18959
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
18228
18960
|
if (secondSep === -1) return null;
|
|
18229
18961
|
const method = rest.slice(0, secondSep);
|
|
18230
|
-
const
|
|
18231
|
-
if (!serviceName || !method || !
|
|
18232
|
-
return { serviceName, method, path:
|
|
18962
|
+
const path78 = rest.slice(secondSep + 1);
|
|
18963
|
+
if (!serviceName || !method || !path78) return null;
|
|
18964
|
+
return { serviceName, method, path: path78 };
|
|
18233
18965
|
}
|
|
18234
18966
|
|
|
18235
18967
|
// src/connectors/cloud-run/map.ts
|
|
@@ -18258,14 +18990,14 @@ function mapLogEntryToSignal2(entry2) {
|
|
|
18258
18990
|
if (!req2) return null;
|
|
18259
18991
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
18260
18992
|
const method = req2.requestMethod.toUpperCase();
|
|
18261
|
-
const
|
|
18262
|
-
if (
|
|
18993
|
+
const path78 = pathFromRequestUrl2(req2.requestUrl);
|
|
18994
|
+
if (path78 === null) return null;
|
|
18263
18995
|
const timestamp = entry2.timestamp;
|
|
18264
18996
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
18265
18997
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD4;
|
|
18266
18998
|
return {
|
|
18267
18999
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
18268
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
19000
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path78 }),
|
|
18269
19001
|
callCount: 1,
|
|
18270
19002
|
errorCount: isError ? 1 : 0,
|
|
18271
19003
|
lastObservedIso: timestamp
|
|
@@ -18282,14 +19014,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
18282
19014
|
|
|
18283
19015
|
// src/connectors/cloud-run/resolve.ts
|
|
18284
19016
|
init_cjs_shims();
|
|
18285
|
-
var
|
|
19017
|
+
var import_types77 = require("@neat.is/types");
|
|
18286
19018
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
18287
19019
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
18288
19020
|
let found = null;
|
|
18289
19021
|
graph.forEachNode((_id, attrs) => {
|
|
18290
19022
|
if (found) return;
|
|
18291
19023
|
const node = attrs;
|
|
18292
|
-
if (node.type !==
|
|
19024
|
+
if (node.type !== import_types77.NodeType.RouteNode) return;
|
|
18293
19025
|
const route = attrs;
|
|
18294
19026
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
18295
19027
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -18304,23 +19036,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
18304
19036
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
18305
19037
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
18306
19038
|
if (!identity) return null;
|
|
18307
|
-
const { serviceName: gcpServiceName, method, path:
|
|
19039
|
+
const { serviceName: gcpServiceName, method, path: path78 } = identity;
|
|
18308
19040
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
18309
19041
|
if (mappedService) {
|
|
18310
19042
|
const routeNodeId = findMatchingRouteNode2(
|
|
18311
19043
|
graph,
|
|
18312
19044
|
mappedService,
|
|
18313
19045
|
method,
|
|
18314
|
-
normalizePathTemplate(
|
|
19046
|
+
normalizePathTemplate(path78)
|
|
18315
19047
|
);
|
|
18316
19048
|
if (routeNodeId) {
|
|
18317
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
19049
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types77.EdgeType.CALLS };
|
|
18318
19050
|
}
|
|
18319
19051
|
}
|
|
18320
19052
|
return {
|
|
18321
|
-
targetNodeId: (0,
|
|
19053
|
+
targetNodeId: (0, import_types77.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
18322
19054
|
serviceName: mappedService ?? gcpServiceName,
|
|
18323
|
-
edgeType:
|
|
19055
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
18324
19056
|
ensureInfraNode: {
|
|
18325
19057
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
18326
19058
|
name: gcpServiceName,
|
|
@@ -18361,7 +19093,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
18361
19093
|
|
|
18362
19094
|
// src/connectors/render/index.ts
|
|
18363
19095
|
init_cjs_shims();
|
|
18364
|
-
var
|
|
19096
|
+
var import_types80 = require("@neat.is/types");
|
|
18365
19097
|
|
|
18366
19098
|
// src/connectors/render/types.ts
|
|
18367
19099
|
init_cjs_shims();
|
|
@@ -18439,7 +19171,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
18439
19171
|
const out = [];
|
|
18440
19172
|
graph.forEachNode((_id, attrs) => {
|
|
18441
19173
|
const node = attrs;
|
|
18442
|
-
if (node.type !==
|
|
19174
|
+
if (node.type !== import_types80.NodeType.RouteNode) return;
|
|
18443
19175
|
const route = attrs;
|
|
18444
19176
|
if (route.service !== serviceName) return;
|
|
18445
19177
|
out.push({
|
|
@@ -18524,7 +19256,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
18524
19256
|
function createRenderResolveTarget(config) {
|
|
18525
19257
|
return (signal) => {
|
|
18526
19258
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
18527
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
19259
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types80.EdgeType.CALLS };
|
|
18528
19260
|
}
|
|
18529
19261
|
return null;
|
|
18530
19262
|
};
|
|
@@ -18662,21 +19394,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
18662
19394
|
|
|
18663
19395
|
// src/connectors/planetscale/resolve.ts
|
|
18664
19396
|
init_cjs_shims();
|
|
18665
|
-
var
|
|
19397
|
+
var import_types84 = require("@neat.is/types");
|
|
18666
19398
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
18667
19399
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
18668
19400
|
const databaseName = `${config.organization}/${config.database}`;
|
|
18669
19401
|
return (signal, _ctx) => {
|
|
18670
19402
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
18671
|
-
const tableId = (0,
|
|
19403
|
+
const tableId = (0, import_types84.infraId)("sql-table", signal.targetName);
|
|
18672
19404
|
if (graph.hasNode(tableId)) {
|
|
18673
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
19405
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types84.EdgeType.CALLS };
|
|
18674
19406
|
}
|
|
18675
|
-
const providerId = (0,
|
|
19407
|
+
const providerId = (0, import_types84.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
18676
19408
|
return {
|
|
18677
19409
|
targetNodeId: providerId,
|
|
18678
19410
|
serviceName: config.serviceName,
|
|
18679
|
-
edgeType:
|
|
19411
|
+
edgeType: import_types84.EdgeType.CALLS,
|
|
18680
19412
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
18681
19413
|
};
|
|
18682
19414
|
};
|
|
@@ -18941,7 +19673,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
18941
19673
|
|
|
18942
19674
|
// src/connectors/eas/resolve.ts
|
|
18943
19675
|
init_cjs_shims();
|
|
18944
|
-
var
|
|
19676
|
+
var import_types89 = require("@neat.is/types");
|
|
18945
19677
|
var NO_ENV2 = "unknown";
|
|
18946
19678
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
18947
19679
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -18957,8 +19689,8 @@ function configBasenamesForPhase(phase) {
|
|
|
18957
19689
|
function configNodeService(graph, configNodeId) {
|
|
18958
19690
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
18959
19691
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18960
|
-
if (edge.type !==
|
|
18961
|
-
const parsed = (0,
|
|
19692
|
+
if (edge.type !== import_types89.EdgeType.CONFIGURED_BY) continue;
|
|
19693
|
+
const parsed = (0, import_types89.parseFileId)(edge.source);
|
|
18962
19694
|
if (parsed) return parsed.service;
|
|
18963
19695
|
}
|
|
18964
19696
|
return null;
|
|
@@ -18969,7 +19701,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
18969
19701
|
graph.forEachNode((id, attrs) => {
|
|
18970
19702
|
if (scoped) return;
|
|
18971
19703
|
const node = attrs;
|
|
18972
|
-
if (node.type !==
|
|
19704
|
+
if (node.type !== import_types89.NodeType.ConfigNode) return;
|
|
18973
19705
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
18974
19706
|
if (anyMatch === null) anyMatch = id;
|
|
18975
19707
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -18986,13 +19718,13 @@ function createEasResolveTarget(graph) {
|
|
|
18986
19718
|
if (basenames.length > 0) {
|
|
18987
19719
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
18988
19720
|
if (configNodeId) {
|
|
18989
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
19721
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types89.EdgeType.CALLS };
|
|
18990
19722
|
}
|
|
18991
19723
|
}
|
|
18992
19724
|
return {
|
|
18993
19725
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
18994
19726
|
serviceName,
|
|
18995
|
-
edgeType:
|
|
19727
|
+
edgeType: import_types89.EdgeType.CALLS
|
|
18996
19728
|
};
|
|
18997
19729
|
};
|
|
18998
19730
|
}
|
|
@@ -19717,11 +20449,11 @@ function registerRoutes(scope, ctx) {
|
|
|
19717
20449
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
19718
20450
|
const parsed = [];
|
|
19719
20451
|
for (const c of candidates) {
|
|
19720
|
-
const r =
|
|
20452
|
+
const r = import_types92.DivergenceTypeSchema.safeParse(c);
|
|
19721
20453
|
if (!r.success) {
|
|
19722
20454
|
return reply.code(400).send({
|
|
19723
20455
|
error: `unknown divergence type "${c}"`,
|
|
19724
|
-
allowed:
|
|
20456
|
+
allowed: import_types92.DivergenceTypeSchema.options
|
|
19725
20457
|
});
|
|
19726
20458
|
}
|
|
19727
20459
|
parsed.push(r.data);
|
|
@@ -20063,7 +20795,7 @@ function registerRoutes(scope, ctx) {
|
|
|
20063
20795
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
20064
20796
|
let violations = await log.readAll();
|
|
20065
20797
|
if (req2.query.severity) {
|
|
20066
|
-
const sev =
|
|
20798
|
+
const sev = import_types92.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
20067
20799
|
if (!sev.success) {
|
|
20068
20800
|
return reply.code(400).send({
|
|
20069
20801
|
error: "invalid severity",
|
|
@@ -20102,7 +20834,7 @@ function registerRoutes(scope, ctx) {
|
|
|
20102
20834
|
scope.post("/policies/check", async (req2, reply) => {
|
|
20103
20835
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
20104
20836
|
if (!proj) return;
|
|
20105
|
-
const parsed =
|
|
20837
|
+
const parsed = import_types92.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
20106
20838
|
if (!parsed.success) {
|
|
20107
20839
|
return reply.code(400).send({
|
|
20108
20840
|
error: "invalid /policies/check body",
|
|
@@ -20423,8 +21155,8 @@ init_auth();
|
|
|
20423
21155
|
|
|
20424
21156
|
// src/unrouted.ts
|
|
20425
21157
|
init_cjs_shims();
|
|
20426
|
-
var
|
|
20427
|
-
var
|
|
21158
|
+
var import_node_fs39 = require("fs");
|
|
21159
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
20428
21160
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
20429
21161
|
return {
|
|
20430
21162
|
timestamp: now.toISOString(),
|
|
@@ -20434,34 +21166,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
20434
21166
|
};
|
|
20435
21167
|
}
|
|
20436
21168
|
async function appendUnroutedSpan(neatHome4, record) {
|
|
20437
|
-
const target =
|
|
20438
|
-
await
|
|
20439
|
-
await
|
|
21169
|
+
const target = import_node_path74.default.join(neatHome4, "errors.ndjson");
|
|
21170
|
+
await import_node_fs39.promises.mkdir(neatHome4, { recursive: true });
|
|
21171
|
+
await import_node_fs39.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
20440
21172
|
}
|
|
20441
21173
|
function unroutedErrorsPath(neatHome4) {
|
|
20442
|
-
return
|
|
21174
|
+
return import_node_path74.default.join(neatHome4, "errors.ndjson");
|
|
20443
21175
|
}
|
|
20444
21176
|
|
|
20445
21177
|
// src/daemon.ts
|
|
20446
|
-
var
|
|
21178
|
+
var import_types93 = require("@neat.is/types");
|
|
20447
21179
|
function daemonJsonPath(scanPath) {
|
|
20448
|
-
return
|
|
21180
|
+
return import_node_path75.default.join(scanPath, "neat-out", "daemon.json");
|
|
20449
21181
|
}
|
|
20450
21182
|
function daemonsDiscoveryDir(home) {
|
|
20451
21183
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
20452
|
-
return
|
|
21184
|
+
return import_node_path75.default.join(base, "daemons");
|
|
20453
21185
|
}
|
|
20454
21186
|
function daemonDiscoveryPath(project, home) {
|
|
20455
|
-
return
|
|
21187
|
+
return import_node_path75.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
20456
21188
|
}
|
|
20457
21189
|
function sanitizeDiscoveryName(project) {
|
|
20458
21190
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
20459
21191
|
}
|
|
20460
21192
|
function neatHomeFromEnv() {
|
|
20461
21193
|
const env = process.env.NEAT_HOME;
|
|
20462
|
-
if (env && env.length > 0) return
|
|
21194
|
+
if (env && env.length > 0) return import_node_path75.default.resolve(env);
|
|
20463
21195
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
20464
|
-
return
|
|
21196
|
+
return import_node_path75.default.join(home, ".neat");
|
|
20465
21197
|
}
|
|
20466
21198
|
function resolveNeatVersion() {
|
|
20467
21199
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -20493,7 +21225,7 @@ async function clearDaemonRecord(record, home) {
|
|
|
20493
21225
|
} catch {
|
|
20494
21226
|
}
|
|
20495
21227
|
try {
|
|
20496
|
-
await
|
|
21228
|
+
await import_node_fs40.promises.unlink(daemonDiscoveryPath(record.project, home));
|
|
20497
21229
|
} catch {
|
|
20498
21230
|
}
|
|
20499
21231
|
}
|
|
@@ -20502,12 +21234,12 @@ function reconcileDaemonRecordSync(record, home) {
|
|
|
20502
21234
|
const stopped = { ...record, status: "stopped" };
|
|
20503
21235
|
const target = daemonJsonPath(record.projectPath);
|
|
20504
21236
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
20505
|
-
(0,
|
|
20506
|
-
(0,
|
|
21237
|
+
(0, import_node_fs40.writeFileSync)(tmp, JSON.stringify(stopped, null, 2) + "\n");
|
|
21238
|
+
(0, import_node_fs40.renameSync)(tmp, target);
|
|
20507
21239
|
} catch {
|
|
20508
21240
|
}
|
|
20509
21241
|
try {
|
|
20510
|
-
(0,
|
|
21242
|
+
(0, import_node_fs40.unlinkSync)(daemonDiscoveryPath(record.project, home));
|
|
20511
21243
|
} catch {
|
|
20512
21244
|
}
|
|
20513
21245
|
}
|
|
@@ -20530,11 +21262,11 @@ function teardownSlot(slot) {
|
|
|
20530
21262
|
}
|
|
20531
21263
|
}
|
|
20532
21264
|
function neatHomeFor(opts) {
|
|
20533
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
21265
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path75.default.resolve(opts.neatHome);
|
|
20534
21266
|
const env = process.env.NEAT_HOME;
|
|
20535
|
-
if (env && env.length > 0) return
|
|
21267
|
+
if (env && env.length > 0) return import_node_path75.default.resolve(env);
|
|
20536
21268
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
20537
|
-
return
|
|
21269
|
+
return import_node_path75.default.join(home, ".neat");
|
|
20538
21270
|
}
|
|
20539
21271
|
function routeSpanToProject(serviceName, projects) {
|
|
20540
21272
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -20582,13 +21314,13 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
20582
21314
|
if (!serviceName) return true;
|
|
20583
21315
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
20584
21316
|
return graph.someNode(
|
|
20585
|
-
(_id, attrs) => attrs.type ===
|
|
21317
|
+
(_id, attrs) => attrs.type === import_types93.NodeType.ServiceNode && attrs.name === serviceName
|
|
20586
21318
|
);
|
|
20587
21319
|
}
|
|
20588
21320
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
20589
|
-
const paths = pathsForProject(entry2.name,
|
|
21321
|
+
const paths = pathsForProject(entry2.name, import_node_path75.default.join(entry2.path, "neat-out"));
|
|
20590
21322
|
try {
|
|
20591
|
-
const stat = await
|
|
21323
|
+
const stat = await import_node_fs40.promises.stat(entry2.path);
|
|
20592
21324
|
if (!stat.isDirectory()) {
|
|
20593
21325
|
throw new Error(`registered path ${entry2.path} is not a directory`);
|
|
20594
21326
|
}
|
|
@@ -20706,7 +21438,7 @@ async function startDaemon(opts = {}) {
|
|
|
20706
21438
|
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;
|
|
20707
21439
|
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;
|
|
20708
21440
|
const singleProject = projectArg;
|
|
20709
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
21441
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path75.default.resolve(projectPathArg) : null;
|
|
20710
21442
|
if (singleProject && !singleProjectPath) {
|
|
20711
21443
|
throw new Error(
|
|
20712
21444
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -20714,14 +21446,14 @@ async function startDaemon(opts = {}) {
|
|
|
20714
21446
|
}
|
|
20715
21447
|
if (!singleProject) {
|
|
20716
21448
|
try {
|
|
20717
|
-
await
|
|
21449
|
+
await import_node_fs40.promises.access(regPath);
|
|
20718
21450
|
} catch {
|
|
20719
21451
|
throw new Error(
|
|
20720
21452
|
`neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
|
|
20721
21453
|
);
|
|
20722
21454
|
}
|
|
20723
21455
|
}
|
|
20724
|
-
const pidPath =
|
|
21456
|
+
const pidPath = import_node_path75.default.join(home, "neatd.pid");
|
|
20725
21457
|
await writeAtomically(pidPath, `${process.pid}
|
|
20726
21458
|
`);
|
|
20727
21459
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -20933,7 +21665,7 @@ async function startDaemon(opts = {}) {
|
|
|
20933
21665
|
}
|
|
20934
21666
|
if (restApp) await restApp.close().catch(() => {
|
|
20935
21667
|
});
|
|
20936
|
-
await
|
|
21668
|
+
await import_node_fs40.promises.unlink(pidPath).catch(() => {
|
|
20937
21669
|
});
|
|
20938
21670
|
throw new Error(
|
|
20939
21671
|
`neatd: failed to bind REST on port ${restPort} \u2014 ${err.message}`
|
|
@@ -21101,7 +21833,7 @@ async function startDaemon(opts = {}) {
|
|
|
21101
21833
|
});
|
|
21102
21834
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
21103
21835
|
});
|
|
21104
|
-
await
|
|
21836
|
+
await import_node_fs40.promises.unlink(pidPath).catch(() => {
|
|
21105
21837
|
});
|
|
21106
21838
|
throw new Error(
|
|
21107
21839
|
`neatd: failed to bind OTLP on port ${otlpPort} \u2014 ${err.message}`
|
|
@@ -21136,7 +21868,7 @@ async function startDaemon(opts = {}) {
|
|
|
21136
21868
|
});
|
|
21137
21869
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
21138
21870
|
});
|
|
21139
|
-
await
|
|
21871
|
+
await import_node_fs40.promises.unlink(pidPath).catch(() => {
|
|
21140
21872
|
});
|
|
21141
21873
|
throw new Error(
|
|
21142
21874
|
`neatd: failed to write daemon.json for "${singleProject}" \u2014 ${err.message}`
|
|
@@ -21183,9 +21915,9 @@ async function startDaemon(opts = {}) {
|
|
|
21183
21915
|
let registryWatcher = null;
|
|
21184
21916
|
let reloadTimer = null;
|
|
21185
21917
|
if (!singleProject) try {
|
|
21186
|
-
const regDir =
|
|
21187
|
-
const regBase =
|
|
21188
|
-
registryWatcher = (0,
|
|
21918
|
+
const regDir = import_node_path75.default.dirname(regPath);
|
|
21919
|
+
const regBase = import_node_path75.default.basename(regPath);
|
|
21920
|
+
registryWatcher = (0, import_node_fs40.watch)(regDir, (_eventType, filename) => {
|
|
21189
21921
|
if (filename !== null && filename !== regBase) return;
|
|
21190
21922
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
21191
21923
|
reloadTimer = setTimeout(() => {
|
|
@@ -21234,7 +21966,7 @@ async function startDaemon(opts = {}) {
|
|
|
21234
21966
|
if (daemonRecord) {
|
|
21235
21967
|
await clearDaemonRecord(daemonRecord, home);
|
|
21236
21968
|
}
|
|
21237
|
-
await
|
|
21969
|
+
await import_node_fs40.promises.unlink(pidPath).catch(() => {
|
|
21238
21970
|
});
|
|
21239
21971
|
};
|
|
21240
21972
|
return {
|
|
@@ -21257,9 +21989,9 @@ init_auth();
|
|
|
21257
21989
|
// src/web-spawn.ts
|
|
21258
21990
|
init_cjs_shims();
|
|
21259
21991
|
var import_node_child_process2 = require("child_process");
|
|
21260
|
-
var
|
|
21992
|
+
var import_node_fs41 = require("fs");
|
|
21261
21993
|
var import_node_net = __toESM(require("net"), 1);
|
|
21262
|
-
var
|
|
21994
|
+
var import_node_path76 = __toESM(require("path"), 1);
|
|
21263
21995
|
var DEFAULT_WEB_PORT = 6328;
|
|
21264
21996
|
var DEFAULT_REST_PORT = 8080;
|
|
21265
21997
|
function asValidPort(value) {
|
|
@@ -21268,11 +22000,11 @@ function asValidPort(value) {
|
|
|
21268
22000
|
}
|
|
21269
22001
|
function projectRoot() {
|
|
21270
22002
|
const fromEnv = process.env.NEAT_SCAN_PATH;
|
|
21271
|
-
return
|
|
22003
|
+
return import_node_path76.default.resolve(fromEnv && fromEnv.length > 0 ? fromEnv : process.cwd());
|
|
21272
22004
|
}
|
|
21273
22005
|
async function readDaemonPorts(root) {
|
|
21274
22006
|
try {
|
|
21275
|
-
const raw = await
|
|
22007
|
+
const raw = await import_node_fs41.promises.readFile(import_node_path76.default.join(root, "neat-out", "daemon.json"), "utf8");
|
|
21276
22008
|
const parsed = JSON.parse(raw);
|
|
21277
22009
|
const ports = parsed?.ports ?? {};
|
|
21278
22010
|
return { web: asValidPort(ports.web), rest: asValidPort(ports.rest) };
|
|
@@ -21317,10 +22049,10 @@ function resolveWebPackageDir() {
|
|
|
21317
22049
|
eval("require")
|
|
21318
22050
|
);
|
|
21319
22051
|
const pkgJsonPath = req.resolve("@neat.is/web/package.json");
|
|
21320
|
-
return
|
|
22052
|
+
return import_node_path76.default.dirname(pkgJsonPath);
|
|
21321
22053
|
}
|
|
21322
22054
|
function resolveStandaloneServerEntry(webDir) {
|
|
21323
|
-
return
|
|
22055
|
+
return import_node_path76.default.join(webDir, ".next/standalone/packages/web/server.js");
|
|
21324
22056
|
}
|
|
21325
22057
|
async function pickInternalPort() {
|
|
21326
22058
|
return new Promise((resolve, reject) => {
|
|
@@ -21373,7 +22105,7 @@ async function spawnWebUI(restPort, opts = {}) {
|
|
|
21373
22105
|
NEAT_API_URL: apiUrl
|
|
21374
22106
|
};
|
|
21375
22107
|
child = (0, import_node_child_process2.spawn)(process.execPath, [serverEntry], {
|
|
21376
|
-
cwd:
|
|
22108
|
+
cwd: import_node_path76.default.dirname(serverEntry),
|
|
21377
22109
|
env,
|
|
21378
22110
|
stdio: ["ignore", "inherit", "inherit"],
|
|
21379
22111
|
detached: false
|
|
@@ -21500,15 +22232,15 @@ async function fetchRegistryVersion(url, timeoutMs, fetchImpl) {
|
|
|
21500
22232
|
}
|
|
21501
22233
|
function isLocalBehind(local, remote) {
|
|
21502
22234
|
if (local === remote) return false;
|
|
21503
|
-
const
|
|
22235
|
+
const parse11 = (v) => {
|
|
21504
22236
|
const core = v.split(/[-+]/)[0] ?? v;
|
|
21505
22237
|
return core.split(".").map((s) => {
|
|
21506
22238
|
const n = Number.parseInt(s, 10);
|
|
21507
22239
|
return Number.isFinite(n) ? n : 0;
|
|
21508
22240
|
});
|
|
21509
22241
|
};
|
|
21510
|
-
const a =
|
|
21511
|
-
const b =
|
|
22242
|
+
const a = parse11(local);
|
|
22243
|
+
const b = parse11(remote);
|
|
21512
22244
|
const len = Math.max(a.length, b.length);
|
|
21513
22245
|
for (let i = 0; i < len; i++) {
|
|
21514
22246
|
const av = a[i] ?? 0;
|
|
@@ -21549,14 +22281,14 @@ function localVersion() {
|
|
|
21549
22281
|
}
|
|
21550
22282
|
function neatHome3() {
|
|
21551
22283
|
if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {
|
|
21552
|
-
return
|
|
22284
|
+
return import_node_path77.default.resolve(process.env.NEAT_HOME);
|
|
21553
22285
|
}
|
|
21554
22286
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
21555
|
-
return
|
|
22287
|
+
return import_node_path77.default.join(home, ".neat");
|
|
21556
22288
|
}
|
|
21557
22289
|
async function readPid() {
|
|
21558
22290
|
try {
|
|
21559
|
-
const raw = await
|
|
22291
|
+
const raw = await import_node_fs42.promises.readFile(import_node_path77.default.join(neatHome3(), "neatd.pid"), "utf8");
|
|
21560
22292
|
const n = Number.parseInt(raw.trim(), 10);
|
|
21561
22293
|
return Number.isFinite(n) ? n : null;
|
|
21562
22294
|
} catch {
|