@neat.is/core 0.9.12-dev.20260831 → 0.9.12
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-3UAUMPIY.js → chunk-RBZNXA5L.js} +591 -460
- package/dist/chunk-RBZNXA5L.js.map +1 -0
- package/dist/{chunk-UNO3X6ZV.js → chunk-WE3AFQYL.js} +468 -19
- package/dist/chunk-WE3AFQYL.js.map +1 -0
- package/dist/cli.cjs +1108 -951
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1229 -645
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +1245 -661
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +661 -534
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-3UAUMPIY.js.map +0 -1
- package/dist/chunk-UNO3X6ZV.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -60,8 +60,8 @@ function mountBearerAuth(app, opts) {
|
|
|
60
60
|
]);
|
|
61
61
|
const publicRead = opts.publicRead === true;
|
|
62
62
|
app.addHook("preHandler", (req, reply, done) => {
|
|
63
|
-
const
|
|
64
|
-
if (exactUnauthPaths.has(
|
|
63
|
+
const path78 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
64
|
+
if (exactUnauthPaths.has(path78) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path78)) {
|
|
65
65
|
done();
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
@@ -193,8 +193,8 @@ function reshapeGrpcRequest(req) {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
function resolveProtoRoot() {
|
|
196
|
-
const here =
|
|
197
|
-
return
|
|
196
|
+
const here = import_node_path53.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
197
|
+
return import_node_path53.default.resolve(here, "..", "proto");
|
|
198
198
|
}
|
|
199
199
|
function loadTraceService() {
|
|
200
200
|
const protoRoot = resolveProtoRoot();
|
|
@@ -262,13 +262,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
262
262
|
})
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
var import_node_url,
|
|
265
|
+
var import_node_url, import_node_path53, import_node_crypto2, grpc, protoLoader;
|
|
266
266
|
var init_otel_grpc = __esm({
|
|
267
267
|
"src/otel-grpc.ts"() {
|
|
268
268
|
"use strict";
|
|
269
269
|
init_cjs_shims();
|
|
270
270
|
import_node_url = require("url");
|
|
271
|
-
|
|
271
|
+
import_node_path53 = __toESM(require("path"), 1);
|
|
272
272
|
import_node_crypto2 = require("crypto");
|
|
273
273
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
274
274
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -414,8 +414,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
414
414
|
const v = attrs[key];
|
|
415
415
|
if (typeof v === "string" && v.length > 0) {
|
|
416
416
|
const q = v.indexOf("?");
|
|
417
|
-
const
|
|
418
|
-
if (
|
|
417
|
+
const path78 = q === -1 ? v : v.slice(0, q);
|
|
418
|
+
if (path78.length > 0) return path78;
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
return void 0;
|
|
@@ -477,10 +477,10 @@ function parseOtlpRequest(body) {
|
|
|
477
477
|
return out;
|
|
478
478
|
}
|
|
479
479
|
function loadProtoRoot() {
|
|
480
|
-
const here =
|
|
481
|
-
const protoRoot =
|
|
480
|
+
const here = import_node_path54.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
481
|
+
const protoRoot = import_node_path54.default.resolve(here, "..", "proto");
|
|
482
482
|
const root = new import_protobufjs.default.Root();
|
|
483
|
-
root.resolvePath = (_origin, target) =>
|
|
483
|
+
root.resolvePath = (_origin, target) => import_node_path54.default.resolve(protoRoot, target);
|
|
484
484
|
root.loadSync(
|
|
485
485
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
486
486
|
{ keepCase: true }
|
|
@@ -766,12 +766,12 @@ function logSpanHandler(span) {
|
|
|
766
766
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
767
767
|
);
|
|
768
768
|
}
|
|
769
|
-
var
|
|
769
|
+
var import_node_path54, import_node_url2, import_node_zlib, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
770
770
|
var init_otel = __esm({
|
|
771
771
|
"src/otel.ts"() {
|
|
772
772
|
"use strict";
|
|
773
773
|
init_cjs_shims();
|
|
774
|
-
|
|
774
|
+
import_node_path54 = __toESM(require("path"), 1);
|
|
775
775
|
import_node_url2 = require("url");
|
|
776
776
|
import_node_zlib = __toESM(require("zlib"), 1);
|
|
777
777
|
import_fastify = __toESM(require("fastify"), 1);
|
|
@@ -1365,19 +1365,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1365
1365
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1366
1366
|
let best = { path: [start], edges: [] };
|
|
1367
1367
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1368
|
-
function step(node,
|
|
1369
|
-
if (
|
|
1370
|
-
best = { path: [...
|
|
1368
|
+
function step(node, path78, edges) {
|
|
1369
|
+
if (path78.length > best.path.length) {
|
|
1370
|
+
best = { path: [...path78], edges: [...edges] };
|
|
1371
1371
|
}
|
|
1372
|
-
if (
|
|
1372
|
+
if (path78.length - 1 >= maxDepth) return;
|
|
1373
1373
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1374
1374
|
for (const [srcId, edge] of incoming) {
|
|
1375
1375
|
if (visited.has(srcId)) continue;
|
|
1376
1376
|
visited.add(srcId);
|
|
1377
|
-
|
|
1377
|
+
path78.push(srcId);
|
|
1378
1378
|
edges.push(edge);
|
|
1379
|
-
step(srcId,
|
|
1380
|
-
|
|
1379
|
+
step(srcId, path78, edges);
|
|
1380
|
+
path78.pop();
|
|
1381
1381
|
edges.pop();
|
|
1382
1382
|
visited.delete(srcId);
|
|
1383
1383
|
}
|
|
@@ -1385,14 +1385,14 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1385
1385
|
step(start, [start], []);
|
|
1386
1386
|
return best;
|
|
1387
1387
|
}
|
|
1388
|
-
function databaseRootCauseShape(graph, origin,
|
|
1388
|
+
function databaseRootCauseShape(graph, origin, walk11) {
|
|
1389
1389
|
const targetDb = origin;
|
|
1390
1390
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1391
1391
|
if (candidatePairs.length === 0) return null;
|
|
1392
|
-
for (const id of
|
|
1392
|
+
for (const id of walk11.path) {
|
|
1393
1393
|
const owner = resolveOwningService(graph, id);
|
|
1394
1394
|
if (!owner) continue;
|
|
1395
|
-
const { id:
|
|
1395
|
+
const { id: serviceId17, svc } = owner;
|
|
1396
1396
|
const deps = svc.dependencies ?? {};
|
|
1397
1397
|
for (const pair of candidatePairs) {
|
|
1398
1398
|
const declared = deps[pair.driver];
|
|
@@ -1405,7 +1405,7 @@ function databaseRootCauseShape(graph, origin, walk10) {
|
|
|
1405
1405
|
);
|
|
1406
1406
|
if (!result.compatible) {
|
|
1407
1407
|
return {
|
|
1408
|
-
rootCauseNode:
|
|
1408
|
+
rootCauseNode: serviceId17,
|
|
1409
1409
|
rootCauseReason: result.reason ?? "incompatible driver",
|
|
1410
1410
|
...result.minDriverVersion ? {
|
|
1411
1411
|
fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`
|
|
@@ -1416,11 +1416,11 @@ function databaseRootCauseShape(graph, origin, walk10) {
|
|
|
1416
1416
|
}
|
|
1417
1417
|
return null;
|
|
1418
1418
|
}
|
|
1419
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1420
|
-
for (const id of
|
|
1419
|
+
function serviceRootCauseShape(graph, _origin, walk11) {
|
|
1420
|
+
for (const id of walk11.path) {
|
|
1421
1421
|
const owner = resolveOwningService(graph, id);
|
|
1422
1422
|
if (!owner) continue;
|
|
1423
|
-
const { id:
|
|
1423
|
+
const { id: serviceId17, svc } = owner;
|
|
1424
1424
|
const deps = svc.dependencies ?? {};
|
|
1425
1425
|
const serviceNodeEngine = svc.nodeEngine;
|
|
1426
1426
|
for (const constraint of nodeEngineConstraints()) {
|
|
@@ -1429,7 +1429,7 @@ function serviceRootCauseShape(graph, _origin, walk10) {
|
|
|
1429
1429
|
const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine);
|
|
1430
1430
|
if (!result.compatible && result.reason) {
|
|
1431
1431
|
return {
|
|
1432
|
-
rootCauseNode:
|
|
1432
|
+
rootCauseNode: serviceId17,
|
|
1433
1433
|
rootCauseReason: result.reason,
|
|
1434
1434
|
...result.requiredNodeVersion ? {
|
|
1435
1435
|
fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`
|
|
@@ -1444,7 +1444,7 @@ function serviceRootCauseShape(graph, _origin, walk10) {
|
|
|
1444
1444
|
const result = checkPackageConflict(conflict, declared, requiredDeclared);
|
|
1445
1445
|
if (!result.compatible && result.reason) {
|
|
1446
1446
|
return {
|
|
1447
|
-
rootCauseNode:
|
|
1447
|
+
rootCauseNode: serviceId17,
|
|
1448
1448
|
rootCauseReason: result.reason,
|
|
1449
1449
|
fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`
|
|
1450
1450
|
};
|
|
@@ -1453,15 +1453,15 @@ function serviceRootCauseShape(graph, _origin, walk10) {
|
|
|
1453
1453
|
}
|
|
1454
1454
|
return null;
|
|
1455
1455
|
}
|
|
1456
|
-
function fileRootCauseShape(graph, origin,
|
|
1456
|
+
function fileRootCauseShape(graph, origin, walk11) {
|
|
1457
1457
|
const owner = resolveOwningService(graph, origin.id);
|
|
1458
1458
|
if (!owner) return null;
|
|
1459
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1459
|
+
return serviceRootCauseShape(graph, owner.svc, walk11);
|
|
1460
1460
|
}
|
|
1461
|
-
function symbolRootCauseShape(graph, origin,
|
|
1461
|
+
function symbolRootCauseShape(graph, origin, walk11) {
|
|
1462
1462
|
const owner = resolveOwningService(graph, origin.id);
|
|
1463
1463
|
if (!owner) return null;
|
|
1464
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1464
|
+
return serviceRootCauseShape(graph, owner.svc, walk11);
|
|
1465
1465
|
}
|
|
1466
1466
|
var rootCauseShapes = {
|
|
1467
1467
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1474,8 +1474,8 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1474
1474
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1475
1475
|
const shape = rootCauseShapes[origin.type];
|
|
1476
1476
|
if (shape) {
|
|
1477
|
-
const
|
|
1478
|
-
const match = shape(graph, origin,
|
|
1477
|
+
const walk11 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1478
|
+
const match = shape(graph, origin, walk11);
|
|
1479
1479
|
if (match) {
|
|
1480
1480
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1481
1481
|
return {
|
|
@@ -1483,9 +1483,9 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1483
1483
|
result: import_types.RootCauseResultSchema.parse({
|
|
1484
1484
|
rootCauseNode: match.rootCauseNode,
|
|
1485
1485
|
rootCauseReason: reason,
|
|
1486
|
-
traversalPath:
|
|
1487
|
-
edgeProvenances:
|
|
1488
|
-
confidence: confidenceFromMix(
|
|
1486
|
+
traversalPath: walk11.path,
|
|
1487
|
+
edgeProvenances: walk11.edges.map((e) => e.provenance),
|
|
1488
|
+
confidence: confidenceFromMix(walk11.edges),
|
|
1489
1489
|
fixRecommendation: match.fixRecommendation
|
|
1490
1490
|
})
|
|
1491
1491
|
};
|
|
@@ -1549,9 +1549,9 @@ function rootCauseFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
1549
1549
|
function isFailingCallEdge(e) {
|
|
1550
1550
|
return e.type === import_types.EdgeType.CALLS && (e.signal?.errorCount ?? 0) > 0;
|
|
1551
1551
|
}
|
|
1552
|
-
function callSourcesForService(graph,
|
|
1553
|
-
const ids = [
|
|
1554
|
-
for (const edgeId of graph.outboundEdges(
|
|
1552
|
+
function callSourcesForService(graph, serviceId17) {
|
|
1553
|
+
const ids = [serviceId17];
|
|
1554
|
+
for (const edgeId of graph.outboundEdges(serviceId17)) {
|
|
1555
1555
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1556
1556
|
if (e.type !== import_types.EdgeType.CONTAINS) continue;
|
|
1557
1557
|
const tgt = graph.getNodeAttributes(e.target);
|
|
@@ -1575,9 +1575,9 @@ function failingCallDominates(e, id, curEdge, curId) {
|
|
|
1575
1575
|
}
|
|
1576
1576
|
return id < curId;
|
|
1577
1577
|
}
|
|
1578
|
-
function dominantFailingCall(graph,
|
|
1578
|
+
function dominantFailingCall(graph, serviceId17, visited) {
|
|
1579
1579
|
let best = null;
|
|
1580
|
-
for (const src of callSourcesForService(graph,
|
|
1580
|
+
for (const src of callSourcesForService(graph, serviceId17)) {
|
|
1581
1581
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
1582
1582
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1583
1583
|
if (!isFailingCallEdge(e)) continue;
|
|
@@ -1592,20 +1592,20 @@ function dominantFailingCall(graph, serviceId16, visited) {
|
|
|
1592
1592
|
return best;
|
|
1593
1593
|
}
|
|
1594
1594
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1595
|
-
const
|
|
1595
|
+
const path78 = [originServiceId];
|
|
1596
1596
|
const edges = [];
|
|
1597
1597
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1598
1598
|
let current = originServiceId;
|
|
1599
1599
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1600
1600
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1601
1601
|
if (!hop) break;
|
|
1602
|
-
|
|
1602
|
+
path78.push(hop.nextService);
|
|
1603
1603
|
edges.push(hop.edge);
|
|
1604
1604
|
visited.add(hop.nextService);
|
|
1605
1605
|
current = hop.nextService;
|
|
1606
1606
|
}
|
|
1607
1607
|
if (edges.length === 0) return null;
|
|
1608
|
-
return { path:
|
|
1608
|
+
return { path: path78, edges, culprit: current };
|
|
1609
1609
|
}
|
|
1610
1610
|
function isStaleCallEdge(e) {
|
|
1611
1611
|
return e.type === import_types.EdgeType.CALLS && e.provenance === import_types.Provenance.STALE;
|
|
@@ -1616,9 +1616,9 @@ function staleCallDominates(e, id, curEdge, curId) {
|
|
|
1616
1616
|
if (ev !== cv) return ev > cv;
|
|
1617
1617
|
return id < curId;
|
|
1618
1618
|
}
|
|
1619
|
-
function dominantStaleCall(graph,
|
|
1619
|
+
function dominantStaleCall(graph, serviceId17, visited) {
|
|
1620
1620
|
const bestByCallee = /* @__PURE__ */ new Map();
|
|
1621
|
-
for (const src of callSourcesForService(graph,
|
|
1621
|
+
for (const src of callSourcesForService(graph, serviceId17)) {
|
|
1622
1622
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
1623
1623
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1624
1624
|
if (e.type !== import_types.EdgeType.CALLS) continue;
|
|
@@ -1641,26 +1641,26 @@ function dominantStaleCall(graph, serviceId16, visited) {
|
|
|
1641
1641
|
return best;
|
|
1642
1642
|
}
|
|
1643
1643
|
function followStaleCallChain(graph, originServiceId, maxDepth) {
|
|
1644
|
-
const
|
|
1644
|
+
const path78 = [originServiceId];
|
|
1645
1645
|
const edges = [];
|
|
1646
1646
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1647
1647
|
let current = originServiceId;
|
|
1648
1648
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1649
1649
|
const hop = dominantStaleCall(graph, current, visited);
|
|
1650
1650
|
if (!hop) break;
|
|
1651
|
-
|
|
1651
|
+
path78.push(hop.nextService);
|
|
1652
1652
|
edges.push(hop.edge);
|
|
1653
1653
|
visited.add(hop.nextService);
|
|
1654
1654
|
current = hop.nextService;
|
|
1655
1655
|
}
|
|
1656
1656
|
if (edges.length === 0) return null;
|
|
1657
|
-
return { path:
|
|
1657
|
+
return { path: path78, edges, culprit: current };
|
|
1658
1658
|
}
|
|
1659
1659
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1660
1660
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1661
1661
|
if (!chain) return null;
|
|
1662
1662
|
const culprit = chain.culprit;
|
|
1663
|
-
const
|
|
1663
|
+
const path78 = [...chain.path];
|
|
1664
1664
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1665
1665
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1666
1666
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1668,14 +1668,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1668
1668
|
if (loc) {
|
|
1669
1669
|
let rootCauseNode = culprit;
|
|
1670
1670
|
if (loc.fileNode) {
|
|
1671
|
-
|
|
1671
|
+
path78.push(loc.fileNode);
|
|
1672
1672
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1673
1673
|
rootCauseNode = loc.fileNode;
|
|
1674
1674
|
}
|
|
1675
1675
|
return import_types.RootCauseResultSchema.parse({
|
|
1676
1676
|
rootCauseNode,
|
|
1677
1677
|
rootCauseReason: loc.rootCauseReason,
|
|
1678
|
-
traversalPath:
|
|
1678
|
+
traversalPath: path78,
|
|
1679
1679
|
edgeProvenances,
|
|
1680
1680
|
confidence,
|
|
1681
1681
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1687,7 +1687,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1687
1687
|
return import_types.RootCauseResultSchema.parse({
|
|
1688
1688
|
rootCauseNode: culprit,
|
|
1689
1689
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1690
|
-
traversalPath:
|
|
1690
|
+
traversalPath: path78,
|
|
1691
1691
|
edgeProvenances,
|
|
1692
1692
|
confidence,
|
|
1693
1693
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2300,10 +2300,10 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
|
2300
2300
|
traversalPath = staleChain.path;
|
|
2301
2301
|
edgeProvenances = staleChain.edges.map((e) => e.provenance);
|
|
2302
2302
|
} else if (top.node !== seedNode) {
|
|
2303
|
-
const
|
|
2304
|
-
if (
|
|
2305
|
-
traversalPath =
|
|
2306
|
-
edgeProvenances =
|
|
2303
|
+
const path78 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
|
|
2304
|
+
if (path78) {
|
|
2305
|
+
traversalPath = path78.nodes;
|
|
2306
|
+
edgeProvenances = path78.edges.map((e) => e.provenance);
|
|
2307
2307
|
} else {
|
|
2308
2308
|
traversalPath = [errorNodeId, top.node];
|
|
2309
2309
|
edgeProvenances = [top.provenance ?? import_types.Provenance.OBSERVED];
|
|
@@ -3127,7 +3127,7 @@ function buildServiceHostIndex(services) {
|
|
|
3127
3127
|
async function walkSourceFiles(dir, excludeDirs = []) {
|
|
3128
3128
|
const excluded = new Set(excludeDirs.map((d) => import_node_path5.default.resolve(d)));
|
|
3129
3129
|
const out = [];
|
|
3130
|
-
async function
|
|
3130
|
+
async function walk11(current) {
|
|
3131
3131
|
const entries = await import_node_fs5.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
3132
3132
|
for (const entry of entries) {
|
|
3133
3133
|
const full = import_node_path5.default.join(current, entry.name);
|
|
@@ -3135,7 +3135,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
3135
3135
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
3136
3136
|
if (excluded.has(import_node_path5.default.resolve(full))) continue;
|
|
3137
3137
|
if (await isPythonVenvDir(full)) continue;
|
|
3138
|
-
await
|
|
3138
|
+
await walk11(full);
|
|
3139
3139
|
} else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path5.default.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
3140
3140
|
// would attribute our instrumentation imports to the user's service.
|
|
3141
3141
|
!isNeatAuthoredSourceFile(entry.name)) {
|
|
@@ -3143,7 +3143,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
3143
3143
|
}
|
|
3144
3144
|
}
|
|
3145
3145
|
}
|
|
3146
|
-
await
|
|
3146
|
+
await walk11(dir);
|
|
3147
3147
|
return out;
|
|
3148
3148
|
}
|
|
3149
3149
|
async function loadSourceFiles(dir, excludeDirs = []) {
|
|
@@ -3739,8 +3739,8 @@ function chiRoutesFromSource(source, parser) {
|
|
|
3739
3739
|
chiWalk(tree.rootNode, "", out);
|
|
3740
3740
|
return out;
|
|
3741
3741
|
}
|
|
3742
|
-
function stripChiRegex(
|
|
3743
|
-
return
|
|
3742
|
+
function stripChiRegex(path78) {
|
|
3743
|
+
return path78.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
3744
3744
|
}
|
|
3745
3745
|
function chiWalk(node, prefix, out) {
|
|
3746
3746
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -4412,9 +4412,9 @@ function rubyRocketRoute(args) {
|
|
|
4412
4412
|
if (!pair || pair.type !== "pair") continue;
|
|
4413
4413
|
const k = pair.childForFieldName("key");
|
|
4414
4414
|
if (k?.type !== "string") continue;
|
|
4415
|
-
const
|
|
4416
|
-
if (
|
|
4417
|
-
return { path:
|
|
4415
|
+
const path78 = rubyLiteral(k);
|
|
4416
|
+
if (path78 === null) continue;
|
|
4417
|
+
return { path: path78, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
4418
4418
|
}
|
|
4419
4419
|
return null;
|
|
4420
4420
|
}
|
|
@@ -6025,8 +6025,8 @@ function pickContainingSymbol(candidates, fn) {
|
|
|
6025
6025
|
return b.symbol.span.startLine - a.symbol.span.startLine;
|
|
6026
6026
|
};
|
|
6027
6027
|
if (fn) {
|
|
6028
|
-
const
|
|
6029
|
-
if (
|
|
6028
|
+
const named2 = candidates.filter((c) => terminalName(c.symbol.qualname) === fn);
|
|
6029
|
+
if (named2.length > 0) return [...named2].sort(bySpan)[0].id;
|
|
6030
6030
|
}
|
|
6031
6031
|
return [...candidates].sort(bySpan)[0].id;
|
|
6032
6032
|
}
|
|
@@ -6969,29 +6969,29 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
6969
6969
|
toPromote.push({ frontierId: id, serviceId: target });
|
|
6970
6970
|
});
|
|
6971
6971
|
let promoted = 0;
|
|
6972
|
-
for (const { frontierId: frontierId2, serviceId:
|
|
6972
|
+
for (const { frontierId: frontierId2, serviceId: serviceId17 } of toPromote) {
|
|
6973
6973
|
if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {
|
|
6974
6974
|
const gate = canPromoteFrontier(graph, frontierId2, opts.policies, opts.policyCtx);
|
|
6975
6975
|
if (!gate.allowed) {
|
|
6976
6976
|
continue;
|
|
6977
6977
|
}
|
|
6978
6978
|
}
|
|
6979
|
-
rewireFrontierEdges(graph, frontierId2,
|
|
6979
|
+
rewireFrontierEdges(graph, frontierId2, serviceId17);
|
|
6980
6980
|
graph.dropNode(frontierId2);
|
|
6981
6981
|
promoted++;
|
|
6982
6982
|
}
|
|
6983
6983
|
return promoted;
|
|
6984
6984
|
}
|
|
6985
|
-
function rewireFrontierEdges(graph, frontierId2,
|
|
6985
|
+
function rewireFrontierEdges(graph, frontierId2, serviceId17) {
|
|
6986
6986
|
const inbound = [...graph.inboundEdges(frontierId2)];
|
|
6987
6987
|
const outbound = [...graph.outboundEdges(frontierId2)];
|
|
6988
6988
|
for (const edgeId of inbound) {
|
|
6989
6989
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
6990
|
-
rebuildEdge(graph, edge, edge.source,
|
|
6990
|
+
rebuildEdge(graph, edge, edge.source, serviceId17, edgeId);
|
|
6991
6991
|
}
|
|
6992
6992
|
for (const edgeId of outbound) {
|
|
6993
6993
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
6994
|
-
rebuildEdge(graph, edge,
|
|
6994
|
+
rebuildEdge(graph, edge, serviceId17, edge.target, edgeId);
|
|
6995
6995
|
}
|
|
6996
6996
|
}
|
|
6997
6997
|
function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
@@ -8127,9 +8127,9 @@ var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
|
8127
8127
|
"StatefulSet",
|
|
8128
8128
|
"DaemonSet"
|
|
8129
8129
|
]);
|
|
8130
|
-
function addAliases(graph,
|
|
8131
|
-
if (!graph.hasNode(
|
|
8132
|
-
const node = graph.getNodeAttributes(
|
|
8130
|
+
function addAliases(graph, serviceId17, candidates) {
|
|
8131
|
+
if (!graph.hasNode(serviceId17)) return;
|
|
8132
|
+
const node = graph.getNodeAttributes(serviceId17);
|
|
8133
8133
|
if (node.type !== import_types19.NodeType.ServiceNode) return;
|
|
8134
8134
|
const set = new Set(node.aliases ?? []);
|
|
8135
8135
|
for (const c of candidates) {
|
|
@@ -8139,7 +8139,7 @@ function addAliases(graph, serviceId16, candidates) {
|
|
|
8139
8139
|
}
|
|
8140
8140
|
if (set.size === 0) return;
|
|
8141
8141
|
const updated = { ...node, aliases: [...set].sort() };
|
|
8142
|
-
graph.replaceNodeAttributes(
|
|
8142
|
+
graph.replaceNodeAttributes(serviceId17, updated);
|
|
8143
8143
|
}
|
|
8144
8144
|
function indexServicesByName(services) {
|
|
8145
8145
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -8172,12 +8172,12 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
|
|
|
8172
8172
|
}
|
|
8173
8173
|
if (!compose?.services) return;
|
|
8174
8174
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
8175
|
-
const
|
|
8176
|
-
if (!
|
|
8175
|
+
const serviceId17 = serviceIndex.get(composeName);
|
|
8176
|
+
if (!serviceId17) continue;
|
|
8177
8177
|
const aliases = /* @__PURE__ */ new Set([composeName]);
|
|
8178
8178
|
if (svc.container_name) aliases.add(svc.container_name);
|
|
8179
8179
|
if (svc.hostname) aliases.add(svc.hostname);
|
|
8180
|
-
addAliases(graph,
|
|
8180
|
+
addAliases(graph, serviceId17, aliases);
|
|
8181
8181
|
}
|
|
8182
8182
|
}
|
|
8183
8183
|
var LABEL_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -9288,7 +9288,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
9288
9288
|
return best;
|
|
9289
9289
|
};
|
|
9290
9290
|
const requests = [];
|
|
9291
|
-
const
|
|
9291
|
+
const walk11 = (node) => {
|
|
9292
9292
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
9293
9293
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
9294
9294
|
if (self && self.kind === "class") {
|
|
@@ -9334,10 +9334,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
9334
9334
|
}
|
|
9335
9335
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
9336
9336
|
const child = node.namedChild(i);
|
|
9337
|
-
if (child)
|
|
9337
|
+
if (child) walk11(child);
|
|
9338
9338
|
}
|
|
9339
9339
|
};
|
|
9340
|
-
|
|
9340
|
+
walk11(root);
|
|
9341
9341
|
for (const req of requests) {
|
|
9342
9342
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
9343
9343
|
if (!targetSid) continue;
|
|
@@ -9445,10 +9445,10 @@ function collectNamedImports(root) {
|
|
|
9445
9445
|
const clause = node.namedChild(i);
|
|
9446
9446
|
if (clause?.type !== "import_clause") continue;
|
|
9447
9447
|
for (let j = 0; j < clause.namedChildCount; j++) {
|
|
9448
|
-
const
|
|
9449
|
-
if (
|
|
9450
|
-
for (let k = 0; k <
|
|
9451
|
-
const spec =
|
|
9448
|
+
const named2 = clause.namedChild(j);
|
|
9449
|
+
if (named2?.type !== "named_imports") continue;
|
|
9450
|
+
for (let k = 0; k < named2.namedChildCount; k++) {
|
|
9451
|
+
const spec = named2.namedChild(k);
|
|
9452
9452
|
if (spec?.type !== "import_specifier") continue;
|
|
9453
9453
|
let isType = false;
|
|
9454
9454
|
for (let t = 0; t < spec.childCount; t++) {
|
|
@@ -10509,7 +10509,7 @@ var import_types24 = require("@neat.is/types");
|
|
|
10509
10509
|
async function walkConfigFiles(dir, excludeDirs = []) {
|
|
10510
10510
|
const excluded = new Set(excludeDirs.map((d) => import_node_path35.default.resolve(d)));
|
|
10511
10511
|
const out = [];
|
|
10512
|
-
async function
|
|
10512
|
+
async function walk11(current) {
|
|
10513
10513
|
const entries = await import_node_fs23.promises.readdir(current, { withFileTypes: true });
|
|
10514
10514
|
for (const entry of entries) {
|
|
10515
10515
|
const full = import_node_path35.default.join(current, entry.name);
|
|
@@ -10517,13 +10517,13 @@ async function walkConfigFiles(dir, excludeDirs = []) {
|
|
|
10517
10517
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
10518
10518
|
if (excluded.has(import_node_path35.default.resolve(full))) continue;
|
|
10519
10519
|
if (await isPythonVenvDir(full)) continue;
|
|
10520
|
-
await
|
|
10520
|
+
await walk11(full);
|
|
10521
10521
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
10522
10522
|
out.push(full);
|
|
10523
10523
|
}
|
|
10524
10524
|
}
|
|
10525
10525
|
}
|
|
10526
|
-
await
|
|
10526
|
+
await walk11(dir);
|
|
10527
10527
|
return out;
|
|
10528
10528
|
}
|
|
10529
10529
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -10614,7 +10614,7 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
10614
10614
|
async function walkProtoFiles(dir, excludeDirs = []) {
|
|
10615
10615
|
const excluded = new Set(excludeDirs.map((d) => import_node_path36.default.resolve(d)));
|
|
10616
10616
|
const out = [];
|
|
10617
|
-
async function
|
|
10617
|
+
async function walk11(current) {
|
|
10618
10618
|
const entries = await import_node_fs24.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
10619
10619
|
for (const entry of entries) {
|
|
10620
10620
|
const full = import_node_path36.default.join(current, entry.name);
|
|
@@ -10622,13 +10622,13 @@ async function walkProtoFiles(dir, excludeDirs = []) {
|
|
|
10622
10622
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
10623
10623
|
if (excluded.has(import_node_path36.default.resolve(full))) continue;
|
|
10624
10624
|
if (await isPythonVenvDir(full)) continue;
|
|
10625
|
-
await
|
|
10625
|
+
await walk11(full);
|
|
10626
10626
|
} else if (entry.isFile() && import_node_path36.default.extname(entry.name) === PROTO_EXTENSION) {
|
|
10627
10627
|
out.push(full);
|
|
10628
10628
|
}
|
|
10629
10629
|
}
|
|
10630
10630
|
}
|
|
10631
|
-
await
|
|
10631
|
+
await walk11(dir);
|
|
10632
10632
|
return out;
|
|
10633
10633
|
}
|
|
10634
10634
|
async function addGrpcMethods(graph, services) {
|
|
@@ -10696,7 +10696,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
10696
10696
|
|
|
10697
10697
|
// src/extract/calls/index.ts
|
|
10698
10698
|
init_cjs_shims();
|
|
10699
|
-
var
|
|
10699
|
+
var import_types45 = require("@neat.is/types");
|
|
10700
10700
|
|
|
10701
10701
|
// src/extract/calls/http.ts
|
|
10702
10702
|
init_cjs_shims();
|
|
@@ -11631,7 +11631,7 @@ function isFirestoreClientFactory(node) {
|
|
|
11631
11631
|
}
|
|
11632
11632
|
function firestoreClientVars(root) {
|
|
11633
11633
|
const vars = /* @__PURE__ */ new Set();
|
|
11634
|
-
const
|
|
11634
|
+
const walk11 = (node) => {
|
|
11635
11635
|
if (node.type === "variable_declarator") {
|
|
11636
11636
|
const name = node.childForFieldName("name");
|
|
11637
11637
|
let value = node.childForFieldName("value");
|
|
@@ -11640,9 +11640,9 @@ function firestoreClientVars(root) {
|
|
|
11640
11640
|
vars.add(name.text);
|
|
11641
11641
|
}
|
|
11642
11642
|
}
|
|
11643
|
-
for (const c of namedChildren(node))
|
|
11643
|
+
for (const c of namedChildren(node)) walk11(c);
|
|
11644
11644
|
};
|
|
11645
|
-
|
|
11645
|
+
walk11(root);
|
|
11646
11646
|
return vars;
|
|
11647
11647
|
}
|
|
11648
11648
|
function isClientExpr(node, clientVars) {
|
|
@@ -11797,7 +11797,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11797
11797
|
}
|
|
11798
11798
|
s.add(field);
|
|
11799
11799
|
};
|
|
11800
|
-
const
|
|
11800
|
+
const walk11 = (node) => {
|
|
11801
11801
|
if (node.type === "call_expression") {
|
|
11802
11802
|
const fn = node.childForFieldName("function");
|
|
11803
11803
|
const line = node.startPosition.row + 1;
|
|
@@ -11837,9 +11837,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11837
11837
|
}
|
|
11838
11838
|
}
|
|
11839
11839
|
}
|
|
11840
|
-
for (const c of namedChildren(node))
|
|
11840
|
+
for (const c of namedChildren(node)) walk11(c);
|
|
11841
11841
|
};
|
|
11842
|
-
|
|
11842
|
+
walk11(tree.rootNode);
|
|
11843
11843
|
const out = [];
|
|
11844
11844
|
for (const [collPath, line] of collLine) {
|
|
11845
11845
|
const byField = writes.get(collPath);
|
|
@@ -12082,8 +12082,8 @@ function parseImportBindings(content) {
|
|
|
12082
12082
|
out.push({ local: ns[1], kind: "namespace", specifier: spec });
|
|
12083
12083
|
continue;
|
|
12084
12084
|
}
|
|
12085
|
-
const
|
|
12086
|
-
if (
|
|
12085
|
+
const named2 = /\{([^}]*)\}/.exec(clause);
|
|
12086
|
+
if (named2) parseDestructure(named2[1], spec, out);
|
|
12087
12087
|
const def = /^(\w+)\s*(?:,|$)/.exec(clause);
|
|
12088
12088
|
if (def && !clause.startsWith("{")) out.push({ local: def[1], kind: "default", specifier: spec });
|
|
12089
12089
|
}
|
|
@@ -12103,8 +12103,8 @@ function fileExportsOf(content, pluralizeOn) {
|
|
|
12103
12103
|
for (const d of defs) if (d.varName) byVar.set(d.varName, d.resolved.name);
|
|
12104
12104
|
const byName = new Map(byVar);
|
|
12105
12105
|
let def;
|
|
12106
|
-
const
|
|
12107
|
-
if (
|
|
12106
|
+
const named2 = /(?:module\.exports|export\s+default)\s*=\s*(\w+)\b/.exec(content);
|
|
12107
|
+
if (named2 && byVar.has(named2[1])) def = byVar.get(named2[1]);
|
|
12108
12108
|
if (!def) {
|
|
12109
12109
|
const inline = /(?:module\.exports|export\s+default)\s*=\s*(?:await\s+)?(?:\w+\s*\.\s*)?model\s*\(\s*['"`]([\w$]+)['"`]/.exec(content);
|
|
12110
12110
|
if (inline) def = pluralizeOn ? pluralizeCollection(inline[1]) : inline[1];
|
|
@@ -12455,13 +12455,13 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
12455
12455
|
return out;
|
|
12456
12456
|
}
|
|
12457
12457
|
|
|
12458
|
-
// src/extract/calls/
|
|
12458
|
+
// src/extract/calls/socket.ts
|
|
12459
12459
|
init_cjs_shims();
|
|
12460
12460
|
var import_node_path47 = __toESM(require("path"), 1);
|
|
12461
12461
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
12462
12462
|
var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
|
|
12463
12463
|
var import_types36 = require("@neat.is/types");
|
|
12464
|
-
var
|
|
12464
|
+
var SOCKET_IMPORT_RE = /(?:^|\n)\s*(?:import\s+socket\b|from\s+socket\s+import\b)/;
|
|
12465
12465
|
var PARSE_CHUNK7 = 16384;
|
|
12466
12466
|
function makePyParser4() {
|
|
12467
12467
|
const p = new import_tree_sitter10.default();
|
|
@@ -12481,22 +12481,109 @@ function namedChildren3(node) {
|
|
|
12481
12481
|
}
|
|
12482
12482
|
return out;
|
|
12483
12483
|
}
|
|
12484
|
+
function walk4(node, visit) {
|
|
12485
|
+
visit(node);
|
|
12486
|
+
for (const c of namedChildren3(node)) walk4(c, visit);
|
|
12487
|
+
}
|
|
12484
12488
|
function pyStaticStringText3(node) {
|
|
12485
12489
|
if (node.type !== "string") return null;
|
|
12486
|
-
for (const
|
|
12490
|
+
for (const child of namedChildren3(node)) {
|
|
12491
|
+
if (child.type === "interpolation") return null;
|
|
12492
|
+
if (child.type === "string_content") return child.text;
|
|
12493
|
+
}
|
|
12494
|
+
return "";
|
|
12495
|
+
}
|
|
12496
|
+
function hasSocketConstructor(root) {
|
|
12497
|
+
let found = false;
|
|
12498
|
+
walk4(root, (n) => {
|
|
12499
|
+
if (found || n.type !== "call") return;
|
|
12500
|
+
const t = n.childForFieldName("function")?.text;
|
|
12501
|
+
if (t === "socket.socket" || t === "socket") found = true;
|
|
12502
|
+
});
|
|
12503
|
+
return found;
|
|
12504
|
+
}
|
|
12505
|
+
function socketEndpointsFromFile(file, serviceDir) {
|
|
12506
|
+
if (!SOCKET_IMPORT_RE.test(file.content)) return [];
|
|
12507
|
+
const tree = parseSource7(makePyParser4(), file.content);
|
|
12508
|
+
if (!hasSocketConstructor(tree.rootNode)) return [];
|
|
12509
|
+
const out = [];
|
|
12510
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12511
|
+
walk4(tree.rootNode, (node) => {
|
|
12512
|
+
if (node.type !== "call") return;
|
|
12513
|
+
const fn = node.childForFieldName("function");
|
|
12514
|
+
if (fn?.type !== "attribute" || fn.childForFieldName("attribute")?.text !== "connect") return;
|
|
12515
|
+
const args = node.childForFieldName("arguments");
|
|
12516
|
+
const first = args ? namedChildren3(args).find((a) => a.type !== "keyword_argument") : void 0;
|
|
12517
|
+
if (!first || first.type !== "tuple") return;
|
|
12518
|
+
const elems = namedChildren3(first);
|
|
12519
|
+
if (elems.length < 2) return;
|
|
12520
|
+
const hostNode = elems[0];
|
|
12521
|
+
const host = hostNode.type === "string" ? pyStaticStringText3(hostNode) : null;
|
|
12522
|
+
const portNode = elems[1];
|
|
12523
|
+
const port = portNode.type === "integer" ? portNode.text : null;
|
|
12524
|
+
const name = host ? port ? `${host}:${port}` : host : "env";
|
|
12525
|
+
if (seen.has(name)) return;
|
|
12526
|
+
seen.add(name);
|
|
12527
|
+
const line = node.startPosition.row + 1;
|
|
12528
|
+
out.push({
|
|
12529
|
+
infraId: (0, import_types36.infraId)("socket", name),
|
|
12530
|
+
name,
|
|
12531
|
+
kind: "socket",
|
|
12532
|
+
edgeType: "CALLS",
|
|
12533
|
+
// A verified `socket.socket(...)` + `.connect((host, port))` call site.
|
|
12534
|
+
confidenceKind: "verified-call-site",
|
|
12535
|
+
evidence: {
|
|
12536
|
+
file: import_node_path47.default.relative(serviceDir, file.path),
|
|
12537
|
+
line,
|
|
12538
|
+
snippet: snippet(file.content, line)
|
|
12539
|
+
}
|
|
12540
|
+
});
|
|
12541
|
+
});
|
|
12542
|
+
return out;
|
|
12543
|
+
}
|
|
12544
|
+
|
|
12545
|
+
// src/extract/calls/django-orm.ts
|
|
12546
|
+
init_cjs_shims();
|
|
12547
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
12548
|
+
var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
|
|
12549
|
+
var import_tree_sitter_python7 = __toESM(require("tree-sitter-python"), 1);
|
|
12550
|
+
var import_types37 = require("@neat.is/types");
|
|
12551
|
+
var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
|
|
12552
|
+
var PARSE_CHUNK8 = 16384;
|
|
12553
|
+
function makePyParser5() {
|
|
12554
|
+
const p = new import_tree_sitter11.default();
|
|
12555
|
+
p.setLanguage(import_tree_sitter_python7.default);
|
|
12556
|
+
return p;
|
|
12557
|
+
}
|
|
12558
|
+
function parseSource8(parser, source) {
|
|
12559
|
+
return parser.parse(
|
|
12560
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK8)
|
|
12561
|
+
);
|
|
12562
|
+
}
|
|
12563
|
+
function namedChildren4(node) {
|
|
12564
|
+
const out = [];
|
|
12565
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
12566
|
+
const c = node.namedChild(i);
|
|
12567
|
+
if (c) out.push(c);
|
|
12568
|
+
}
|
|
12569
|
+
return out;
|
|
12570
|
+
}
|
|
12571
|
+
function pyStaticStringText4(node) {
|
|
12572
|
+
if (node.type !== "string") return null;
|
|
12573
|
+
for (const c of namedChildren4(node)) {
|
|
12487
12574
|
if (c.type === "interpolation") return null;
|
|
12488
12575
|
if (c.type === "string_content") return c.text;
|
|
12489
12576
|
}
|
|
12490
12577
|
return "";
|
|
12491
12578
|
}
|
|
12492
|
-
function
|
|
12579
|
+
function walk5(node, visit) {
|
|
12493
12580
|
visit(node);
|
|
12494
|
-
for (const c of
|
|
12581
|
+
for (const c of namedChildren4(node)) walk5(c, visit);
|
|
12495
12582
|
}
|
|
12496
12583
|
function extendsDjangoModel(cls) {
|
|
12497
12584
|
const supers = cls.childForFieldName("superclasses");
|
|
12498
12585
|
if (!supers) return false;
|
|
12499
|
-
for (const a of
|
|
12586
|
+
for (const a of namedChildren4(supers)) {
|
|
12500
12587
|
const t = a.text;
|
|
12501
12588
|
if (t === "models.Model" || t === "Model" || t.endsWith(".Model")) return true;
|
|
12502
12589
|
}
|
|
@@ -12504,31 +12591,31 @@ function extendsDjangoModel(cls) {
|
|
|
12504
12591
|
}
|
|
12505
12592
|
function readMeta(body) {
|
|
12506
12593
|
const out = {};
|
|
12507
|
-
for (const stmt of
|
|
12594
|
+
for (const stmt of namedChildren4(body)) {
|
|
12508
12595
|
if (stmt.type !== "class_definition") continue;
|
|
12509
12596
|
if (stmt.childForFieldName("name")?.text !== "Meta") continue;
|
|
12510
12597
|
const metaBody = stmt.childForFieldName("body");
|
|
12511
12598
|
if (!metaBody) continue;
|
|
12512
|
-
for (const ms of
|
|
12599
|
+
for (const ms of namedChildren4(metaBody)) {
|
|
12513
12600
|
if (ms.type !== "expression_statement") continue;
|
|
12514
12601
|
const a = ms.namedChild(0);
|
|
12515
12602
|
if (a?.type !== "assignment") continue;
|
|
12516
12603
|
const l = a.childForFieldName("left")?.text;
|
|
12517
12604
|
const r = a.childForFieldName("right");
|
|
12518
12605
|
if (r?.type !== "string") continue;
|
|
12519
|
-
if (l === "db_table") out.dbTable =
|
|
12520
|
-
if (l === "app_label") out.appLabel =
|
|
12606
|
+
if (l === "db_table") out.dbTable = pyStaticStringText4(r) ?? void 0;
|
|
12607
|
+
if (l === "app_label") out.appLabel = pyStaticStringText4(r) ?? void 0;
|
|
12521
12608
|
}
|
|
12522
12609
|
}
|
|
12523
12610
|
return out;
|
|
12524
12611
|
}
|
|
12525
12612
|
function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
12526
12613
|
if (!DJANGO_IMPORT_RE.test(file.content)) return [];
|
|
12527
|
-
const tree =
|
|
12614
|
+
const tree = parseSource8(makePyParser5(), file.content);
|
|
12528
12615
|
const out = [];
|
|
12529
12616
|
const seen = /* @__PURE__ */ new Set();
|
|
12530
|
-
const defaultAppLabel =
|
|
12531
|
-
|
|
12617
|
+
const defaultAppLabel = import_node_path48.default.basename(import_node_path48.default.dirname(file.path));
|
|
12618
|
+
walk5(tree.rootNode, (node) => {
|
|
12532
12619
|
if (node.type !== "class_definition") return;
|
|
12533
12620
|
if (!extendsDjangoModel(node)) return;
|
|
12534
12621
|
const nameNode = node.childForFieldName("name");
|
|
@@ -12540,12 +12627,12 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12540
12627
|
seen.add(table);
|
|
12541
12628
|
const line = node.startPosition.row + 1;
|
|
12542
12629
|
out.push({
|
|
12543
|
-
infraId: (0,
|
|
12630
|
+
infraId: (0, import_types37.infraId)("sql-table", table),
|
|
12544
12631
|
name: table,
|
|
12545
12632
|
kind: "sql-table",
|
|
12546
12633
|
edgeType: "CALLS",
|
|
12547
12634
|
confidenceKind: "verified-call-site",
|
|
12548
|
-
evidence: { file:
|
|
12635
|
+
evidence: { file: import_node_path48.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
12549
12636
|
});
|
|
12550
12637
|
});
|
|
12551
12638
|
return out;
|
|
@@ -12553,18 +12640,18 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12553
12640
|
|
|
12554
12641
|
// src/extract/calls/drizzle.ts
|
|
12555
12642
|
init_cjs_shims();
|
|
12556
|
-
var
|
|
12557
|
-
var
|
|
12643
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
12644
|
+
var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
|
|
12558
12645
|
var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12559
|
-
var
|
|
12646
|
+
var import_types38 = require("@neat.is/types");
|
|
12560
12647
|
var DRIZZLE_IMPORT_RE = /drizzle-orm/;
|
|
12561
12648
|
var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
|
|
12562
12649
|
function parserForExt3(ext) {
|
|
12563
|
-
const p = new
|
|
12650
|
+
const p = new import_tree_sitter12.default();
|
|
12564
12651
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript7.default);
|
|
12565
12652
|
return p;
|
|
12566
12653
|
}
|
|
12567
|
-
function
|
|
12654
|
+
function namedChildren5(node) {
|
|
12568
12655
|
const out = [];
|
|
12569
12656
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
12570
12657
|
const c = node.namedChild(i);
|
|
@@ -12574,7 +12661,7 @@ function namedChildren4(node) {
|
|
|
12574
12661
|
}
|
|
12575
12662
|
function stringLiteralText4(node) {
|
|
12576
12663
|
if (!node || node.type !== "string") return null;
|
|
12577
|
-
for (const child of
|
|
12664
|
+
for (const child of namedChildren5(node)) {
|
|
12578
12665
|
if (child.type === "string_fragment") return child.text;
|
|
12579
12666
|
}
|
|
12580
12667
|
return "";
|
|
@@ -12582,7 +12669,7 @@ function stringLiteralText4(node) {
|
|
|
12582
12669
|
function firstStringArg(call) {
|
|
12583
12670
|
const args = call.childForFieldName("arguments");
|
|
12584
12671
|
if (!args) return null;
|
|
12585
|
-
for (const arg of
|
|
12672
|
+
for (const arg of namedChildren5(args)) {
|
|
12586
12673
|
if (arg.type === "string") return stringLiteralText4(arg);
|
|
12587
12674
|
return null;
|
|
12588
12675
|
}
|
|
@@ -12617,7 +12704,7 @@ function keyName2(key) {
|
|
|
12617
12704
|
function columnsFromObject(obj) {
|
|
12618
12705
|
const out = [];
|
|
12619
12706
|
const seen = /* @__PURE__ */ new Set();
|
|
12620
|
-
for (const child of
|
|
12707
|
+
for (const child of namedChildren5(obj)) {
|
|
12621
12708
|
if (child.type !== "pair") continue;
|
|
12622
12709
|
const value = child.childForFieldName("value");
|
|
12623
12710
|
const key = keyName2(child.childForFieldName("key"));
|
|
@@ -12631,15 +12718,15 @@ function columnsFromObject(obj) {
|
|
|
12631
12718
|
}
|
|
12632
12719
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
12633
12720
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12634
|
-
const tree = parseSource3(parserForExt3(
|
|
12721
|
+
const tree = parseSource3(parserForExt3(import_node_path49.default.extname(file.path)), file.content);
|
|
12635
12722
|
const out = [];
|
|
12636
12723
|
const seen = /* @__PURE__ */ new Set();
|
|
12637
|
-
const
|
|
12724
|
+
const walk11 = (node) => {
|
|
12638
12725
|
if (node.type === "call_expression") {
|
|
12639
12726
|
const fn = node.childForFieldName("function");
|
|
12640
12727
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
12641
12728
|
const args = node.childForFieldName("arguments");
|
|
12642
|
-
const argNodes = args ?
|
|
12729
|
+
const argNodes = args ? namedChildren5(args) : [];
|
|
12643
12730
|
const tableName = stringLiteralText4(argNodes[0] ?? null);
|
|
12644
12731
|
const obj = argNodes[1];
|
|
12645
12732
|
if (tableName && obj?.type === "object" && !seen.has(tableName)) {
|
|
@@ -12647,14 +12734,14 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12647
12734
|
const columns = columnsFromObject(obj);
|
|
12648
12735
|
const line = node.startPosition.row + 1;
|
|
12649
12736
|
out.push({
|
|
12650
|
-
infraId: (0,
|
|
12737
|
+
infraId: (0, import_types38.infraId)("sql-table", tableName),
|
|
12651
12738
|
name: tableName,
|
|
12652
12739
|
kind: "sql-table",
|
|
12653
12740
|
edgeType: "CALLS",
|
|
12654
12741
|
confidenceKind: "structural",
|
|
12655
12742
|
columns,
|
|
12656
12743
|
evidence: {
|
|
12657
|
-
file:
|
|
12744
|
+
file: import_node_path49.default.relative(serviceDir, file.path),
|
|
12658
12745
|
line,
|
|
12659
12746
|
snippet: snippet(file.content, line)
|
|
12660
12747
|
}
|
|
@@ -12662,9 +12749,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12662
12749
|
}
|
|
12663
12750
|
}
|
|
12664
12751
|
}
|
|
12665
|
-
for (const c of
|
|
12752
|
+
for (const c of namedChildren5(node)) walk11(c);
|
|
12666
12753
|
};
|
|
12667
|
-
|
|
12754
|
+
walk11(tree.rootNode);
|
|
12668
12755
|
return out;
|
|
12669
12756
|
}
|
|
12670
12757
|
function enclosingVarName(call) {
|
|
@@ -12686,12 +12773,12 @@ function enclosingVarName(call) {
|
|
|
12686
12773
|
function collectDrizzleTables(root) {
|
|
12687
12774
|
const tables = [];
|
|
12688
12775
|
const varToTable = /* @__PURE__ */ new Map();
|
|
12689
|
-
const
|
|
12776
|
+
const walk11 = (node) => {
|
|
12690
12777
|
if (node.type === "call_expression") {
|
|
12691
12778
|
const fn = node.childForFieldName("function");
|
|
12692
12779
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
12693
12780
|
const args = node.childForFieldName("arguments");
|
|
12694
|
-
const argNodes = args ?
|
|
12781
|
+
const argNodes = args ? namedChildren5(args) : [];
|
|
12695
12782
|
const tableName = stringLiteralText4(argNodes[0] ?? null);
|
|
12696
12783
|
const obj = argNodes[1]?.type === "object" ? argNodes[1] : null;
|
|
12697
12784
|
if (tableName) {
|
|
@@ -12701,9 +12788,9 @@ function collectDrizzleTables(root) {
|
|
|
12701
12788
|
}
|
|
12702
12789
|
}
|
|
12703
12790
|
}
|
|
12704
|
-
for (const c of
|
|
12791
|
+
for (const c of namedChildren5(node)) walk11(c);
|
|
12705
12792
|
};
|
|
12706
|
-
|
|
12793
|
+
walk11(root);
|
|
12707
12794
|
return { tables, varToTable };
|
|
12708
12795
|
}
|
|
12709
12796
|
function referencesTargetVar(call) {
|
|
@@ -12711,7 +12798,7 @@ function referencesTargetVar(call) {
|
|
|
12711
12798
|
if (fn?.type !== "member_expression") return null;
|
|
12712
12799
|
if (fn.childForFieldName("property")?.text !== "references") return null;
|
|
12713
12800
|
const args = call.childForFieldName("arguments");
|
|
12714
|
-
const first = args ?
|
|
12801
|
+
const first = args ? namedChildren5(args)[0] ?? null : null;
|
|
12715
12802
|
if (first?.type !== "arrow_function") return null;
|
|
12716
12803
|
const body = first.childForFieldName("body");
|
|
12717
12804
|
if (body?.type !== "member_expression") return null;
|
|
@@ -12720,13 +12807,13 @@ function referencesTargetVar(call) {
|
|
|
12720
12807
|
}
|
|
12721
12808
|
function drizzleForeignKeys(file, serviceDir) {
|
|
12722
12809
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12723
|
-
const tree = parseSource3(parserForExt3(
|
|
12810
|
+
const tree = parseSource3(parserForExt3(import_node_path49.default.extname(file.path)), file.content);
|
|
12724
12811
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
12725
12812
|
const out = [];
|
|
12726
12813
|
const seen = /* @__PURE__ */ new Set();
|
|
12727
12814
|
for (const table of tables) {
|
|
12728
12815
|
if (!table.object) continue;
|
|
12729
|
-
const
|
|
12816
|
+
const walk11 = (node) => {
|
|
12730
12817
|
if (node.type === "call_expression") {
|
|
12731
12818
|
const targetVar = referencesTargetVar(node);
|
|
12732
12819
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -12739,7 +12826,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12739
12826
|
childTable: table.tableName,
|
|
12740
12827
|
parentTable,
|
|
12741
12828
|
evidence: {
|
|
12742
|
-
file:
|
|
12829
|
+
file: import_node_path49.default.relative(serviceDir, file.path),
|
|
12743
12830
|
line,
|
|
12744
12831
|
snippet: snippet(file.content, line)
|
|
12745
12832
|
}
|
|
@@ -12747,17 +12834,17 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12747
12834
|
}
|
|
12748
12835
|
}
|
|
12749
12836
|
}
|
|
12750
|
-
for (const c of
|
|
12837
|
+
for (const c of namedChildren5(node)) walk11(c);
|
|
12751
12838
|
};
|
|
12752
|
-
|
|
12839
|
+
walk11(table.object);
|
|
12753
12840
|
}
|
|
12754
12841
|
return out;
|
|
12755
12842
|
}
|
|
12756
12843
|
|
|
12757
12844
|
// src/extract/calls/prisma.ts
|
|
12758
12845
|
init_cjs_shims();
|
|
12759
|
-
var
|
|
12760
|
-
var
|
|
12846
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
12847
|
+
var import_types39 = require("@neat.is/types");
|
|
12761
12848
|
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
12762
12849
|
"Int",
|
|
12763
12850
|
"String",
|
|
@@ -12805,14 +12892,14 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12805
12892
|
if (seenTable.has(b.tableName)) return;
|
|
12806
12893
|
seenTable.add(b.tableName);
|
|
12807
12894
|
out.push({
|
|
12808
|
-
infraId: (0,
|
|
12895
|
+
infraId: (0, import_types39.infraId)("sql-table", b.tableName),
|
|
12809
12896
|
name: b.tableName,
|
|
12810
12897
|
kind: "sql-table",
|
|
12811
12898
|
edgeType: "CALLS",
|
|
12812
12899
|
confidenceKind: "structural",
|
|
12813
12900
|
columns: b.columns,
|
|
12814
12901
|
evidence: {
|
|
12815
|
-
file:
|
|
12902
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12816
12903
|
line: b.startLine,
|
|
12817
12904
|
snippet: snippet(content, b.startLine)
|
|
12818
12905
|
}
|
|
@@ -12873,7 +12960,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12873
12960
|
}
|
|
12874
12961
|
async function prismaColumnEndpoints(serviceDir) {
|
|
12875
12962
|
const schemaPath = await findFirst(serviceDir, [
|
|
12876
|
-
|
|
12963
|
+
import_node_path50.default.join("prisma", "schema.prisma"),
|
|
12877
12964
|
"schema.prisma"
|
|
12878
12965
|
]);
|
|
12879
12966
|
if (!schemaPath) return [];
|
|
@@ -12948,7 +13035,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12948
13035
|
childTable: current.table,
|
|
12949
13036
|
parentTable,
|
|
12950
13037
|
evidence: {
|
|
12951
|
-
file:
|
|
13038
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12952
13039
|
line: lineNo,
|
|
12953
13040
|
snippet: snippet(content, lineNo)
|
|
12954
13041
|
}
|
|
@@ -12963,7 +13050,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12963
13050
|
}
|
|
12964
13051
|
async function prismaForeignKeys(serviceDir) {
|
|
12965
13052
|
const schemaPath = await findFirst(serviceDir, [
|
|
12966
|
-
|
|
13053
|
+
import_node_path50.default.join("prisma", "schema.prisma"),
|
|
12967
13054
|
"schema.prisma"
|
|
12968
13055
|
]);
|
|
12969
13056
|
if (!schemaPath) return [];
|
|
@@ -12974,27 +13061,27 @@ async function prismaForeignKeys(serviceDir) {
|
|
|
12974
13061
|
|
|
12975
13062
|
// src/extract/calls/activerecord.ts
|
|
12976
13063
|
init_cjs_shims();
|
|
12977
|
-
var
|
|
12978
|
-
var
|
|
13064
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
13065
|
+
var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
|
|
12979
13066
|
var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
|
|
12980
|
-
var
|
|
13067
|
+
var import_types40 = require("@neat.is/types");
|
|
12981
13068
|
var AR_SCHEMA_RE = /ActiveRecord::Schema/;
|
|
12982
|
-
var
|
|
13069
|
+
var PARSE_CHUNK9 = 16384;
|
|
12983
13070
|
function makeRubyParser2() {
|
|
12984
|
-
const p = new
|
|
13071
|
+
const p = new import_tree_sitter13.default();
|
|
12985
13072
|
p.setLanguage(import_tree_sitter_ruby3.default);
|
|
12986
13073
|
return p;
|
|
12987
13074
|
}
|
|
12988
|
-
function
|
|
13075
|
+
function parseSource9(parser, source) {
|
|
12989
13076
|
return parser.parse(
|
|
12990
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
13077
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK9)
|
|
12991
13078
|
);
|
|
12992
13079
|
}
|
|
12993
|
-
function
|
|
13080
|
+
function walk6(node, visit) {
|
|
12994
13081
|
visit(node);
|
|
12995
13082
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
12996
13083
|
const c = node.namedChild(i);
|
|
12997
|
-
if (c)
|
|
13084
|
+
if (c) walk6(c, visit);
|
|
12998
13085
|
}
|
|
12999
13086
|
}
|
|
13000
13087
|
function rubyLiteral2(node) {
|
|
@@ -13165,24 +13252,24 @@ function readCreateTable(call) {
|
|
|
13165
13252
|
}
|
|
13166
13253
|
function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
13167
13254
|
if (!AR_SCHEMA_RE.test(file.content)) return [];
|
|
13168
|
-
const tree =
|
|
13255
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
13169
13256
|
const out = [];
|
|
13170
13257
|
const seen = /* @__PURE__ */ new Set();
|
|
13171
|
-
|
|
13258
|
+
walk6(tree.rootNode, (node) => {
|
|
13172
13259
|
if (node.type !== "call") return;
|
|
13173
13260
|
if (blockCallMethod(node) !== "create_table") return;
|
|
13174
13261
|
const table = readCreateTable(node);
|
|
13175
13262
|
if (!table || seen.has(table.name)) return;
|
|
13176
13263
|
seen.add(table.name);
|
|
13177
13264
|
out.push({
|
|
13178
|
-
infraId: (0,
|
|
13265
|
+
infraId: (0, import_types40.infraId)("sql-table", table.name),
|
|
13179
13266
|
name: table.name,
|
|
13180
13267
|
kind: "sql-table",
|
|
13181
13268
|
edgeType: "CALLS",
|
|
13182
13269
|
confidenceKind: "structural",
|
|
13183
13270
|
...table.columns.length > 0 ? { columns: table.columns } : {},
|
|
13184
13271
|
evidence: {
|
|
13185
|
-
file:
|
|
13272
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
13186
13273
|
line: table.line,
|
|
13187
13274
|
snippet: snippet(file.content, table.line)
|
|
13188
13275
|
}
|
|
@@ -13192,7 +13279,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
|
13192
13279
|
}
|
|
13193
13280
|
function railsSchemaForeignKeys(file, serviceDir) {
|
|
13194
13281
|
if (!AR_SCHEMA_RE.test(file.content)) return [];
|
|
13195
|
-
const tree =
|
|
13282
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
13196
13283
|
const out = [];
|
|
13197
13284
|
const seen = /* @__PURE__ */ new Set();
|
|
13198
13285
|
const emit = (childTable, parentTable, line) => {
|
|
@@ -13204,13 +13291,13 @@ function railsSchemaForeignKeys(file, serviceDir) {
|
|
|
13204
13291
|
childTable,
|
|
13205
13292
|
parentTable,
|
|
13206
13293
|
evidence: {
|
|
13207
|
-
file:
|
|
13294
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
13208
13295
|
line,
|
|
13209
13296
|
snippet: snippet(file.content, line)
|
|
13210
13297
|
}
|
|
13211
13298
|
});
|
|
13212
13299
|
};
|
|
13213
|
-
|
|
13300
|
+
walk6(tree.rootNode, (node) => {
|
|
13214
13301
|
if (node.type !== "call") return;
|
|
13215
13302
|
const method = blockCallMethod(node);
|
|
13216
13303
|
if (method === "add_foreign_key") {
|
|
@@ -13271,23 +13358,23 @@ function modelTable(cls) {
|
|
|
13271
13358
|
return tableize(nameNode.text);
|
|
13272
13359
|
}
|
|
13273
13360
|
function railsModelEndpointsFromFile(file, serviceDir) {
|
|
13274
|
-
const tree =
|
|
13361
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
13275
13362
|
const out = [];
|
|
13276
13363
|
const seen = /* @__PURE__ */ new Set();
|
|
13277
|
-
|
|
13364
|
+
walk6(tree.rootNode, (node) => {
|
|
13278
13365
|
if (node.type !== "class" || !isActiveRecordModel(node)) return;
|
|
13279
13366
|
const table = modelTable(node);
|
|
13280
13367
|
if (!table || seen.has(table)) return;
|
|
13281
13368
|
seen.add(table);
|
|
13282
13369
|
const line = node.startPosition.row + 1;
|
|
13283
13370
|
out.push({
|
|
13284
|
-
infraId: (0,
|
|
13371
|
+
infraId: (0, import_types40.infraId)("sql-table", table),
|
|
13285
13372
|
name: table,
|
|
13286
13373
|
kind: "sql-table",
|
|
13287
13374
|
edgeType: "CALLS",
|
|
13288
13375
|
confidenceKind: "verified-call-site",
|
|
13289
13376
|
evidence: {
|
|
13290
|
-
file:
|
|
13377
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
13291
13378
|
line,
|
|
13292
13379
|
snippet: snippet(file.content, line)
|
|
13293
13380
|
}
|
|
@@ -13297,10 +13384,10 @@ function railsModelEndpointsFromFile(file, serviceDir) {
|
|
|
13297
13384
|
}
|
|
13298
13385
|
var AR_ASSOCIATIONS = /* @__PURE__ */ new Set(["belongs_to", "has_many", "has_one"]);
|
|
13299
13386
|
function railsModelForeignKeys(file, serviceDir) {
|
|
13300
|
-
const tree =
|
|
13387
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
13301
13388
|
const out = [];
|
|
13302
13389
|
const seen = /* @__PURE__ */ new Set();
|
|
13303
|
-
|
|
13390
|
+
walk6(tree.rootNode, (node) => {
|
|
13304
13391
|
if (node.type !== "class" || !isActiveRecordModel(node)) return;
|
|
13305
13392
|
const thisTable = modelTable(node);
|
|
13306
13393
|
if (!thisTable) return;
|
|
@@ -13324,7 +13411,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
13324
13411
|
childTable,
|
|
13325
13412
|
parentTable,
|
|
13326
13413
|
evidence: {
|
|
13327
|
-
file:
|
|
13414
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
13328
13415
|
line,
|
|
13329
13416
|
snippet: snippet(file.content, line)
|
|
13330
13417
|
}
|
|
@@ -13336,27 +13423,27 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
13336
13423
|
|
|
13337
13424
|
// src/extract/calls/eloquent.ts
|
|
13338
13425
|
init_cjs_shims();
|
|
13339
|
-
var
|
|
13340
|
-
var
|
|
13426
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
13427
|
+
var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
|
|
13341
13428
|
var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
|
|
13342
|
-
var
|
|
13429
|
+
var import_types41 = require("@neat.is/types");
|
|
13343
13430
|
var LARAVEL_SCHEMA_RE = /\bSchema::(create|createIfNotExists|table)\b/;
|
|
13344
|
-
var
|
|
13431
|
+
var PARSE_CHUNK10 = 16384;
|
|
13345
13432
|
function makePhpParser2() {
|
|
13346
|
-
const p = new
|
|
13433
|
+
const p = new import_tree_sitter14.default();
|
|
13347
13434
|
p.setLanguage(import_tree_sitter_php3.default.php_only);
|
|
13348
13435
|
return p;
|
|
13349
13436
|
}
|
|
13350
|
-
function
|
|
13437
|
+
function parseSource10(parser, source) {
|
|
13351
13438
|
return parser.parse(
|
|
13352
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
13439
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK10)
|
|
13353
13440
|
);
|
|
13354
13441
|
}
|
|
13355
|
-
function
|
|
13442
|
+
function walk7(node, visit) {
|
|
13356
13443
|
visit(node);
|
|
13357
13444
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13358
13445
|
const c = node.namedChild(i);
|
|
13359
|
-
if (c)
|
|
13446
|
+
if (c) walk7(c, visit);
|
|
13360
13447
|
}
|
|
13361
13448
|
}
|
|
13362
13449
|
function phpStaticString2(node) {
|
|
@@ -13567,9 +13654,9 @@ function columnsFromCall(chain, blueprintVar) {
|
|
|
13567
13654
|
}
|
|
13568
13655
|
function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
13569
13656
|
if (!LARAVEL_SCHEMA_RE.test(file.content)) return [];
|
|
13570
|
-
const tree =
|
|
13657
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
13571
13658
|
const out = [];
|
|
13572
|
-
|
|
13659
|
+
walk7(tree.rootNode, (node) => {
|
|
13573
13660
|
if (!isSchemaCall(node)) return;
|
|
13574
13661
|
const bp = readBlueprint(node);
|
|
13575
13662
|
if (!bp) return;
|
|
@@ -13586,14 +13673,14 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
13586
13673
|
}
|
|
13587
13674
|
}
|
|
13588
13675
|
out.push({
|
|
13589
|
-
infraId: (0,
|
|
13676
|
+
infraId: (0, import_types41.infraId)("sql-table", bp.table),
|
|
13590
13677
|
name: bp.table,
|
|
13591
13678
|
kind: "sql-table",
|
|
13592
13679
|
edgeType: "CALLS",
|
|
13593
13680
|
confidenceKind: "structural",
|
|
13594
13681
|
...columns.length > 0 ? { columns } : {},
|
|
13595
13682
|
evidence: {
|
|
13596
|
-
file:
|
|
13683
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
13597
13684
|
line: bp.line,
|
|
13598
13685
|
snippet: snippet(file.content, bp.line)
|
|
13599
13686
|
}
|
|
@@ -13603,7 +13690,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
13603
13690
|
}
|
|
13604
13691
|
function laravelMigrationForeignKeys(file, serviceDir) {
|
|
13605
13692
|
if (!LARAVEL_SCHEMA_RE.test(file.content)) return [];
|
|
13606
|
-
const tree =
|
|
13693
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
13607
13694
|
const out = [];
|
|
13608
13695
|
const seen = /* @__PURE__ */ new Set();
|
|
13609
13696
|
const emit = (childTable, parentTable, line) => {
|
|
@@ -13615,13 +13702,13 @@ function laravelMigrationForeignKeys(file, serviceDir) {
|
|
|
13615
13702
|
childTable,
|
|
13616
13703
|
parentTable,
|
|
13617
13704
|
evidence: {
|
|
13618
|
-
file:
|
|
13705
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
13619
13706
|
line,
|
|
13620
13707
|
snippet: snippet(file.content, line)
|
|
13621
13708
|
}
|
|
13622
13709
|
});
|
|
13623
13710
|
};
|
|
13624
|
-
|
|
13711
|
+
walk7(tree.rootNode, (node) => {
|
|
13625
13712
|
if (!isSchemaCall(node)) return;
|
|
13626
13713
|
const bp = readBlueprint(node);
|
|
13627
13714
|
if (!bp || !bp.closureBody) return;
|
|
@@ -13719,23 +13806,23 @@ function walkWithinClass(cls, visit) {
|
|
|
13719
13806
|
recur(body);
|
|
13720
13807
|
}
|
|
13721
13808
|
function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
13722
|
-
const tree =
|
|
13809
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
13723
13810
|
const out = [];
|
|
13724
13811
|
const seen = /* @__PURE__ */ new Set();
|
|
13725
|
-
|
|
13812
|
+
walk7(tree.rootNode, (node) => {
|
|
13726
13813
|
if (node.type !== "class_declaration" || !isEloquentModel(node)) return;
|
|
13727
13814
|
const table = modelTable2(node);
|
|
13728
13815
|
if (!table || seen.has(table)) return;
|
|
13729
13816
|
seen.add(table);
|
|
13730
13817
|
const line = node.startPosition.row + 1;
|
|
13731
13818
|
out.push({
|
|
13732
|
-
infraId: (0,
|
|
13819
|
+
infraId: (0, import_types41.infraId)("sql-table", table),
|
|
13733
13820
|
name: table,
|
|
13734
13821
|
kind: "sql-table",
|
|
13735
13822
|
edgeType: "CALLS",
|
|
13736
13823
|
confidenceKind: "verified-call-site",
|
|
13737
13824
|
evidence: {
|
|
13738
|
-
file:
|
|
13825
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
13739
13826
|
line,
|
|
13740
13827
|
snippet: snippet(file.content, line)
|
|
13741
13828
|
}
|
|
@@ -13745,10 +13832,10 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
|
13745
13832
|
}
|
|
13746
13833
|
var ELOQUENT_RELATIONS = /* @__PURE__ */ new Set(["belongsTo", "hasMany", "hasOne"]);
|
|
13747
13834
|
function laravelModelForeignKeys(file, serviceDir) {
|
|
13748
|
-
const tree =
|
|
13835
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
13749
13836
|
const out = [];
|
|
13750
13837
|
const seen = /* @__PURE__ */ new Set();
|
|
13751
|
-
|
|
13838
|
+
walk7(tree.rootNode, (node) => {
|
|
13752
13839
|
if (node.type !== "class_declaration" || !isEloquentModel(node)) return;
|
|
13753
13840
|
const thisTable = modelTable2(node);
|
|
13754
13841
|
if (!thisTable) return;
|
|
@@ -13771,7 +13858,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13771
13858
|
childTable,
|
|
13772
13859
|
parentTable,
|
|
13773
13860
|
evidence: {
|
|
13774
|
-
file:
|
|
13861
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
13775
13862
|
line,
|
|
13776
13863
|
snippet: snippet(file.content, line)
|
|
13777
13864
|
}
|
|
@@ -13783,12 +13870,12 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13783
13870
|
|
|
13784
13871
|
// src/extract/calls/go.ts
|
|
13785
13872
|
init_cjs_shims();
|
|
13786
|
-
var
|
|
13787
|
-
var
|
|
13873
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
13874
|
+
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
13788
13875
|
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
13789
|
-
var
|
|
13876
|
+
var import_types42 = require("@neat.is/types");
|
|
13790
13877
|
init_otel();
|
|
13791
|
-
var
|
|
13878
|
+
var PARSE_CHUNK11 = 16384;
|
|
13792
13879
|
var DATABASE_SQL_METHODS = /* @__PURE__ */ new Set([
|
|
13793
13880
|
"Query",
|
|
13794
13881
|
"QueryContext",
|
|
@@ -13814,20 +13901,20 @@ var SQLX_METHODS = /* @__PURE__ */ new Set([
|
|
|
13814
13901
|
var DATABASE_SQL_IMPORT = "database/sql";
|
|
13815
13902
|
var SQLX_IMPORT = "github.com/jmoiron/sqlx";
|
|
13816
13903
|
function makeGoParser3() {
|
|
13817
|
-
const p = new
|
|
13904
|
+
const p = new import_tree_sitter15.default();
|
|
13818
13905
|
p.setLanguage(import_tree_sitter_go4.default);
|
|
13819
13906
|
return p;
|
|
13820
13907
|
}
|
|
13821
|
-
function
|
|
13908
|
+
function parseSource11(parser, source) {
|
|
13822
13909
|
return parser.parse(
|
|
13823
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
13910
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
13824
13911
|
);
|
|
13825
13912
|
}
|
|
13826
|
-
function
|
|
13913
|
+
function walk8(node, visit) {
|
|
13827
13914
|
visit(node);
|
|
13828
13915
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13829
13916
|
const child = node.namedChild(i);
|
|
13830
|
-
if (child)
|
|
13917
|
+
if (child) walk8(child, visit);
|
|
13831
13918
|
}
|
|
13832
13919
|
}
|
|
13833
13920
|
function goStringLiteralValue(node) {
|
|
@@ -13840,7 +13927,7 @@ function goStringLiteralValue(node) {
|
|
|
13840
13927
|
}
|
|
13841
13928
|
function goImportsAny(root, names) {
|
|
13842
13929
|
let found = false;
|
|
13843
|
-
|
|
13930
|
+
walk8(root, (node) => {
|
|
13844
13931
|
if (found || node.type !== "import_spec") return;
|
|
13845
13932
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13846
13933
|
const value = goStringLiteralValue(node.namedChild(i));
|
|
@@ -13858,14 +13945,14 @@ function firstStringLiteralArg(argsNode) {
|
|
|
13858
13945
|
return null;
|
|
13859
13946
|
}
|
|
13860
13947
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
13861
|
-
if (
|
|
13948
|
+
if (import_node_path55.default.extname(file.path) !== ".go") return [];
|
|
13862
13949
|
if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
|
|
13863
|
-
const tree =
|
|
13950
|
+
const tree = parseSource11(makeGoParser3(), file.content);
|
|
13864
13951
|
const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
|
|
13865
13952
|
const importsSqlx = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([SQLX_IMPORT]));
|
|
13866
13953
|
if (!importsDatabaseSql && !importsSqlx) return [];
|
|
13867
13954
|
const out = [];
|
|
13868
|
-
|
|
13955
|
+
walk8(tree.rootNode, (node) => {
|
|
13869
13956
|
if (node.type !== "call_expression") return;
|
|
13870
13957
|
const fn = node.childForFieldName("function");
|
|
13871
13958
|
if (fn?.type !== "selector_expression") return;
|
|
@@ -13880,14 +13967,14 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13880
13967
|
const columns = columnsFromSqlStatement(sql);
|
|
13881
13968
|
const line = node.startPosition.row + 1;
|
|
13882
13969
|
out.push({
|
|
13883
|
-
infraId: (0,
|
|
13970
|
+
infraId: (0, import_types42.infraId)("sql-table", table),
|
|
13884
13971
|
name: table,
|
|
13885
13972
|
kind: "sql-table",
|
|
13886
13973
|
edgeType: "CALLS",
|
|
13887
13974
|
confidenceKind: "verified-call-site",
|
|
13888
13975
|
...columns.length > 0 ? { columns } : {},
|
|
13889
13976
|
evidence: {
|
|
13890
|
-
file: toPosix(
|
|
13977
|
+
file: toPosix(import_node_path55.default.relative(serviceDir, file.path)),
|
|
13891
13978
|
line,
|
|
13892
13979
|
snippet: snippet(file.content, line)
|
|
13893
13980
|
}
|
|
@@ -13898,27 +13985,27 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13898
13985
|
|
|
13899
13986
|
// src/extract/calls/gorm.ts
|
|
13900
13987
|
init_cjs_shims();
|
|
13901
|
-
var
|
|
13902
|
-
var
|
|
13988
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
13989
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
13903
13990
|
var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
|
|
13904
|
-
var
|
|
13991
|
+
var import_types43 = require("@neat.is/types");
|
|
13905
13992
|
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
13906
|
-
var
|
|
13993
|
+
var PARSE_CHUNK12 = 16384;
|
|
13907
13994
|
function makeGoParser4() {
|
|
13908
|
-
const p = new
|
|
13995
|
+
const p = new import_tree_sitter16.default();
|
|
13909
13996
|
p.setLanguage(import_tree_sitter_go5.default);
|
|
13910
13997
|
return p;
|
|
13911
13998
|
}
|
|
13912
|
-
function
|
|
13999
|
+
function parseSource12(parser, source) {
|
|
13913
14000
|
return parser.parse(
|
|
13914
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
14001
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK12)
|
|
13915
14002
|
);
|
|
13916
14003
|
}
|
|
13917
|
-
function
|
|
14004
|
+
function walk9(node, visit) {
|
|
13918
14005
|
visit(node);
|
|
13919
14006
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13920
14007
|
const c = node.namedChild(i);
|
|
13921
|
-
if (c)
|
|
14008
|
+
if (c) walk9(c, visit);
|
|
13922
14009
|
}
|
|
13923
14010
|
}
|
|
13924
14011
|
var COMMON_INITIALISMS = [
|
|
@@ -14151,7 +14238,7 @@ function readField(fieldDecl) {
|
|
|
14151
14238
|
}
|
|
14152
14239
|
function collectStructs(tree) {
|
|
14153
14240
|
const structs = /* @__PURE__ */ new Map();
|
|
14154
|
-
|
|
14241
|
+
walk9(tree.rootNode, (node) => {
|
|
14155
14242
|
if (node.type !== "type_spec") return;
|
|
14156
14243
|
const nameNode = node.childForFieldName("name");
|
|
14157
14244
|
const typeNode = node.childForFieldName("type");
|
|
@@ -14200,7 +14287,7 @@ function compositeStructName(arg) {
|
|
|
14200
14287
|
}
|
|
14201
14288
|
function collectCallModels(tree) {
|
|
14202
14289
|
const models = /* @__PURE__ */ new Set();
|
|
14203
|
-
|
|
14290
|
+
walk9(tree.rootNode, (node) => {
|
|
14204
14291
|
if (node.type !== "call_expression") return;
|
|
14205
14292
|
const fn = node.childForFieldName("function");
|
|
14206
14293
|
if (fn?.type !== "selector_expression") return;
|
|
@@ -14220,7 +14307,7 @@ function collectCallModels(tree) {
|
|
|
14220
14307
|
function collectTableNameOverrides(tree) {
|
|
14221
14308
|
const overrides = /* @__PURE__ */ new Map();
|
|
14222
14309
|
const declarers = /* @__PURE__ */ new Set();
|
|
14223
|
-
|
|
14310
|
+
walk9(tree.rootNode, (node) => {
|
|
14224
14311
|
if (node.type !== "method_declaration") return;
|
|
14225
14312
|
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
14226
14313
|
const receiver = node.childForFieldName("receiver");
|
|
@@ -14237,7 +14324,7 @@ function collectTableNameOverrides(tree) {
|
|
|
14237
14324
|
const body = node.childForFieldName("body");
|
|
14238
14325
|
if (!body) return;
|
|
14239
14326
|
let literal = null;
|
|
14240
|
-
|
|
14327
|
+
walk9(body, (n) => {
|
|
14241
14328
|
if (literal !== null) return;
|
|
14242
14329
|
if (n.type !== "return_statement") return;
|
|
14243
14330
|
const exprList = n.namedChild(0);
|
|
@@ -14331,9 +14418,9 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
|
14331
14418
|
seen.delete(struct.name);
|
|
14332
14419
|
}
|
|
14333
14420
|
function gormEndpointsFromFile(file, serviceDir) {
|
|
14334
|
-
if (
|
|
14421
|
+
if (import_node_path56.default.extname(file.path) !== ".go") return [];
|
|
14335
14422
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
14336
|
-
const tree =
|
|
14423
|
+
const tree = parseSource12(makeGoParser4(), file.content);
|
|
14337
14424
|
const { structs, models, tableFor } = analyze(tree);
|
|
14338
14425
|
const out = [];
|
|
14339
14426
|
const seenTables = /* @__PURE__ */ new Set();
|
|
@@ -14346,14 +14433,14 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
14346
14433
|
const columns = [];
|
|
14347
14434
|
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
14348
14435
|
out.push({
|
|
14349
|
-
infraId: (0,
|
|
14436
|
+
infraId: (0, import_types43.infraId)("sql-table", table),
|
|
14350
14437
|
name: table,
|
|
14351
14438
|
kind: "sql-table",
|
|
14352
14439
|
edgeType: "CALLS",
|
|
14353
14440
|
confidenceKind: "structural",
|
|
14354
14441
|
...columns.length > 0 ? { columns } : {},
|
|
14355
14442
|
evidence: {
|
|
14356
|
-
file: toPosix(
|
|
14443
|
+
file: toPosix(import_node_path56.default.relative(serviceDir, file.path)),
|
|
14357
14444
|
line: struct.line,
|
|
14358
14445
|
snippet: snippet(file.content, struct.line)
|
|
14359
14446
|
}
|
|
@@ -14362,9 +14449,9 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
14362
14449
|
return out;
|
|
14363
14450
|
}
|
|
14364
14451
|
function gormForeignKeys(file, serviceDir) {
|
|
14365
|
-
if (
|
|
14452
|
+
if (import_node_path56.default.extname(file.path) !== ".go") return [];
|
|
14366
14453
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
14367
|
-
const tree =
|
|
14454
|
+
const tree = parseSource12(makeGoParser4(), file.content);
|
|
14368
14455
|
const { structs, models, tableFor } = analyze(tree);
|
|
14369
14456
|
const out = [];
|
|
14370
14457
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -14377,7 +14464,7 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
14377
14464
|
childTable,
|
|
14378
14465
|
parentTable,
|
|
14379
14466
|
evidence: {
|
|
14380
|
-
file: toPosix(
|
|
14467
|
+
file: toPosix(import_node_path56.default.relative(serviceDir, file.path)),
|
|
14381
14468
|
line,
|
|
14382
14469
|
snippet: snippet(file.content, line)
|
|
14383
14470
|
}
|
|
@@ -14414,27 +14501,27 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
14414
14501
|
|
|
14415
14502
|
// src/extract/calls/efcore.ts
|
|
14416
14503
|
init_cjs_shims();
|
|
14417
|
-
var
|
|
14418
|
-
var
|
|
14504
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
14505
|
+
var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
|
|
14419
14506
|
var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
14420
|
-
var
|
|
14507
|
+
var import_types44 = require("@neat.is/types");
|
|
14421
14508
|
var EFCORE_GATE = /Microsoft\.EntityFrameworkCore|DataAnnotations\.Schema|\bDbContext\b|\bDbSet\s*</;
|
|
14422
|
-
var
|
|
14509
|
+
var PARSE_CHUNK13 = 16384;
|
|
14423
14510
|
function makeCsParser() {
|
|
14424
|
-
const p = new
|
|
14511
|
+
const p = new import_tree_sitter17.default();
|
|
14425
14512
|
p.setLanguage(import_tree_sitter_c_sharp2.default);
|
|
14426
14513
|
return p;
|
|
14427
14514
|
}
|
|
14428
|
-
function
|
|
14515
|
+
function parseSource13(parser, source) {
|
|
14429
14516
|
return parser.parse(
|
|
14430
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
14517
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK13)
|
|
14431
14518
|
);
|
|
14432
14519
|
}
|
|
14433
|
-
function
|
|
14520
|
+
function walk10(node, visit) {
|
|
14434
14521
|
visit(node);
|
|
14435
14522
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14436
14523
|
const c = node.namedChild(i);
|
|
14437
|
-
if (c)
|
|
14524
|
+
if (c) walk10(c, visit);
|
|
14438
14525
|
}
|
|
14439
14526
|
}
|
|
14440
14527
|
function firstChildOfType(node, type) {
|
|
@@ -14493,28 +14580,28 @@ function tableFromToTable(call) {
|
|
|
14493
14580
|
return value ? csStringLiteral(value) : null;
|
|
14494
14581
|
}
|
|
14495
14582
|
function efcoreEndpointsFromFile(file, serviceDir) {
|
|
14496
|
-
if (
|
|
14583
|
+
if (import_node_path57.default.extname(file.path) !== ".cs") return [];
|
|
14497
14584
|
if (!EFCORE_GATE.test(file.content)) return [];
|
|
14498
|
-
const tree =
|
|
14585
|
+
const tree = parseSource13(makeCsParser(), file.content);
|
|
14499
14586
|
const out = [];
|
|
14500
14587
|
const seen = /* @__PURE__ */ new Set();
|
|
14501
14588
|
const push = (name, line) => {
|
|
14502
14589
|
if (!name || seen.has(name)) return;
|
|
14503
14590
|
seen.add(name);
|
|
14504
14591
|
out.push({
|
|
14505
|
-
infraId: (0,
|
|
14592
|
+
infraId: (0, import_types44.infraId)("sql-table", name),
|
|
14506
14593
|
name,
|
|
14507
14594
|
kind: "sql-table",
|
|
14508
14595
|
edgeType: "CALLS",
|
|
14509
14596
|
confidenceKind: "structural",
|
|
14510
14597
|
evidence: {
|
|
14511
|
-
file: toPosix(
|
|
14598
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
14512
14599
|
line,
|
|
14513
14600
|
snippet: snippet(file.content, line)
|
|
14514
14601
|
}
|
|
14515
14602
|
});
|
|
14516
14603
|
};
|
|
14517
|
-
|
|
14604
|
+
walk10(tree.rootNode, (node) => {
|
|
14518
14605
|
if (node.type === "attribute") {
|
|
14519
14606
|
const table = tableFromAttribute(node);
|
|
14520
14607
|
if (table) push(table, node.startPosition.row + 1);
|
|
@@ -14532,11 +14619,11 @@ function efcoreEndpointsFromFile(file, serviceDir) {
|
|
|
14532
14619
|
function edgeTypeFromEndpoint(ep) {
|
|
14533
14620
|
switch (ep.edgeType) {
|
|
14534
14621
|
case "PUBLISHES_TO":
|
|
14535
|
-
return
|
|
14622
|
+
return import_types45.EdgeType.PUBLISHES_TO;
|
|
14536
14623
|
case "CONSUMES_FROM":
|
|
14537
|
-
return
|
|
14624
|
+
return import_types45.EdgeType.CONSUMES_FROM;
|
|
14538
14625
|
default:
|
|
14539
|
-
return
|
|
14626
|
+
return import_types45.EdgeType.CALLS;
|
|
14540
14627
|
}
|
|
14541
14628
|
}
|
|
14542
14629
|
function isAwsKind(kind) {
|
|
@@ -14591,6 +14678,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14591
14678
|
} catch (err) {
|
|
14592
14679
|
recordExtractionError("efcore data-axis extraction", file.path, err);
|
|
14593
14680
|
}
|
|
14681
|
+
try {
|
|
14682
|
+
endpoints.push(...socketEndpointsFromFile(file, service.dir));
|
|
14683
|
+
} catch (err) {
|
|
14684
|
+
recordExtractionError("python socket call extraction", file.path, err);
|
|
14685
|
+
}
|
|
14594
14686
|
}
|
|
14595
14687
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
14596
14688
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
@@ -14601,7 +14693,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14601
14693
|
if (!graph.hasNode(ep.infraId)) {
|
|
14602
14694
|
const node = {
|
|
14603
14695
|
id: ep.infraId,
|
|
14604
|
-
type:
|
|
14696
|
+
type: import_types45.NodeType.InfraNode,
|
|
14605
14697
|
name: ep.name,
|
|
14606
14698
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
14607
14699
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -14614,21 +14706,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14614
14706
|
}
|
|
14615
14707
|
if (ep.columns && ep.columns.length > 0) {
|
|
14616
14708
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14617
|
-
if (node.type ===
|
|
14709
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14618
14710
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14619
14711
|
...node,
|
|
14620
14712
|
columns: foldColumns(
|
|
14621
14713
|
node.columns,
|
|
14622
14714
|
ep.columns,
|
|
14623
|
-
|
|
14624
|
-
(0,
|
|
14715
|
+
import_types45.Provenance.EXTRACTED,
|
|
14716
|
+
(0, import_types45.confidenceForExtracted)(ep.confidenceKind)
|
|
14625
14717
|
)
|
|
14626
14718
|
});
|
|
14627
14719
|
}
|
|
14628
14720
|
}
|
|
14629
14721
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
14630
14722
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14631
|
-
if (node.type ===
|
|
14723
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14632
14724
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14633
14725
|
...node,
|
|
14634
14726
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -14636,7 +14728,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14636
14728
|
}
|
|
14637
14729
|
}
|
|
14638
14730
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
14639
|
-
const confidence = (0,
|
|
14731
|
+
const confidence = (0, import_types45.confidenceForExtracted)(ep.confidenceKind);
|
|
14640
14732
|
const relFile = toPosix(ep.evidence.file);
|
|
14641
14733
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
14642
14734
|
graph,
|
|
@@ -14646,7 +14738,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14646
14738
|
);
|
|
14647
14739
|
nodesAdded += n;
|
|
14648
14740
|
edgesAdded += e;
|
|
14649
|
-
if (!(0,
|
|
14741
|
+
if (!(0, import_types45.passesExtractedFloor)(confidence)) {
|
|
14650
14742
|
noteExtractedDropped({
|
|
14651
14743
|
source: fileNodeId,
|
|
14652
14744
|
target: ep.infraId,
|
|
@@ -14666,7 +14758,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14666
14758
|
source: fileNodeId,
|
|
14667
14759
|
target: ep.infraId,
|
|
14668
14760
|
type: edgeType,
|
|
14669
|
-
provenance:
|
|
14761
|
+
provenance: import_types45.Provenance.EXTRACTED,
|
|
14670
14762
|
confidence,
|
|
14671
14763
|
evidence: ep.evidence
|
|
14672
14764
|
};
|
|
@@ -14689,7 +14781,7 @@ async function addCallEdges(graph, services) {
|
|
|
14689
14781
|
|
|
14690
14782
|
// src/extract/table-edges.ts
|
|
14691
14783
|
init_cjs_shims();
|
|
14692
|
-
var
|
|
14784
|
+
var import_types46 = require("@neat.is/types");
|
|
14693
14785
|
async function addTableEdges(graph, services) {
|
|
14694
14786
|
let nodesAdded = 0;
|
|
14695
14787
|
let edgesAdded = 0;
|
|
@@ -14717,20 +14809,20 @@ async function addTableEdges(graph, services) {
|
|
|
14717
14809
|
}
|
|
14718
14810
|
refs.push(...modelRefs);
|
|
14719
14811
|
for (const ref of refs) {
|
|
14720
|
-
const childId = (0,
|
|
14721
|
-
const parentId = (0,
|
|
14812
|
+
const childId = (0, import_types46.infraId)("sql-table", ref.childTable);
|
|
14813
|
+
const parentId = (0, import_types46.infraId)("sql-table", ref.parentTable);
|
|
14722
14814
|
if (childId === parentId) continue;
|
|
14723
14815
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
14724
14816
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
14725
|
-
const edgeId = (0,
|
|
14817
|
+
const edgeId = (0, import_types46.extractedEdgeId)(childId, parentId, import_types46.EdgeType.REFERENCES);
|
|
14726
14818
|
if (graph.hasEdge(edgeId)) continue;
|
|
14727
14819
|
const edge = {
|
|
14728
14820
|
id: edgeId,
|
|
14729
14821
|
source: childId,
|
|
14730
14822
|
target: parentId,
|
|
14731
|
-
type:
|
|
14732
|
-
provenance:
|
|
14733
|
-
confidence: (0,
|
|
14823
|
+
type: import_types46.EdgeType.REFERENCES,
|
|
14824
|
+
provenance: import_types46.Provenance.EXTRACTED,
|
|
14825
|
+
confidence: (0, import_types46.confidenceForExtracted)("structural"),
|
|
14734
14826
|
evidence: ref.evidence
|
|
14735
14827
|
};
|
|
14736
14828
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -14743,7 +14835,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
14743
14835
|
if (graph.hasNode(id)) return 0;
|
|
14744
14836
|
const node = {
|
|
14745
14837
|
id,
|
|
14746
|
-
type:
|
|
14838
|
+
type: import_types46.NodeType.InfraNode,
|
|
14747
14839
|
name,
|
|
14748
14840
|
provider: "self",
|
|
14749
14841
|
kind: "sql-table"
|
|
@@ -14757,16 +14849,16 @@ init_cjs_shims();
|
|
|
14757
14849
|
|
|
14758
14850
|
// src/extract/infra/docker-compose.ts
|
|
14759
14851
|
init_cjs_shims();
|
|
14760
|
-
var
|
|
14761
|
-
var
|
|
14852
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
14853
|
+
var import_types48 = require("@neat.is/types");
|
|
14762
14854
|
|
|
14763
14855
|
// src/extract/infra/shared.ts
|
|
14764
14856
|
init_cjs_shims();
|
|
14765
|
-
var
|
|
14857
|
+
var import_types47 = require("@neat.is/types");
|
|
14766
14858
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
14767
14859
|
return {
|
|
14768
|
-
id: (0,
|
|
14769
|
-
type:
|
|
14860
|
+
id: (0, import_types47.infraId)(kind, name),
|
|
14861
|
+
type: import_types47.NodeType.InfraNode,
|
|
14770
14862
|
name,
|
|
14771
14863
|
provider,
|
|
14772
14864
|
kind,
|
|
@@ -14810,8 +14902,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
14810
14902
|
source: anchorId,
|
|
14811
14903
|
target: node.id,
|
|
14812
14904
|
type: edgeType,
|
|
14813
|
-
provenance:
|
|
14814
|
-
confidence: (0,
|
|
14905
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
14906
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
14815
14907
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14816
14908
|
};
|
|
14817
14909
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14828,7 +14920,7 @@ function dependsOnList(value) {
|
|
|
14828
14920
|
}
|
|
14829
14921
|
function serviceNameToServiceNode(name, services) {
|
|
14830
14922
|
for (const s of services) {
|
|
14831
|
-
if (s.node.name === name ||
|
|
14923
|
+
if (s.node.name === name || import_node_path58.default.basename(s.dir) === name) return s.node.id;
|
|
14832
14924
|
}
|
|
14833
14925
|
return null;
|
|
14834
14926
|
}
|
|
@@ -14837,7 +14929,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14837
14929
|
let edgesAdded = 0;
|
|
14838
14930
|
let composePath = null;
|
|
14839
14931
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
14840
|
-
const abs =
|
|
14932
|
+
const abs = import_node_path58.default.join(scanPath, name);
|
|
14841
14933
|
if (await exists(abs)) {
|
|
14842
14934
|
composePath = abs;
|
|
14843
14935
|
break;
|
|
@@ -14850,13 +14942,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14850
14942
|
} catch (err) {
|
|
14851
14943
|
recordExtractionError(
|
|
14852
14944
|
"infra docker-compose",
|
|
14853
|
-
|
|
14945
|
+
import_node_path58.default.relative(scanPath, composePath),
|
|
14854
14946
|
err
|
|
14855
14947
|
);
|
|
14856
14948
|
return { nodesAdded, edgesAdded };
|
|
14857
14949
|
}
|
|
14858
14950
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
14859
|
-
const evidenceFile =
|
|
14951
|
+
const evidenceFile = import_node_path58.default.relative(scanPath, composePath).split(import_node_path58.default.sep).join("/");
|
|
14860
14952
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
14861
14953
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
14862
14954
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -14878,15 +14970,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14878
14970
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
14879
14971
|
const targetId = composeNameToNodeId.get(dep);
|
|
14880
14972
|
if (!targetId) continue;
|
|
14881
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
14973
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types48.EdgeType.DEPENDS_ON);
|
|
14882
14974
|
if (graph.hasEdge(edgeId)) continue;
|
|
14883
14975
|
const edge = {
|
|
14884
14976
|
id: edgeId,
|
|
14885
14977
|
source: sourceId,
|
|
14886
14978
|
target: targetId,
|
|
14887
|
-
type:
|
|
14888
|
-
provenance:
|
|
14889
|
-
confidence: (0,
|
|
14979
|
+
type: import_types48.EdgeType.DEPENDS_ON,
|
|
14980
|
+
provenance: import_types48.Provenance.EXTRACTED,
|
|
14981
|
+
confidence: (0, import_types48.confidenceForExtracted)("structural"),
|
|
14890
14982
|
evidence: { file: evidenceFile }
|
|
14891
14983
|
};
|
|
14892
14984
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14898,9 +14990,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14898
14990
|
|
|
14899
14991
|
// src/extract/infra/dockerfile.ts
|
|
14900
14992
|
init_cjs_shims();
|
|
14901
|
-
var
|
|
14993
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14902
14994
|
var import_node_fs25 = require("fs");
|
|
14903
|
-
var
|
|
14995
|
+
var import_types49 = require("@neat.is/types");
|
|
14904
14996
|
function readDockerfile(content) {
|
|
14905
14997
|
let image = null;
|
|
14906
14998
|
const ports = [];
|
|
@@ -14929,7 +15021,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14929
15021
|
let nodesAdded = 0;
|
|
14930
15022
|
let edgesAdded = 0;
|
|
14931
15023
|
for (const service of services) {
|
|
14932
|
-
const dockerfilePath =
|
|
15024
|
+
const dockerfilePath = import_node_path59.default.join(service.dir, "Dockerfile");
|
|
14933
15025
|
if (!await exists(dockerfilePath)) continue;
|
|
14934
15026
|
let content;
|
|
14935
15027
|
try {
|
|
@@ -14937,7 +15029,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14937
15029
|
} catch (err) {
|
|
14938
15030
|
recordExtractionError(
|
|
14939
15031
|
"infra dockerfile",
|
|
14940
|
-
|
|
15032
|
+
import_node_path59.default.relative(scanPath, dockerfilePath),
|
|
14941
15033
|
err
|
|
14942
15034
|
);
|
|
14943
15035
|
continue;
|
|
@@ -14949,8 +15041,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14949
15041
|
graph.addNode(node.id, node);
|
|
14950
15042
|
nodesAdded++;
|
|
14951
15043
|
}
|
|
14952
|
-
const relDockerfile = toPosix(
|
|
14953
|
-
const evidenceFile = toPosix(
|
|
15044
|
+
const relDockerfile = toPosix(import_node_path59.default.relative(service.dir, dockerfilePath));
|
|
15045
|
+
const evidenceFile = toPosix(import_node_path59.default.relative(scanPath, dockerfilePath));
|
|
14954
15046
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14955
15047
|
graph,
|
|
14956
15048
|
service.pkg.name,
|
|
@@ -14959,15 +15051,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14959
15051
|
);
|
|
14960
15052
|
nodesAdded += fn;
|
|
14961
15053
|
edgesAdded += fe;
|
|
14962
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
15054
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types49.EdgeType.RUNS_ON);
|
|
14963
15055
|
if (!graph.hasEdge(edgeId)) {
|
|
14964
15056
|
const edge = {
|
|
14965
15057
|
id: edgeId,
|
|
14966
15058
|
source: fileNodeId,
|
|
14967
15059
|
target: node.id,
|
|
14968
|
-
type:
|
|
14969
|
-
provenance:
|
|
14970
|
-
confidence: (0,
|
|
15060
|
+
type: import_types49.EdgeType.RUNS_ON,
|
|
15061
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15062
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14971
15063
|
evidence: {
|
|
14972
15064
|
file: evidenceFile,
|
|
14973
15065
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -14982,15 +15074,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14982
15074
|
graph.addNode(portNode.id, portNode);
|
|
14983
15075
|
nodesAdded++;
|
|
14984
15076
|
}
|
|
14985
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
15077
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types49.EdgeType.CONNECTS_TO);
|
|
14986
15078
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
14987
15079
|
const portEdge = {
|
|
14988
15080
|
id: portEdgeId,
|
|
14989
15081
|
source: fileNodeId,
|
|
14990
15082
|
target: portNode.id,
|
|
14991
|
-
type:
|
|
14992
|
-
provenance:
|
|
14993
|
-
confidence: (0,
|
|
15083
|
+
type: import_types49.EdgeType.CONNECTS_TO,
|
|
15084
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15085
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14994
15086
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
14995
15087
|
};
|
|
14996
15088
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -15003,8 +15095,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
15003
15095
|
// src/extract/infra/terraform.ts
|
|
15004
15096
|
init_cjs_shims();
|
|
15005
15097
|
var import_node_fs26 = require("fs");
|
|
15006
|
-
var
|
|
15007
|
-
var
|
|
15098
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
15099
|
+
var import_types50 = require("@neat.is/types");
|
|
15008
15100
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
15009
15101
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
15010
15102
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -15014,11 +15106,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
15014
15106
|
for (const entry of entries) {
|
|
15015
15107
|
if (entry.isDirectory()) {
|
|
15016
15108
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
15017
|
-
const child =
|
|
15109
|
+
const child = import_node_path60.default.join(start, entry.name);
|
|
15018
15110
|
if (await isPythonVenvDir(child)) continue;
|
|
15019
15111
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
15020
15112
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
15021
|
-
out.push(
|
|
15113
|
+
out.push(import_node_path60.default.join(start, entry.name));
|
|
15022
15114
|
}
|
|
15023
15115
|
}
|
|
15024
15116
|
return out;
|
|
@@ -15050,7 +15142,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
15050
15142
|
const files = await walkTfFiles(scanPath);
|
|
15051
15143
|
for (const file of files) {
|
|
15052
15144
|
const content = await import_node_fs26.promises.readFile(file, "utf8");
|
|
15053
|
-
const evidenceFile = toPosix(
|
|
15145
|
+
const evidenceFile = toPosix(import_node_path60.default.relative(scanPath, file));
|
|
15054
15146
|
const resources = [];
|
|
15055
15147
|
const byKey = /* @__PURE__ */ new Map();
|
|
15056
15148
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -15085,16 +15177,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
15085
15177
|
if (!target) continue;
|
|
15086
15178
|
if (seen.has(target.nodeId)) continue;
|
|
15087
15179
|
seen.add(target.nodeId);
|
|
15088
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
15180
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types50.EdgeType.DEPENDS_ON);
|
|
15089
15181
|
if (graph.hasEdge(edgeId)) continue;
|
|
15090
15182
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
15091
15183
|
const edge = {
|
|
15092
15184
|
id: edgeId,
|
|
15093
15185
|
source: resource.nodeId,
|
|
15094
15186
|
target: target.nodeId,
|
|
15095
|
-
type:
|
|
15096
|
-
provenance:
|
|
15097
|
-
confidence: (0,
|
|
15187
|
+
type: import_types50.EdgeType.DEPENDS_ON,
|
|
15188
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
15189
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
15098
15190
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
15099
15191
|
};
|
|
15100
15192
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -15108,8 +15200,9 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
15108
15200
|
// src/extract/infra/k8s.ts
|
|
15109
15201
|
init_cjs_shims();
|
|
15110
15202
|
var import_node_fs27 = require("fs");
|
|
15111
|
-
var
|
|
15203
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
15112
15204
|
var import_yaml3 = require("yaml");
|
|
15205
|
+
var import_types51 = require("@neat.is/types");
|
|
15113
15206
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
15114
15207
|
Service: "k8s-service",
|
|
15115
15208
|
Deployment: "k8s-deployment",
|
|
@@ -15119,6 +15212,7 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
15119
15212
|
Job: "k8s-job",
|
|
15120
15213
|
Ingress: "k8s-ingress"
|
|
15121
15214
|
};
|
|
15215
|
+
var WORKLOAD_KINDS = /* @__PURE__ */ new Set(["Deployment", "StatefulSet", "DaemonSet"]);
|
|
15122
15216
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
15123
15217
|
if (depth > max) return [];
|
|
15124
15218
|
const out = [];
|
|
@@ -15126,17 +15220,18 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
15126
15220
|
for (const entry of entries) {
|
|
15127
15221
|
if (entry.isDirectory()) {
|
|
15128
15222
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
15129
|
-
const child =
|
|
15223
|
+
const child = import_node_path61.default.join(start, entry.name);
|
|
15130
15224
|
if (await isPythonVenvDir(child)) continue;
|
|
15131
15225
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
15132
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
15133
|
-
out.push(
|
|
15226
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path61.default.extname(entry.name))) {
|
|
15227
|
+
out.push(import_node_path61.default.join(start, entry.name));
|
|
15134
15228
|
}
|
|
15135
15229
|
}
|
|
15136
15230
|
return out;
|
|
15137
15231
|
}
|
|
15138
15232
|
async function addK8sResources(graph, scanPath) {
|
|
15139
15233
|
let nodesAdded = 0;
|
|
15234
|
+
let edgesAdded = 0;
|
|
15140
15235
|
const files = await walkYamlFiles2(scanPath);
|
|
15141
15236
|
for (const file of files) {
|
|
15142
15237
|
const content = await import_node_fs27.promises.readFile(file, "utf8");
|
|
@@ -15146,31 +15241,63 @@ async function addK8sResources(graph, scanPath) {
|
|
|
15146
15241
|
} catch {
|
|
15147
15242
|
continue;
|
|
15148
15243
|
}
|
|
15244
|
+
const relFile = toPosix(import_node_path61.default.relative(scanPath, file));
|
|
15149
15245
|
for (const doc of docs) {
|
|
15150
15246
|
if (!doc?.kind || !doc.metadata?.name) continue;
|
|
15151
15247
|
const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind];
|
|
15152
15248
|
if (!infraKind) continue;
|
|
15153
|
-
const
|
|
15154
|
-
const
|
|
15249
|
+
const name = doc.metadata.name;
|
|
15250
|
+
const isWorkload = WORKLOAD_KINDS.has(doc.kind);
|
|
15251
|
+
const image = isWorkload ? doc.spec?.template?.spec?.containers?.[0]?.image : void 0;
|
|
15252
|
+
const replicas = isWorkload && typeof doc.spec?.replicas === "number" ? doc.spec.replicas : void 0;
|
|
15253
|
+
const base = makeInfraNode(infraKind, name, "kubernetes");
|
|
15254
|
+
const node = {
|
|
15255
|
+
...base,
|
|
15256
|
+
...doc.metadata.namespace ? { namespace: doc.metadata.namespace } : {},
|
|
15257
|
+
...image ? { image } : {},
|
|
15258
|
+
...replicas !== void 0 ? { replicas } : {}
|
|
15259
|
+
};
|
|
15155
15260
|
if (!graph.hasNode(node.id)) {
|
|
15156
15261
|
graph.addNode(node.id, node);
|
|
15157
15262
|
nodesAdded++;
|
|
15158
15263
|
}
|
|
15264
|
+
if (isWorkload) {
|
|
15265
|
+
const svcId = (0, import_types51.serviceId)(name);
|
|
15266
|
+
if (graph.hasNode(svcId)) {
|
|
15267
|
+
const svc = graph.getNodeAttributes(svcId);
|
|
15268
|
+
graph.replaceNodeAttributes(svcId, {
|
|
15269
|
+
...svc,
|
|
15270
|
+
platform: svc.platform ?? "kubernetes",
|
|
15271
|
+
...image ? { declaredImage: image } : {},
|
|
15272
|
+
...replicas !== void 0 ? { declaredReplicas: replicas } : {}
|
|
15273
|
+
});
|
|
15274
|
+
edgesAdded += emitPlatformResourceEdge(
|
|
15275
|
+
graph,
|
|
15276
|
+
svcId,
|
|
15277
|
+
import_types51.EdgeType.RUNS_ON,
|
|
15278
|
+
infraKind,
|
|
15279
|
+
name,
|
|
15280
|
+
"kubernetes",
|
|
15281
|
+
relFile,
|
|
15282
|
+
lineContaining(content, image)
|
|
15283
|
+
).edgesAdded;
|
|
15284
|
+
}
|
|
15285
|
+
}
|
|
15159
15286
|
}
|
|
15160
15287
|
}
|
|
15161
|
-
return { nodesAdded, edgesAdded
|
|
15288
|
+
return { nodesAdded, edgesAdded };
|
|
15162
15289
|
}
|
|
15163
15290
|
|
|
15164
15291
|
// src/extract/infra/cloudflare.ts
|
|
15165
15292
|
init_cjs_shims();
|
|
15166
15293
|
var import_node_fs28 = require("fs");
|
|
15167
|
-
var
|
|
15294
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
15168
15295
|
var import_smol_toml3 = require("smol-toml");
|
|
15169
|
-
var
|
|
15296
|
+
var import_types52 = require("@neat.is/types");
|
|
15170
15297
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
15171
15298
|
async function readWranglerConfig(dir) {
|
|
15172
15299
|
for (const filename of WRANGLER_FILENAMES) {
|
|
15173
|
-
const abs =
|
|
15300
|
+
const abs = import_node_path62.default.join(dir, filename);
|
|
15174
15301
|
if (!await exists(abs)) continue;
|
|
15175
15302
|
const raw = await import_node_fs28.promises.readFile(abs, "utf8");
|
|
15176
15303
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -15214,8 +15341,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
15214
15341
|
source: anchorId,
|
|
15215
15342
|
target: node.id,
|
|
15216
15343
|
type: edgeType,
|
|
15217
|
-
provenance:
|
|
15218
|
-
confidence: (0,
|
|
15344
|
+
provenance: import_types52.Provenance.EXTRACTED,
|
|
15345
|
+
confidence: (0, import_types52.confidenceForExtracted)("structural"),
|
|
15219
15346
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
15220
15347
|
};
|
|
15221
15348
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -15233,11 +15360,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15233
15360
|
try {
|
|
15234
15361
|
read = await readWranglerConfig(service.dir);
|
|
15235
15362
|
} catch (err) {
|
|
15236
|
-
recordExtractionError("infra cloudflare",
|
|
15363
|
+
recordExtractionError("infra cloudflare", import_node_path62.default.relative(scanPath, service.dir), err);
|
|
15237
15364
|
continue;
|
|
15238
15365
|
}
|
|
15239
15366
|
if (!read || !read.config.name) continue;
|
|
15240
|
-
const evidenceFile = toPosix(
|
|
15367
|
+
const evidenceFile = toPosix(import_node_path62.default.relative(scanPath, import_node_path62.default.join(service.dir, read.relFile)));
|
|
15241
15368
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
15242
15369
|
}
|
|
15243
15370
|
for (const worker of discovered) {
|
|
@@ -15249,7 +15376,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15249
15376
|
}
|
|
15250
15377
|
let anchorId = service.node.id;
|
|
15251
15378
|
if (config.main) {
|
|
15252
|
-
const entryRelPath = toPosix(
|
|
15379
|
+
const entryRelPath = toPosix(import_node_path62.default.normalize(config.main));
|
|
15253
15380
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
15254
15381
|
graph,
|
|
15255
15382
|
service.pkg.name,
|
|
@@ -15276,15 +15403,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15276
15403
|
nodesAdded++;
|
|
15277
15404
|
}
|
|
15278
15405
|
if (runtimeNode.id !== anchorId) {
|
|
15279
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
15406
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types52.EdgeType.RUNS_ON);
|
|
15280
15407
|
if (!graph.hasEdge(runsOnId)) {
|
|
15281
15408
|
const edge = {
|
|
15282
15409
|
id: runsOnId,
|
|
15283
15410
|
source: anchorId,
|
|
15284
15411
|
target: runtimeNode.id,
|
|
15285
|
-
type:
|
|
15286
|
-
provenance:
|
|
15287
|
-
confidence: (0,
|
|
15412
|
+
type: import_types52.EdgeType.RUNS_ON,
|
|
15413
|
+
provenance: import_types52.Provenance.EXTRACTED,
|
|
15414
|
+
confidence: (0, import_types52.confidenceForExtracted)("structural"),
|
|
15288
15415
|
evidence: {
|
|
15289
15416
|
file: evidenceFile,
|
|
15290
15417
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -15298,7 +15425,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15298
15425
|
const result = addResourceEdge(
|
|
15299
15426
|
graph,
|
|
15300
15427
|
anchorId,
|
|
15301
|
-
|
|
15428
|
+
import_types52.EdgeType.CONNECTS_TO,
|
|
15302
15429
|
"cloudflare-route",
|
|
15303
15430
|
route,
|
|
15304
15431
|
evidenceFile,
|
|
@@ -15322,7 +15449,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15322
15449
|
const result = addResourceEdge(
|
|
15323
15450
|
graph,
|
|
15324
15451
|
anchorId,
|
|
15325
|
-
|
|
15452
|
+
import_types52.EdgeType.DEPENDS_ON,
|
|
15326
15453
|
group.kind,
|
|
15327
15454
|
name,
|
|
15328
15455
|
evidenceFile,
|
|
@@ -15336,7 +15463,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15336
15463
|
const result = addResourceEdge(
|
|
15337
15464
|
graph,
|
|
15338
15465
|
anchorId,
|
|
15339
|
-
|
|
15466
|
+
import_types52.EdgeType.DEPENDS_ON,
|
|
15340
15467
|
"cloudflare-cron",
|
|
15341
15468
|
cron,
|
|
15342
15469
|
evidenceFile,
|
|
@@ -15349,7 +15476,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15349
15476
|
const result = addResourceEdge(
|
|
15350
15477
|
graph,
|
|
15351
15478
|
anchorId,
|
|
15352
|
-
|
|
15479
|
+
import_types52.EdgeType.DEPENDS_ON,
|
|
15353
15480
|
"cloudflare-env-var",
|
|
15354
15481
|
varName,
|
|
15355
15482
|
evidenceFile,
|
|
@@ -15362,15 +15489,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15362
15489
|
if (!svc.service) continue;
|
|
15363
15490
|
const target = workerIndex.get(svc.service);
|
|
15364
15491
|
if (target && target.anchorId !== anchorId) {
|
|
15365
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
15492
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types52.EdgeType.CALLS);
|
|
15366
15493
|
if (!graph.hasEdge(edgeId)) {
|
|
15367
15494
|
const edge = {
|
|
15368
15495
|
id: edgeId,
|
|
15369
15496
|
source: anchorId,
|
|
15370
15497
|
target: target.anchorId,
|
|
15371
|
-
type:
|
|
15372
|
-
provenance:
|
|
15373
|
-
confidence: (0,
|
|
15498
|
+
type: import_types52.EdgeType.CALLS,
|
|
15499
|
+
provenance: import_types52.Provenance.EXTRACTED,
|
|
15500
|
+
confidence: (0, import_types52.confidenceForExtracted)("structural"),
|
|
15374
15501
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
15375
15502
|
};
|
|
15376
15503
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -15381,7 +15508,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15381
15508
|
const result = addResourceEdge(
|
|
15382
15509
|
graph,
|
|
15383
15510
|
anchorId,
|
|
15384
|
-
|
|
15511
|
+
import_types52.EdgeType.DEPENDS_ON,
|
|
15385
15512
|
"cloudflare-service-binding",
|
|
15386
15513
|
svc.service,
|
|
15387
15514
|
evidenceFile,
|
|
@@ -15397,12 +15524,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
15397
15524
|
// src/extract/infra/vercel.ts
|
|
15398
15525
|
init_cjs_shims();
|
|
15399
15526
|
var import_node_fs29 = require("fs");
|
|
15400
|
-
var
|
|
15401
|
-
var
|
|
15527
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
15528
|
+
var import_types53 = require("@neat.is/types");
|
|
15402
15529
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
15403
15530
|
async function readVercelConfig(dir) {
|
|
15404
15531
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
15405
|
-
const abs =
|
|
15532
|
+
const abs = import_node_path63.default.join(dir, filename);
|
|
15406
15533
|
if (!await exists(abs)) continue;
|
|
15407
15534
|
const raw = await import_node_fs29.promises.readFile(abs, "utf8");
|
|
15408
15535
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -15411,7 +15538,7 @@ async function readVercelConfig(dir) {
|
|
|
15411
15538
|
return null;
|
|
15412
15539
|
}
|
|
15413
15540
|
async function readLinkedProjectName(dir) {
|
|
15414
|
-
const abs =
|
|
15541
|
+
const abs = import_node_path63.default.join(dir, ".vercel", "project.json");
|
|
15415
15542
|
if (!await exists(abs)) return void 0;
|
|
15416
15543
|
const parsed = JSON.parse(await import_node_fs29.promises.readFile(abs, "utf8"));
|
|
15417
15544
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -15429,7 +15556,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
15429
15556
|
read = await readVercelConfig(service.dir);
|
|
15430
15557
|
projectName = await readLinkedProjectName(service.dir);
|
|
15431
15558
|
} catch (err) {
|
|
15432
|
-
recordExtractionError("infra vercel",
|
|
15559
|
+
recordExtractionError("infra vercel", import_node_path63.default.relative(scanPath, service.dir), err);
|
|
15433
15560
|
continue;
|
|
15434
15561
|
}
|
|
15435
15562
|
if (!read && !projectName) continue;
|
|
@@ -15445,7 +15572,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
15445
15572
|
const anchorId = service.node.id;
|
|
15446
15573
|
if (!read) continue;
|
|
15447
15574
|
const { config, relFile, raw } = read;
|
|
15448
|
-
const evidenceFile = toPosix(
|
|
15575
|
+
const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, import_node_path63.default.join(service.dir, relFile)));
|
|
15449
15576
|
const add = (edgeType, kind, name) => {
|
|
15450
15577
|
if (!name) return;
|
|
15451
15578
|
const result = emitPlatformResourceEdge(
|
|
@@ -15461,12 +15588,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
15461
15588
|
nodesAdded += result.nodesAdded;
|
|
15462
15589
|
edgesAdded += result.edgesAdded;
|
|
15463
15590
|
};
|
|
15464
|
-
add(
|
|
15465
|
-
for (const cron of config.crons ?? []) add(
|
|
15466
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
15467
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
15591
|
+
add(import_types53.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
15592
|
+
for (const cron of config.crons ?? []) add(import_types53.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
15593
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types53.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
15594
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types53.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
15468
15595
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
15469
|
-
add(
|
|
15596
|
+
add(import_types53.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
15470
15597
|
}
|
|
15471
15598
|
}
|
|
15472
15599
|
return { nodesAdded, edgesAdded };
|
|
@@ -15475,13 +15602,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
15475
15602
|
// src/extract/infra/railway.ts
|
|
15476
15603
|
init_cjs_shims();
|
|
15477
15604
|
var import_node_fs30 = require("fs");
|
|
15478
|
-
var
|
|
15605
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
15479
15606
|
var import_smol_toml4 = require("smol-toml");
|
|
15480
|
-
var
|
|
15607
|
+
var import_types54 = require("@neat.is/types");
|
|
15481
15608
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
15482
15609
|
async function readRailwayConfig(dir) {
|
|
15483
15610
|
for (const filename of RAILWAY_FILENAMES) {
|
|
15484
|
-
const abs =
|
|
15611
|
+
const abs = import_node_path64.default.join(dir, filename);
|
|
15485
15612
|
if (!await exists(abs)) continue;
|
|
15486
15613
|
const raw = await import_node_fs30.promises.readFile(abs, "utf8");
|
|
15487
15614
|
const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -15497,7 +15624,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
15497
15624
|
try {
|
|
15498
15625
|
read = await readRailwayConfig(service.dir);
|
|
15499
15626
|
} catch (err) {
|
|
15500
|
-
recordExtractionError("infra railway",
|
|
15627
|
+
recordExtractionError("infra railway", import_node_path64.default.relative(scanPath, service.dir), err);
|
|
15501
15628
|
continue;
|
|
15502
15629
|
}
|
|
15503
15630
|
if (!read) continue;
|
|
@@ -15507,7 +15634,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
15507
15634
|
}
|
|
15508
15635
|
const anchorId = service.node.id;
|
|
15509
15636
|
const { config, relFile, raw } = read;
|
|
15510
|
-
const evidenceFile = toPosix(
|
|
15637
|
+
const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, import_node_path64.default.join(service.dir, relFile)));
|
|
15511
15638
|
const add = (edgeType, kind, name) => {
|
|
15512
15639
|
if (!name) return;
|
|
15513
15640
|
const result = emitPlatformResourceEdge(
|
|
@@ -15523,9 +15650,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
15523
15650
|
nodesAdded += result.nodesAdded;
|
|
15524
15651
|
edgesAdded += result.edgesAdded;
|
|
15525
15652
|
};
|
|
15526
|
-
add(
|
|
15527
|
-
add(
|
|
15528
|
-
add(
|
|
15653
|
+
add(import_types54.EdgeType.RUNS_ON, "railway", "railway");
|
|
15654
|
+
add(import_types54.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
15655
|
+
add(import_types54.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
15529
15656
|
}
|
|
15530
15657
|
return { nodesAdded, edgesAdded };
|
|
15531
15658
|
}
|
|
@@ -15533,12 +15660,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
15533
15660
|
// src/extract/infra/supabase.ts
|
|
15534
15661
|
init_cjs_shims();
|
|
15535
15662
|
var import_node_fs31 = require("fs");
|
|
15536
|
-
var
|
|
15663
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
15537
15664
|
var import_smol_toml5 = require("smol-toml");
|
|
15538
|
-
var
|
|
15665
|
+
var import_types55 = require("@neat.is/types");
|
|
15539
15666
|
async function readSupabaseConfig(dir) {
|
|
15540
|
-
const relFile =
|
|
15541
|
-
const abs =
|
|
15667
|
+
const relFile = import_node_path65.default.join("supabase", "config.toml");
|
|
15668
|
+
const abs = import_node_path65.default.join(dir, relFile);
|
|
15542
15669
|
if (!await exists(abs)) return null;
|
|
15543
15670
|
const raw = await import_node_fs31.promises.readFile(abs, "utf8");
|
|
15544
15671
|
const config = (0, import_smol_toml5.parse)(raw);
|
|
@@ -15552,7 +15679,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15552
15679
|
try {
|
|
15553
15680
|
read = await readSupabaseConfig(service.dir);
|
|
15554
15681
|
} catch (err) {
|
|
15555
|
-
recordExtractionError("infra supabase",
|
|
15682
|
+
recordExtractionError("infra supabase", import_node_path65.default.relative(scanPath, service.dir), err);
|
|
15556
15683
|
continue;
|
|
15557
15684
|
}
|
|
15558
15685
|
if (!read) continue;
|
|
@@ -15567,7 +15694,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15567
15694
|
});
|
|
15568
15695
|
}
|
|
15569
15696
|
const anchorId = service.node.id;
|
|
15570
|
-
const evidenceFile = toPosix(
|
|
15697
|
+
const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, relFile)));
|
|
15571
15698
|
const add = (edgeType, kind, name) => {
|
|
15572
15699
|
if (!name) return;
|
|
15573
15700
|
const result = emitPlatformResourceEdge(
|
|
@@ -15583,10 +15710,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15583
15710
|
nodesAdded += result.nodesAdded;
|
|
15584
15711
|
edgesAdded += result.edgesAdded;
|
|
15585
15712
|
};
|
|
15586
|
-
add(
|
|
15587
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
15588
|
-
if (config.storage) add(
|
|
15589
|
-
if (config.auth) add(
|
|
15713
|
+
add(import_types55.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
15714
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types55.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
15715
|
+
if (config.storage) add(import_types55.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
15716
|
+
if (config.auth) add(import_types55.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
15590
15717
|
}
|
|
15591
15718
|
return { nodesAdded, edgesAdded };
|
|
15592
15719
|
}
|
|
@@ -15609,18 +15736,18 @@ async function addInfra(graph, scanPath, services) {
|
|
|
15609
15736
|
|
|
15610
15737
|
// src/extract/zod-shapes.ts
|
|
15611
15738
|
init_cjs_shims();
|
|
15612
|
-
var
|
|
15613
|
-
var
|
|
15739
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
15740
|
+
var import_tree_sitter18 = __toESM(require("tree-sitter"), 1);
|
|
15614
15741
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
15615
|
-
var
|
|
15742
|
+
var import_types56 = require("@neat.is/types");
|
|
15616
15743
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
15617
15744
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
15618
15745
|
function parserForExt4(ext) {
|
|
15619
|
-
const p = new
|
|
15746
|
+
const p = new import_tree_sitter18.default();
|
|
15620
15747
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
15621
15748
|
return p;
|
|
15622
15749
|
}
|
|
15623
|
-
function
|
|
15750
|
+
function namedChildren6(node) {
|
|
15624
15751
|
const out = [];
|
|
15625
15752
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
15626
15753
|
const c = node.namedChild(i);
|
|
@@ -15630,7 +15757,7 @@ function namedChildren5(node) {
|
|
|
15630
15757
|
}
|
|
15631
15758
|
function stringLiteralText5(node) {
|
|
15632
15759
|
if (!node || node.type !== "string") return null;
|
|
15633
|
-
for (const child of
|
|
15760
|
+
for (const child of namedChildren6(node)) {
|
|
15634
15761
|
if (child.type === "string_fragment") return child.text;
|
|
15635
15762
|
}
|
|
15636
15763
|
return "";
|
|
@@ -15655,12 +15782,12 @@ function zodCallKind(call) {
|
|
|
15655
15782
|
function firstArg(call) {
|
|
15656
15783
|
const args = call.childForFieldName("arguments");
|
|
15657
15784
|
if (!args) return null;
|
|
15658
|
-
return
|
|
15785
|
+
return namedChildren6(args)[0] ?? null;
|
|
15659
15786
|
}
|
|
15660
15787
|
function fieldsFromObject(obj) {
|
|
15661
15788
|
const out = [];
|
|
15662
15789
|
const seen = /* @__PURE__ */ new Set();
|
|
15663
|
-
for (const child of
|
|
15790
|
+
for (const child of namedChildren6(obj)) {
|
|
15664
15791
|
if (child.type === "spread_element") return null;
|
|
15665
15792
|
if (child.type !== "pair") continue;
|
|
15666
15793
|
const key = child.childForFieldName("key");
|
|
@@ -15676,7 +15803,7 @@ function fieldsFromObject(obj) {
|
|
|
15676
15803
|
function membersFromEnum(arr) {
|
|
15677
15804
|
const out = [];
|
|
15678
15805
|
const seen = /* @__PURE__ */ new Set();
|
|
15679
|
-
for (const child of
|
|
15806
|
+
for (const child of namedChildren6(arr)) {
|
|
15680
15807
|
if (child.type !== "string") return null;
|
|
15681
15808
|
const value = stringLiteralText5(child);
|
|
15682
15809
|
if (value !== null && value !== "" && !seen.has(value)) {
|
|
@@ -15688,10 +15815,10 @@ function membersFromEnum(arr) {
|
|
|
15688
15815
|
}
|
|
15689
15816
|
function topLevelSchemas(root) {
|
|
15690
15817
|
const out = [];
|
|
15691
|
-
for (const stmt of
|
|
15818
|
+
for (const stmt of namedChildren6(root)) {
|
|
15692
15819
|
const decl = stmt.type === "export_statement" ? stmt.childForFieldName("declaration") : stmt;
|
|
15693
15820
|
if (decl?.type !== "lexical_declaration" && decl?.type !== "variable_declaration") continue;
|
|
15694
|
-
for (const declarator of
|
|
15821
|
+
for (const declarator of namedChildren6(decl)) {
|
|
15695
15822
|
if (declarator.type !== "variable_declarator") continue;
|
|
15696
15823
|
const name = declarator.childForFieldName("name");
|
|
15697
15824
|
const value = declarator.childForFieldName("value");
|
|
@@ -15704,7 +15831,7 @@ function topLevelSchemas(root) {
|
|
|
15704
15831
|
}
|
|
15705
15832
|
function zodShapesFromFile(file, serviceDir) {
|
|
15706
15833
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
15707
|
-
const tree = parseSource3(parserForExt4(
|
|
15834
|
+
const tree = parseSource3(parserForExt4(import_node_path66.default.extname(file.path)), file.content);
|
|
15708
15835
|
const out = [];
|
|
15709
15836
|
const seen = /* @__PURE__ */ new Set();
|
|
15710
15837
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -15718,11 +15845,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
15718
15845
|
seen.add(name);
|
|
15719
15846
|
const line = call.startPosition.row + 1;
|
|
15720
15847
|
out.push({
|
|
15721
|
-
infraId: (0,
|
|
15848
|
+
infraId: (0, import_types56.infraId)("zod-schema", name),
|
|
15722
15849
|
name,
|
|
15723
15850
|
fields,
|
|
15724
15851
|
evidence: {
|
|
15725
|
-
file:
|
|
15852
|
+
file: import_node_path66.default.relative(serviceDir, file.path),
|
|
15726
15853
|
line,
|
|
15727
15854
|
snippet: snippet(file.content, line)
|
|
15728
15855
|
}
|
|
@@ -15753,7 +15880,7 @@ async function addZodShapes(graph, services) {
|
|
|
15753
15880
|
if (!graph.hasNode(shape.infraId)) {
|
|
15754
15881
|
const node = {
|
|
15755
15882
|
id: shape.infraId,
|
|
15756
|
-
type:
|
|
15883
|
+
type: import_types56.NodeType.InfraNode,
|
|
15757
15884
|
name: shape.name,
|
|
15758
15885
|
provider: "self",
|
|
15759
15886
|
kind: "zod-schema"
|
|
@@ -15763,14 +15890,14 @@ async function addZodShapes(graph, services) {
|
|
|
15763
15890
|
}
|
|
15764
15891
|
if (shape.fields.length > 0) {
|
|
15765
15892
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
15766
|
-
if (node.type ===
|
|
15893
|
+
if (node.type === import_types56.NodeType.InfraNode) {
|
|
15767
15894
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
15768
15895
|
...node,
|
|
15769
15896
|
columns: foldColumns(
|
|
15770
15897
|
node.columns,
|
|
15771
15898
|
shape.fields,
|
|
15772
|
-
|
|
15773
|
-
(0,
|
|
15899
|
+
import_types56.Provenance.EXTRACTED,
|
|
15900
|
+
(0, import_types56.confidenceForExtracted)("structural")
|
|
15774
15901
|
)
|
|
15775
15902
|
});
|
|
15776
15903
|
}
|
|
@@ -15784,15 +15911,15 @@ async function addZodShapes(graph, services) {
|
|
|
15784
15911
|
);
|
|
15785
15912
|
nodesAdded += n;
|
|
15786
15913
|
edgesAdded += e;
|
|
15787
|
-
const edgeId = (0,
|
|
15914
|
+
const edgeId = (0, import_types56.extractedEdgeId)(fileNodeId, shape.infraId, import_types56.EdgeType.CONTAINS);
|
|
15788
15915
|
if (!graph.hasEdge(edgeId)) {
|
|
15789
15916
|
const edge = {
|
|
15790
15917
|
id: edgeId,
|
|
15791
15918
|
source: fileNodeId,
|
|
15792
15919
|
target: shape.infraId,
|
|
15793
|
-
type:
|
|
15794
|
-
provenance:
|
|
15795
|
-
confidence: (0,
|
|
15920
|
+
type: import_types56.EdgeType.CONTAINS,
|
|
15921
|
+
provenance: import_types56.Provenance.EXTRACTED,
|
|
15922
|
+
confidence: (0, import_types56.confidenceForExtracted)("structural"),
|
|
15796
15923
|
evidence: shape.evidence
|
|
15797
15924
|
};
|
|
15798
15925
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -15806,7 +15933,7 @@ async function addZodShapes(graph, services) {
|
|
|
15806
15933
|
|
|
15807
15934
|
// src/extract/firestore-rules.ts
|
|
15808
15935
|
init_cjs_shims();
|
|
15809
|
-
var
|
|
15936
|
+
var import_types57 = require("@neat.is/types");
|
|
15810
15937
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
15811
15938
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
15812
15939
|
function stripComments(src) {
|
|
@@ -15946,7 +16073,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
15946
16073
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
15947
16074
|
graph.forEachNode((id, attrs) => {
|
|
15948
16075
|
const node = attrs;
|
|
15949
|
-
if (node.type !==
|
|
16076
|
+
if (node.type !== import_types57.NodeType.InfraNode) return;
|
|
15950
16077
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
15951
16078
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
15952
16079
|
if (!fields || fields.size === 0) return;
|
|
@@ -15959,17 +16086,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
15959
16086
|
}
|
|
15960
16087
|
|
|
15961
16088
|
// src/extract/index.ts
|
|
15962
|
-
var
|
|
16089
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
15963
16090
|
|
|
15964
16091
|
// src/extract/retire.ts
|
|
15965
16092
|
init_cjs_shims();
|
|
15966
16093
|
var import_node_fs32 = require("fs");
|
|
15967
|
-
var
|
|
15968
|
-
var
|
|
16094
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
16095
|
+
var import_types58 = require("@neat.is/types");
|
|
15969
16096
|
function dropOrphanedFileNodes(graph) {
|
|
15970
16097
|
const orphans = [];
|
|
15971
16098
|
graph.forEachNode((id, attrs) => {
|
|
15972
|
-
if (attrs.type !==
|
|
16099
|
+
if (attrs.type !== import_types58.NodeType.FileNode) return;
|
|
15973
16100
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
15974
16101
|
orphans.push(id);
|
|
15975
16102
|
}
|
|
@@ -15982,14 +16109,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
15982
16109
|
const bases = [scanPath, ...serviceDirs];
|
|
15983
16110
|
graph.forEachEdge((id, attrs) => {
|
|
15984
16111
|
const edge = attrs;
|
|
15985
|
-
if (edge.provenance !==
|
|
16112
|
+
if (edge.provenance !== import_types58.Provenance.EXTRACTED) return;
|
|
15986
16113
|
const evidenceFile = edge.evidence?.file;
|
|
15987
16114
|
if (!evidenceFile) return;
|
|
15988
|
-
if (
|
|
16115
|
+
if (import_node_path67.default.isAbsolute(evidenceFile)) {
|
|
15989
16116
|
if (!(0, import_node_fs32.existsSync)(evidenceFile)) toDrop.push(id);
|
|
15990
16117
|
return;
|
|
15991
16118
|
}
|
|
15992
|
-
const found = bases.some((base) => (0, import_node_fs32.existsSync)(
|
|
16119
|
+
const found = bases.some((base) => (0, import_node_fs32.existsSync)(import_node_path67.default.join(base, evidenceFile)));
|
|
15993
16120
|
if (!found) toDrop.push(id);
|
|
15994
16121
|
});
|
|
15995
16122
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -16046,7 +16173,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
16046
16173
|
}
|
|
16047
16174
|
const droppedEntries = drainDroppedExtracted();
|
|
16048
16175
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
16049
|
-
const rejectedPath =
|
|
16176
|
+
const rejectedPath = import_node_path68.default.join(import_node_path68.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
16050
16177
|
try {
|
|
16051
16178
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
16052
16179
|
} catch (err) {
|
|
@@ -16081,8 +16208,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
16081
16208
|
// src/persist.ts
|
|
16082
16209
|
init_cjs_shims();
|
|
16083
16210
|
var import_node_fs33 = require("fs");
|
|
16084
|
-
var
|
|
16085
|
-
var
|
|
16211
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
16212
|
+
var import_types59 = require("@neat.is/types");
|
|
16086
16213
|
var SCHEMA_VERSION = 7;
|
|
16087
16214
|
function migrateV1ToV2(payload) {
|
|
16088
16215
|
const nodes = payload.graph.nodes;
|
|
@@ -16106,7 +16233,7 @@ function migrateV5ToV6(payload) {
|
|
|
16106
16233
|
if (Array.isArray(nodes)) {
|
|
16107
16234
|
for (const node of nodes) {
|
|
16108
16235
|
const attrs = node.attributes;
|
|
16109
|
-
if (!attrs || attrs.type !==
|
|
16236
|
+
if (!attrs || attrs.type !== import_types59.NodeType.InfraNode) continue;
|
|
16110
16237
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
16111
16238
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
16112
16239
|
}
|
|
@@ -16122,12 +16249,12 @@ function migrateV2ToV3(payload) {
|
|
|
16122
16249
|
for (const edge of edges) {
|
|
16123
16250
|
const attrs = edge.attributes;
|
|
16124
16251
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
16125
|
-
attrs.provenance =
|
|
16252
|
+
attrs.provenance = import_types59.Provenance.OBSERVED;
|
|
16126
16253
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
16127
16254
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
16128
16255
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
16129
16256
|
if (type && source && target) {
|
|
16130
|
-
const newId = (0,
|
|
16257
|
+
const newId = (0, import_types59.observedEdgeId)(source, target, type);
|
|
16131
16258
|
attrs.id = newId;
|
|
16132
16259
|
if (edge.key) edge.key = newId;
|
|
16133
16260
|
}
|
|
@@ -16136,7 +16263,7 @@ function migrateV2ToV3(payload) {
|
|
|
16136
16263
|
return { ...payload, schemaVersion: 3 };
|
|
16137
16264
|
}
|
|
16138
16265
|
async function ensureDir(filePath) {
|
|
16139
|
-
await import_node_fs33.promises.mkdir(
|
|
16266
|
+
await import_node_fs33.promises.mkdir(import_node_path69.default.dirname(filePath), { recursive: true });
|
|
16140
16267
|
}
|
|
16141
16268
|
async function saveGraphToDisk(graph, outPath) {
|
|
16142
16269
|
await ensureDir(outPath);
|
|
@@ -16228,19 +16355,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
16228
16355
|
init_cjs_shims();
|
|
16229
16356
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
16230
16357
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
16231
|
-
var
|
|
16358
|
+
var import_types100 = require("@neat.is/types");
|
|
16232
16359
|
|
|
16233
16360
|
// src/extend/index.ts
|
|
16234
16361
|
init_cjs_shims();
|
|
16235
16362
|
var import_node_fs35 = require("fs");
|
|
16236
|
-
var
|
|
16363
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
16237
16364
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
16238
16365
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
16239
16366
|
|
|
16240
16367
|
// src/installers/package-manager.ts
|
|
16241
16368
|
init_cjs_shims();
|
|
16242
16369
|
var import_node_fs34 = require("fs");
|
|
16243
|
-
var
|
|
16370
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
16244
16371
|
var import_node_child_process = require("child_process");
|
|
16245
16372
|
var LOCKFILE_PRIORITY = [
|
|
16246
16373
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -16262,22 +16389,22 @@ async function exists2(p) {
|
|
|
16262
16389
|
}
|
|
16263
16390
|
}
|
|
16264
16391
|
async function detectPackageManager(serviceDir) {
|
|
16265
|
-
let dir =
|
|
16392
|
+
let dir = import_node_path70.default.resolve(serviceDir);
|
|
16266
16393
|
const stops = /* @__PURE__ */ new Set();
|
|
16267
16394
|
for (let i = 0; i < 64; i++) {
|
|
16268
16395
|
if (stops.has(dir)) break;
|
|
16269
16396
|
stops.add(dir);
|
|
16270
16397
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
16271
|
-
const lockPath =
|
|
16398
|
+
const lockPath = import_node_path70.default.join(dir, candidate.lockfile);
|
|
16272
16399
|
if (await exists2(lockPath)) {
|
|
16273
16400
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
16274
16401
|
}
|
|
16275
16402
|
}
|
|
16276
|
-
const parent =
|
|
16403
|
+
const parent = import_node_path70.default.dirname(dir);
|
|
16277
16404
|
if (parent === dir) break;
|
|
16278
16405
|
dir = parent;
|
|
16279
16406
|
}
|
|
16280
|
-
return { pm: "npm", cwd:
|
|
16407
|
+
return { pm: "npm", cwd: import_node_path70.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
16281
16408
|
}
|
|
16282
16409
|
async function runPackageManagerInstall(cmd) {
|
|
16283
16410
|
return new Promise((resolve) => {
|
|
@@ -16326,7 +16453,7 @@ async function fileExists2(p) {
|
|
|
16326
16453
|
}
|
|
16327
16454
|
}
|
|
16328
16455
|
async function readPackageJson(scanPath) {
|
|
16329
|
-
const pkgPath =
|
|
16456
|
+
const pkgPath = import_node_path71.default.join(scanPath, "package.json");
|
|
16330
16457
|
const raw = await import_node_fs35.promises.readFile(pkgPath, "utf8");
|
|
16331
16458
|
return JSON.parse(raw);
|
|
16332
16459
|
}
|
|
@@ -16340,27 +16467,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
16340
16467
|
]);
|
|
16341
16468
|
async function findHookFiles(scanPath) {
|
|
16342
16469
|
const found = [];
|
|
16343
|
-
const
|
|
16470
|
+
const walk11 = async (dir) => {
|
|
16344
16471
|
const entries = await import_node_fs35.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
16345
16472
|
for (const entry of entries) {
|
|
16346
16473
|
if (entry.isDirectory()) {
|
|
16347
16474
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
16348
|
-
await
|
|
16475
|
+
await walk11(import_node_path71.default.join(dir, entry.name));
|
|
16349
16476
|
} else if (entry.isFile()) {
|
|
16350
16477
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
16351
|
-
const rel =
|
|
16352
|
-
found.push(rel.split(
|
|
16478
|
+
const rel = import_node_path71.default.relative(scanPath, import_node_path71.default.join(dir, entry.name));
|
|
16479
|
+
found.push(rel.split(import_node_path71.default.sep).join("/"));
|
|
16353
16480
|
}
|
|
16354
16481
|
}
|
|
16355
16482
|
}
|
|
16356
16483
|
};
|
|
16357
|
-
await
|
|
16484
|
+
await walk11(scanPath);
|
|
16358
16485
|
return found.sort();
|
|
16359
16486
|
}
|
|
16360
16487
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
16361
16488
|
let fallback = null;
|
|
16362
16489
|
for (const file of hookFiles) {
|
|
16363
|
-
const content = await import_node_fs35.promises.readFile(
|
|
16490
|
+
const content = await import_node_fs35.promises.readFile(import_node_path71.default.join(scanPath, file), "utf8");
|
|
16364
16491
|
const patched = splicedContent(content, snippet2);
|
|
16365
16492
|
if (patched !== null) return { file, content, patched };
|
|
16366
16493
|
if (fallback === null) fallback = { file, content };
|
|
@@ -16368,11 +16495,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
16368
16495
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
16369
16496
|
}
|
|
16370
16497
|
function extendLogPath() {
|
|
16371
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
16498
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path71.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
16372
16499
|
}
|
|
16373
16500
|
async function appendExtendLog(entry) {
|
|
16374
16501
|
const logPath = extendLogPath();
|
|
16375
|
-
await import_node_fs35.promises.mkdir(
|
|
16502
|
+
await import_node_fs35.promises.mkdir(import_node_path71.default.dirname(logPath), { recursive: true });
|
|
16376
16503
|
await import_node_fs35.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
16377
16504
|
}
|
|
16378
16505
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -16431,7 +16558,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
16431
16558
|
}
|
|
16432
16559
|
async function describeProjectInstrumentation(ctx) {
|
|
16433
16560
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
16434
|
-
const envNeat = await fileExists2(
|
|
16561
|
+
const envNeat = await fileExists2(import_node_path71.default.join(ctx.scanPath, ".env.neat"));
|
|
16435
16562
|
const registryInstrPackages = new Set(
|
|
16436
16563
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
16437
16564
|
);
|
|
@@ -16453,7 +16580,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
16453
16580
|
);
|
|
16454
16581
|
}
|
|
16455
16582
|
for (const file of hookFiles) {
|
|
16456
|
-
const content = await import_node_fs35.promises.readFile(
|
|
16583
|
+
const content = await import_node_fs35.promises.readFile(import_node_path71.default.join(ctx.scanPath, file), "utf8");
|
|
16457
16584
|
if (content.includes(args.registration_snippet)) {
|
|
16458
16585
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
16459
16586
|
}
|
|
@@ -16465,10 +16592,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
16465
16592
|
);
|
|
16466
16593
|
}
|
|
16467
16594
|
const primaryFile = primary.file;
|
|
16468
|
-
const primaryPath =
|
|
16595
|
+
const primaryPath = import_node_path71.default.join(ctx.scanPath, primaryFile);
|
|
16469
16596
|
const filesTouched = [];
|
|
16470
16597
|
const depsAdded = [];
|
|
16471
|
-
const pkgPath =
|
|
16598
|
+
const pkgPath = import_node_path71.default.join(ctx.scanPath, "package.json");
|
|
16472
16599
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
16473
16600
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
16474
16601
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -16507,7 +16634,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
16507
16634
|
};
|
|
16508
16635
|
}
|
|
16509
16636
|
for (const file of hookFiles) {
|
|
16510
|
-
const content = await import_node_fs35.promises.readFile(
|
|
16637
|
+
const content = await import_node_fs35.promises.readFile(import_node_path71.default.join(ctx.scanPath, file), "utf8");
|
|
16511
16638
|
if (content.includes(args.registration_snippet)) {
|
|
16512
16639
|
return {
|
|
16513
16640
|
library: args.library,
|
|
@@ -16548,7 +16675,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
16548
16675
|
if (!match) {
|
|
16549
16676
|
return { undone: false, message: "no apply found for library" };
|
|
16550
16677
|
}
|
|
16551
|
-
const pkgPath =
|
|
16678
|
+
const pkgPath = import_node_path71.default.join(ctx.scanPath, "package.json");
|
|
16552
16679
|
if (await fileExists2(pkgPath)) {
|
|
16553
16680
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
16554
16681
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -16559,7 +16686,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
16559
16686
|
}
|
|
16560
16687
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
16561
16688
|
for (const file of hookFiles) {
|
|
16562
|
-
const filePath =
|
|
16689
|
+
const filePath = import_node_path71.default.join(ctx.scanPath, file);
|
|
16563
16690
|
const content = await import_node_fs35.promises.readFile(filePath, "utf8");
|
|
16564
16691
|
if (content.includes(match.registration_snippet)) {
|
|
16565
16692
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -16575,39 +16702,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
16575
16702
|
|
|
16576
16703
|
// src/divergences.ts
|
|
16577
16704
|
init_cjs_shims();
|
|
16578
|
-
var
|
|
16705
|
+
var import_types60 = require("@neat.is/types");
|
|
16579
16706
|
function bucketKey(source, target, type) {
|
|
16580
16707
|
return `${type}|${source}|${target}`;
|
|
16581
16708
|
}
|
|
16582
16709
|
function bucketSourceFor(graph, edge) {
|
|
16583
|
-
if (edge.type !==
|
|
16584
|
-
const parsed = (0,
|
|
16710
|
+
if (edge.type !== import_types60.EdgeType.CONNECTS_TO) return edge.source;
|
|
16711
|
+
const parsed = (0, import_types60.parseFileId)(edge.source);
|
|
16585
16712
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
16586
16713
|
const target = graph.getNodeAttributes(edge.target);
|
|
16587
|
-
if (target.type !==
|
|
16588
|
-
return (0,
|
|
16714
|
+
if (target.type !== import_types60.NodeType.DatabaseNode) return edge.source;
|
|
16715
|
+
return (0, import_types60.serviceId)(parsed.service);
|
|
16589
16716
|
}
|
|
16590
16717
|
function bucketEdges(graph) {
|
|
16591
16718
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
16592
16719
|
graph.forEachEdge((id, attrs) => {
|
|
16593
16720
|
const e = attrs;
|
|
16594
|
-
const parsed = (0,
|
|
16721
|
+
const parsed = (0, import_types60.parseEdgeId)(id);
|
|
16595
16722
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
16596
16723
|
const source = bucketSourceFor(graph, e);
|
|
16597
16724
|
const key = bucketKey(source, e.target, e.type);
|
|
16598
16725
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
16599
16726
|
switch (provenance) {
|
|
16600
|
-
case
|
|
16727
|
+
case import_types60.Provenance.EXTRACTED:
|
|
16601
16728
|
cur.extracted = e;
|
|
16602
16729
|
break;
|
|
16603
|
-
case
|
|
16730
|
+
case import_types60.Provenance.OBSERVED:
|
|
16604
16731
|
cur.observed = e;
|
|
16605
16732
|
break;
|
|
16606
|
-
case
|
|
16733
|
+
case import_types60.Provenance.INFERRED:
|
|
16607
16734
|
cur.inferred = e;
|
|
16608
16735
|
break;
|
|
16609
16736
|
default:
|
|
16610
|
-
if (e.provenance ===
|
|
16737
|
+
if (e.provenance === import_types60.Provenance.STALE) cur.stale = e;
|
|
16611
16738
|
}
|
|
16612
16739
|
buckets2.set(key, cur);
|
|
16613
16740
|
});
|
|
@@ -16616,22 +16743,22 @@ function bucketEdges(graph) {
|
|
|
16616
16743
|
function nodeIsFrontier(graph, nodeId) {
|
|
16617
16744
|
if (!graph.hasNode(nodeId)) return false;
|
|
16618
16745
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
16619
|
-
return attrs.type ===
|
|
16746
|
+
return attrs.type === import_types60.NodeType.FrontierNode;
|
|
16620
16747
|
}
|
|
16621
16748
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
16622
16749
|
if (!graph.hasNode(nodeId)) return false;
|
|
16623
16750
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
16624
|
-
return attrs.type ===
|
|
16751
|
+
return attrs.type === import_types60.NodeType.WebSocketChannelNode;
|
|
16625
16752
|
}
|
|
16626
16753
|
function nodeIsServerAction(graph, nodeId) {
|
|
16627
16754
|
if (!graph.hasNode(nodeId)) return false;
|
|
16628
16755
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
16629
|
-
return attrs.type ===
|
|
16756
|
+
return attrs.type === import_types60.NodeType.ServerActionNode;
|
|
16630
16757
|
}
|
|
16631
16758
|
function nodeIsSymbol(graph, nodeId) {
|
|
16632
16759
|
if (!graph.hasNode(nodeId)) return false;
|
|
16633
16760
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
16634
|
-
return attrs.type ===
|
|
16761
|
+
return attrs.type === import_types60.NodeType.SymbolNode;
|
|
16635
16762
|
}
|
|
16636
16763
|
function clampConfidence(n) {
|
|
16637
16764
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -16651,14 +16778,14 @@ function gradedConfidence(edge) {
|
|
|
16651
16778
|
return clampConfidence(confidenceForEdge(edge));
|
|
16652
16779
|
}
|
|
16653
16780
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
16654
|
-
|
|
16655
|
-
|
|
16656
|
-
|
|
16657
|
-
|
|
16781
|
+
import_types60.EdgeType.CALLS,
|
|
16782
|
+
import_types60.EdgeType.CONNECTS_TO,
|
|
16783
|
+
import_types60.EdgeType.PUBLISHES_TO,
|
|
16784
|
+
import_types60.EdgeType.CONSUMES_FROM
|
|
16658
16785
|
]);
|
|
16659
16786
|
function detectMissingDivergences(graph, bucket) {
|
|
16660
16787
|
const out = [];
|
|
16661
|
-
if (bucket.type ===
|
|
16788
|
+
if (bucket.type === import_types60.EdgeType.CONTAINS) return out;
|
|
16662
16789
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
16663
16790
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
16664
16791
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -16700,7 +16827,7 @@ function declaredHostFor(svc) {
|
|
|
16700
16827
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
16701
16828
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
16702
16829
|
const e = graph.getEdgeAttributes(edgeId);
|
|
16703
|
-
if (e.type ===
|
|
16830
|
+
if (e.type === import_types60.EdgeType.CONFIGURED_BY && e.provenance === import_types60.Provenance.EXTRACTED) {
|
|
16704
16831
|
return true;
|
|
16705
16832
|
}
|
|
16706
16833
|
}
|
|
@@ -16713,10 +16840,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
16713
16840
|
const out = [];
|
|
16714
16841
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
16715
16842
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
16716
|
-
if (edge.type !==
|
|
16717
|
-
if (edge.provenance !==
|
|
16843
|
+
if (edge.type !== import_types60.EdgeType.CONNECTS_TO) continue;
|
|
16844
|
+
if (edge.provenance !== import_types60.Provenance.OBSERVED) continue;
|
|
16718
16845
|
const target = graph.getNodeAttributes(edge.target);
|
|
16719
|
-
if (target.type !==
|
|
16846
|
+
if (target.type !== import_types60.NodeType.DatabaseNode) continue;
|
|
16720
16847
|
const observedHost = target.host?.trim();
|
|
16721
16848
|
if (!observedHost) continue;
|
|
16722
16849
|
if (observedHost === declaredHost) continue;
|
|
@@ -16738,10 +16865,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
16738
16865
|
const deps = svc.dependencies ?? {};
|
|
16739
16866
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
16740
16867
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
16741
|
-
if (edge.type !==
|
|
16742
|
-
if (edge.provenance !==
|
|
16868
|
+
if (edge.type !== import_types60.EdgeType.CONNECTS_TO) continue;
|
|
16869
|
+
if (edge.provenance !== import_types60.Provenance.OBSERVED) continue;
|
|
16743
16870
|
const target = graph.getNodeAttributes(edge.target);
|
|
16744
|
-
if (target.type !==
|
|
16871
|
+
if (target.type !== import_types60.NodeType.DatabaseNode) continue;
|
|
16745
16872
|
for (const pair of compatPairs()) {
|
|
16746
16873
|
if (pair.engine !== target.engine) continue;
|
|
16747
16874
|
const declared = deps[pair.driver];
|
|
@@ -16885,11 +17012,11 @@ function symbolLocus(graph, ev) {
|
|
|
16885
17012
|
const location = filepath ? `${filepath}${lineno !== void 0 ? `:${lineno}` : ""}` : void 0;
|
|
16886
17013
|
const affected = ev.affectedNode;
|
|
16887
17014
|
const affectedInGraph = affected.length > 0 && graph.hasNode(affected);
|
|
16888
|
-
const affectedIsCode = affectedInGraph && ((0,
|
|
17015
|
+
const affectedIsCode = affectedInGraph && ((0, import_types60.parseSymbolId)(affected) !== null || (0, import_types60.parseFileId)(affected) !== null);
|
|
16889
17016
|
if (affectedIsCode) return { node: affected, ...location ? { location } : {} };
|
|
16890
17017
|
if (!location) return null;
|
|
16891
17018
|
if (affectedInGraph) return { node: affected, location };
|
|
16892
|
-
const svc = (0,
|
|
17019
|
+
const svc = (0, import_types60.serviceId)(ev.service);
|
|
16893
17020
|
if (graph.hasNode(svc)) return { node: svc, location };
|
|
16894
17021
|
return null;
|
|
16895
17022
|
}
|
|
@@ -16932,7 +17059,7 @@ function detectSymbolMismatches(graph, incidents) {
|
|
|
16932
17059
|
mismatchKind: g.kind,
|
|
16933
17060
|
...g.symbol ? { symbol: g.symbol } : {},
|
|
16934
17061
|
...g.location ? { location: g.location } : {},
|
|
16935
|
-
provenance:
|
|
17062
|
+
provenance: import_types60.Provenance.INFERRED,
|
|
16936
17063
|
incidentId: g.latest.id,
|
|
16937
17064
|
errorMessage: g.latest.errorMessage,
|
|
16938
17065
|
incidentCount: g.count,
|
|
@@ -16949,7 +17076,7 @@ var OBSERVED_FAILING_CONFIDENCE = 0.6;
|
|
|
16949
17076
|
function detectObservedFailingEdge(graph, bucket) {
|
|
16950
17077
|
if (!bucket.extracted || !bucket.observed) return [];
|
|
16951
17078
|
if (!OBSERVABLE_EDGE_TYPES.has(bucket.type)) return [];
|
|
16952
|
-
if (bucket.observed.provenance !==
|
|
17079
|
+
if (bucket.observed.provenance !== import_types60.Provenance.OBSERVED) return [];
|
|
16953
17080
|
const signal = bucket.observed.signal;
|
|
16954
17081
|
if (!signal) return [];
|
|
16955
17082
|
const { spanCount, errorCount } = signal;
|
|
@@ -16963,7 +17090,7 @@ function detectObservedFailingEdge(graph, bucket) {
|
|
|
16963
17090
|
source: bucket.source,
|
|
16964
17091
|
target: bucket.target,
|
|
16965
17092
|
failureKind: "error-rate",
|
|
16966
|
-
provenance:
|
|
17093
|
+
provenance: import_types60.Provenance.INFERRED,
|
|
16967
17094
|
edgeType: bucket.type,
|
|
16968
17095
|
observed: bucket.observed,
|
|
16969
17096
|
spanCount,
|
|
@@ -17063,7 +17190,7 @@ function detectObservedFailingIncidents(graph, incidents) {
|
|
|
17063
17190
|
source: g.node,
|
|
17064
17191
|
target: g.node,
|
|
17065
17192
|
failureKind: g.kind,
|
|
17066
|
-
provenance:
|
|
17193
|
+
provenance: import_types60.Provenance.INFERRED,
|
|
17067
17194
|
...g.location ? { location: g.location } : {},
|
|
17068
17195
|
incidentId: g.latest.id,
|
|
17069
17196
|
errorMessage: g.latest.errorMessage,
|
|
@@ -17082,24 +17209,24 @@ function involvesNode(d, nodeId) {
|
|
|
17082
17209
|
function datastoreEverObserved(graph, nodeId) {
|
|
17083
17210
|
if (!graph.hasNode(nodeId)) return false;
|
|
17084
17211
|
const n = graph.getNodeAttributes(nodeId);
|
|
17085
|
-
if (n.type ===
|
|
17212
|
+
if (n.type === import_types60.NodeType.DatabaseNode) {
|
|
17086
17213
|
const via = n.discoveredVia;
|
|
17087
17214
|
if (via === "otel" || via === "merged") return true;
|
|
17088
17215
|
}
|
|
17089
17216
|
for (const edgeId of graph.inboundEdges(nodeId)) {
|
|
17090
17217
|
const e = graph.getEdgeAttributes(edgeId);
|
|
17091
|
-
if (e.provenance ===
|
|
17218
|
+
if (e.provenance === import_types60.Provenance.OBSERVED || e.provenance === import_types60.Provenance.STALE) return true;
|
|
17092
17219
|
}
|
|
17093
17220
|
return false;
|
|
17094
17221
|
}
|
|
17095
|
-
function serviceHasObservedSameEngineStore(graph, buckets2,
|
|
17222
|
+
function serviceHasObservedSameEngineStore(graph, buckets2, serviceId17, engine, excludeTarget) {
|
|
17096
17223
|
for (const bucket of buckets2.values()) {
|
|
17097
|
-
if (bucket.type !==
|
|
17098
|
-
if (bucket.source !==
|
|
17224
|
+
if (bucket.type !== import_types60.EdgeType.CONNECTS_TO) continue;
|
|
17225
|
+
if (bucket.source !== serviceId17) continue;
|
|
17099
17226
|
if (bucket.target === excludeTarget) continue;
|
|
17100
17227
|
if (!graph.hasNode(bucket.target)) continue;
|
|
17101
17228
|
const target = graph.getNodeAttributes(bucket.target);
|
|
17102
|
-
if (target.type !==
|
|
17229
|
+
if (target.type !== import_types60.NodeType.DatabaseNode) continue;
|
|
17103
17230
|
if (target.engine !== engine) continue;
|
|
17104
17231
|
if (bucket.observed || datastoreEverObserved(graph, bucket.target)) return true;
|
|
17105
17232
|
}
|
|
@@ -17109,10 +17236,10 @@ var DEAD_CODE_PROBE_CONFIDENCE = 0.1;
|
|
|
17109
17236
|
function dampenDeadCodeProbes(graph, buckets2, all) {
|
|
17110
17237
|
return all.map((d) => {
|
|
17111
17238
|
if (d.type !== "missing-observed") return d;
|
|
17112
|
-
if (!d.extracted || d.edgeType !==
|
|
17239
|
+
if (!d.extracted || d.edgeType !== import_types60.EdgeType.CONNECTS_TO) return d;
|
|
17113
17240
|
if (!graph.hasNode(d.target)) return d;
|
|
17114
17241
|
const target = graph.getNodeAttributes(d.target);
|
|
17115
|
-
if (target.type !==
|
|
17242
|
+
if (target.type !== import_types60.NodeType.DatabaseNode) return d;
|
|
17116
17243
|
if (d.extracted.evidence?.hostSource !== "literal") return d;
|
|
17117
17244
|
if (datastoreEverObserved(graph, d.target)) return d;
|
|
17118
17245
|
const engine = target.engine;
|
|
@@ -17132,7 +17259,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
17132
17259
|
for (const d of all) {
|
|
17133
17260
|
if (d.type !== "host-mismatch") continue;
|
|
17134
17261
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
17135
|
-
declaredHalf.add((0,
|
|
17262
|
+
declaredHalf.add((0, import_types60.databaseId)(d.extractedHost));
|
|
17136
17263
|
}
|
|
17137
17264
|
if (observedHalf.size === 0) return all;
|
|
17138
17265
|
return all.filter((d) => {
|
|
@@ -17152,13 +17279,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
17152
17279
|
}
|
|
17153
17280
|
graph.forEachNode((nodeId, attrs) => {
|
|
17154
17281
|
const n = attrs;
|
|
17155
|
-
if (n.type ===
|
|
17282
|
+
if (n.type === import_types60.NodeType.ServiceNode) {
|
|
17156
17283
|
const svc = n;
|
|
17157
17284
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
17158
17285
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
17159
17286
|
return;
|
|
17160
17287
|
}
|
|
17161
|
-
if (n.type ===
|
|
17288
|
+
if (n.type === import_types60.NodeType.InfraNode && n.kind === "sql-table") {
|
|
17162
17289
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
17163
17290
|
}
|
|
17164
17291
|
});
|
|
@@ -17218,7 +17345,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
17218
17345
|
const bloc = "location" in b && b.location ? b.location : "";
|
|
17219
17346
|
return aloc.localeCompare(bloc);
|
|
17220
17347
|
});
|
|
17221
|
-
return
|
|
17348
|
+
return import_types60.DivergenceResultSchema.parse({
|
|
17222
17349
|
divergences: filtered,
|
|
17223
17350
|
totalAffected: filtered.length,
|
|
17224
17351
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -17272,7 +17399,7 @@ function queryLogEntries(opts) {
|
|
|
17272
17399
|
|
|
17273
17400
|
// src/goodybag.ts
|
|
17274
17401
|
init_cjs_shims();
|
|
17275
|
-
var
|
|
17402
|
+
var import_types61 = require("@neat.is/types");
|
|
17276
17403
|
var CODE_FILEPATH_ATTR2 = "code.filepath";
|
|
17277
17404
|
var CODE_LINENO_ATTR2 = "code.lineno";
|
|
17278
17405
|
var BLAST_NEAREST_LIMIT = 5;
|
|
@@ -17297,7 +17424,7 @@ function locusOf(graph, ev) {
|
|
|
17297
17424
|
...Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {},
|
|
17298
17425
|
...node?.name ? { symbol: node.name } : {},
|
|
17299
17426
|
service: node?.service ?? ev.service,
|
|
17300
|
-
provenance:
|
|
17427
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17301
17428
|
};
|
|
17302
17429
|
}
|
|
17303
17430
|
function locusFromNode(graph, nodeId) {
|
|
@@ -17313,7 +17440,7 @@ function locusFromNode(graph, nodeId) {
|
|
|
17313
17440
|
...typeof end === "number" ? { lineEnd: end } : {},
|
|
17314
17441
|
...n.qualname ? { symbol: shortLabel(graph, nodeId) } : {},
|
|
17315
17442
|
...n.service ? { service: n.service } : {},
|
|
17316
|
-
provenance:
|
|
17443
|
+
provenance: import_types61.Provenance.INFERRED
|
|
17317
17444
|
};
|
|
17318
17445
|
}
|
|
17319
17446
|
function promoteCauseLocus(graph, causeNode, incidents) {
|
|
@@ -17322,7 +17449,7 @@ function promoteCauseLocus(graph, causeNode, incidents) {
|
|
|
17322
17449
|
);
|
|
17323
17450
|
if (native) {
|
|
17324
17451
|
const l = locusOf(graph, native);
|
|
17325
|
-
if (l) return { ...l, symbol: shortLabel(graph, causeNode), provenance:
|
|
17452
|
+
if (l) return { ...l, symbol: shortLabel(graph, causeNode), provenance: import_types61.Provenance.INFERRED };
|
|
17326
17453
|
}
|
|
17327
17454
|
return locusFromNode(graph, causeNode);
|
|
17328
17455
|
}
|
|
@@ -17371,7 +17498,7 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
|
17371
17498
|
const chain = (rc.traversalPath ?? []).map((node, i) => ({
|
|
17372
17499
|
node,
|
|
17373
17500
|
grain: grainOf2(graph, node),
|
|
17374
|
-
provenance: provs[i] ?? provs[provs.length - 1] ??
|
|
17501
|
+
provenance: provs[i] ?? provs[provs.length - 1] ?? import_types61.Provenance.INFERRED
|
|
17375
17502
|
}));
|
|
17376
17503
|
rootCause = {
|
|
17377
17504
|
node: rc.rootCauseNode,
|
|
@@ -17401,7 +17528,7 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
|
17401
17528
|
kind: "incident",
|
|
17402
17529
|
id: errorEvent.id,
|
|
17403
17530
|
at: errorEvent.timestamp,
|
|
17404
|
-
incidentKind: (0,
|
|
17531
|
+
incidentKind: (0, import_types61.incidentKindOf)(errorEvent),
|
|
17405
17532
|
service: errorEvent.service,
|
|
17406
17533
|
affectedNode: affected,
|
|
17407
17534
|
message: errorEvent.errorMessage,
|
|
@@ -17418,12 +17545,12 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
|
17418
17545
|
...divergences.length > 0 ? { divergence: divergences } : {},
|
|
17419
17546
|
headline: renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)
|
|
17420
17547
|
};
|
|
17421
|
-
return
|
|
17548
|
+
return import_types61.IncidentCardSchema.parse(card);
|
|
17422
17549
|
}
|
|
17423
17550
|
|
|
17424
17551
|
// src/ask.ts
|
|
17425
17552
|
init_cjs_shims();
|
|
17426
|
-
var
|
|
17553
|
+
var import_types62 = require("@neat.is/types");
|
|
17427
17554
|
var DEFAULT_MAX_NODES = 3;
|
|
17428
17555
|
var MAX_FACTS_PER_SECTION = 6;
|
|
17429
17556
|
var INTENT_RULES = [
|
|
@@ -17651,18 +17778,18 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17651
17778
|
};
|
|
17652
17779
|
graph.forEachNode((id, attrs) => {
|
|
17653
17780
|
const node = attrs;
|
|
17654
|
-
if (node.type ===
|
|
17781
|
+
if (node.type === import_types62.NodeType.FrontierNode) return;
|
|
17655
17782
|
const name = nodeName(node);
|
|
17656
17783
|
const body = idBody(id);
|
|
17657
17784
|
const labelTokens = /* @__PURE__ */ new Set([...tokens(body), ...tokens(name)]);
|
|
17658
17785
|
if (labelTokens.size === 0) return;
|
|
17659
17786
|
let matched = 0;
|
|
17660
17787
|
for (const t of qTokens) if (labelTokens.has(t)) matched += 1;
|
|
17661
|
-
const
|
|
17662
|
-
if (matched === 0 && !
|
|
17788
|
+
const named2 = body.length >= 2 && normalized.includes(body.toLowerCase()) || name.length >= 2 && normalized.includes(name.toLowerCase());
|
|
17789
|
+
if (matched === 0 && !named2) return;
|
|
17663
17790
|
const coverage = qTokens.length > 0 ? matched / qTokens.length : 0;
|
|
17664
|
-
const via =
|
|
17665
|
-
const score =
|
|
17791
|
+
const via = named2 ? "id" : matched > 0 && tokens(name).some((t) => qTokens.includes(t)) ? "label" : "token";
|
|
17792
|
+
const score = named2 ? Math.max(0.9, coverage) : Math.min(0.85, 0.3 + 0.7 * coverage);
|
|
17666
17793
|
consider({ nodeId: id, label: name, via, score: Math.min(1, score) });
|
|
17667
17794
|
});
|
|
17668
17795
|
if (searchIndex) {
|
|
@@ -17670,7 +17797,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17670
17797
|
const res = await searchIndex.search(question, 10);
|
|
17671
17798
|
if (res.provider !== "substring") {
|
|
17672
17799
|
for (const m of res.matches) {
|
|
17673
|
-
if (m.node.type ===
|
|
17800
|
+
if (m.node.type === import_types62.NodeType.FrontierNode) continue;
|
|
17674
17801
|
const already = best.get(m.node.id);
|
|
17675
17802
|
if (!already && m.score < EMBED_MIN_SCORE) continue;
|
|
17676
17803
|
consider({
|
|
@@ -17708,7 +17835,7 @@ function edgeSignalNote(e) {
|
|
|
17708
17835
|
function buildRootCauseSection(graph, node, incidents, now) {
|
|
17709
17836
|
const result = getRootCause(graph, node, void 0, incidents, { now });
|
|
17710
17837
|
if (!result) return null;
|
|
17711
|
-
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ??
|
|
17838
|
+
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types62.Provenance.OBSERVED;
|
|
17712
17839
|
const facts = [
|
|
17713
17840
|
{
|
|
17714
17841
|
text: `Root cause: ${result.rootCauseNode} \u2014 ${result.rootCauseReason}`,
|
|
@@ -17758,7 +17885,7 @@ function buildObservedSection(graph, node) {
|
|
|
17758
17885
|
if (result.observed && result.inboundObservedCount > 0) {
|
|
17759
17886
|
facts.push({
|
|
17760
17887
|
text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 a pure receiver`,
|
|
17761
|
-
provenance:
|
|
17888
|
+
provenance: import_types62.Provenance.OBSERVED
|
|
17762
17889
|
});
|
|
17763
17890
|
} else {
|
|
17764
17891
|
return null;
|
|
@@ -17786,7 +17913,7 @@ function buildIncidentsSection(node, incidents) {
|
|
|
17786
17913
|
const facts = ordered.map((ev) => ({
|
|
17787
17914
|
text: `${ev.timestamp} \u2014 ${ev.service}: ${ev.errorMessage}`,
|
|
17788
17915
|
// ErrorEvents are observation records — OBSERVED by definition.
|
|
17789
|
-
provenance:
|
|
17916
|
+
provenance: import_types62.Provenance.OBSERVED
|
|
17790
17917
|
}));
|
|
17791
17918
|
return { heading: `Recent incidents (OBSERVED) \u2014 ${relevant.length} recorded`, facts };
|
|
17792
17919
|
}
|
|
@@ -17846,7 +17973,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17846
17973
|
}
|
|
17847
17974
|
const byKey = /* @__PURE__ */ new Map();
|
|
17848
17975
|
for (const ev of incidents) {
|
|
17849
|
-
const key = ev.affectedNode || (0,
|
|
17976
|
+
const key = ev.affectedNode || (0, import_types62.serviceId)(ev.service);
|
|
17850
17977
|
const cur = byKey.get(key);
|
|
17851
17978
|
if (!cur) {
|
|
17852
17979
|
byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
|
|
@@ -17861,7 +17988,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17861
17988
|
const rows = [...byKey.values()].sort((a, b) => b.count - a.count || b.latest.localeCompare(a.latest) || a.key.localeCompare(b.key)).slice(0, MAX_FACTS_PER_SECTION);
|
|
17862
17989
|
const facts = rows.map((r) => ({
|
|
17863
17990
|
text: `${r.key} \u2014 ${r.count} incident${r.count === 1 ? "" : "s"}, latest ${r.latest}: ${r.sampleMsg}`,
|
|
17864
|
-
provenance:
|
|
17991
|
+
provenance: import_types62.Provenance.OBSERVED
|
|
17865
17992
|
}));
|
|
17866
17993
|
return {
|
|
17867
17994
|
heading: `Incidents across the system \u2014 ${incidents.length} recorded`,
|
|
@@ -17874,7 +18001,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17874
18001
|
graph.forEachNode((_id, attrs) => {
|
|
17875
18002
|
const node = attrs;
|
|
17876
18003
|
nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1);
|
|
17877
|
-
if (node.type ===
|
|
18004
|
+
if (node.type === import_types62.NodeType.ServiceNode) services.push(node.id);
|
|
17878
18005
|
});
|
|
17879
18006
|
const edgeByProv = /* @__PURE__ */ new Map();
|
|
17880
18007
|
graph.forEachEdge((_id, attrs) => {
|
|
@@ -17886,10 +18013,10 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17886
18013
|
const shapeFacts = [
|
|
17887
18014
|
{ text: `${graph.order} nodes, ${graph.size} edges` },
|
|
17888
18015
|
{
|
|
17889
|
-
text: `${count(
|
|
18016
|
+
text: `${count(import_types62.NodeType.ServiceNode)} services, ${count(import_types62.NodeType.FileNode)} files, ${count(import_types62.NodeType.SymbolNode)} symbols, ${count(import_types62.NodeType.DatabaseNode)} databases`
|
|
17890
18017
|
}
|
|
17891
18018
|
];
|
|
17892
|
-
for (const p of [
|
|
18019
|
+
for (const p of [import_types62.Provenance.EXTRACTED, import_types62.Provenance.OBSERVED, import_types62.Provenance.INFERRED, import_types62.Provenance.STALE]) {
|
|
17893
18020
|
const n = edgeByProv.get(p) ?? 0;
|
|
17894
18021
|
if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? "" : "s"}`, provenance: p });
|
|
17895
18022
|
}
|
|
@@ -17906,7 +18033,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17906
18033
|
if (incidents && incidents.length > 0) {
|
|
17907
18034
|
const incCount = /* @__PURE__ */ new Map();
|
|
17908
18035
|
for (const ev of incidents) {
|
|
17909
|
-
const key = ev.affectedNode || (0,
|
|
18036
|
+
const key = ev.affectedNode || (0, import_types62.serviceId)(ev.service);
|
|
17910
18037
|
incCount.set(key, (incCount.get(key) ?? 0) + 1);
|
|
17911
18038
|
}
|
|
17912
18039
|
const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
|
|
@@ -17914,7 +18041,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17914
18041
|
heading: `Nodes with incidents \u2014 ${incidents.length} recorded`,
|
|
17915
18042
|
facts: top.map(([k, n]) => ({
|
|
17916
18043
|
text: `${k} \u2014 ${n} incident${n === 1 ? "" : "s"}`,
|
|
17917
|
-
provenance:
|
|
18044
|
+
provenance: import_types62.Provenance.OBSERVED
|
|
17918
18045
|
}))
|
|
17919
18046
|
});
|
|
17920
18047
|
}
|
|
@@ -18050,7 +18177,7 @@ async function askGraph(graph, question, opts = {}) {
|
|
|
18050
18177
|
const provSet = /* @__PURE__ */ new Set();
|
|
18051
18178
|
for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance);
|
|
18052
18179
|
const confidence = sections[0]?.facts[0]?.confidence;
|
|
18053
|
-
return
|
|
18180
|
+
return import_types62.AskResultSchema.parse({
|
|
18054
18181
|
question,
|
|
18055
18182
|
intent,
|
|
18056
18183
|
matched,
|
|
@@ -18142,23 +18269,23 @@ function canonicalJson(value) {
|
|
|
18142
18269
|
|
|
18143
18270
|
// src/projects.ts
|
|
18144
18271
|
init_cjs_shims();
|
|
18145
|
-
var
|
|
18272
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
18146
18273
|
function pathsForProject(project, baseDir) {
|
|
18147
18274
|
if (project === DEFAULT_PROJECT) {
|
|
18148
18275
|
return {
|
|
18149
|
-
snapshotPath:
|
|
18150
|
-
errorsPath:
|
|
18151
|
-
staleEventsPath:
|
|
18152
|
-
embeddingsCachePath:
|
|
18153
|
-
policyViolationsPath:
|
|
18276
|
+
snapshotPath: import_node_path72.default.join(baseDir, "graph.json"),
|
|
18277
|
+
errorsPath: import_node_path72.default.join(baseDir, "errors.ndjson"),
|
|
18278
|
+
staleEventsPath: import_node_path72.default.join(baseDir, "stale-events.ndjson"),
|
|
18279
|
+
embeddingsCachePath: import_node_path72.default.join(baseDir, "embeddings.json"),
|
|
18280
|
+
policyViolationsPath: import_node_path72.default.join(baseDir, "policy-violations.ndjson")
|
|
18154
18281
|
};
|
|
18155
18282
|
}
|
|
18156
18283
|
return {
|
|
18157
|
-
snapshotPath:
|
|
18158
|
-
errorsPath:
|
|
18159
|
-
staleEventsPath:
|
|
18160
|
-
embeddingsCachePath:
|
|
18161
|
-
policyViolationsPath:
|
|
18284
|
+
snapshotPath: import_node_path72.default.join(baseDir, `${project}.json`),
|
|
18285
|
+
errorsPath: import_node_path72.default.join(baseDir, `errors.${project}.ndjson`),
|
|
18286
|
+
staleEventsPath: import_node_path72.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
18287
|
+
embeddingsCachePath: import_node_path72.default.join(baseDir, `embeddings.${project}.json`),
|
|
18288
|
+
policyViolationsPath: import_node_path72.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
18162
18289
|
};
|
|
18163
18290
|
}
|
|
18164
18291
|
var Projects = class {
|
|
@@ -18196,26 +18323,26 @@ var Projects = class {
|
|
|
18196
18323
|
init_cjs_shims();
|
|
18197
18324
|
var import_node_fs37 = require("fs");
|
|
18198
18325
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
18199
|
-
var
|
|
18200
|
-
var
|
|
18326
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
18327
|
+
var import_types63 = require("@neat.is/types");
|
|
18201
18328
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
18202
18329
|
var LOCK_RETRY_MS = 50;
|
|
18203
18330
|
function neatHome() {
|
|
18204
18331
|
const override = process.env.NEAT_HOME;
|
|
18205
|
-
if (override && override.length > 0) return
|
|
18206
|
-
return
|
|
18332
|
+
if (override && override.length > 0) return import_node_path73.default.resolve(override);
|
|
18333
|
+
return import_node_path73.default.join(import_node_os3.default.homedir(), ".neat");
|
|
18207
18334
|
}
|
|
18208
18335
|
function registryPath() {
|
|
18209
|
-
return
|
|
18336
|
+
return import_node_path73.default.join(neatHome(), "projects.json");
|
|
18210
18337
|
}
|
|
18211
18338
|
function registryLockPath() {
|
|
18212
|
-
return
|
|
18339
|
+
return import_node_path73.default.join(neatHome(), "projects.json.lock");
|
|
18213
18340
|
}
|
|
18214
18341
|
function daemonPidPath() {
|
|
18215
|
-
return
|
|
18342
|
+
return import_node_path73.default.join(neatHome(), "neatd.pid");
|
|
18216
18343
|
}
|
|
18217
18344
|
function daemonsDir() {
|
|
18218
|
-
return
|
|
18345
|
+
return import_node_path73.default.join(neatHome(), "daemons");
|
|
18219
18346
|
}
|
|
18220
18347
|
function isFiniteInt(v) {
|
|
18221
18348
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -18256,7 +18383,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
18256
18383
|
const out = [];
|
|
18257
18384
|
for (const name of names) {
|
|
18258
18385
|
if (!name.endsWith(".json")) continue;
|
|
18259
|
-
const file =
|
|
18386
|
+
const file = import_node_path73.default.join(dir, name);
|
|
18260
18387
|
let raw;
|
|
18261
18388
|
try {
|
|
18262
18389
|
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
@@ -18333,7 +18460,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
18333
18460
|
}
|
|
18334
18461
|
}
|
|
18335
18462
|
async function normalizeProjectPath(input) {
|
|
18336
|
-
const resolved =
|
|
18463
|
+
const resolved = import_node_path73.default.resolve(input);
|
|
18337
18464
|
try {
|
|
18338
18465
|
return await import_node_fs37.promises.realpath(resolved);
|
|
18339
18466
|
} catch {
|
|
@@ -18341,7 +18468,7 @@ async function normalizeProjectPath(input) {
|
|
|
18341
18468
|
}
|
|
18342
18469
|
}
|
|
18343
18470
|
async function writeAtomically(target, contents) {
|
|
18344
|
-
await import_node_fs37.promises.mkdir(
|
|
18471
|
+
await import_node_fs37.promises.mkdir(import_node_path73.default.dirname(target), { recursive: true });
|
|
18345
18472
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
18346
18473
|
const fd = await import_node_fs37.promises.open(tmp, "w");
|
|
18347
18474
|
try {
|
|
@@ -18354,7 +18481,7 @@ async function writeAtomically(target, contents) {
|
|
|
18354
18481
|
}
|
|
18355
18482
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
18356
18483
|
const deadline = Date.now() + timeoutMs;
|
|
18357
|
-
await import_node_fs37.promises.mkdir(
|
|
18484
|
+
await import_node_fs37.promises.mkdir(import_node_path73.default.dirname(lockPath), { recursive: true });
|
|
18358
18485
|
let probedHolder = false;
|
|
18359
18486
|
while (true) {
|
|
18360
18487
|
try {
|
|
@@ -18407,10 +18534,10 @@ async function readRegistry() {
|
|
|
18407
18534
|
throw err;
|
|
18408
18535
|
}
|
|
18409
18536
|
const parsed = JSON.parse(raw);
|
|
18410
|
-
return
|
|
18537
|
+
return import_types63.RegistryFileSchema.parse(parsed);
|
|
18411
18538
|
}
|
|
18412
18539
|
async function writeRegistry(reg) {
|
|
18413
|
-
const validated =
|
|
18540
|
+
const validated = import_types63.RegistryFileSchema.parse(reg);
|
|
18414
18541
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
18415
18542
|
}
|
|
18416
18543
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -18605,7 +18732,7 @@ init_auth();
|
|
|
18605
18732
|
// src/connectors-config.ts
|
|
18606
18733
|
init_cjs_shims();
|
|
18607
18734
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
18608
|
-
var
|
|
18735
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
18609
18736
|
var import_node_fs38 = require("fs");
|
|
18610
18737
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
18611
18738
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -18620,11 +18747,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
18620
18747
|
};
|
|
18621
18748
|
function neatHome2() {
|
|
18622
18749
|
const override = process.env.NEAT_HOME;
|
|
18623
|
-
if (override && override.length > 0) return
|
|
18624
|
-
return
|
|
18750
|
+
if (override && override.length > 0) return import_node_path74.default.resolve(override);
|
|
18751
|
+
return import_node_path74.default.join(import_node_os4.default.homedir(), ".neat");
|
|
18625
18752
|
}
|
|
18626
18753
|
function connectorsConfigPath(home = neatHome2()) {
|
|
18627
|
-
return
|
|
18754
|
+
return import_node_path74.default.join(home, "connectors.json");
|
|
18628
18755
|
}
|
|
18629
18756
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
18630
18757
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -18811,15 +18938,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
18811
18938
|
|
|
18812
18939
|
// src/connectors/index.ts
|
|
18813
18940
|
init_cjs_shims();
|
|
18814
|
-
var
|
|
18941
|
+
var import_types64 = require("@neat.is/types");
|
|
18815
18942
|
var NO_ENV = "unknown";
|
|
18816
18943
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
18817
18944
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18818
18945
|
const sites = [];
|
|
18819
18946
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
18820
18947
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18821
|
-
if (edge.provenance !==
|
|
18822
|
-
const parsed = (0,
|
|
18948
|
+
if (edge.provenance !== import_types64.Provenance.EXTRACTED) continue;
|
|
18949
|
+
const parsed = (0, import_types64.parseFileId)(edge.source);
|
|
18823
18950
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
18824
18951
|
const site = { relPath: edge.evidence.file };
|
|
18825
18952
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -18830,7 +18957,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
18830
18957
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
18831
18958
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18832
18959
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
18833
|
-
if (attrs.type !==
|
|
18960
|
+
if (attrs.type !== import_types64.NodeType.RouteNode || !attrs.path) return void 0;
|
|
18834
18961
|
const site = { relPath: attrs.path };
|
|
18835
18962
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
18836
18963
|
return site;
|
|
@@ -19328,10 +19455,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
19328
19455
|
// src/connectors/supabase/map.ts
|
|
19329
19456
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
19330
19457
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
19331
|
-
function targetFromRestPath(
|
|
19332
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
19458
|
+
function targetFromRestPath(path78) {
|
|
19459
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path78);
|
|
19333
19460
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
19334
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
19461
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path78);
|
|
19335
19462
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
19336
19463
|
return null;
|
|
19337
19464
|
}
|
|
@@ -19379,7 +19506,7 @@ function tableNameFromQueryText(query) {
|
|
|
19379
19506
|
if (SYSTEM_SCHEMA_PREFIXES.some((prefix) => lower.startsWith(prefix))) return null;
|
|
19380
19507
|
return name;
|
|
19381
19508
|
}
|
|
19382
|
-
function diffPgStatStatementsToSignals(rows, previous,
|
|
19509
|
+
function diffPgStatStatementsToSignals(rows, previous, nowIso3) {
|
|
19383
19510
|
const signals = [];
|
|
19384
19511
|
const seen = /* @__PURE__ */ new Set();
|
|
19385
19512
|
if (!Array.isArray(rows)) return signals;
|
|
@@ -19401,7 +19528,7 @@ function diffPgStatStatementsToSignals(rows, previous, nowIso2) {
|
|
|
19401
19528
|
targetName: table,
|
|
19402
19529
|
callCount: delta,
|
|
19403
19530
|
errorCount: 0,
|
|
19404
|
-
lastObservedIso:
|
|
19531
|
+
lastObservedIso: nowIso3,
|
|
19405
19532
|
...columns.length > 0 ? { columns } : {}
|
|
19406
19533
|
});
|
|
19407
19534
|
}
|
|
@@ -19442,23 +19569,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
19442
19569
|
|
|
19443
19570
|
// src/connectors/supabase/resolve.ts
|
|
19444
19571
|
init_cjs_shims();
|
|
19445
|
-
var
|
|
19572
|
+
var import_types66 = require("@neat.is/types");
|
|
19446
19573
|
function createSupabaseResolveTarget(graph, config) {
|
|
19447
19574
|
return (signal, _ctx) => {
|
|
19448
19575
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
19449
19576
|
return null;
|
|
19450
19577
|
}
|
|
19451
|
-
const subResourceId = (0,
|
|
19578
|
+
const subResourceId = (0, import_types66.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
19452
19579
|
if (graph.hasNode(subResourceId)) {
|
|
19453
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
19580
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
19454
19581
|
}
|
|
19455
|
-
const bareResourceId = (0,
|
|
19582
|
+
const bareResourceId = (0, import_types66.infraId)(signal.targetKind, signal.targetName);
|
|
19456
19583
|
if (graph.hasNode(bareResourceId)) {
|
|
19457
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
19584
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
19458
19585
|
}
|
|
19459
|
-
const projectLevelId = (0,
|
|
19586
|
+
const projectLevelId = (0, import_types66.infraId)("supabase", config.nodeRef);
|
|
19460
19587
|
if (graph.hasNode(projectLevelId)) {
|
|
19461
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
19588
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
19462
19589
|
}
|
|
19463
19590
|
return null;
|
|
19464
19591
|
};
|
|
@@ -19551,7 +19678,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
19551
19678
|
|
|
19552
19679
|
// src/connectors/railway/index.ts
|
|
19553
19680
|
init_cjs_shims();
|
|
19554
|
-
var
|
|
19681
|
+
var import_types70 = require("@neat.is/types");
|
|
19555
19682
|
|
|
19556
19683
|
// src/connectors/railway/client.ts
|
|
19557
19684
|
init_cjs_shims();
|
|
@@ -19702,7 +19829,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
19702
19829
|
const out = [];
|
|
19703
19830
|
graph.forEachNode((_id, attrs) => {
|
|
19704
19831
|
const node = attrs;
|
|
19705
|
-
if (node.type !==
|
|
19832
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
19706
19833
|
const route = attrs;
|
|
19707
19834
|
if (route.service !== serviceName) return;
|
|
19708
19835
|
out.push({
|
|
@@ -19806,12 +19933,12 @@ function createRailwayResolveTarget(config) {
|
|
|
19806
19933
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
19807
19934
|
if (!serviceName) return null;
|
|
19808
19935
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
19809
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
19936
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types70.EdgeType.CALLS };
|
|
19810
19937
|
}
|
|
19811
19938
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
19812
19939
|
const peerName = config.serviceNameById[signal.targetName];
|
|
19813
19940
|
if (!peerName) return null;
|
|
19814
|
-
return { targetNodeId: (0,
|
|
19941
|
+
return { targetNodeId: (0, import_types70.serviceId)(peerName), serviceName, edgeType: import_types70.EdgeType.CONNECTS_TO };
|
|
19815
19942
|
}
|
|
19816
19943
|
return null;
|
|
19817
19944
|
};
|
|
@@ -19935,9 +20062,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
19935
20062
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
19936
20063
|
if (secondSep === -1) return null;
|
|
19937
20064
|
const method = rest.slice(0, secondSep);
|
|
19938
|
-
const
|
|
19939
|
-
if (!resourceName || !method || !
|
|
19940
|
-
return { resourceName, method, path:
|
|
20065
|
+
const path78 = rest.slice(secondSep + 1);
|
|
20066
|
+
if (!resourceName || !method || !path78) return null;
|
|
20067
|
+
return { resourceName, method, path: path78 };
|
|
19941
20068
|
}
|
|
19942
20069
|
function resourceNameFor(type, labels) {
|
|
19943
20070
|
if (!labels) return null;
|
|
@@ -19975,14 +20102,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
19975
20102
|
if (!req) return null;
|
|
19976
20103
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
19977
20104
|
const method = req.requestMethod.toUpperCase();
|
|
19978
|
-
const
|
|
19979
|
-
if (
|
|
20105
|
+
const path78 = pathFromRequestUrl(req.requestUrl);
|
|
20106
|
+
if (path78 === null) return null;
|
|
19980
20107
|
const timestamp = entry.timestamp;
|
|
19981
20108
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
19982
20109
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
19983
20110
|
return {
|
|
19984
20111
|
targetKind: resourceType,
|
|
19985
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
20112
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path78 }),
|
|
19986
20113
|
callCount: 1,
|
|
19987
20114
|
errorCount: isError ? 1 : 0,
|
|
19988
20115
|
lastObservedIso: timestamp
|
|
@@ -19999,7 +20126,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
19999
20126
|
|
|
20000
20127
|
// src/connectors/firebase/resolve.ts
|
|
20001
20128
|
init_cjs_shims();
|
|
20002
|
-
var
|
|
20129
|
+
var import_types71 = require("@neat.is/types");
|
|
20003
20130
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
20004
20131
|
switch (resourceType) {
|
|
20005
20132
|
case "cloud_function":
|
|
@@ -20014,7 +20141,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
20014
20141
|
const entries = [];
|
|
20015
20142
|
graph.forEachNode((_id, attrs) => {
|
|
20016
20143
|
const node = attrs;
|
|
20017
|
-
if (node.type !==
|
|
20144
|
+
if (node.type !== import_types71.NodeType.RouteNode) return;
|
|
20018
20145
|
const route = attrs;
|
|
20019
20146
|
if (route.service !== serviceName) return;
|
|
20020
20147
|
entries.push({
|
|
@@ -20046,7 +20173,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
20046
20173
|
return {
|
|
20047
20174
|
targetNodeId: match.routeNodeId,
|
|
20048
20175
|
serviceName,
|
|
20049
|
-
edgeType:
|
|
20176
|
+
edgeType: import_types71.EdgeType.CALLS
|
|
20050
20177
|
};
|
|
20051
20178
|
};
|
|
20052
20179
|
}
|
|
@@ -20073,7 +20200,7 @@ init_cjs_shims();
|
|
|
20073
20200
|
|
|
20074
20201
|
// src/connectors/cloudflare/connector.ts
|
|
20075
20202
|
init_cjs_shims();
|
|
20076
|
-
var
|
|
20203
|
+
var import_types73 = require("@neat.is/types");
|
|
20077
20204
|
|
|
20078
20205
|
// src/connectors/cloudflare/client.ts
|
|
20079
20206
|
init_cjs_shims();
|
|
@@ -20189,7 +20316,7 @@ function mapEventToSignal(event) {
|
|
|
20189
20316
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
20190
20317
|
const statusCode = metadata?.statusCode;
|
|
20191
20318
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
20192
|
-
const
|
|
20319
|
+
const path78 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
20193
20320
|
return {
|
|
20194
20321
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
20195
20322
|
targetName: scriptName,
|
|
@@ -20197,7 +20324,7 @@ function mapEventToSignal(event) {
|
|
|
20197
20324
|
errorCount: isError ? 1 : 0,
|
|
20198
20325
|
lastObservedIso: observedAt.toISOString(),
|
|
20199
20326
|
method,
|
|
20200
|
-
...
|
|
20327
|
+
...path78 ? { path: path78 } : {},
|
|
20201
20328
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
20202
20329
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
20203
20330
|
};
|
|
@@ -20237,19 +20364,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
20237
20364
|
graph.forEachNode((id, attrs) => {
|
|
20238
20365
|
if (found) return;
|
|
20239
20366
|
const a = attrs;
|
|
20240
|
-
if (a.type ===
|
|
20367
|
+
if (a.type === import_types73.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
20241
20368
|
found = id;
|
|
20242
20369
|
}
|
|
20243
20370
|
});
|
|
20244
20371
|
return found;
|
|
20245
20372
|
}
|
|
20246
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
20247
|
-
const normalizedPath = normalizePathTemplate(
|
|
20373
|
+
function findMatchingRouteNode(graph, serviceName, method, path78) {
|
|
20374
|
+
const normalizedPath = normalizePathTemplate(path78);
|
|
20248
20375
|
let found = null;
|
|
20249
20376
|
graph.forEachNode((id, attrs) => {
|
|
20250
20377
|
if (found) return;
|
|
20251
20378
|
const a = attrs;
|
|
20252
|
-
if (a.type !==
|
|
20379
|
+
if (a.type !== import_types73.NodeType.RouteNode || a.service !== serviceName) return;
|
|
20253
20380
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
20254
20381
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
20255
20382
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -20261,18 +20388,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20261
20388
|
return (signal) => {
|
|
20262
20389
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
20263
20390
|
const scriptName = signal.targetName;
|
|
20264
|
-
const { method, path:
|
|
20391
|
+
const { method, path: path78 } = signal;
|
|
20265
20392
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
20266
|
-
if (!method || !
|
|
20267
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
20393
|
+
if (!method || !path78) return wholeFileId;
|
|
20394
|
+
return findMatchingRouteNode(graph, serviceName, method, path78) ?? wholeFileId;
|
|
20268
20395
|
};
|
|
20269
20396
|
const mapping = config.workers?.[scriptName];
|
|
20270
20397
|
if (mapping) {
|
|
20271
|
-
const wholeFileId = (0,
|
|
20398
|
+
const wholeFileId = (0, import_types73.fileId)(mapping.service, mapping.entryFile);
|
|
20272
20399
|
return {
|
|
20273
20400
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
20274
20401
|
serviceName: mapping.service,
|
|
20275
|
-
edgeType:
|
|
20402
|
+
edgeType: import_types73.EdgeType.CALLS
|
|
20276
20403
|
};
|
|
20277
20404
|
}
|
|
20278
20405
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -20281,13 +20408,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20281
20408
|
return {
|
|
20282
20409
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
20283
20410
|
serviceName: fileNode.service,
|
|
20284
|
-
edgeType:
|
|
20411
|
+
edgeType: import_types73.EdgeType.CALLS
|
|
20285
20412
|
};
|
|
20286
20413
|
}
|
|
20287
20414
|
return {
|
|
20288
|
-
targetNodeId: (0,
|
|
20415
|
+
targetNodeId: (0, import_types73.infraId)("cloudflare-worker", scriptName),
|
|
20289
20416
|
serviceName: scriptName,
|
|
20290
|
-
edgeType:
|
|
20417
|
+
edgeType: import_types73.EdgeType.CALLS,
|
|
20291
20418
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
20292
20419
|
};
|
|
20293
20420
|
};
|
|
@@ -20483,14 +20610,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
20483
20610
|
|
|
20484
20611
|
// src/connectors/neon/resolve.ts
|
|
20485
20612
|
init_cjs_shims();
|
|
20486
|
-
var
|
|
20613
|
+
var import_types77 = require("@neat.is/types");
|
|
20487
20614
|
function createNeonResolveTarget(config) {
|
|
20488
20615
|
return (signal) => {
|
|
20489
20616
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20490
20617
|
return {
|
|
20491
|
-
targetNodeId: (0,
|
|
20618
|
+
targetNodeId: (0, import_types77.infraId)("sql-table", signal.targetName),
|
|
20492
20619
|
serviceName: config.serviceName,
|
|
20493
|
-
edgeType:
|
|
20620
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
20494
20621
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
20495
20622
|
};
|
|
20496
20623
|
};
|
|
@@ -20616,9 +20743,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
20616
20743
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
20617
20744
|
if (secondSep === -1) return null;
|
|
20618
20745
|
const method = rest.slice(0, secondSep);
|
|
20619
|
-
const
|
|
20620
|
-
if (!serviceName || !method || !
|
|
20621
|
-
return { serviceName, method, path:
|
|
20746
|
+
const path78 = rest.slice(secondSep + 1);
|
|
20747
|
+
if (!serviceName || !method || !path78) return null;
|
|
20748
|
+
return { serviceName, method, path: path78 };
|
|
20622
20749
|
}
|
|
20623
20750
|
|
|
20624
20751
|
// src/connectors/cloud-run/map.ts
|
|
@@ -20647,14 +20774,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
20647
20774
|
if (!req) return null;
|
|
20648
20775
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
20649
20776
|
const method = req.requestMethod.toUpperCase();
|
|
20650
|
-
const
|
|
20651
|
-
if (
|
|
20777
|
+
const path78 = pathFromRequestUrl2(req.requestUrl);
|
|
20778
|
+
if (path78 === null) return null;
|
|
20652
20779
|
const timestamp = entry.timestamp;
|
|
20653
20780
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
20654
20781
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
20655
20782
|
return {
|
|
20656
20783
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
20657
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
20784
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path78 }),
|
|
20658
20785
|
callCount: 1,
|
|
20659
20786
|
errorCount: isError ? 1 : 0,
|
|
20660
20787
|
lastObservedIso: timestamp
|
|
@@ -20671,14 +20798,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
20671
20798
|
|
|
20672
20799
|
// src/connectors/cloud-run/resolve.ts
|
|
20673
20800
|
init_cjs_shims();
|
|
20674
|
-
var
|
|
20801
|
+
var import_types81 = require("@neat.is/types");
|
|
20675
20802
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
20676
20803
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
20677
20804
|
let found = null;
|
|
20678
20805
|
graph.forEachNode((_id, attrs) => {
|
|
20679
20806
|
if (found) return;
|
|
20680
20807
|
const node = attrs;
|
|
20681
|
-
if (node.type !==
|
|
20808
|
+
if (node.type !== import_types81.NodeType.RouteNode) return;
|
|
20682
20809
|
const route = attrs;
|
|
20683
20810
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20684
20811
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20693,23 +20820,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
20693
20820
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
20694
20821
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
20695
20822
|
if (!identity) return null;
|
|
20696
|
-
const { serviceName: gcpServiceName, method, path:
|
|
20823
|
+
const { serviceName: gcpServiceName, method, path: path78 } = identity;
|
|
20697
20824
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
20698
20825
|
if (mappedService) {
|
|
20699
20826
|
const routeNodeId = findMatchingRouteNode2(
|
|
20700
20827
|
graph,
|
|
20701
20828
|
mappedService,
|
|
20702
20829
|
method,
|
|
20703
|
-
normalizePathTemplate(
|
|
20830
|
+
normalizePathTemplate(path78)
|
|
20704
20831
|
);
|
|
20705
20832
|
if (routeNodeId) {
|
|
20706
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20833
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types81.EdgeType.CALLS };
|
|
20707
20834
|
}
|
|
20708
20835
|
}
|
|
20709
20836
|
return {
|
|
20710
|
-
targetNodeId: (0,
|
|
20837
|
+
targetNodeId: (0, import_types81.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
20711
20838
|
serviceName: mappedService ?? gcpServiceName,
|
|
20712
|
-
edgeType:
|
|
20839
|
+
edgeType: import_types81.EdgeType.CALLS,
|
|
20713
20840
|
ensureInfraNode: {
|
|
20714
20841
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
20715
20842
|
name: gcpServiceName,
|
|
@@ -20836,9 +20963,9 @@ function parseGcpLbTargetName(targetName) {
|
|
|
20836
20963
|
const secondSep = rest.indexOf(FIELD_SEP3);
|
|
20837
20964
|
if (secondSep === -1) return null;
|
|
20838
20965
|
const method = rest.slice(0, secondSep);
|
|
20839
|
-
const
|
|
20840
|
-
if (!backendServiceName || !method || !
|
|
20841
|
-
return { backendServiceName, method, path:
|
|
20966
|
+
const path78 = rest.slice(secondSep + 1);
|
|
20967
|
+
if (!backendServiceName || !method || !path78) return null;
|
|
20968
|
+
return { backendServiceName, method, path: path78 };
|
|
20842
20969
|
}
|
|
20843
20970
|
|
|
20844
20971
|
// src/connectors/gcp-lb/map.ts
|
|
@@ -20867,14 +20994,14 @@ function mapLogEntryToSignal3(entry) {
|
|
|
20867
20994
|
if (!req) return null;
|
|
20868
20995
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
20869
20996
|
const method = req.requestMethod.toUpperCase();
|
|
20870
|
-
const
|
|
20871
|
-
if (
|
|
20997
|
+
const path78 = pathFromRequestUrl3(req.requestUrl);
|
|
20998
|
+
if (path78 === null) return null;
|
|
20872
20999
|
const timestamp = entry.timestamp;
|
|
20873
21000
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
20874
21001
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD5;
|
|
20875
21002
|
return {
|
|
20876
21003
|
targetKind: GCP_LB_TARGET_KIND,
|
|
20877
|
-
targetName: packGcpLbTargetName({ backendServiceName, method, path:
|
|
21004
|
+
targetName: packGcpLbTargetName({ backendServiceName, method, path: path78 }),
|
|
20878
21005
|
callCount: 1,
|
|
20879
21006
|
errorCount: isError ? 1 : 0,
|
|
20880
21007
|
lastObservedIso: timestamp
|
|
@@ -20891,14 +21018,14 @@ function mapLogEntriesToSignals3(entries) {
|
|
|
20891
21018
|
|
|
20892
21019
|
// src/connectors/gcp-lb/resolve.ts
|
|
20893
21020
|
init_cjs_shims();
|
|
20894
|
-
var
|
|
21021
|
+
var import_types85 = require("@neat.is/types");
|
|
20895
21022
|
var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
|
|
20896
21023
|
function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
|
|
20897
21024
|
let found = null;
|
|
20898
21025
|
graph.forEachNode((_id, attrs) => {
|
|
20899
21026
|
if (found) return;
|
|
20900
21027
|
const node = attrs;
|
|
20901
|
-
if (node.type !==
|
|
21028
|
+
if (node.type !== import_types85.NodeType.RouteNode) return;
|
|
20902
21029
|
const route = attrs;
|
|
20903
21030
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20904
21031
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20913,23 +21040,23 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
20913
21040
|
if (signal.targetKind !== GCP_LB_TARGET_KIND) return null;
|
|
20914
21041
|
const identity = parseGcpLbTargetName(signal.targetName);
|
|
20915
21042
|
if (!identity) return null;
|
|
20916
|
-
const { backendServiceName, method, path:
|
|
21043
|
+
const { backendServiceName, method, path: path78 } = identity;
|
|
20917
21044
|
const mappedService = config.backendServiceMap?.[backendServiceName];
|
|
20918
21045
|
if (mappedService) {
|
|
20919
21046
|
const routeNodeId = findMatchingRouteNode3(
|
|
20920
21047
|
graph,
|
|
20921
21048
|
mappedService,
|
|
20922
21049
|
method,
|
|
20923
|
-
normalizePathTemplate(
|
|
21050
|
+
normalizePathTemplate(path78)
|
|
20924
21051
|
);
|
|
20925
21052
|
if (routeNodeId) {
|
|
20926
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
21053
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types85.EdgeType.CALLS };
|
|
20927
21054
|
}
|
|
20928
21055
|
}
|
|
20929
21056
|
return {
|
|
20930
|
-
targetNodeId: (0,
|
|
21057
|
+
targetNodeId: (0, import_types85.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
|
|
20931
21058
|
serviceName: mappedService ?? backendServiceName,
|
|
20932
|
-
edgeType:
|
|
21059
|
+
edgeType: import_types85.EdgeType.CALLS,
|
|
20933
21060
|
ensureInfraNode: {
|
|
20934
21061
|
kind: GCP_LB_BACKEND_INFRA_KIND,
|
|
20935
21062
|
name: backendServiceName,
|
|
@@ -20970,7 +21097,7 @@ function createGcpLbConnector(graph, config = {}) {
|
|
|
20970
21097
|
|
|
20971
21098
|
// src/connectors/render/index.ts
|
|
20972
21099
|
init_cjs_shims();
|
|
20973
|
-
var
|
|
21100
|
+
var import_types88 = require("@neat.is/types");
|
|
20974
21101
|
|
|
20975
21102
|
// src/connectors/render/types.ts
|
|
20976
21103
|
init_cjs_shims();
|
|
@@ -21048,7 +21175,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
21048
21175
|
const out = [];
|
|
21049
21176
|
graph.forEachNode((_id, attrs) => {
|
|
21050
21177
|
const node = attrs;
|
|
21051
|
-
if (node.type !==
|
|
21178
|
+
if (node.type !== import_types88.NodeType.RouteNode) return;
|
|
21052
21179
|
const route = attrs;
|
|
21053
21180
|
if (route.service !== serviceName) return;
|
|
21054
21181
|
out.push({
|
|
@@ -21133,7 +21260,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
21133
21260
|
function createRenderResolveTarget(config) {
|
|
21134
21261
|
return (signal) => {
|
|
21135
21262
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
21136
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
21263
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types88.EdgeType.CALLS };
|
|
21137
21264
|
}
|
|
21138
21265
|
return null;
|
|
21139
21266
|
};
|
|
@@ -21271,21 +21398,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
21271
21398
|
|
|
21272
21399
|
// src/connectors/planetscale/resolve.ts
|
|
21273
21400
|
init_cjs_shims();
|
|
21274
|
-
var
|
|
21401
|
+
var import_types92 = require("@neat.is/types");
|
|
21275
21402
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
21276
21403
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
21277
21404
|
const databaseName = `${config.organization}/${config.database}`;
|
|
21278
21405
|
return (signal, _ctx) => {
|
|
21279
21406
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
21280
|
-
const tableId = (0,
|
|
21407
|
+
const tableId = (0, import_types92.infraId)("sql-table", signal.targetName);
|
|
21281
21408
|
if (graph.hasNode(tableId)) {
|
|
21282
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
21409
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types92.EdgeType.CALLS };
|
|
21283
21410
|
}
|
|
21284
|
-
const providerId = (0,
|
|
21411
|
+
const providerId = (0, import_types92.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
21285
21412
|
return {
|
|
21286
21413
|
targetNodeId: providerId,
|
|
21287
21414
|
serviceName: config.serviceName,
|
|
21288
|
-
edgeType:
|
|
21415
|
+
edgeType: import_types92.EdgeType.CALLS,
|
|
21289
21416
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
21290
21417
|
};
|
|
21291
21418
|
};
|
|
@@ -21550,7 +21677,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
21550
21677
|
|
|
21551
21678
|
// src/connectors/eas/resolve.ts
|
|
21552
21679
|
init_cjs_shims();
|
|
21553
|
-
var
|
|
21680
|
+
var import_types97 = require("@neat.is/types");
|
|
21554
21681
|
var NO_ENV2 = "unknown";
|
|
21555
21682
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
21556
21683
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -21566,8 +21693,8 @@ function configBasenamesForPhase(phase) {
|
|
|
21566
21693
|
function configNodeService(graph, configNodeId) {
|
|
21567
21694
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
21568
21695
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
21569
|
-
if (edge.type !==
|
|
21570
|
-
const parsed = (0,
|
|
21696
|
+
if (edge.type !== import_types97.EdgeType.CONFIGURED_BY) continue;
|
|
21697
|
+
const parsed = (0, import_types97.parseFileId)(edge.source);
|
|
21571
21698
|
if (parsed) return parsed.service;
|
|
21572
21699
|
}
|
|
21573
21700
|
return null;
|
|
@@ -21578,7 +21705,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
21578
21705
|
graph.forEachNode((id, attrs) => {
|
|
21579
21706
|
if (scoped) return;
|
|
21580
21707
|
const node = attrs;
|
|
21581
|
-
if (node.type !==
|
|
21708
|
+
if (node.type !== import_types97.NodeType.ConfigNode) return;
|
|
21582
21709
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
21583
21710
|
if (anyMatch === null) anyMatch = id;
|
|
21584
21711
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -21595,13 +21722,13 @@ function createEasResolveTarget(graph) {
|
|
|
21595
21722
|
if (basenames.length > 0) {
|
|
21596
21723
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
21597
21724
|
if (configNodeId) {
|
|
21598
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
21725
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types97.EdgeType.CALLS };
|
|
21599
21726
|
}
|
|
21600
21727
|
}
|
|
21601
21728
|
return {
|
|
21602
21729
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
21603
21730
|
serviceName,
|
|
21604
|
-
edgeType:
|
|
21731
|
+
edgeType: import_types97.EdgeType.CALLS
|
|
21605
21732
|
};
|
|
21606
21733
|
};
|
|
21607
21734
|
}
|
|
@@ -22218,11 +22345,11 @@ function serializeGraph(graph) {
|
|
|
22218
22345
|
}
|
|
22219
22346
|
function projectFromReq(req, singleProject) {
|
|
22220
22347
|
const params = req.params;
|
|
22221
|
-
const
|
|
22348
|
+
const named2 = params.project;
|
|
22222
22349
|
if (singleProject) {
|
|
22223
|
-
return
|
|
22350
|
+
return named2 === void 0 || named2 === DEFAULT_PROJECT ? singleProject : named2;
|
|
22224
22351
|
}
|
|
22225
|
-
return
|
|
22352
|
+
return named2 ?? DEFAULT_PROJECT;
|
|
22226
22353
|
}
|
|
22227
22354
|
function resolveProject(registry, req, reply, bootstrap, singleProject) {
|
|
22228
22355
|
const name = projectFromReq(req, singleProject);
|
|
@@ -22363,11 +22490,11 @@ function registerRoutes(scope, ctx) {
|
|
|
22363
22490
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
22364
22491
|
const parsed = [];
|
|
22365
22492
|
for (const c of candidates) {
|
|
22366
|
-
const r =
|
|
22493
|
+
const r = import_types100.DivergenceTypeSchema.safeParse(c);
|
|
22367
22494
|
if (!r.success) {
|
|
22368
22495
|
return reply.code(400).send({
|
|
22369
22496
|
error: `unknown divergence type "${c}"`,
|
|
22370
|
-
allowed:
|
|
22497
|
+
allowed: import_types100.DivergenceTypeSchema.options
|
|
22371
22498
|
});
|
|
22372
22499
|
}
|
|
22373
22500
|
parsed.push(r.data);
|
|
@@ -22763,7 +22890,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22763
22890
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
22764
22891
|
let violations = await log.readAll();
|
|
22765
22892
|
if (req.query.severity) {
|
|
22766
|
-
const sev =
|
|
22893
|
+
const sev = import_types100.PolicySeveritySchema.safeParse(req.query.severity);
|
|
22767
22894
|
if (!sev.success) {
|
|
22768
22895
|
return reply.code(400).send({
|
|
22769
22896
|
error: "invalid severity",
|
|
@@ -22802,7 +22929,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22802
22929
|
scope.post("/policies/check", async (req, reply) => {
|
|
22803
22930
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22804
22931
|
if (!proj) return;
|
|
22805
|
-
const parsed =
|
|
22932
|
+
const parsed = import_types100.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
22806
22933
|
if (!parsed.success) {
|
|
22807
22934
|
return reply.code(400).send({
|
|
22808
22935
|
error: "invalid /policies/check body",
|
|
@@ -23123,16 +23250,458 @@ init_otel_grpc();
|
|
|
23123
23250
|
|
|
23124
23251
|
// src/daemon.ts
|
|
23125
23252
|
init_cjs_shims();
|
|
23126
|
-
var
|
|
23127
|
-
var
|
|
23253
|
+
var import_node_fs41 = require("fs");
|
|
23254
|
+
var import_node_path77 = __toESM(require("path"), 1);
|
|
23128
23255
|
var import_node_module = require("module");
|
|
23129
23256
|
init_otel();
|
|
23257
|
+
|
|
23258
|
+
// src/connectors/kubernetes/index.ts
|
|
23259
|
+
init_cjs_shims();
|
|
23260
|
+
|
|
23261
|
+
// src/connectors/kubernetes/client.ts
|
|
23262
|
+
init_cjs_shims();
|
|
23263
|
+
var import_node_https = require("https");
|
|
23264
|
+
function deploymentsPath(namespace) {
|
|
23265
|
+
return `/apis/apps/v1/namespaces/${namespace}/deployments`;
|
|
23266
|
+
}
|
|
23267
|
+
function podsPath(namespace) {
|
|
23268
|
+
return `/api/v1/namespaces/${namespace}/pods`;
|
|
23269
|
+
}
|
|
23270
|
+
function makeK8sFetchImpl(transport) {
|
|
23271
|
+
const agent = new import_node_https.Agent({
|
|
23272
|
+
...transport.ca ? { ca: transport.ca } : {},
|
|
23273
|
+
...transport.clientCert ? { cert: transport.clientCert } : {},
|
|
23274
|
+
...transport.clientKey ? { key: transport.clientKey } : {},
|
|
23275
|
+
rejectUnauthorized: !transport.insecureSkipTlsVerify
|
|
23276
|
+
});
|
|
23277
|
+
return ((url, init) => new Promise((resolve, reject) => {
|
|
23278
|
+
const u = new URL(String(url));
|
|
23279
|
+
const req = (0, import_node_https.request)(
|
|
23280
|
+
u,
|
|
23281
|
+
{
|
|
23282
|
+
method: (init?.method ?? "GET").toUpperCase(),
|
|
23283
|
+
headers: init?.headers ?? {},
|
|
23284
|
+
agent
|
|
23285
|
+
},
|
|
23286
|
+
(res) => {
|
|
23287
|
+
const chunks = [];
|
|
23288
|
+
res.on("data", (c) => chunks.push(c));
|
|
23289
|
+
res.on("end", () => {
|
|
23290
|
+
const body = Buffer.concat(chunks).toString("utf8");
|
|
23291
|
+
const status2 = res.statusCode ?? 0;
|
|
23292
|
+
resolve({
|
|
23293
|
+
ok: status2 >= 200 && status2 < 300,
|
|
23294
|
+
status: status2,
|
|
23295
|
+
statusText: res.statusMessage ?? "",
|
|
23296
|
+
json: async () => JSON.parse(body),
|
|
23297
|
+
text: async () => body
|
|
23298
|
+
});
|
|
23299
|
+
});
|
|
23300
|
+
}
|
|
23301
|
+
);
|
|
23302
|
+
req.on("error", reject);
|
|
23303
|
+
const signal = init?.signal;
|
|
23304
|
+
if (signal) {
|
|
23305
|
+
if (signal.aborted) req.destroy(new Error("aborted"));
|
|
23306
|
+
else signal.addEventListener("abort", () => req.destroy(new Error("aborted")), { once: true });
|
|
23307
|
+
}
|
|
23308
|
+
req.end();
|
|
23309
|
+
}));
|
|
23310
|
+
}
|
|
23311
|
+
async function listResource(transport, namespace, path78, opts = {}) {
|
|
23312
|
+
const base = opts.apiUrl ?? transport.server;
|
|
23313
|
+
const url = `${base.replace(/\/$/, "")}${path78}`;
|
|
23314
|
+
const fetchImpl = opts.fetchImpl ?? makeK8sFetchImpl(transport);
|
|
23315
|
+
const res = await junctionFetch(
|
|
23316
|
+
url,
|
|
23317
|
+
{ method: "GET", headers: { ...transport.token ? bearerAuthHeader(transport.token) : {}, Accept: "application/json" } },
|
|
23318
|
+
// accountKey: the (cluster, namespace) pair — an identifier, safe to log, the
|
|
23319
|
+
// rate-limit bucket for one namespace on one cluster (ADR-131).
|
|
23320
|
+
{ provider: "kubernetes", accountKey: `${safeHost(transport.server)}/${namespace}`, fetchImpl }
|
|
23321
|
+
);
|
|
23322
|
+
if (!res.ok) {
|
|
23323
|
+
throw new Error(`kubernetes ${path78} failed: ${res.status} ${res.statusText}`);
|
|
23324
|
+
}
|
|
23325
|
+
const json = await res.json();
|
|
23326
|
+
return Array.isArray(json.items) ? json.items : [];
|
|
23327
|
+
}
|
|
23328
|
+
function safeHost(server) {
|
|
23329
|
+
try {
|
|
23330
|
+
return new URL(server).host;
|
|
23331
|
+
} catch {
|
|
23332
|
+
return "cluster";
|
|
23333
|
+
}
|
|
23334
|
+
}
|
|
23335
|
+
async function fetchDeployments(transport, namespace, opts = {}) {
|
|
23336
|
+
return listResource(transport, namespace, deploymentsPath(namespace), opts);
|
|
23337
|
+
}
|
|
23338
|
+
async function fetchPods(transport, namespace, opts = {}) {
|
|
23339
|
+
return listResource(transport, namespace, podsPath(namespace), opts);
|
|
23340
|
+
}
|
|
23341
|
+
|
|
23342
|
+
// src/connectors/kubernetes/kubeconfig.ts
|
|
23343
|
+
init_cjs_shims();
|
|
23344
|
+
var import_node_fs39 = require("fs");
|
|
23345
|
+
var import_yaml4 = require("yaml");
|
|
23346
|
+
function pemFrom(dataField, pathField) {
|
|
23347
|
+
if (typeof dataField === "string" && dataField.length > 0) {
|
|
23348
|
+
return Buffer.from(dataField, "base64").toString("utf8");
|
|
23349
|
+
}
|
|
23350
|
+
if (typeof pathField === "string" && pathField.length > 0) {
|
|
23351
|
+
return (0, import_node_fs39.readFileSync)(pathField, "utf8");
|
|
23352
|
+
}
|
|
23353
|
+
return void 0;
|
|
23354
|
+
}
|
|
23355
|
+
function named(list, name) {
|
|
23356
|
+
if (!Array.isArray(list)) return void 0;
|
|
23357
|
+
const hit = list.find((e) => e && e.name === name);
|
|
23358
|
+
return hit;
|
|
23359
|
+
}
|
|
23360
|
+
function parseKubeconfig(kubeconfig) {
|
|
23361
|
+
const looksInline = /\n/.test(kubeconfig) || /(^|\s)clusters\s*:/.test(kubeconfig);
|
|
23362
|
+
const text = looksInline ? kubeconfig : (0, import_node_fs39.readFileSync)(kubeconfig, "utf8");
|
|
23363
|
+
let doc;
|
|
23364
|
+
try {
|
|
23365
|
+
doc = (0, import_yaml4.parse)(text);
|
|
23366
|
+
} catch {
|
|
23367
|
+
throw new Error("kubernetes connector: kubeconfig is not valid YAML");
|
|
23368
|
+
}
|
|
23369
|
+
if (!doc || typeof doc !== "object") {
|
|
23370
|
+
throw new Error("kubernetes connector: kubeconfig is empty or malformed");
|
|
23371
|
+
}
|
|
23372
|
+
const currentContext = doc["current-context"];
|
|
23373
|
+
if (typeof currentContext !== "string" || currentContext.length === 0) {
|
|
23374
|
+
throw new Error("kubernetes connector: kubeconfig has no current-context");
|
|
23375
|
+
}
|
|
23376
|
+
const ctxEntry = named(doc["contexts"], currentContext);
|
|
23377
|
+
const ctx = ctxEntry?.context;
|
|
23378
|
+
if (!ctx) {
|
|
23379
|
+
throw new Error(`kubernetes connector: kubeconfig context "${currentContext}" not found`);
|
|
23380
|
+
}
|
|
23381
|
+
const clusterEntry = named(doc["clusters"], String(ctx["cluster"] ?? ""));
|
|
23382
|
+
const cluster = clusterEntry?.cluster;
|
|
23383
|
+
if (!cluster || typeof cluster["server"] !== "string") {
|
|
23384
|
+
throw new Error("kubernetes connector: kubeconfig current context has no cluster server");
|
|
23385
|
+
}
|
|
23386
|
+
const userEntry = named(doc["users"], String(ctx["user"] ?? ""));
|
|
23387
|
+
const user = userEntry?.user ?? {};
|
|
23388
|
+
const transport = {
|
|
23389
|
+
server: cluster["server"],
|
|
23390
|
+
insecureSkipTlsVerify: cluster["insecure-skip-tls-verify"] === true
|
|
23391
|
+
};
|
|
23392
|
+
const ca = pemFrom(cluster["certificate-authority-data"], cluster["certificate-authority"]);
|
|
23393
|
+
if (ca) transport.ca = ca;
|
|
23394
|
+
if (typeof user["token"] === "string" && user["token"].length > 0) transport.token = user["token"];
|
|
23395
|
+
const clientCert = pemFrom(user["client-certificate-data"], user["client-certificate"]);
|
|
23396
|
+
const clientKey = pemFrom(user["client-key-data"], user["client-key"]);
|
|
23397
|
+
if (clientCert) transport.clientCert = clientCert;
|
|
23398
|
+
if (clientKey) transport.clientKey = clientKey;
|
|
23399
|
+
return transport;
|
|
23400
|
+
}
|
|
23401
|
+
function resolveK8sTransport(creds, config) {
|
|
23402
|
+
if (creds.kubeconfig) return parseKubeconfig(creds.kubeconfig);
|
|
23403
|
+
if (!config.apiServerUrl) {
|
|
23404
|
+
throw new Error("kubernetes connector: options.apiServerUrl is required with a token credential");
|
|
23405
|
+
}
|
|
23406
|
+
const transport = {
|
|
23407
|
+
server: config.apiServerUrl,
|
|
23408
|
+
insecureSkipTlsVerify: config.insecureSkipTlsVerify === true
|
|
23409
|
+
};
|
|
23410
|
+
if (creds.token) transport.token = creds.token;
|
|
23411
|
+
if (config.caCert) transport.ca = config.caCert;
|
|
23412
|
+
return transport;
|
|
23413
|
+
}
|
|
23414
|
+
|
|
23415
|
+
// src/connectors/kubernetes/map.ts
|
|
23416
|
+
init_cjs_shims();
|
|
23417
|
+
|
|
23418
|
+
// src/connectors/kubernetes/types.ts
|
|
23419
|
+
init_cjs_shims();
|
|
23420
|
+
function readK8sCredentials(raw) {
|
|
23421
|
+
const token = typeof raw["token"] === "string" && raw["token"].length > 0 ? raw["token"] : void 0;
|
|
23422
|
+
const kubeconfig = typeof raw["kubeconfig"] === "string" && raw["kubeconfig"].length > 0 ? raw["kubeconfig"] : void 0;
|
|
23423
|
+
if (!token && !kubeconfig) {
|
|
23424
|
+
throw new Error("kubernetes connector: credentials must carry a token or a kubeconfig");
|
|
23425
|
+
}
|
|
23426
|
+
const out = {};
|
|
23427
|
+
if (token) out.token = token;
|
|
23428
|
+
if (kubeconfig) out.kubeconfig = kubeconfig;
|
|
23429
|
+
return out;
|
|
23430
|
+
}
|
|
23431
|
+
var IMAGE_PULL_REASONS = /* @__PURE__ */ new Set(["ImagePullBackOff", "ErrImagePull", "InvalidImageName"]);
|
|
23432
|
+
var CRASH_LOOP_REASON = "CrashLoopBackOff";
|
|
23433
|
+
var FIELD_SEP5 = "\0";
|
|
23434
|
+
var K8S_TARGET_KIND = "k8s-workload";
|
|
23435
|
+
function packK8sTargetName(identity) {
|
|
23436
|
+
return [identity.serviceName, identity.fault].join(FIELD_SEP5);
|
|
23437
|
+
}
|
|
23438
|
+
function parseK8sTargetName(targetName) {
|
|
23439
|
+
const sep = targetName.indexOf(FIELD_SEP5);
|
|
23440
|
+
if (sep === -1) return null;
|
|
23441
|
+
const serviceName = targetName.slice(0, sep);
|
|
23442
|
+
const fault = targetName.slice(sep + 1);
|
|
23443
|
+
if (!serviceName || !fault) return null;
|
|
23444
|
+
return { serviceName, fault };
|
|
23445
|
+
}
|
|
23446
|
+
|
|
23447
|
+
// src/connectors/kubernetes/map.ts
|
|
23448
|
+
function serviceNameFor(deployment, config) {
|
|
23449
|
+
const name = deployment.metadata?.name ?? "";
|
|
23450
|
+
return config.serviceMap?.[name] ?? name;
|
|
23451
|
+
}
|
|
23452
|
+
function podMatchesSelector(pod, selector) {
|
|
23453
|
+
if (!selector || Object.keys(selector).length === 0) return false;
|
|
23454
|
+
const labels = pod.metadata?.labels ?? {};
|
|
23455
|
+
return Object.entries(selector).every(([k, v]) => labels[k] === v);
|
|
23456
|
+
}
|
|
23457
|
+
function podsForDeployment(deployment, pods) {
|
|
23458
|
+
const selector = deployment.spec?.selector?.matchLabels;
|
|
23459
|
+
return pods.filter((p) => podMatchesSelector(p, selector));
|
|
23460
|
+
}
|
|
23461
|
+
function nowIso2() {
|
|
23462
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
23463
|
+
}
|
|
23464
|
+
function podLevelFault(deployment, pods) {
|
|
23465
|
+
const name = deployment.metadata?.name ?? "";
|
|
23466
|
+
const owned = podsForDeployment(deployment, pods);
|
|
23467
|
+
let crash = null;
|
|
23468
|
+
for (const pod of owned) {
|
|
23469
|
+
for (const cs of pod.status?.containerStatuses ?? []) {
|
|
23470
|
+
const reason = cs.state?.waiting?.reason;
|
|
23471
|
+
if (typeof reason !== "string") continue;
|
|
23472
|
+
if (IMAGE_PULL_REASONS.has(reason)) {
|
|
23473
|
+
const image = typeof cs.image === "string" ? cs.image : "unknown image";
|
|
23474
|
+
const attrs = { "k8s.image": image, "k8s.waitingReason": reason };
|
|
23475
|
+
const wm = cs.state?.waiting?.message;
|
|
23476
|
+
if (typeof wm === "string" && wm.length > 0) attrs["k8s.waitingMessage"] = wm;
|
|
23477
|
+
return {
|
|
23478
|
+
fault: "image-pull",
|
|
23479
|
+
message: `Deployment ${name} cannot pull image ${image} (${reason})`,
|
|
23480
|
+
timestamp: pod.status?.startTime ?? nowIso2(),
|
|
23481
|
+
attributes: attrs
|
|
23482
|
+
};
|
|
23483
|
+
}
|
|
23484
|
+
if (reason === CRASH_LOOP_REASON && !crash) crash = { cs, pod };
|
|
23485
|
+
}
|
|
23486
|
+
}
|
|
23487
|
+
if (crash) {
|
|
23488
|
+
const { cs, pod } = crash;
|
|
23489
|
+
const term = cs.lastState?.terminated;
|
|
23490
|
+
const termReason = typeof term?.reason === "string" ? term.reason : void 0;
|
|
23491
|
+
const termMsg = typeof term?.message === "string" ? term.message.trim() : void 0;
|
|
23492
|
+
const restarts = typeof cs.restartCount === "number" ? cs.restartCount : 0;
|
|
23493
|
+
const detail = termReason ? `last terminated: ${termReason}${termMsg ? ` \u2014 ${termMsg}` : ""}${typeof term?.exitCode === "number" ? ` (exit ${term.exitCode})` : ""}` : "no last-termination detail reported";
|
|
23494
|
+
const attrs = { "k8s.waitingReason": CRASH_LOOP_REASON, "k8s.restartCount": restarts };
|
|
23495
|
+
if (termReason) attrs["k8s.terminatedReason"] = termReason;
|
|
23496
|
+
if (termMsg) attrs["k8s.terminatedMessage"] = termMsg;
|
|
23497
|
+
if (typeof term?.exitCode === "number") attrs["k8s.exitCode"] = term.exitCode;
|
|
23498
|
+
if (typeof cs.image === "string") attrs["k8s.image"] = cs.image;
|
|
23499
|
+
return {
|
|
23500
|
+
fault: "crash-loop",
|
|
23501
|
+
message: `Deployment ${name} is crashlooping (restarts: ${restarts}); ${detail}`,
|
|
23502
|
+
timestamp: term?.finishedAt ?? pod.status?.startTime ?? nowIso2(),
|
|
23503
|
+
attributes: attrs
|
|
23504
|
+
};
|
|
23505
|
+
}
|
|
23506
|
+
return null;
|
|
23507
|
+
}
|
|
23508
|
+
function classifyDeployment(deployment, pods, expectedZero) {
|
|
23509
|
+
const name = deployment.metadata?.name ?? "";
|
|
23510
|
+
const desired = typeof deployment.spec?.replicas === "number" ? deployment.spec.replicas : 1;
|
|
23511
|
+
const ready = typeof deployment.status?.readyReplicas === "number" ? deployment.status.readyReplicas : 0;
|
|
23512
|
+
if (desired === 0) {
|
|
23513
|
+
if (expectedZero?.has(name)) return null;
|
|
23514
|
+
return {
|
|
23515
|
+
fault: "scaled-to-zero",
|
|
23516
|
+
message: `Deployment ${name} is scaled to 0 \u2014 no running pods (desired 0)`,
|
|
23517
|
+
timestamp: nowIso2(),
|
|
23518
|
+
attributes: { "k8s.desiredReplicas": 0, "k8s.readyReplicas": ready }
|
|
23519
|
+
};
|
|
23520
|
+
}
|
|
23521
|
+
if (ready >= desired) return null;
|
|
23522
|
+
const podFault = podLevelFault(deployment, pods);
|
|
23523
|
+
if (podFault) {
|
|
23524
|
+
podFault.attributes["k8s.desiredReplicas"] = desired;
|
|
23525
|
+
podFault.attributes["k8s.readyReplicas"] = ready;
|
|
23526
|
+
return podFault;
|
|
23527
|
+
}
|
|
23528
|
+
return {
|
|
23529
|
+
fault: "no-ready-replicas",
|
|
23530
|
+
message: `Deployment ${name} has no ready replicas (desired ${desired}, ready ${ready})`,
|
|
23531
|
+
timestamp: nowIso2(),
|
|
23532
|
+
attributes: { "k8s.desiredReplicas": desired, "k8s.readyReplicas": ready }
|
|
23533
|
+
};
|
|
23534
|
+
}
|
|
23535
|
+
function mapDeploymentToSignal(deployment, pods, config) {
|
|
23536
|
+
const name = deployment.metadata?.name;
|
|
23537
|
+
if (typeof name !== "string" || name.length === 0) return null;
|
|
23538
|
+
const expectedZero = config.expectedZero ? new Set(config.expectedZero) : void 0;
|
|
23539
|
+
const finding = classifyDeployment(deployment, pods, expectedZero);
|
|
23540
|
+
if (!finding) return null;
|
|
23541
|
+
const serviceName = serviceNameFor(deployment, config);
|
|
23542
|
+
const namespace = deployment.metadata?.namespace ?? config.namespace;
|
|
23543
|
+
const attributes = {
|
|
23544
|
+
"k8s.namespace": namespace,
|
|
23545
|
+
"k8s.deployment": name,
|
|
23546
|
+
"k8s.fault": finding.fault,
|
|
23547
|
+
...finding.attributes
|
|
23548
|
+
};
|
|
23549
|
+
return {
|
|
23550
|
+
targetKind: K8S_TARGET_KIND,
|
|
23551
|
+
targetName: packK8sTargetName({ serviceName, fault: finding.fault }),
|
|
23552
|
+
// Incident-only — no edge, so no call/error count to replay.
|
|
23553
|
+
callCount: 0,
|
|
23554
|
+
errorCount: 0,
|
|
23555
|
+
lastObservedIso: finding.timestamp,
|
|
23556
|
+
incident: {
|
|
23557
|
+
id: `k8s:deploy:${namespace}:${name}:${finding.fault}`,
|
|
23558
|
+
timestamp: finding.timestamp,
|
|
23559
|
+
service: serviceName,
|
|
23560
|
+
errorType: "k8s-deploy-failure",
|
|
23561
|
+
errorMessage: finding.message,
|
|
23562
|
+
attributes
|
|
23563
|
+
}
|
|
23564
|
+
};
|
|
23565
|
+
}
|
|
23566
|
+
function mapWorkloadsToSignals(deployments, pods, config) {
|
|
23567
|
+
const out = [];
|
|
23568
|
+
for (const deployment of deployments) {
|
|
23569
|
+
const signal = mapDeploymentToSignal(deployment, pods, config);
|
|
23570
|
+
if (signal) out.push(signal);
|
|
23571
|
+
}
|
|
23572
|
+
return out;
|
|
23573
|
+
}
|
|
23574
|
+
|
|
23575
|
+
// src/connectors/kubernetes/resolve.ts
|
|
23576
|
+
init_cjs_shims();
|
|
23577
|
+
var import_types102 = require("@neat.is/types");
|
|
23578
|
+
var NO_ENV3 = "unknown";
|
|
23579
|
+
function createK8sResolveTarget(graph) {
|
|
23580
|
+
return (signal) => {
|
|
23581
|
+
if (signal.targetKind !== K8S_TARGET_KIND) return null;
|
|
23582
|
+
const identity = parseK8sTargetName(signal.targetName);
|
|
23583
|
+
if (!identity) return null;
|
|
23584
|
+
const { serviceName } = identity;
|
|
23585
|
+
return {
|
|
23586
|
+
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV3),
|
|
23587
|
+
serviceName,
|
|
23588
|
+
edgeType: import_types102.EdgeType.CALLS
|
|
23589
|
+
};
|
|
23590
|
+
};
|
|
23591
|
+
}
|
|
23592
|
+
|
|
23593
|
+
// src/connectors/kubernetes/substrate.ts
|
|
23594
|
+
init_cjs_shims();
|
|
23595
|
+
var import_promises = require("fs/promises");
|
|
23596
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
23597
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
23598
|
+
function defaultHome() {
|
|
23599
|
+
const override = process.env.NEAT_HOME;
|
|
23600
|
+
if (override && override.length > 0) return import_node_path75.default.resolve(override);
|
|
23601
|
+
return import_node_path75.default.join(import_node_os5.default.homedir(), ".neat");
|
|
23602
|
+
}
|
|
23603
|
+
function k8sSubstrateConfigPath(home = defaultHome()) {
|
|
23604
|
+
return import_node_path75.default.join(home, "k8s.json");
|
|
23605
|
+
}
|
|
23606
|
+
async function readK8sSubstrateConfig(home = defaultHome()) {
|
|
23607
|
+
let raw;
|
|
23608
|
+
try {
|
|
23609
|
+
raw = await (0, import_promises.readFile)(k8sSubstrateConfigPath(home), "utf8");
|
|
23610
|
+
} catch {
|
|
23611
|
+
return { version: 1, deployments: [] };
|
|
23612
|
+
}
|
|
23613
|
+
try {
|
|
23614
|
+
const parsed = JSON.parse(raw);
|
|
23615
|
+
if (!parsed || !Array.isArray(parsed.deployments)) return { version: 1, deployments: [] };
|
|
23616
|
+
return parsed;
|
|
23617
|
+
} catch {
|
|
23618
|
+
return { version: 1, deployments: [] };
|
|
23619
|
+
}
|
|
23620
|
+
}
|
|
23621
|
+
async function startK8sSubstratePolling(input) {
|
|
23622
|
+
const config = await readK8sSubstrateConfig(input.home);
|
|
23623
|
+
const env = input.env ?? process.env;
|
|
23624
|
+
const stops = [];
|
|
23625
|
+
for (const entry of config.deployments) {
|
|
23626
|
+
if (entry.project !== void 0 && entry.project !== input.project) continue;
|
|
23627
|
+
if (typeof entry.namespace !== "string" || entry.namespace.length === 0) {
|
|
23628
|
+
input.onSkip?.(entry, "missing namespace");
|
|
23629
|
+
continue;
|
|
23630
|
+
}
|
|
23631
|
+
let credentials;
|
|
23632
|
+
try {
|
|
23633
|
+
const resolved = resolveCredential(entry.credential, env);
|
|
23634
|
+
credentials = resolved.kind === "fields" ? { ...resolved.fields } : { token: resolved.value };
|
|
23635
|
+
} catch (err) {
|
|
23636
|
+
input.onSkip?.(entry, err.message);
|
|
23637
|
+
continue;
|
|
23638
|
+
}
|
|
23639
|
+
const cfg = {
|
|
23640
|
+
namespace: entry.namespace,
|
|
23641
|
+
...entry.apiServerUrl ? { apiServerUrl: entry.apiServerUrl } : {},
|
|
23642
|
+
...entry.caCert ? { caCert: entry.caCert } : {},
|
|
23643
|
+
...entry.insecureSkipTlsVerify ? { insecureSkipTlsVerify: true } : {},
|
|
23644
|
+
...entry.serviceMap ? { serviceMap: entry.serviceMap } : {},
|
|
23645
|
+
...entry.expectedZero ? { expectedZero: entry.expectedZero } : {}
|
|
23646
|
+
};
|
|
23647
|
+
const { connector, resolveTarget } = createKubernetesConnector(input.graph, cfg, input.fetchImpl);
|
|
23648
|
+
const stop = startConnectorPollLoop(
|
|
23649
|
+
connector,
|
|
23650
|
+
{
|
|
23651
|
+
projectDir: input.projectDir,
|
|
23652
|
+
project: input.project,
|
|
23653
|
+
credentials,
|
|
23654
|
+
...input.errorsPath ? { errorsPath: input.errorsPath } : {}
|
|
23655
|
+
},
|
|
23656
|
+
input.graph,
|
|
23657
|
+
resolveTarget,
|
|
23658
|
+
{ connectorId: `k8s:${entry.id}`, ...entry.intervalMs ? { intervalMs: entry.intervalMs } : {} }
|
|
23659
|
+
);
|
|
23660
|
+
stops.push(stop);
|
|
23661
|
+
}
|
|
23662
|
+
return () => {
|
|
23663
|
+
for (const stop of stops) stop();
|
|
23664
|
+
};
|
|
23665
|
+
}
|
|
23666
|
+
|
|
23667
|
+
// src/connectors/kubernetes/index.ts
|
|
23668
|
+
var KubernetesConnector = class {
|
|
23669
|
+
constructor(config, fetchImpl) {
|
|
23670
|
+
this.config = config;
|
|
23671
|
+
this.fetchImpl = fetchImpl;
|
|
23672
|
+
}
|
|
23673
|
+
config;
|
|
23674
|
+
fetchImpl;
|
|
23675
|
+
provider = "kubernetes";
|
|
23676
|
+
async poll(ctx) {
|
|
23677
|
+
const creds = readK8sCredentials(ctx.credentials);
|
|
23678
|
+
const transport = resolveK8sTransport(creds, this.config);
|
|
23679
|
+
const namespace = this.config.namespace;
|
|
23680
|
+
const opts = {
|
|
23681
|
+
...this.config.apiUrl ? { apiUrl: this.config.apiUrl } : {},
|
|
23682
|
+
...this.fetchImpl ? { fetchImpl: this.fetchImpl } : {}
|
|
23683
|
+
};
|
|
23684
|
+
const [deployments, pods] = await Promise.all([
|
|
23685
|
+
fetchDeployments(transport, namespace, opts),
|
|
23686
|
+
fetchPods(transport, namespace, opts)
|
|
23687
|
+
]);
|
|
23688
|
+
return mapWorkloadsToSignals(deployments, pods, this.config);
|
|
23689
|
+
}
|
|
23690
|
+
};
|
|
23691
|
+
function createKubernetesConnector(graph, config, fetchImpl) {
|
|
23692
|
+
return {
|
|
23693
|
+
connector: new KubernetesConnector(config, fetchImpl),
|
|
23694
|
+
resolveTarget: createK8sResolveTarget(graph)
|
|
23695
|
+
};
|
|
23696
|
+
}
|
|
23697
|
+
|
|
23698
|
+
// src/daemon.ts
|
|
23130
23699
|
init_auth();
|
|
23131
23700
|
|
|
23132
23701
|
// src/unrouted.ts
|
|
23133
23702
|
init_cjs_shims();
|
|
23134
|
-
var
|
|
23135
|
-
var
|
|
23703
|
+
var import_node_fs40 = require("fs");
|
|
23704
|
+
var import_node_path76 = __toESM(require("path"), 1);
|
|
23136
23705
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
23137
23706
|
return {
|
|
23138
23707
|
timestamp: now.toISOString(),
|
|
@@ -23142,34 +23711,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
23142
23711
|
};
|
|
23143
23712
|
}
|
|
23144
23713
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
23145
|
-
const target =
|
|
23146
|
-
await
|
|
23147
|
-
await
|
|
23714
|
+
const target = import_node_path76.default.join(neatHome3, "errors.ndjson");
|
|
23715
|
+
await import_node_fs40.promises.mkdir(neatHome3, { recursive: true });
|
|
23716
|
+
await import_node_fs40.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
23148
23717
|
}
|
|
23149
23718
|
function unroutedErrorsPath(neatHome3) {
|
|
23150
|
-
return
|
|
23719
|
+
return import_node_path76.default.join(neatHome3, "errors.ndjson");
|
|
23151
23720
|
}
|
|
23152
23721
|
|
|
23153
23722
|
// src/daemon.ts
|
|
23154
|
-
var
|
|
23723
|
+
var import_types105 = require("@neat.is/types");
|
|
23155
23724
|
function daemonJsonPath(scanPath) {
|
|
23156
|
-
return
|
|
23725
|
+
return import_node_path77.default.join(scanPath, "neat-out", "daemon.json");
|
|
23157
23726
|
}
|
|
23158
23727
|
function daemonsDiscoveryDir(home) {
|
|
23159
23728
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
23160
|
-
return
|
|
23729
|
+
return import_node_path77.default.join(base, "daemons");
|
|
23161
23730
|
}
|
|
23162
23731
|
function daemonDiscoveryPath(project, home) {
|
|
23163
|
-
return
|
|
23732
|
+
return import_node_path77.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
23164
23733
|
}
|
|
23165
23734
|
function sanitizeDiscoveryName(project) {
|
|
23166
23735
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
23167
23736
|
}
|
|
23168
23737
|
function neatHomeFromEnv() {
|
|
23169
23738
|
const env = process.env.NEAT_HOME;
|
|
23170
|
-
if (env && env.length > 0) return
|
|
23739
|
+
if (env && env.length > 0) return import_node_path77.default.resolve(env);
|
|
23171
23740
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
23172
|
-
return
|
|
23741
|
+
return import_node_path77.default.join(home, ".neat");
|
|
23173
23742
|
}
|
|
23174
23743
|
function resolveNeatVersion() {
|
|
23175
23744
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -23201,7 +23770,7 @@ async function clearDaemonRecord(record, home) {
|
|
|
23201
23770
|
} catch {
|
|
23202
23771
|
}
|
|
23203
23772
|
try {
|
|
23204
|
-
await
|
|
23773
|
+
await import_node_fs41.promises.unlink(daemonDiscoveryPath(record.project, home));
|
|
23205
23774
|
} catch {
|
|
23206
23775
|
}
|
|
23207
23776
|
}
|
|
@@ -23218,17 +23787,21 @@ function teardownSlot(slot) {
|
|
|
23218
23787
|
slot.stopConnectors();
|
|
23219
23788
|
} catch {
|
|
23220
23789
|
}
|
|
23790
|
+
try {
|
|
23791
|
+
slot.stopK8sSubstrate();
|
|
23792
|
+
} catch {
|
|
23793
|
+
}
|
|
23221
23794
|
try {
|
|
23222
23795
|
slot.detachEvents();
|
|
23223
23796
|
} catch {
|
|
23224
23797
|
}
|
|
23225
23798
|
}
|
|
23226
23799
|
function neatHomeFor(opts) {
|
|
23227
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
23800
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path77.default.resolve(opts.neatHome);
|
|
23228
23801
|
const env = process.env.NEAT_HOME;
|
|
23229
|
-
if (env && env.length > 0) return
|
|
23802
|
+
if (env && env.length > 0) return import_node_path77.default.resolve(env);
|
|
23230
23803
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
23231
|
-
return
|
|
23804
|
+
return import_node_path77.default.join(home, ".neat");
|
|
23232
23805
|
}
|
|
23233
23806
|
function routeSpanToProject(serviceName, projects) {
|
|
23234
23807
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -23276,13 +23849,13 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
23276
23849
|
if (!serviceName) return true;
|
|
23277
23850
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
23278
23851
|
return graph.someNode(
|
|
23279
|
-
(_id, attrs) => attrs.type ===
|
|
23852
|
+
(_id, attrs) => attrs.type === import_types105.NodeType.ServiceNode && attrs.name === serviceName
|
|
23280
23853
|
);
|
|
23281
23854
|
}
|
|
23282
23855
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
23283
|
-
const paths = pathsForProject(entry.name,
|
|
23856
|
+
const paths = pathsForProject(entry.name, import_node_path77.default.join(entry.path, "neat-out"));
|
|
23284
23857
|
try {
|
|
23285
|
-
const stat = await
|
|
23858
|
+
const stat = await import_node_fs41.promises.stat(entry.path);
|
|
23286
23859
|
if (!stat.isDirectory()) {
|
|
23287
23860
|
throw new Error(`registered path ${entry.path} is not a directory`);
|
|
23288
23861
|
}
|
|
@@ -23302,6 +23875,8 @@ async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
|
23302
23875
|
},
|
|
23303
23876
|
stopConnectors: () => {
|
|
23304
23877
|
},
|
|
23878
|
+
stopK8sSubstrate: () => {
|
|
23879
|
+
},
|
|
23305
23880
|
detachEvents: () => {
|
|
23306
23881
|
},
|
|
23307
23882
|
status: "broken",
|
|
@@ -23334,6 +23909,14 @@ async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
|
23334
23909
|
`neatd: connector "${skipped.id}" (${skipped.provider}) skipped for project "${entry.name}" \u2014 ${reason}`
|
|
23335
23910
|
)
|
|
23336
23911
|
});
|
|
23912
|
+
const stopK8sSubstrate = await startK8sSubstratePolling({
|
|
23913
|
+
project: entry.name,
|
|
23914
|
+
graph,
|
|
23915
|
+
projectDir: entry.path,
|
|
23916
|
+
errorsPath: paths.errorsPath,
|
|
23917
|
+
...neatHome3 ? { home: neatHome3 } : {},
|
|
23918
|
+
onSkip: (skipped, reason) => console.warn(`neatd: k8s substrate "${skipped.id}" skipped for project "${entry.name}" \u2014 ${reason}`)
|
|
23919
|
+
});
|
|
23337
23920
|
await touchLastSeen(entry.name).catch(() => {
|
|
23338
23921
|
});
|
|
23339
23922
|
return {
|
|
@@ -23344,6 +23927,7 @@ async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
|
23344
23927
|
stopPersist,
|
|
23345
23928
|
stopStaleness,
|
|
23346
23929
|
stopConnectors,
|
|
23930
|
+
stopK8sSubstrate,
|
|
23347
23931
|
detachEvents,
|
|
23348
23932
|
status: "active"
|
|
23349
23933
|
};
|
|
@@ -23400,7 +23984,7 @@ async function startDaemon(opts = {}) {
|
|
|
23400
23984
|
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;
|
|
23401
23985
|
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;
|
|
23402
23986
|
const singleProject = projectArg;
|
|
23403
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
23987
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path77.default.resolve(projectPathArg) : null;
|
|
23404
23988
|
if (singleProject && !singleProjectPath) {
|
|
23405
23989
|
throw new Error(
|
|
23406
23990
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -23408,14 +23992,14 @@ async function startDaemon(opts = {}) {
|
|
|
23408
23992
|
}
|
|
23409
23993
|
if (!singleProject) {
|
|
23410
23994
|
try {
|
|
23411
|
-
await
|
|
23995
|
+
await import_node_fs41.promises.access(regPath);
|
|
23412
23996
|
} catch {
|
|
23413
23997
|
throw new Error(
|
|
23414
23998
|
`neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
|
|
23415
23999
|
);
|
|
23416
24000
|
}
|
|
23417
24001
|
}
|
|
23418
|
-
const pidPath =
|
|
24002
|
+
const pidPath = import_node_path77.default.join(home, "neatd.pid");
|
|
23419
24003
|
await writeAtomically(pidPath, `${process.pid}
|
|
23420
24004
|
`);
|
|
23421
24005
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -23627,7 +24211,7 @@ async function startDaemon(opts = {}) {
|
|
|
23627
24211
|
}
|
|
23628
24212
|
if (restApp) await restApp.close().catch(() => {
|
|
23629
24213
|
});
|
|
23630
|
-
await
|
|
24214
|
+
await import_node_fs41.promises.unlink(pidPath).catch(() => {
|
|
23631
24215
|
});
|
|
23632
24216
|
throw new Error(
|
|
23633
24217
|
`neatd: failed to bind REST on port ${restPort} \u2014 ${err.message}`
|
|
@@ -23805,7 +24389,7 @@ async function startDaemon(opts = {}) {
|
|
|
23805
24389
|
});
|
|
23806
24390
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
23807
24391
|
});
|
|
23808
|
-
await
|
|
24392
|
+
await import_node_fs41.promises.unlink(pidPath).catch(() => {
|
|
23809
24393
|
});
|
|
23810
24394
|
throw new Error(
|
|
23811
24395
|
`neatd: failed to bind OTLP on port ${otlpPort} \u2014 ${err.message}`
|
|
@@ -23840,7 +24424,7 @@ async function startDaemon(opts = {}) {
|
|
|
23840
24424
|
});
|
|
23841
24425
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
23842
24426
|
});
|
|
23843
|
-
await
|
|
24427
|
+
await import_node_fs41.promises.unlink(pidPath).catch(() => {
|
|
23844
24428
|
});
|
|
23845
24429
|
throw new Error(
|
|
23846
24430
|
`neatd: failed to write daemon.json for "${singleProject}" \u2014 ${err.message}`
|
|
@@ -23887,9 +24471,9 @@ async function startDaemon(opts = {}) {
|
|
|
23887
24471
|
let registryWatcher = null;
|
|
23888
24472
|
let reloadTimer = null;
|
|
23889
24473
|
if (!singleProject) try {
|
|
23890
|
-
const regDir =
|
|
23891
|
-
const regBase =
|
|
23892
|
-
registryWatcher = (0,
|
|
24474
|
+
const regDir = import_node_path77.default.dirname(regPath);
|
|
24475
|
+
const regBase = import_node_path77.default.basename(regPath);
|
|
24476
|
+
registryWatcher = (0, import_node_fs41.watch)(regDir, (_eventType, filename) => {
|
|
23893
24477
|
if (filename !== null && filename !== regBase) return;
|
|
23894
24478
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
23895
24479
|
reloadTimer = setTimeout(() => {
|
|
@@ -23938,7 +24522,7 @@ async function startDaemon(opts = {}) {
|
|
|
23938
24522
|
if (daemonRecord) {
|
|
23939
24523
|
await clearDaemonRecord(daemonRecord, home);
|
|
23940
24524
|
}
|
|
23941
|
-
await
|
|
24525
|
+
await import_node_fs41.promises.unlink(pidPath).catch(() => {
|
|
23942
24526
|
});
|
|
23943
24527
|
};
|
|
23944
24528
|
return {
|