@neat.is/core 0.7.6 → 0.7.7
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-6H757ZNM.js → chunk-4GCV46AP.js} +2 -2
- package/dist/{chunk-XT4NNFH6.js → chunk-UI3AFJAF.js} +765 -216
- package/dist/chunk-UI3AFJAF.js.map +1 -0
- package/dist/{chunk-P2ZEKJ35.js → chunk-Y43UCVZS.js} +9 -6
- package/dist/chunk-Y43UCVZS.js.map +1 -0
- package/dist/{chunk-XHSK4BGL.js → chunk-YVZRBT4C.js} +3 -3
- package/dist/cli.cjs +1143 -590
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +945 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +954 -401
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-APVZSB6W.js → otel-grpc-DPSAGRUU.js} +3 -3
- package/dist/server.cjs +877 -324
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-P2ZEKJ35.js.map +0 -1
- package/dist/chunk-XT4NNFH6.js.map +0 -1
- /package/dist/{chunk-6H757ZNM.js.map → chunk-4GCV46AP.js.map} +0 -0
- /package/dist/{chunk-XHSK4BGL.js.map → chunk-YVZRBT4C.js.map} +0 -0
- /package/dist/{otel-grpc-APVZSB6W.js.map → otel-grpc-DPSAGRUU.js.map} +0 -0
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 path68 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
64
|
+
if (exactUnauthPaths.has(path68) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path68)) {
|
|
65
65
|
done();
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
@@ -342,7 +342,7 @@ function pickEnv(spanAttrs, resourceAttrs) {
|
|
|
342
342
|
return ENV_FALLBACK;
|
|
343
343
|
}
|
|
344
344
|
function normalizeDbSystem(attrs) {
|
|
345
|
-
const raw = attrs["db.system"];
|
|
345
|
+
const raw = attrs["db.system"] ?? attrs["db.system.name"];
|
|
346
346
|
if (typeof raw !== "string") return void 0;
|
|
347
347
|
return raw === "mongoose" ? "mongodb" : raw;
|
|
348
348
|
}
|
|
@@ -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 path68 = q === -1 ? v : v.slice(0, q);
|
|
418
|
+
if (path68.length > 0) return path68;
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
return void 0;
|
|
@@ -434,6 +434,9 @@ function parseOtlpRequest(body) {
|
|
|
434
434
|
for (const ss of rs.scopeSpans ?? []) {
|
|
435
435
|
for (const span of ss.spans ?? []) {
|
|
436
436
|
const attrs = attrsToRecord(span.attributes);
|
|
437
|
+
const dbSqlText = typeof attrs["db.statement"] === "string" ? attrs["db.statement"] : typeof attrs["db.query.text"] === "string" ? attrs["db.query.text"] : void 0;
|
|
438
|
+
const dbSystemName = normalizeDbSystem(attrs);
|
|
439
|
+
const directDbTable = typeof attrs["db.sql.table"] === "string" ? attrs["db.sql.table"] : dbSystemName !== "mongodb" && typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : void 0;
|
|
437
440
|
const parsed = {
|
|
438
441
|
service,
|
|
439
442
|
resourceServiceNamePresent,
|
|
@@ -448,11 +451,11 @@ function parseOtlpRequest(body) {
|
|
|
448
451
|
durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),
|
|
449
452
|
env: pickEnv(attrs, resourceAttrs),
|
|
450
453
|
attributes: attrs,
|
|
451
|
-
dbSystem:
|
|
454
|
+
dbSystem: dbSystemName,
|
|
452
455
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
453
456
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
454
|
-
dbTable:
|
|
455
|
-
dbColumns:
|
|
457
|
+
dbTable: directDbTable ?? (dbSqlText ? tableFromSqlStatement(dbSqlText) ?? void 0 : void 0),
|
|
458
|
+
dbColumns: dbSqlText ? columnsFromSqlStatement(dbSqlText) : void 0,
|
|
456
459
|
httpRoute: typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0,
|
|
457
460
|
httpMethod: typeof attrs["http.request.method"] === "string" ? attrs["http.request.method"] : typeof attrs["http.method"] === "string" ? attrs["http.method"] : void 0,
|
|
458
461
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
@@ -1314,19 +1317,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1314
1317
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1315
1318
|
let best = { path: [start], edges: [] };
|
|
1316
1319
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1317
|
-
function step(node,
|
|
1318
|
-
if (
|
|
1319
|
-
best = { path: [...
|
|
1320
|
+
function step(node, path68, edges) {
|
|
1321
|
+
if (path68.length > best.path.length) {
|
|
1322
|
+
best = { path: [...path68], edges: [...edges] };
|
|
1320
1323
|
}
|
|
1321
|
-
if (
|
|
1324
|
+
if (path68.length - 1 >= maxDepth) return;
|
|
1322
1325
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1323
1326
|
for (const [srcId, edge] of incoming) {
|
|
1324
1327
|
if (visited.has(srcId)) continue;
|
|
1325
1328
|
visited.add(srcId);
|
|
1326
|
-
|
|
1329
|
+
path68.push(srcId);
|
|
1327
1330
|
edges.push(edge);
|
|
1328
|
-
step(srcId,
|
|
1329
|
-
|
|
1331
|
+
step(srcId, path68, edges);
|
|
1332
|
+
path68.pop();
|
|
1330
1333
|
edges.pop();
|
|
1331
1334
|
visited.delete(srcId);
|
|
1332
1335
|
}
|
|
@@ -1334,11 +1337,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1334
1337
|
step(start, [start], []);
|
|
1335
1338
|
return best;
|
|
1336
1339
|
}
|
|
1337
|
-
function databaseRootCauseShape(graph, origin,
|
|
1340
|
+
function databaseRootCauseShape(graph, origin, walk9) {
|
|
1338
1341
|
const targetDb = origin;
|
|
1339
1342
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1340
1343
|
if (candidatePairs.length === 0) return null;
|
|
1341
|
-
for (const id of
|
|
1344
|
+
for (const id of walk9.path) {
|
|
1342
1345
|
const owner = resolveOwningService(graph, id);
|
|
1343
1346
|
if (!owner) continue;
|
|
1344
1347
|
const { id: serviceId9, svc } = owner;
|
|
@@ -1365,8 +1368,8 @@ function databaseRootCauseShape(graph, origin, walk8) {
|
|
|
1365
1368
|
}
|
|
1366
1369
|
return null;
|
|
1367
1370
|
}
|
|
1368
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1369
|
-
for (const id of
|
|
1371
|
+
function serviceRootCauseShape(graph, _origin, walk9) {
|
|
1372
|
+
for (const id of walk9.path) {
|
|
1370
1373
|
const owner = resolveOwningService(graph, id);
|
|
1371
1374
|
if (!owner) continue;
|
|
1372
1375
|
const { id: serviceId9, svc } = owner;
|
|
@@ -1402,15 +1405,15 @@ function serviceRootCauseShape(graph, _origin, walk8) {
|
|
|
1402
1405
|
}
|
|
1403
1406
|
return null;
|
|
1404
1407
|
}
|
|
1405
|
-
function fileRootCauseShape(graph, origin,
|
|
1408
|
+
function fileRootCauseShape(graph, origin, walk9) {
|
|
1406
1409
|
const owner = resolveOwningService(graph, origin.id);
|
|
1407
1410
|
if (!owner) return null;
|
|
1408
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1411
|
+
return serviceRootCauseShape(graph, owner.svc, walk9);
|
|
1409
1412
|
}
|
|
1410
|
-
function symbolRootCauseShape(graph, origin,
|
|
1413
|
+
function symbolRootCauseShape(graph, origin, walk9) {
|
|
1411
1414
|
const owner = resolveOwningService(graph, origin.id);
|
|
1412
1415
|
if (!owner) return null;
|
|
1413
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1416
|
+
return serviceRootCauseShape(graph, owner.svc, walk9);
|
|
1414
1417
|
}
|
|
1415
1418
|
var rootCauseShapes = {
|
|
1416
1419
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1423,16 +1426,16 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1423
1426
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1424
1427
|
const shape = rootCauseShapes[origin.type];
|
|
1425
1428
|
if (shape) {
|
|
1426
|
-
const
|
|
1427
|
-
const match = shape(graph, origin,
|
|
1429
|
+
const walk9 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1430
|
+
const match = shape(graph, origin, walk9);
|
|
1428
1431
|
if (match) {
|
|
1429
1432
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1430
1433
|
return import_types.RootCauseResultSchema.parse({
|
|
1431
1434
|
rootCauseNode: match.rootCauseNode,
|
|
1432
1435
|
rootCauseReason: reason,
|
|
1433
|
-
traversalPath:
|
|
1434
|
-
edgeProvenances:
|
|
1435
|
-
confidence: confidenceFromMix(
|
|
1436
|
+
traversalPath: walk9.path,
|
|
1437
|
+
edgeProvenances: walk9.edges.map((e) => e.provenance),
|
|
1438
|
+
confidence: confidenceFromMix(walk9.edges),
|
|
1436
1439
|
fixRecommendation: match.fixRecommendation
|
|
1437
1440
|
});
|
|
1438
1441
|
}
|
|
@@ -1533,26 +1536,26 @@ function dominantFailingCall(graph, serviceId9, visited) {
|
|
|
1533
1536
|
return best;
|
|
1534
1537
|
}
|
|
1535
1538
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1536
|
-
const
|
|
1539
|
+
const path68 = [originServiceId];
|
|
1537
1540
|
const edges = [];
|
|
1538
1541
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1539
1542
|
let current = originServiceId;
|
|
1540
1543
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1541
1544
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1542
1545
|
if (!hop) break;
|
|
1543
|
-
|
|
1546
|
+
path68.push(hop.nextService);
|
|
1544
1547
|
edges.push(hop.edge);
|
|
1545
1548
|
visited.add(hop.nextService);
|
|
1546
1549
|
current = hop.nextService;
|
|
1547
1550
|
}
|
|
1548
1551
|
if (edges.length === 0) return null;
|
|
1549
|
-
return { path:
|
|
1552
|
+
return { path: path68, edges, culprit: current };
|
|
1550
1553
|
}
|
|
1551
1554
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1552
1555
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1553
1556
|
if (!chain) return null;
|
|
1554
1557
|
const culprit = chain.culprit;
|
|
1555
|
-
const
|
|
1558
|
+
const path68 = [...chain.path];
|
|
1556
1559
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1557
1560
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1558
1561
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1560,14 +1563,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1560
1563
|
if (loc) {
|
|
1561
1564
|
let rootCauseNode = culprit;
|
|
1562
1565
|
if (loc.fileNode) {
|
|
1563
|
-
|
|
1566
|
+
path68.push(loc.fileNode);
|
|
1564
1567
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1565
1568
|
rootCauseNode = loc.fileNode;
|
|
1566
1569
|
}
|
|
1567
1570
|
return import_types.RootCauseResultSchema.parse({
|
|
1568
1571
|
rootCauseNode,
|
|
1569
1572
|
rootCauseReason: loc.rootCauseReason,
|
|
1570
|
-
traversalPath:
|
|
1573
|
+
traversalPath: path68,
|
|
1571
1574
|
edgeProvenances,
|
|
1572
1575
|
confidence,
|
|
1573
1576
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1579,7 +1582,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1579
1582
|
return import_types.RootCauseResultSchema.parse({
|
|
1580
1583
|
rootCauseNode: culprit,
|
|
1581
1584
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1582
|
-
traversalPath:
|
|
1585
|
+
traversalPath: path68,
|
|
1583
1586
|
edgeProvenances,
|
|
1584
1587
|
confidence,
|
|
1585
1588
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2514,14 +2517,14 @@ function buildServiceHostIndex(services) {
|
|
|
2514
2517
|
}
|
|
2515
2518
|
async function walkSourceFiles(dir) {
|
|
2516
2519
|
const out = [];
|
|
2517
|
-
async function
|
|
2520
|
+
async function walk9(current) {
|
|
2518
2521
|
const entries = await import_node_fs5.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2519
2522
|
for (const entry of entries) {
|
|
2520
2523
|
const full = import_node_path5.default.join(current, entry.name);
|
|
2521
2524
|
if (entry.isDirectory()) {
|
|
2522
2525
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2523
2526
|
if (await isPythonVenvDir(full)) continue;
|
|
2524
|
-
await
|
|
2527
|
+
await walk9(full);
|
|
2525
2528
|
} 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
|
|
2526
2529
|
// would attribute our instrumentation imports to the user's service.
|
|
2527
2530
|
!isNeatAuthoredSourceFile(entry.name)) {
|
|
@@ -2529,7 +2532,7 @@ async function walkSourceFiles(dir) {
|
|
|
2529
2532
|
}
|
|
2530
2533
|
}
|
|
2531
2534
|
}
|
|
2532
|
-
await
|
|
2535
|
+
await walk9(dir);
|
|
2533
2536
|
return out;
|
|
2534
2537
|
}
|
|
2535
2538
|
async function loadSourceFiles(dir) {
|
|
@@ -3043,7 +3046,7 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
3043
3046
|
]);
|
|
3044
3047
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3045
3048
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
3046
|
-
function
|
|
3049
|
+
function goRouterRoutesFromSource(source, parser, framework) {
|
|
3047
3050
|
const tree = parseSource2(parser, source);
|
|
3048
3051
|
const prefixes = /* @__PURE__ */ new Map();
|
|
3049
3052
|
const out = [];
|
|
@@ -3053,10 +3056,12 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3053
3056
|
const value = node.childForFieldName("right")?.namedChild(0) ?? node.childForFieldName("value");
|
|
3054
3057
|
if (name && value?.type === "call_expression") {
|
|
3055
3058
|
const fn2 = value.childForFieldName("function");
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3059
|
+
if (fn2?.childForFieldName("field")?.text === "Group") {
|
|
3060
|
+
const leaf2 = goStringLiteral(value.childForFieldName("arguments")?.namedChild(0));
|
|
3061
|
+
if (leaf2 !== null) {
|
|
3062
|
+
const parent = fn2.childForFieldName("operand")?.text ?? "";
|
|
3063
|
+
prefixes.set(name, (prefixes.get(parent) ?? "") + leaf2);
|
|
3064
|
+
}
|
|
3060
3065
|
}
|
|
3061
3066
|
}
|
|
3062
3067
|
return;
|
|
@@ -3067,18 +3072,32 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3067
3072
|
const method = fn.childForFieldName("field")?.text?.toUpperCase();
|
|
3068
3073
|
if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return;
|
|
3069
3074
|
const receiver = fn.childForFieldName("operand")?.text ?? "";
|
|
3070
|
-
const
|
|
3071
|
-
if (
|
|
3072
|
-
const leaf = first.text.slice(1, -1);
|
|
3075
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3076
|
+
if (leaf === null) return;
|
|
3073
3077
|
out.push({
|
|
3074
|
-
method
|
|
3078
|
+
method,
|
|
3075
3079
|
pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? "") + leaf),
|
|
3076
3080
|
line: node.startPosition.row + 1,
|
|
3077
|
-
framework
|
|
3081
|
+
framework
|
|
3078
3082
|
});
|
|
3079
3083
|
});
|
|
3080
3084
|
return out;
|
|
3081
3085
|
}
|
|
3086
|
+
function goStringLiteral(node) {
|
|
3087
|
+
if (node?.type === "interpreted_string_literal" || node?.type === "raw_string_literal") {
|
|
3088
|
+
return node.text.slice(1, -1);
|
|
3089
|
+
}
|
|
3090
|
+
return null;
|
|
3091
|
+
}
|
|
3092
|
+
function ginRoutesFromSource(source, parser) {
|
|
3093
|
+
return goRouterRoutesFromSource(source, parser, "gin");
|
|
3094
|
+
}
|
|
3095
|
+
function echoRoutesFromSource(source, parser) {
|
|
3096
|
+
return goRouterRoutesFromSource(source, parser, "echo");
|
|
3097
|
+
}
|
|
3098
|
+
function fiberRoutesFromSource(source, parser) {
|
|
3099
|
+
return goRouterRoutesFromSource(source, parser, "fiber");
|
|
3100
|
+
}
|
|
3082
3101
|
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
3083
3102
|
var NESTJS_METHODS = /* @__PURE__ */ new Map([
|
|
3084
3103
|
["Get", "GET"],
|
|
@@ -3663,9 +3682,9 @@ function rubyRocketRoute(args) {
|
|
|
3663
3682
|
if (!pair || pair.type !== "pair") continue;
|
|
3664
3683
|
const k = pair.childForFieldName("key");
|
|
3665
3684
|
if (k?.type !== "string") continue;
|
|
3666
|
-
const
|
|
3667
|
-
if (
|
|
3668
|
-
return { path:
|
|
3685
|
+
const path68 = rubyLiteral(k);
|
|
3686
|
+
if (path68 === null) continue;
|
|
3687
|
+
return { path: path68, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3669
3688
|
}
|
|
3670
3689
|
return null;
|
|
3671
3690
|
}
|
|
@@ -4342,9 +4361,11 @@ async function addRoutes(graph, services) {
|
|
|
4342
4361
|
const hasFlask = deps["flask"] !== void 0;
|
|
4343
4362
|
const hasDjango = deps["django"] !== void 0;
|
|
4344
4363
|
const hasGin = deps["github.com/gin-gonic/gin"] !== void 0;
|
|
4364
|
+
const hasEcho = deps["github.com/labstack/echo/v4"] !== void 0 || deps["github.com/labstack/echo"] !== void 0;
|
|
4365
|
+
const hasFiber = deps["github.com/gofiber/fiber/v2"] !== void 0 || deps["github.com/gofiber/fiber/v3"] !== void 0;
|
|
4345
4366
|
const hasRails = deps["rails"] !== void 0;
|
|
4346
4367
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4347
|
-
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasRails && !hasLaravel)
|
|
4368
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasRails && !hasLaravel)
|
|
4348
4369
|
continue;
|
|
4349
4370
|
const files = await loadSourceFiles(service.dir);
|
|
4350
4371
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4368,7 +4389,10 @@ async function addRoutes(graph, services) {
|
|
|
4368
4389
|
} else if (isRb) {
|
|
4369
4390
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4370
4391
|
} else if (isGo) {
|
|
4371
|
-
routes =
|
|
4392
|
+
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4393
|
+
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
4394
|
+
else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser);
|
|
4395
|
+
else routes = [];
|
|
4372
4396
|
} else if (isPy) {
|
|
4373
4397
|
routes = hasFastapi || hasFlask ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? "fastapi" : "flask") : [];
|
|
4374
4398
|
if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser));
|
|
@@ -5978,6 +6002,12 @@ function parseGoMod(source) {
|
|
|
5978
6002
|
}
|
|
5979
6003
|
return { module: module2, ...goVersion ? { goVersion } : {}, dependencies };
|
|
5980
6004
|
}
|
|
6005
|
+
function goFramework(deps) {
|
|
6006
|
+
if (deps["github.com/gin-gonic/gin"]) return "gin";
|
|
6007
|
+
if (deps["github.com/labstack/echo/v4"] || deps["github.com/labstack/echo"]) return "echo";
|
|
6008
|
+
if (deps["github.com/gofiber/fiber/v2"] || deps["github.com/gofiber/fiber/v3"]) return "fiber";
|
|
6009
|
+
return void 0;
|
|
6010
|
+
}
|
|
5981
6011
|
async function discoverGoService(scanPath, dir) {
|
|
5982
6012
|
let raw;
|
|
5983
6013
|
try {
|
|
@@ -5989,6 +6019,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5989
6019
|
if (!mod) return null;
|
|
5990
6020
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
5991
6021
|
const pkg = { name, dependencies: mod.dependencies };
|
|
6022
|
+
const framework = goFramework(mod.dependencies);
|
|
5992
6023
|
const node = {
|
|
5993
6024
|
id: (0, import_types9.serviceId)(name),
|
|
5994
6025
|
type: import_types9.NodeType.ServiceNode,
|
|
@@ -5996,7 +6027,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5996
6027
|
language: "go",
|
|
5997
6028
|
dependencies: mod.dependencies,
|
|
5998
6029
|
repoPath: import_node_path10.default.relative(scanPath, dir),
|
|
5999
|
-
...
|
|
6030
|
+
...framework ? { framework } : {}
|
|
6000
6031
|
};
|
|
6001
6032
|
return { pkg, dir, node };
|
|
6002
6033
|
}
|
|
@@ -6896,7 +6927,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
6896
6927
|
return best;
|
|
6897
6928
|
};
|
|
6898
6929
|
const requests = [];
|
|
6899
|
-
const
|
|
6930
|
+
const walk9 = (node) => {
|
|
6900
6931
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
6901
6932
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
6902
6933
|
if (self && self.kind === "class") {
|
|
@@ -6942,10 +6973,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
6942
6973
|
}
|
|
6943
6974
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6944
6975
|
const child = node.namedChild(i);
|
|
6945
|
-
if (child)
|
|
6976
|
+
if (child) walk9(child);
|
|
6946
6977
|
}
|
|
6947
6978
|
};
|
|
6948
|
-
|
|
6979
|
+
walk9(root);
|
|
6949
6980
|
for (const req of requests) {
|
|
6950
6981
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
6951
6982
|
if (!targetSid) continue;
|
|
@@ -7958,20 +7989,20 @@ var import_node_path28 = __toESM(require("path"), 1);
|
|
|
7958
7989
|
var import_types18 = require("@neat.is/types");
|
|
7959
7990
|
async function walkConfigFiles(dir) {
|
|
7960
7991
|
const out = [];
|
|
7961
|
-
async function
|
|
7992
|
+
async function walk9(current) {
|
|
7962
7993
|
const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true });
|
|
7963
7994
|
for (const entry of entries) {
|
|
7964
7995
|
const full = import_node_path28.default.join(current, entry.name);
|
|
7965
7996
|
if (entry.isDirectory()) {
|
|
7966
7997
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
7967
7998
|
if (await isPythonVenvDir(full)) continue;
|
|
7968
|
-
await
|
|
7999
|
+
await walk9(full);
|
|
7969
8000
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
7970
8001
|
out.push(full);
|
|
7971
8002
|
}
|
|
7972
8003
|
}
|
|
7973
8004
|
}
|
|
7974
|
-
await
|
|
8005
|
+
await walk9(dir);
|
|
7975
8006
|
return out;
|
|
7976
8007
|
}
|
|
7977
8008
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -8061,20 +8092,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
8061
8092
|
}
|
|
8062
8093
|
async function walkProtoFiles(dir) {
|
|
8063
8094
|
const out = [];
|
|
8064
|
-
async function
|
|
8095
|
+
async function walk9(current) {
|
|
8065
8096
|
const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
8066
8097
|
for (const entry of entries) {
|
|
8067
8098
|
const full = import_node_path29.default.join(current, entry.name);
|
|
8068
8099
|
if (entry.isDirectory()) {
|
|
8069
8100
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
8070
8101
|
if (await isPythonVenvDir(full)) continue;
|
|
8071
|
-
await
|
|
8102
|
+
await walk9(full);
|
|
8072
8103
|
} else if (entry.isFile() && import_node_path29.default.extname(entry.name) === PROTO_EXTENSION) {
|
|
8073
8104
|
out.push(full);
|
|
8074
8105
|
}
|
|
8075
8106
|
}
|
|
8076
8107
|
}
|
|
8077
|
-
await
|
|
8108
|
+
await walk9(dir);
|
|
8078
8109
|
return out;
|
|
8079
8110
|
}
|
|
8080
8111
|
async function addGrpcMethods(graph, services) {
|
|
@@ -8142,7 +8173,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
8142
8173
|
|
|
8143
8174
|
// src/extract/calls/index.ts
|
|
8144
8175
|
init_cjs_shims();
|
|
8145
|
-
var
|
|
8176
|
+
var import_types37 = require("@neat.is/types");
|
|
8146
8177
|
|
|
8147
8178
|
// src/extract/calls/http.ts
|
|
8148
8179
|
init_cjs_shims();
|
|
@@ -8896,7 +8927,7 @@ function isFirestoreClientFactory(node) {
|
|
|
8896
8927
|
}
|
|
8897
8928
|
function firestoreClientVars(root) {
|
|
8898
8929
|
const vars = /* @__PURE__ */ new Set();
|
|
8899
|
-
const
|
|
8930
|
+
const walk9 = (node) => {
|
|
8900
8931
|
if (node.type === "variable_declarator") {
|
|
8901
8932
|
const name = node.childForFieldName("name");
|
|
8902
8933
|
let value = node.childForFieldName("value");
|
|
@@ -8905,9 +8936,9 @@ function firestoreClientVars(root) {
|
|
|
8905
8936
|
vars.add(name.text);
|
|
8906
8937
|
}
|
|
8907
8938
|
}
|
|
8908
|
-
for (const c of namedChildren(node))
|
|
8939
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
8909
8940
|
};
|
|
8910
|
-
|
|
8941
|
+
walk9(root);
|
|
8911
8942
|
return vars;
|
|
8912
8943
|
}
|
|
8913
8944
|
function isClientExpr(node, clientVars) {
|
|
@@ -9062,7 +9093,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9062
9093
|
}
|
|
9063
9094
|
s.add(field);
|
|
9064
9095
|
};
|
|
9065
|
-
const
|
|
9096
|
+
const walk9 = (node) => {
|
|
9066
9097
|
if (node.type === "call_expression") {
|
|
9067
9098
|
const fn = node.childForFieldName("function");
|
|
9068
9099
|
const line = node.startPosition.row + 1;
|
|
@@ -9102,9 +9133,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9102
9133
|
}
|
|
9103
9134
|
}
|
|
9104
9135
|
}
|
|
9105
|
-
for (const c of namedChildren(node))
|
|
9136
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
9106
9137
|
};
|
|
9107
|
-
|
|
9138
|
+
walk9(tree.rootNode);
|
|
9108
9139
|
const out = [];
|
|
9109
9140
|
for (const [collPath, line] of collLine) {
|
|
9110
9141
|
const byField = writes.get(collPath);
|
|
@@ -9899,7 +9930,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9899
9930
|
const tree = parseSource3(parserForExt2(import_node_path41.default.extname(file.path)), file.content);
|
|
9900
9931
|
const out = [];
|
|
9901
9932
|
const seen = /* @__PURE__ */ new Set();
|
|
9902
|
-
const
|
|
9933
|
+
const walk9 = (node) => {
|
|
9903
9934
|
if (node.type === "call_expression") {
|
|
9904
9935
|
const fn = node.childForFieldName("function");
|
|
9905
9936
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9927,9 +9958,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9927
9958
|
}
|
|
9928
9959
|
}
|
|
9929
9960
|
}
|
|
9930
|
-
for (const c of namedChildren4(node))
|
|
9961
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9931
9962
|
};
|
|
9932
|
-
|
|
9963
|
+
walk9(tree.rootNode);
|
|
9933
9964
|
return out;
|
|
9934
9965
|
}
|
|
9935
9966
|
function enclosingVarName(call) {
|
|
@@ -9951,7 +9982,7 @@ function enclosingVarName(call) {
|
|
|
9951
9982
|
function collectDrizzleTables(root) {
|
|
9952
9983
|
const tables = [];
|
|
9953
9984
|
const varToTable = /* @__PURE__ */ new Map();
|
|
9954
|
-
const
|
|
9985
|
+
const walk9 = (node) => {
|
|
9955
9986
|
if (node.type === "call_expression") {
|
|
9956
9987
|
const fn = node.childForFieldName("function");
|
|
9957
9988
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9966,9 +9997,9 @@ function collectDrizzleTables(root) {
|
|
|
9966
9997
|
}
|
|
9967
9998
|
}
|
|
9968
9999
|
}
|
|
9969
|
-
for (const c of namedChildren4(node))
|
|
10000
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9970
10001
|
};
|
|
9971
|
-
|
|
10002
|
+
walk9(root);
|
|
9972
10003
|
return { tables, varToTable };
|
|
9973
10004
|
}
|
|
9974
10005
|
function referencesTargetVar(call) {
|
|
@@ -9991,7 +10022,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
9991
10022
|
const seen = /* @__PURE__ */ new Set();
|
|
9992
10023
|
for (const table of tables) {
|
|
9993
10024
|
if (!table.object) continue;
|
|
9994
|
-
const
|
|
10025
|
+
const walk9 = (node) => {
|
|
9995
10026
|
if (node.type === "call_expression") {
|
|
9996
10027
|
const targetVar = referencesTargetVar(node);
|
|
9997
10028
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -10012,9 +10043,9 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
10012
10043
|
}
|
|
10013
10044
|
}
|
|
10014
10045
|
}
|
|
10015
|
-
for (const c of namedChildren4(node))
|
|
10046
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
10016
10047
|
};
|
|
10017
|
-
|
|
10048
|
+
walk9(table.object);
|
|
10018
10049
|
}
|
|
10019
10050
|
return out;
|
|
10020
10051
|
}
|
|
@@ -11094,15 +11125,531 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
11094
11125
|
return out;
|
|
11095
11126
|
}
|
|
11096
11127
|
|
|
11128
|
+
// src/extract/calls/gorm.ts
|
|
11129
|
+
init_cjs_shims();
|
|
11130
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11131
|
+
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
11132
|
+
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
11133
|
+
var import_types36 = require("@neat.is/types");
|
|
11134
|
+
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
11135
|
+
var PARSE_CHUNK11 = 16384;
|
|
11136
|
+
function makeGoParser3() {
|
|
11137
|
+
const p = new import_tree_sitter15.default();
|
|
11138
|
+
p.setLanguage(import_tree_sitter_go4.default);
|
|
11139
|
+
return p;
|
|
11140
|
+
}
|
|
11141
|
+
function parseSource10(parser, source) {
|
|
11142
|
+
return parser.parse(
|
|
11143
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
11144
|
+
);
|
|
11145
|
+
}
|
|
11146
|
+
function walk8(node, visit) {
|
|
11147
|
+
visit(node);
|
|
11148
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11149
|
+
const c = node.namedChild(i);
|
|
11150
|
+
if (c) walk8(c, visit);
|
|
11151
|
+
}
|
|
11152
|
+
}
|
|
11153
|
+
var COMMON_INITIALISMS = [
|
|
11154
|
+
"ASCII",
|
|
11155
|
+
"HTTPS",
|
|
11156
|
+
"UTF8",
|
|
11157
|
+
"XSRF",
|
|
11158
|
+
"HTML",
|
|
11159
|
+
"HTTP",
|
|
11160
|
+
"JSON",
|
|
11161
|
+
"UUID",
|
|
11162
|
+
"XMPP",
|
|
11163
|
+
"ACL",
|
|
11164
|
+
"API",
|
|
11165
|
+
"CPU",
|
|
11166
|
+
"CSS",
|
|
11167
|
+
"DNS",
|
|
11168
|
+
"EOF",
|
|
11169
|
+
"GUID",
|
|
11170
|
+
"LHS",
|
|
11171
|
+
"QPS",
|
|
11172
|
+
"RAM",
|
|
11173
|
+
"RHS",
|
|
11174
|
+
"RPC",
|
|
11175
|
+
"SLA",
|
|
11176
|
+
"SQL",
|
|
11177
|
+
"SSH",
|
|
11178
|
+
"TCP",
|
|
11179
|
+
"TLS",
|
|
11180
|
+
"TTL",
|
|
11181
|
+
"UDP",
|
|
11182
|
+
"UID",
|
|
11183
|
+
"URI",
|
|
11184
|
+
"URL",
|
|
11185
|
+
"UID",
|
|
11186
|
+
"XSS",
|
|
11187
|
+
"ID",
|
|
11188
|
+
"IP",
|
|
11189
|
+
"UI",
|
|
11190
|
+
"VM",
|
|
11191
|
+
"XML"
|
|
11192
|
+
].sort((a, b) => b.length - a.length);
|
|
11193
|
+
function titleCase(word) {
|
|
11194
|
+
return word.charAt(0) + word.slice(1).toLowerCase();
|
|
11195
|
+
}
|
|
11196
|
+
function replaceInitialisms(name) {
|
|
11197
|
+
let out = "";
|
|
11198
|
+
let i = 0;
|
|
11199
|
+
while (i < name.length) {
|
|
11200
|
+
let matched = false;
|
|
11201
|
+
for (const init of COMMON_INITIALISMS) {
|
|
11202
|
+
if (name.startsWith(init, i)) {
|
|
11203
|
+
out += titleCase(init);
|
|
11204
|
+
i += init.length;
|
|
11205
|
+
matched = true;
|
|
11206
|
+
break;
|
|
11207
|
+
}
|
|
11208
|
+
}
|
|
11209
|
+
if (!matched) {
|
|
11210
|
+
out += name[i];
|
|
11211
|
+
i++;
|
|
11212
|
+
}
|
|
11213
|
+
}
|
|
11214
|
+
return out;
|
|
11215
|
+
}
|
|
11216
|
+
var isUpper = (c) => c >= "A" && c <= "Z";
|
|
11217
|
+
var isDigit = (c) => c >= "0" && c <= "9";
|
|
11218
|
+
function toDBName(name) {
|
|
11219
|
+
if (name === "") return "";
|
|
11220
|
+
const value = replaceInitialisms(name);
|
|
11221
|
+
if (value.length === 1) return value.toLowerCase();
|
|
11222
|
+
let buf = "";
|
|
11223
|
+
let lastCase = false;
|
|
11224
|
+
let curCase = isUpper(value[0]);
|
|
11225
|
+
for (let i = 0; i < value.length - 1; i++) {
|
|
11226
|
+
const v = value[i];
|
|
11227
|
+
const nextCase = isUpper(value[i + 1]);
|
|
11228
|
+
const nextNumber = isDigit(value[i + 1]);
|
|
11229
|
+
if (curCase) {
|
|
11230
|
+
if (lastCase && (nextCase || nextNumber)) {
|
|
11231
|
+
buf += v.toLowerCase();
|
|
11232
|
+
} else {
|
|
11233
|
+
if (i > 0 && value[i - 1] !== "_" && lastCase !== curCase) buf += "_";
|
|
11234
|
+
buf += v.toLowerCase();
|
|
11235
|
+
}
|
|
11236
|
+
} else {
|
|
11237
|
+
buf += v;
|
|
11238
|
+
}
|
|
11239
|
+
lastCase = curCase;
|
|
11240
|
+
curCase = nextCase;
|
|
11241
|
+
}
|
|
11242
|
+
const last = value[value.length - 1];
|
|
11243
|
+
if (curCase) {
|
|
11244
|
+
if (!lastCase && value.length > 1) buf += "_";
|
|
11245
|
+
buf += last.toLowerCase();
|
|
11246
|
+
} else {
|
|
11247
|
+
buf += last;
|
|
11248
|
+
}
|
|
11249
|
+
return buf;
|
|
11250
|
+
}
|
|
11251
|
+
var UNCOUNTABLE = /* @__PURE__ */ new Set([
|
|
11252
|
+
"equipment",
|
|
11253
|
+
"information",
|
|
11254
|
+
"rice",
|
|
11255
|
+
"money",
|
|
11256
|
+
"species",
|
|
11257
|
+
"series",
|
|
11258
|
+
"fish",
|
|
11259
|
+
"sheep",
|
|
11260
|
+
"jeans",
|
|
11261
|
+
"police"
|
|
11262
|
+
]);
|
|
11263
|
+
var IRREGULAR = [
|
|
11264
|
+
["person", "people"],
|
|
11265
|
+
["man", "men"],
|
|
11266
|
+
["child", "children"],
|
|
11267
|
+
["sex", "sexes"],
|
|
11268
|
+
["move", "moves"]
|
|
11269
|
+
];
|
|
11270
|
+
var PLURAL_RULES = [
|
|
11271
|
+
[/(quiz)$/i, "$1zes"],
|
|
11272
|
+
[/^(ox)$/i, "$1en"],
|
|
11273
|
+
[/([ml])ouse$/i, "$1ice"],
|
|
11274
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"],
|
|
11275
|
+
[/(x|ch|ss|sh)$/i, "$1es"],
|
|
11276
|
+
[/([^aeiouy]|qu)y$/i, "$1ies"],
|
|
11277
|
+
[/(hive)$/i, "$1s"],
|
|
11278
|
+
[/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
|
|
11279
|
+
[/sis$/i, "ses"],
|
|
11280
|
+
[/([ti])um$/i, "$1a"],
|
|
11281
|
+
[/([ti])a$/i, "$1a"],
|
|
11282
|
+
[/(buffal|tomat)o$/i, "$1oes"],
|
|
11283
|
+
[/(bu)s$/i, "$1ses"],
|
|
11284
|
+
[/(alias|status)$/i, "$1es"],
|
|
11285
|
+
[/(octop|vir)i$/i, "$1i"],
|
|
11286
|
+
[/(octop|vir)us$/i, "$1i"],
|
|
11287
|
+
[/(ax|test)is$/i, "$1es"],
|
|
11288
|
+
[/s$/i, "s"]
|
|
11289
|
+
];
|
|
11290
|
+
function pluralize3(word) {
|
|
11291
|
+
if (word === "") return word;
|
|
11292
|
+
const lower = word.toLowerCase();
|
|
11293
|
+
for (const u of UNCOUNTABLE) {
|
|
11294
|
+
if (lower === u || lower.endsWith("_" + u)) return word;
|
|
11295
|
+
}
|
|
11296
|
+
for (const [sing, plur] of IRREGULAR) {
|
|
11297
|
+
const re = new RegExp(sing + "$", "i");
|
|
11298
|
+
if (re.test(word)) return word.replace(re, plur);
|
|
11299
|
+
}
|
|
11300
|
+
for (const [re, rep] of PLURAL_RULES) {
|
|
11301
|
+
if (re.test(word)) return word.replace(re, rep);
|
|
11302
|
+
}
|
|
11303
|
+
return word + "s";
|
|
11304
|
+
}
|
|
11305
|
+
function deriveTableName(structName) {
|
|
11306
|
+
return pluralize3(toDBName(structName));
|
|
11307
|
+
}
|
|
11308
|
+
function stringLiteralValue(node) {
|
|
11309
|
+
if (!node) return null;
|
|
11310
|
+
if (node.type === "interpreted_string_literal" || node.type === "raw_string_literal") {
|
|
11311
|
+
const t = node.text;
|
|
11312
|
+
return t.length >= 2 ? t.slice(1, -1) : "";
|
|
11313
|
+
}
|
|
11314
|
+
return null;
|
|
11315
|
+
}
|
|
11316
|
+
function parseGormTag(tagNode) {
|
|
11317
|
+
const tag = {};
|
|
11318
|
+
if (!tagNode) return tag;
|
|
11319
|
+
let inner = tagNode.text;
|
|
11320
|
+
if (inner.length >= 2) inner = inner.slice(1, -1);
|
|
11321
|
+
if (tagNode.type === "interpreted_string_literal") inner = inner.replace(/\\"/g, '"');
|
|
11322
|
+
const m = inner.match(/gorm:"([^"]*)"/);
|
|
11323
|
+
if (!m) return tag;
|
|
11324
|
+
for (const part of m[1].split(";")) {
|
|
11325
|
+
if (part === "") continue;
|
|
11326
|
+
const idx = part.indexOf(":");
|
|
11327
|
+
const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase();
|
|
11328
|
+
const value = idx >= 0 ? part.slice(idx + 1).trim() : "";
|
|
11329
|
+
if (key === "-") tag.skip = true;
|
|
11330
|
+
else if (key === "column") tag.column = value;
|
|
11331
|
+
else if (key === "primarykey" || key === "primary_key") tag.primaryKey = true;
|
|
11332
|
+
else if (key === "foreignkey") tag.foreignKey = value;
|
|
11333
|
+
else if (key === "many2many") tag.many2many = value;
|
|
11334
|
+
else if (key === "embedded") tag.embedded = true;
|
|
11335
|
+
else if (key === "embeddedprefix") tag.embeddedPrefix = value;
|
|
11336
|
+
}
|
|
11337
|
+
return tag;
|
|
11338
|
+
}
|
|
11339
|
+
function unwrapType(typeNode) {
|
|
11340
|
+
let isSlice = false;
|
|
11341
|
+
let isPointer = false;
|
|
11342
|
+
let n = typeNode;
|
|
11343
|
+
while (n && (n.type === "slice_type" || n.type === "array_type" || n.type === "pointer_type")) {
|
|
11344
|
+
if (n.type === "slice_type" || n.type === "array_type") isSlice = true;
|
|
11345
|
+
if (n.type === "pointer_type") isPointer = true;
|
|
11346
|
+
n = n.childForFieldName("element") ?? n.namedChild(n.namedChildCount - 1);
|
|
11347
|
+
}
|
|
11348
|
+
if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11349
|
+
if (n.type === "type_identifier") {
|
|
11350
|
+
return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11351
|
+
}
|
|
11352
|
+
if (n.type === "qualified_type") {
|
|
11353
|
+
const pkg = n.childForFieldName("package")?.text ?? n.namedChild(0)?.text ?? null;
|
|
11354
|
+
const nm = n.childForFieldName("name")?.text ?? n.namedChild(1)?.text ?? null;
|
|
11355
|
+
return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true };
|
|
11356
|
+
}
|
|
11357
|
+
return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11358
|
+
}
|
|
11359
|
+
function readField(fieldDecl) {
|
|
11360
|
+
const names = [];
|
|
11361
|
+
let tagNode = null;
|
|
11362
|
+
for (let i = 0; i < fieldDecl.namedChildCount; i++) {
|
|
11363
|
+
const c = fieldDecl.namedChild(i);
|
|
11364
|
+
if (!c) continue;
|
|
11365
|
+
if (c.type === "field_identifier") names.push(c.text);
|
|
11366
|
+
else if (c.type === "raw_string_literal" || c.type === "interpreted_string_literal") tagNode = c;
|
|
11367
|
+
}
|
|
11368
|
+
const typeNode = fieldDecl.childForFieldName("type");
|
|
11369
|
+
const t = unwrapType(typeNode);
|
|
11370
|
+
return {
|
|
11371
|
+
names,
|
|
11372
|
+
typeName: t.name,
|
|
11373
|
+
qualifier: t.qualifier,
|
|
11374
|
+
isSlice: t.isSlice,
|
|
11375
|
+
isPointer: t.isPointer,
|
|
11376
|
+
isQualified: t.isQualified,
|
|
11377
|
+
tag: parseGormTag(tagNode),
|
|
11378
|
+
line: fieldDecl.startPosition.row + 1
|
|
11379
|
+
};
|
|
11380
|
+
}
|
|
11381
|
+
function collectStructs(tree) {
|
|
11382
|
+
const structs = /* @__PURE__ */ new Map();
|
|
11383
|
+
walk8(tree.rootNode, (node) => {
|
|
11384
|
+
if (node.type !== "type_spec") return;
|
|
11385
|
+
const nameNode = node.childForFieldName("name");
|
|
11386
|
+
const typeNode = node.childForFieldName("type");
|
|
11387
|
+
if (!nameNode || typeNode?.type !== "struct_type") return;
|
|
11388
|
+
const list = typeNode.childForFieldName("body") ?? typeNode.namedChild(0);
|
|
11389
|
+
const fields = [];
|
|
11390
|
+
if (list && list.type === "field_declaration_list") {
|
|
11391
|
+
for (let i = 0; i < list.namedChildCount; i++) {
|
|
11392
|
+
const fd = list.namedChild(i);
|
|
11393
|
+
if (fd?.type === "field_declaration") fields.push(readField(fd));
|
|
11394
|
+
}
|
|
11395
|
+
}
|
|
11396
|
+
structs.set(nameNode.text, {
|
|
11397
|
+
name: nameNode.text,
|
|
11398
|
+
fields,
|
|
11399
|
+
line: node.startPosition.row + 1
|
|
11400
|
+
});
|
|
11401
|
+
});
|
|
11402
|
+
return structs;
|
|
11403
|
+
}
|
|
11404
|
+
var GORM_MODEL_METHODS = /* @__PURE__ */ new Set([
|
|
11405
|
+
"AutoMigrate",
|
|
11406
|
+
"Model",
|
|
11407
|
+
"Create",
|
|
11408
|
+
"Find",
|
|
11409
|
+
"First",
|
|
11410
|
+
"Take",
|
|
11411
|
+
"Last",
|
|
11412
|
+
"Save",
|
|
11413
|
+
"Delete",
|
|
11414
|
+
"Where",
|
|
11415
|
+
"FirstOrCreate",
|
|
11416
|
+
"FirstOrInit"
|
|
11417
|
+
]);
|
|
11418
|
+
function compositeStructName(arg) {
|
|
11419
|
+
let n = arg;
|
|
11420
|
+
if (n.type === "unary_expression") n = n.childForFieldName("operand") ?? n.namedChild(0);
|
|
11421
|
+
if (!n || n.type !== "composite_literal") return null;
|
|
11422
|
+
const typeNode = n.childForFieldName("type");
|
|
11423
|
+
if (!typeNode) return null;
|
|
11424
|
+
if (typeNode.type === "type_identifier") return typeNode.text;
|
|
11425
|
+
if (typeNode.type === "qualified_type") {
|
|
11426
|
+
return typeNode.childForFieldName("name")?.text ?? typeNode.namedChild(1)?.text ?? null;
|
|
11427
|
+
}
|
|
11428
|
+
return null;
|
|
11429
|
+
}
|
|
11430
|
+
function collectCallModels(tree) {
|
|
11431
|
+
const models = /* @__PURE__ */ new Set();
|
|
11432
|
+
walk8(tree.rootNode, (node) => {
|
|
11433
|
+
if (node.type !== "call_expression") return;
|
|
11434
|
+
const fn = node.childForFieldName("function");
|
|
11435
|
+
if (fn?.type !== "selector_expression") return;
|
|
11436
|
+
const method = fn.childForFieldName("field")?.text;
|
|
11437
|
+
if (!method || !GORM_MODEL_METHODS.has(method)) return;
|
|
11438
|
+
const args = node.childForFieldName("arguments");
|
|
11439
|
+
if (!args) return;
|
|
11440
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
11441
|
+
const arg = args.namedChild(i);
|
|
11442
|
+
if (!arg) continue;
|
|
11443
|
+
const name = compositeStructName(arg);
|
|
11444
|
+
if (name) models.add(name);
|
|
11445
|
+
}
|
|
11446
|
+
});
|
|
11447
|
+
return models;
|
|
11448
|
+
}
|
|
11449
|
+
function collectTableNameOverrides(tree) {
|
|
11450
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
11451
|
+
const declarers = /* @__PURE__ */ new Set();
|
|
11452
|
+
walk8(tree.rootNode, (node) => {
|
|
11453
|
+
if (node.type !== "method_declaration") return;
|
|
11454
|
+
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
11455
|
+
const receiver = node.childForFieldName("receiver");
|
|
11456
|
+
if (!receiver) return;
|
|
11457
|
+
let recvType = null;
|
|
11458
|
+
for (let i = 0; i < receiver.namedChildCount; i++) {
|
|
11459
|
+
const pd = receiver.namedChild(i);
|
|
11460
|
+
if (pd?.type !== "parameter_declaration") continue;
|
|
11461
|
+
const t = unwrapType(pd.childForFieldName("type"));
|
|
11462
|
+
recvType = t.name;
|
|
11463
|
+
}
|
|
11464
|
+
if (!recvType) return;
|
|
11465
|
+
declarers.add(recvType);
|
|
11466
|
+
const body = node.childForFieldName("body");
|
|
11467
|
+
if (!body) return;
|
|
11468
|
+
let literal = null;
|
|
11469
|
+
walk8(body, (n) => {
|
|
11470
|
+
if (literal !== null) return;
|
|
11471
|
+
if (n.type !== "return_statement") return;
|
|
11472
|
+
const exprList = n.namedChild(0);
|
|
11473
|
+
const first = exprList?.namedChild(0) ?? exprList;
|
|
11474
|
+
const v = stringLiteralValue(first);
|
|
11475
|
+
if (v) literal = v;
|
|
11476
|
+
});
|
|
11477
|
+
if (literal !== null) overrides.set(recvType, literal);
|
|
11478
|
+
});
|
|
11479
|
+
return { overrides, declarers };
|
|
11480
|
+
}
|
|
11481
|
+
function isRelationField(field, structs) {
|
|
11482
|
+
if (field.names.length === 0) return false;
|
|
11483
|
+
if (field.isQualified) return false;
|
|
11484
|
+
if (!field.typeName) return false;
|
|
11485
|
+
return structs.has(field.typeName);
|
|
11486
|
+
}
|
|
11487
|
+
function isGormModelEmbed(field) {
|
|
11488
|
+
return field.names.length === 0 && field.qualifier === "gorm" && field.typeName === "Model";
|
|
11489
|
+
}
|
|
11490
|
+
function analyze(tree) {
|
|
11491
|
+
const structs = collectStructs(tree);
|
|
11492
|
+
const { overrides, declarers } = collectTableNameOverrides(tree);
|
|
11493
|
+
const callModels = collectCallModels(tree);
|
|
11494
|
+
const models = /* @__PURE__ */ new Set();
|
|
11495
|
+
for (const [name, info] of structs) {
|
|
11496
|
+
if (info.fields.some(isGormModelEmbed)) models.add(name);
|
|
11497
|
+
}
|
|
11498
|
+
for (const name of callModels) if (structs.has(name)) models.add(name);
|
|
11499
|
+
for (const name of declarers) if (structs.has(name)) models.add(name);
|
|
11500
|
+
let grew = true;
|
|
11501
|
+
while (grew) {
|
|
11502
|
+
grew = false;
|
|
11503
|
+
for (const name of Array.from(models)) {
|
|
11504
|
+
const info = structs.get(name);
|
|
11505
|
+
if (!info) continue;
|
|
11506
|
+
for (const field of info.fields) {
|
|
11507
|
+
if (!isRelationField(field, structs)) continue;
|
|
11508
|
+
const target = field.typeName;
|
|
11509
|
+
if (!models.has(target) && structs.has(target)) {
|
|
11510
|
+
models.add(target);
|
|
11511
|
+
grew = true;
|
|
11512
|
+
}
|
|
11513
|
+
}
|
|
11514
|
+
}
|
|
11515
|
+
}
|
|
11516
|
+
const tableFor = (structName) => overrides.get(structName) ?? deriveTableName(structName);
|
|
11517
|
+
return { structs, models, tableFor };
|
|
11518
|
+
}
|
|
11519
|
+
function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
11520
|
+
if (seen.has(struct.name)) return;
|
|
11521
|
+
seen.add(struct.name);
|
|
11522
|
+
const add = (col) => {
|
|
11523
|
+
const full = prefix + col;
|
|
11524
|
+
if (!emitted.has(full)) {
|
|
11525
|
+
emitted.add(full);
|
|
11526
|
+
out.push(full);
|
|
11527
|
+
}
|
|
11528
|
+
};
|
|
11529
|
+
for (const field of struct.fields) {
|
|
11530
|
+
if (field.tag.skip) continue;
|
|
11531
|
+
if (field.names.length === 0) {
|
|
11532
|
+
if (isGormModelEmbed(field)) {
|
|
11533
|
+
add("id");
|
|
11534
|
+
add("created_at");
|
|
11535
|
+
add("updated_at");
|
|
11536
|
+
add("deleted_at");
|
|
11537
|
+
} else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11538
|
+
collectColumns(structs.get(field.typeName), structs, seen, prefix, out, emitted);
|
|
11539
|
+
}
|
|
11540
|
+
continue;
|
|
11541
|
+
}
|
|
11542
|
+
if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11543
|
+
collectColumns(
|
|
11544
|
+
structs.get(field.typeName),
|
|
11545
|
+
structs,
|
|
11546
|
+
seen,
|
|
11547
|
+
prefix + (field.tag.embeddedPrefix ?? ""),
|
|
11548
|
+
out,
|
|
11549
|
+
emitted
|
|
11550
|
+
);
|
|
11551
|
+
continue;
|
|
11552
|
+
}
|
|
11553
|
+
if (isRelationField(field, structs)) continue;
|
|
11554
|
+
if (field.names.length === 1 && field.tag.column) {
|
|
11555
|
+
add(field.tag.column);
|
|
11556
|
+
} else {
|
|
11557
|
+
for (const n of field.names) add(toDBName(n));
|
|
11558
|
+
}
|
|
11559
|
+
}
|
|
11560
|
+
seen.delete(struct.name);
|
|
11561
|
+
}
|
|
11562
|
+
function gormEndpointsFromFile(file, serviceDir) {
|
|
11563
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11564
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11565
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11566
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11567
|
+
const out = [];
|
|
11568
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
11569
|
+
for (const name of models) {
|
|
11570
|
+
const struct = structs.get(name);
|
|
11571
|
+
if (!struct) continue;
|
|
11572
|
+
const table = tableFor(name);
|
|
11573
|
+
if (seenTables.has(table)) continue;
|
|
11574
|
+
seenTables.add(table);
|
|
11575
|
+
const columns = [];
|
|
11576
|
+
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
11577
|
+
out.push({
|
|
11578
|
+
infraId: (0, import_types36.infraId)("sql-table", table),
|
|
11579
|
+
name: table,
|
|
11580
|
+
kind: "sql-table",
|
|
11581
|
+
edgeType: "CALLS",
|
|
11582
|
+
confidenceKind: "structural",
|
|
11583
|
+
...columns.length > 0 ? { columns } : {},
|
|
11584
|
+
evidence: {
|
|
11585
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11586
|
+
line: struct.line,
|
|
11587
|
+
snippet: snippet(file.content, struct.line)
|
|
11588
|
+
}
|
|
11589
|
+
});
|
|
11590
|
+
}
|
|
11591
|
+
return out;
|
|
11592
|
+
}
|
|
11593
|
+
function gormForeignKeys(file, serviceDir) {
|
|
11594
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11595
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11596
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11597
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11598
|
+
const out = [];
|
|
11599
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11600
|
+
const emit = (childTable, parentTable, line) => {
|
|
11601
|
+
if (!childTable || !parentTable || childTable === parentTable) return;
|
|
11602
|
+
const key = `${childTable}->${parentTable}`;
|
|
11603
|
+
if (seen.has(key)) return;
|
|
11604
|
+
seen.add(key);
|
|
11605
|
+
out.push({
|
|
11606
|
+
childTable,
|
|
11607
|
+
parentTable,
|
|
11608
|
+
evidence: {
|
|
11609
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11610
|
+
line,
|
|
11611
|
+
snippet: snippet(file.content, line)
|
|
11612
|
+
}
|
|
11613
|
+
});
|
|
11614
|
+
};
|
|
11615
|
+
for (const name of models) {
|
|
11616
|
+
const struct = structs.get(name);
|
|
11617
|
+
if (!struct) continue;
|
|
11618
|
+
const thisTable = tableFor(name);
|
|
11619
|
+
const scalarNames = new Set(
|
|
11620
|
+
struct.fields.filter((f) => f.names.length > 0 && !isRelationField(f, structs)).flatMap((f) => f.names)
|
|
11621
|
+
);
|
|
11622
|
+
for (const field of struct.fields) {
|
|
11623
|
+
if (field.tag.skip) continue;
|
|
11624
|
+
if (!isRelationField(field, structs)) continue;
|
|
11625
|
+
const relTable = tableFor(field.typeName);
|
|
11626
|
+
if (field.tag.many2many) {
|
|
11627
|
+
emit(field.tag.many2many, thisTable, field.line);
|
|
11628
|
+
emit(field.tag.many2many, relTable, field.line);
|
|
11629
|
+
continue;
|
|
11630
|
+
}
|
|
11631
|
+
if (field.isSlice) {
|
|
11632
|
+
emit(relTable, thisTable, field.line);
|
|
11633
|
+
continue;
|
|
11634
|
+
}
|
|
11635
|
+
const convFk = field.names[0] + "ID";
|
|
11636
|
+
const belongsTo = scalarNames.has(convFk) || (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false);
|
|
11637
|
+
if (belongsTo) emit(thisTable, relTable, field.line);
|
|
11638
|
+
else emit(relTable, thisTable, field.line);
|
|
11639
|
+
}
|
|
11640
|
+
}
|
|
11641
|
+
return out;
|
|
11642
|
+
}
|
|
11643
|
+
|
|
11097
11644
|
// src/extract/calls/index.ts
|
|
11098
11645
|
function edgeTypeFromEndpoint(ep) {
|
|
11099
11646
|
switch (ep.edgeType) {
|
|
11100
11647
|
case "PUBLISHES_TO":
|
|
11101
|
-
return
|
|
11648
|
+
return import_types37.EdgeType.PUBLISHES_TO;
|
|
11102
11649
|
case "CONSUMES_FROM":
|
|
11103
|
-
return
|
|
11650
|
+
return import_types37.EdgeType.CONSUMES_FROM;
|
|
11104
11651
|
default:
|
|
11105
|
-
return
|
|
11652
|
+
return import_types37.EdgeType.CALLS;
|
|
11106
11653
|
}
|
|
11107
11654
|
}
|
|
11108
11655
|
function isAwsKind(kind) {
|
|
@@ -11135,6 +11682,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11135
11682
|
} catch (err) {
|
|
11136
11683
|
recordExtractionError("go SQL call extraction", file.path, err);
|
|
11137
11684
|
}
|
|
11685
|
+
try {
|
|
11686
|
+
endpoints.push(...gormEndpointsFromFile(file, service.dir));
|
|
11687
|
+
} catch (err) {
|
|
11688
|
+
recordExtractionError("gorm data-axis extraction", file.path, err);
|
|
11689
|
+
}
|
|
11138
11690
|
try {
|
|
11139
11691
|
endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir));
|
|
11140
11692
|
endpoints.push(...railsModelEndpointsFromFile(file, service.dir));
|
|
@@ -11157,7 +11709,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11157
11709
|
if (!graph.hasNode(ep.infraId)) {
|
|
11158
11710
|
const node = {
|
|
11159
11711
|
id: ep.infraId,
|
|
11160
|
-
type:
|
|
11712
|
+
type: import_types37.NodeType.InfraNode,
|
|
11161
11713
|
name: ep.name,
|
|
11162
11714
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
11163
11715
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -11170,21 +11722,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11170
11722
|
}
|
|
11171
11723
|
if (ep.columns && ep.columns.length > 0) {
|
|
11172
11724
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11173
|
-
if (node.type ===
|
|
11725
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11174
11726
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11175
11727
|
...node,
|
|
11176
11728
|
columns: foldColumns(
|
|
11177
11729
|
node.columns,
|
|
11178
11730
|
ep.columns,
|
|
11179
|
-
|
|
11180
|
-
(0,
|
|
11731
|
+
import_types37.Provenance.EXTRACTED,
|
|
11732
|
+
(0, import_types37.confidenceForExtracted)(ep.confidenceKind)
|
|
11181
11733
|
)
|
|
11182
11734
|
});
|
|
11183
11735
|
}
|
|
11184
11736
|
}
|
|
11185
11737
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
11186
11738
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11187
|
-
if (node.type ===
|
|
11739
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11188
11740
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11189
11741
|
...node,
|
|
11190
11742
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -11192,7 +11744,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11192
11744
|
}
|
|
11193
11745
|
}
|
|
11194
11746
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
11195
|
-
const confidence = (0,
|
|
11747
|
+
const confidence = (0, import_types37.confidenceForExtracted)(ep.confidenceKind);
|
|
11196
11748
|
const relFile = toPosix(ep.evidence.file);
|
|
11197
11749
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
11198
11750
|
graph,
|
|
@@ -11202,7 +11754,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11202
11754
|
);
|
|
11203
11755
|
nodesAdded += n;
|
|
11204
11756
|
edgesAdded += e;
|
|
11205
|
-
if (!(0,
|
|
11757
|
+
if (!(0, import_types37.passesExtractedFloor)(confidence)) {
|
|
11206
11758
|
noteExtractedDropped({
|
|
11207
11759
|
source: fileNodeId,
|
|
11208
11760
|
target: ep.infraId,
|
|
@@ -11222,7 +11774,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11222
11774
|
source: fileNodeId,
|
|
11223
11775
|
target: ep.infraId,
|
|
11224
11776
|
type: edgeType,
|
|
11225
|
-
provenance:
|
|
11777
|
+
provenance: import_types37.Provenance.EXTRACTED,
|
|
11226
11778
|
confidence,
|
|
11227
11779
|
evidence: ep.evidence
|
|
11228
11780
|
};
|
|
@@ -11245,7 +11797,7 @@ async function addCallEdges(graph, services) {
|
|
|
11245
11797
|
|
|
11246
11798
|
// src/extract/table-edges.ts
|
|
11247
11799
|
init_cjs_shims();
|
|
11248
|
-
var
|
|
11800
|
+
var import_types38 = require("@neat.is/types");
|
|
11249
11801
|
async function addTableEdges(graph, services) {
|
|
11250
11802
|
let nodesAdded = 0;
|
|
11251
11803
|
let edgesAdded = 0;
|
|
@@ -11259,6 +11811,7 @@ async function addTableEdges(graph, services) {
|
|
|
11259
11811
|
refs.push(...sqlalchemyForeignKeys(file, service.dir));
|
|
11260
11812
|
refs.push(...railsSchemaForeignKeys(file, service.dir));
|
|
11261
11813
|
refs.push(...laravelMigrationForeignKeys(file, service.dir));
|
|
11814
|
+
refs.push(...gormForeignKeys(file, service.dir));
|
|
11262
11815
|
modelRefs.push(...railsModelForeignKeys(file, service.dir));
|
|
11263
11816
|
modelRefs.push(...laravelModelForeignKeys(file, service.dir));
|
|
11264
11817
|
} catch (err) {
|
|
@@ -11272,20 +11825,20 @@ async function addTableEdges(graph, services) {
|
|
|
11272
11825
|
}
|
|
11273
11826
|
refs.push(...modelRefs);
|
|
11274
11827
|
for (const ref of refs) {
|
|
11275
|
-
const childId = (0,
|
|
11276
|
-
const parentId = (0,
|
|
11828
|
+
const childId = (0, import_types38.infraId)("sql-table", ref.childTable);
|
|
11829
|
+
const parentId = (0, import_types38.infraId)("sql-table", ref.parentTable);
|
|
11277
11830
|
if (childId === parentId) continue;
|
|
11278
11831
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
11279
11832
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
11280
|
-
const edgeId = (0,
|
|
11833
|
+
const edgeId = (0, import_types38.extractedEdgeId)(childId, parentId, import_types38.EdgeType.REFERENCES);
|
|
11281
11834
|
if (graph.hasEdge(edgeId)) continue;
|
|
11282
11835
|
const edge = {
|
|
11283
11836
|
id: edgeId,
|
|
11284
11837
|
source: childId,
|
|
11285
11838
|
target: parentId,
|
|
11286
|
-
type:
|
|
11287
|
-
provenance:
|
|
11288
|
-
confidence: (0,
|
|
11839
|
+
type: import_types38.EdgeType.REFERENCES,
|
|
11840
|
+
provenance: import_types38.Provenance.EXTRACTED,
|
|
11841
|
+
confidence: (0, import_types38.confidenceForExtracted)("structural"),
|
|
11289
11842
|
evidence: ref.evidence
|
|
11290
11843
|
};
|
|
11291
11844
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -11298,7 +11851,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
11298
11851
|
if (graph.hasNode(id)) return 0;
|
|
11299
11852
|
const node = {
|
|
11300
11853
|
id,
|
|
11301
|
-
type:
|
|
11854
|
+
type: import_types38.NodeType.InfraNode,
|
|
11302
11855
|
name,
|
|
11303
11856
|
provider: "self",
|
|
11304
11857
|
kind: "sql-table"
|
|
@@ -11312,16 +11865,16 @@ init_cjs_shims();
|
|
|
11312
11865
|
|
|
11313
11866
|
// src/extract/infra/docker-compose.ts
|
|
11314
11867
|
init_cjs_shims();
|
|
11315
|
-
var
|
|
11316
|
-
var
|
|
11868
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11869
|
+
var import_types40 = require("@neat.is/types");
|
|
11317
11870
|
|
|
11318
11871
|
// src/extract/infra/shared.ts
|
|
11319
11872
|
init_cjs_shims();
|
|
11320
|
-
var
|
|
11873
|
+
var import_types39 = require("@neat.is/types");
|
|
11321
11874
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
11322
11875
|
return {
|
|
11323
|
-
id: (0,
|
|
11324
|
-
type:
|
|
11876
|
+
id: (0, import_types39.infraId)(kind, name),
|
|
11877
|
+
type: import_types39.NodeType.InfraNode,
|
|
11325
11878
|
name,
|
|
11326
11879
|
provider,
|
|
11327
11880
|
kind,
|
|
@@ -11365,8 +11918,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
11365
11918
|
source: anchorId,
|
|
11366
11919
|
target: node.id,
|
|
11367
11920
|
type: edgeType,
|
|
11368
|
-
provenance:
|
|
11369
|
-
confidence: (0,
|
|
11921
|
+
provenance: import_types39.Provenance.EXTRACTED,
|
|
11922
|
+
confidence: (0, import_types39.confidenceForExtracted)("structural"),
|
|
11370
11923
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11371
11924
|
};
|
|
11372
11925
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11383,7 +11936,7 @@ function dependsOnList(value) {
|
|
|
11383
11936
|
}
|
|
11384
11937
|
function serviceNameToServiceNode(name, services) {
|
|
11385
11938
|
for (const s of services) {
|
|
11386
|
-
if (s.node.name === name ||
|
|
11939
|
+
if (s.node.name === name || import_node_path49.default.basename(s.dir) === name) return s.node.id;
|
|
11387
11940
|
}
|
|
11388
11941
|
return null;
|
|
11389
11942
|
}
|
|
@@ -11392,7 +11945,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11392
11945
|
let edgesAdded = 0;
|
|
11393
11946
|
let composePath = null;
|
|
11394
11947
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
11395
|
-
const abs =
|
|
11948
|
+
const abs = import_node_path49.default.join(scanPath, name);
|
|
11396
11949
|
if (await exists(abs)) {
|
|
11397
11950
|
composePath = abs;
|
|
11398
11951
|
break;
|
|
@@ -11405,13 +11958,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11405
11958
|
} catch (err) {
|
|
11406
11959
|
recordExtractionError(
|
|
11407
11960
|
"infra docker-compose",
|
|
11408
|
-
|
|
11961
|
+
import_node_path49.default.relative(scanPath, composePath),
|
|
11409
11962
|
err
|
|
11410
11963
|
);
|
|
11411
11964
|
return { nodesAdded, edgesAdded };
|
|
11412
11965
|
}
|
|
11413
11966
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
11414
|
-
const evidenceFile =
|
|
11967
|
+
const evidenceFile = import_node_path49.default.relative(scanPath, composePath).split(import_node_path49.default.sep).join("/");
|
|
11415
11968
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
11416
11969
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
11417
11970
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -11433,15 +11986,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11433
11986
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
11434
11987
|
const targetId = composeNameToNodeId.get(dep);
|
|
11435
11988
|
if (!targetId) continue;
|
|
11436
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
11989
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types40.EdgeType.DEPENDS_ON);
|
|
11437
11990
|
if (graph.hasEdge(edgeId)) continue;
|
|
11438
11991
|
const edge = {
|
|
11439
11992
|
id: edgeId,
|
|
11440
11993
|
source: sourceId,
|
|
11441
11994
|
target: targetId,
|
|
11442
|
-
type:
|
|
11443
|
-
provenance:
|
|
11444
|
-
confidence: (0,
|
|
11995
|
+
type: import_types40.EdgeType.DEPENDS_ON,
|
|
11996
|
+
provenance: import_types40.Provenance.EXTRACTED,
|
|
11997
|
+
confidence: (0, import_types40.confidenceForExtracted)("structural"),
|
|
11445
11998
|
evidence: { file: evidenceFile }
|
|
11446
11999
|
};
|
|
11447
12000
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11453,9 +12006,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11453
12006
|
|
|
11454
12007
|
// src/extract/infra/dockerfile.ts
|
|
11455
12008
|
init_cjs_shims();
|
|
11456
|
-
var
|
|
12009
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11457
12010
|
var import_node_fs18 = require("fs");
|
|
11458
|
-
var
|
|
12011
|
+
var import_types41 = require("@neat.is/types");
|
|
11459
12012
|
function readDockerfile(content) {
|
|
11460
12013
|
let image = null;
|
|
11461
12014
|
const ports = [];
|
|
@@ -11484,7 +12037,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11484
12037
|
let nodesAdded = 0;
|
|
11485
12038
|
let edgesAdded = 0;
|
|
11486
12039
|
for (const service of services) {
|
|
11487
|
-
const dockerfilePath =
|
|
12040
|
+
const dockerfilePath = import_node_path50.default.join(service.dir, "Dockerfile");
|
|
11488
12041
|
if (!await exists(dockerfilePath)) continue;
|
|
11489
12042
|
let content;
|
|
11490
12043
|
try {
|
|
@@ -11492,7 +12045,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11492
12045
|
} catch (err) {
|
|
11493
12046
|
recordExtractionError(
|
|
11494
12047
|
"infra dockerfile",
|
|
11495
|
-
|
|
12048
|
+
import_node_path50.default.relative(scanPath, dockerfilePath),
|
|
11496
12049
|
err
|
|
11497
12050
|
);
|
|
11498
12051
|
continue;
|
|
@@ -11504,8 +12057,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11504
12057
|
graph.addNode(node.id, node);
|
|
11505
12058
|
nodesAdded++;
|
|
11506
12059
|
}
|
|
11507
|
-
const relDockerfile = toPosix(
|
|
11508
|
-
const evidenceFile = toPosix(
|
|
12060
|
+
const relDockerfile = toPosix(import_node_path50.default.relative(service.dir, dockerfilePath));
|
|
12061
|
+
const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, dockerfilePath));
|
|
11509
12062
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11510
12063
|
graph,
|
|
11511
12064
|
service.pkg.name,
|
|
@@ -11514,15 +12067,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11514
12067
|
);
|
|
11515
12068
|
nodesAdded += fn;
|
|
11516
12069
|
edgesAdded += fe;
|
|
11517
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
12070
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types41.EdgeType.RUNS_ON);
|
|
11518
12071
|
if (!graph.hasEdge(edgeId)) {
|
|
11519
12072
|
const edge = {
|
|
11520
12073
|
id: edgeId,
|
|
11521
12074
|
source: fileNodeId,
|
|
11522
12075
|
target: node.id,
|
|
11523
|
-
type:
|
|
11524
|
-
provenance:
|
|
11525
|
-
confidence: (0,
|
|
12076
|
+
type: import_types41.EdgeType.RUNS_ON,
|
|
12077
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12078
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11526
12079
|
evidence: {
|
|
11527
12080
|
file: evidenceFile,
|
|
11528
12081
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -11537,15 +12090,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11537
12090
|
graph.addNode(portNode.id, portNode);
|
|
11538
12091
|
nodesAdded++;
|
|
11539
12092
|
}
|
|
11540
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
12093
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types41.EdgeType.CONNECTS_TO);
|
|
11541
12094
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
11542
12095
|
const portEdge = {
|
|
11543
12096
|
id: portEdgeId,
|
|
11544
12097
|
source: fileNodeId,
|
|
11545
12098
|
target: portNode.id,
|
|
11546
|
-
type:
|
|
11547
|
-
provenance:
|
|
11548
|
-
confidence: (0,
|
|
12099
|
+
type: import_types41.EdgeType.CONNECTS_TO,
|
|
12100
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12101
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11549
12102
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
11550
12103
|
};
|
|
11551
12104
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -11558,8 +12111,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11558
12111
|
// src/extract/infra/terraform.ts
|
|
11559
12112
|
init_cjs_shims();
|
|
11560
12113
|
var import_node_fs19 = require("fs");
|
|
11561
|
-
var
|
|
11562
|
-
var
|
|
12114
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12115
|
+
var import_types42 = require("@neat.is/types");
|
|
11563
12116
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
11564
12117
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
11565
12118
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -11569,11 +12122,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
11569
12122
|
for (const entry of entries) {
|
|
11570
12123
|
if (entry.isDirectory()) {
|
|
11571
12124
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
11572
|
-
const child =
|
|
12125
|
+
const child = import_node_path51.default.join(start, entry.name);
|
|
11573
12126
|
if (await isPythonVenvDir(child)) continue;
|
|
11574
12127
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
11575
12128
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
11576
|
-
out.push(
|
|
12129
|
+
out.push(import_node_path51.default.join(start, entry.name));
|
|
11577
12130
|
}
|
|
11578
12131
|
}
|
|
11579
12132
|
return out;
|
|
@@ -11605,7 +12158,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11605
12158
|
const files = await walkTfFiles(scanPath);
|
|
11606
12159
|
for (const file of files) {
|
|
11607
12160
|
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
11608
|
-
const evidenceFile = toPosix(
|
|
12161
|
+
const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, file));
|
|
11609
12162
|
const resources = [];
|
|
11610
12163
|
const byKey = /* @__PURE__ */ new Map();
|
|
11611
12164
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -11640,16 +12193,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11640
12193
|
if (!target) continue;
|
|
11641
12194
|
if (seen.has(target.nodeId)) continue;
|
|
11642
12195
|
seen.add(target.nodeId);
|
|
11643
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
12196
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types42.EdgeType.DEPENDS_ON);
|
|
11644
12197
|
if (graph.hasEdge(edgeId)) continue;
|
|
11645
12198
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
11646
12199
|
const edge = {
|
|
11647
12200
|
id: edgeId,
|
|
11648
12201
|
source: resource.nodeId,
|
|
11649
12202
|
target: target.nodeId,
|
|
11650
|
-
type:
|
|
11651
|
-
provenance:
|
|
11652
|
-
confidence: (0,
|
|
12203
|
+
type: import_types42.EdgeType.DEPENDS_ON,
|
|
12204
|
+
provenance: import_types42.Provenance.EXTRACTED,
|
|
12205
|
+
confidence: (0, import_types42.confidenceForExtracted)("structural"),
|
|
11653
12206
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
11654
12207
|
};
|
|
11655
12208
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11663,7 +12216,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11663
12216
|
// src/extract/infra/k8s.ts
|
|
11664
12217
|
init_cjs_shims();
|
|
11665
12218
|
var import_node_fs20 = require("fs");
|
|
11666
|
-
var
|
|
12219
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
11667
12220
|
var import_yaml3 = require("yaml");
|
|
11668
12221
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
11669
12222
|
Service: "k8s-service",
|
|
@@ -11681,11 +12234,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
11681
12234
|
for (const entry of entries) {
|
|
11682
12235
|
if (entry.isDirectory()) {
|
|
11683
12236
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
11684
|
-
const child =
|
|
12237
|
+
const child = import_node_path52.default.join(start, entry.name);
|
|
11685
12238
|
if (await isPythonVenvDir(child)) continue;
|
|
11686
12239
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
11687
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
11688
|
-
out.push(
|
|
12240
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path52.default.extname(entry.name))) {
|
|
12241
|
+
out.push(import_node_path52.default.join(start, entry.name));
|
|
11689
12242
|
}
|
|
11690
12243
|
}
|
|
11691
12244
|
return out;
|
|
@@ -11719,13 +12272,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
11719
12272
|
// src/extract/infra/cloudflare.ts
|
|
11720
12273
|
init_cjs_shims();
|
|
11721
12274
|
var import_node_fs21 = require("fs");
|
|
11722
|
-
var
|
|
12275
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
11723
12276
|
var import_smol_toml2 = require("smol-toml");
|
|
11724
|
-
var
|
|
12277
|
+
var import_types43 = require("@neat.is/types");
|
|
11725
12278
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
11726
12279
|
async function readWranglerConfig(dir) {
|
|
11727
12280
|
for (const filename of WRANGLER_FILENAMES) {
|
|
11728
|
-
const abs =
|
|
12281
|
+
const abs = import_node_path53.default.join(dir, filename);
|
|
11729
12282
|
if (!await exists(abs)) continue;
|
|
11730
12283
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
11731
12284
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11769,8 +12322,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
11769
12322
|
source: anchorId,
|
|
11770
12323
|
target: node.id,
|
|
11771
12324
|
type: edgeType,
|
|
11772
|
-
provenance:
|
|
11773
|
-
confidence: (0,
|
|
12325
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12326
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11774
12327
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11775
12328
|
};
|
|
11776
12329
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11788,11 +12341,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11788
12341
|
try {
|
|
11789
12342
|
read = await readWranglerConfig(service.dir);
|
|
11790
12343
|
} catch (err) {
|
|
11791
|
-
recordExtractionError("infra cloudflare",
|
|
12344
|
+
recordExtractionError("infra cloudflare", import_node_path53.default.relative(scanPath, service.dir), err);
|
|
11792
12345
|
continue;
|
|
11793
12346
|
}
|
|
11794
12347
|
if (!read || !read.config.name) continue;
|
|
11795
|
-
const evidenceFile = toPosix(
|
|
12348
|
+
const evidenceFile = toPosix(import_node_path53.default.relative(scanPath, import_node_path53.default.join(service.dir, read.relFile)));
|
|
11796
12349
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
11797
12350
|
}
|
|
11798
12351
|
for (const worker of discovered) {
|
|
@@ -11804,7 +12357,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11804
12357
|
}
|
|
11805
12358
|
let anchorId = service.node.id;
|
|
11806
12359
|
if (config.main) {
|
|
11807
|
-
const entryRelPath = toPosix(
|
|
12360
|
+
const entryRelPath = toPosix(import_node_path53.default.normalize(config.main));
|
|
11808
12361
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11809
12362
|
graph,
|
|
11810
12363
|
service.pkg.name,
|
|
@@ -11831,15 +12384,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11831
12384
|
nodesAdded++;
|
|
11832
12385
|
}
|
|
11833
12386
|
if (runtimeNode.id !== anchorId) {
|
|
11834
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
12387
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types43.EdgeType.RUNS_ON);
|
|
11835
12388
|
if (!graph.hasEdge(runsOnId)) {
|
|
11836
12389
|
const edge = {
|
|
11837
12390
|
id: runsOnId,
|
|
11838
12391
|
source: anchorId,
|
|
11839
12392
|
target: runtimeNode.id,
|
|
11840
|
-
type:
|
|
11841
|
-
provenance:
|
|
11842
|
-
confidence: (0,
|
|
12393
|
+
type: import_types43.EdgeType.RUNS_ON,
|
|
12394
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12395
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11843
12396
|
evidence: {
|
|
11844
12397
|
file: evidenceFile,
|
|
11845
12398
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -11853,7 +12406,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11853
12406
|
const result = addResourceEdge(
|
|
11854
12407
|
graph,
|
|
11855
12408
|
anchorId,
|
|
11856
|
-
|
|
12409
|
+
import_types43.EdgeType.CONNECTS_TO,
|
|
11857
12410
|
"cloudflare-route",
|
|
11858
12411
|
route,
|
|
11859
12412
|
evidenceFile,
|
|
@@ -11877,7 +12430,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11877
12430
|
const result = addResourceEdge(
|
|
11878
12431
|
graph,
|
|
11879
12432
|
anchorId,
|
|
11880
|
-
|
|
12433
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11881
12434
|
group.kind,
|
|
11882
12435
|
name,
|
|
11883
12436
|
evidenceFile,
|
|
@@ -11891,7 +12444,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11891
12444
|
const result = addResourceEdge(
|
|
11892
12445
|
graph,
|
|
11893
12446
|
anchorId,
|
|
11894
|
-
|
|
12447
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11895
12448
|
"cloudflare-cron",
|
|
11896
12449
|
cron,
|
|
11897
12450
|
evidenceFile,
|
|
@@ -11904,7 +12457,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11904
12457
|
const result = addResourceEdge(
|
|
11905
12458
|
graph,
|
|
11906
12459
|
anchorId,
|
|
11907
|
-
|
|
12460
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11908
12461
|
"cloudflare-env-var",
|
|
11909
12462
|
varName,
|
|
11910
12463
|
evidenceFile,
|
|
@@ -11917,15 +12470,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11917
12470
|
if (!svc.service) continue;
|
|
11918
12471
|
const target = workerIndex.get(svc.service);
|
|
11919
12472
|
if (target && target.anchorId !== anchorId) {
|
|
11920
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
12473
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types43.EdgeType.CALLS);
|
|
11921
12474
|
if (!graph.hasEdge(edgeId)) {
|
|
11922
12475
|
const edge = {
|
|
11923
12476
|
id: edgeId,
|
|
11924
12477
|
source: anchorId,
|
|
11925
12478
|
target: target.anchorId,
|
|
11926
|
-
type:
|
|
11927
|
-
provenance:
|
|
11928
|
-
confidence: (0,
|
|
12479
|
+
type: import_types43.EdgeType.CALLS,
|
|
12480
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12481
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11929
12482
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
11930
12483
|
};
|
|
11931
12484
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11936,7 +12489,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11936
12489
|
const result = addResourceEdge(
|
|
11937
12490
|
graph,
|
|
11938
12491
|
anchorId,
|
|
11939
|
-
|
|
12492
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11940
12493
|
"cloudflare-service-binding",
|
|
11941
12494
|
svc.service,
|
|
11942
12495
|
evidenceFile,
|
|
@@ -11952,12 +12505,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11952
12505
|
// src/extract/infra/vercel.ts
|
|
11953
12506
|
init_cjs_shims();
|
|
11954
12507
|
var import_node_fs22 = require("fs");
|
|
11955
|
-
var
|
|
11956
|
-
var
|
|
12508
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
12509
|
+
var import_types44 = require("@neat.is/types");
|
|
11957
12510
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
11958
12511
|
async function readVercelConfig(dir) {
|
|
11959
12512
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
11960
|
-
const abs =
|
|
12513
|
+
const abs = import_node_path54.default.join(dir, filename);
|
|
11961
12514
|
if (!await exists(abs)) continue;
|
|
11962
12515
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
11963
12516
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11966,7 +12519,7 @@ async function readVercelConfig(dir) {
|
|
|
11966
12519
|
return null;
|
|
11967
12520
|
}
|
|
11968
12521
|
async function readLinkedProjectName(dir) {
|
|
11969
|
-
const abs =
|
|
12522
|
+
const abs = import_node_path54.default.join(dir, ".vercel", "project.json");
|
|
11970
12523
|
if (!await exists(abs)) return void 0;
|
|
11971
12524
|
const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
|
|
11972
12525
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -11984,7 +12537,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11984
12537
|
read = await readVercelConfig(service.dir);
|
|
11985
12538
|
projectName = await readLinkedProjectName(service.dir);
|
|
11986
12539
|
} catch (err) {
|
|
11987
|
-
recordExtractionError("infra vercel",
|
|
12540
|
+
recordExtractionError("infra vercel", import_node_path54.default.relative(scanPath, service.dir), err);
|
|
11988
12541
|
continue;
|
|
11989
12542
|
}
|
|
11990
12543
|
if (!read && !projectName) continue;
|
|
@@ -12000,7 +12553,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12000
12553
|
const anchorId = service.node.id;
|
|
12001
12554
|
if (!read) continue;
|
|
12002
12555
|
const { config, relFile, raw } = read;
|
|
12003
|
-
const evidenceFile = toPosix(
|
|
12556
|
+
const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, relFile)));
|
|
12004
12557
|
const add = (edgeType, kind, name) => {
|
|
12005
12558
|
if (!name) return;
|
|
12006
12559
|
const result = emitPlatformResourceEdge(
|
|
@@ -12016,12 +12569,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12016
12569
|
nodesAdded += result.nodesAdded;
|
|
12017
12570
|
edgesAdded += result.edgesAdded;
|
|
12018
12571
|
};
|
|
12019
|
-
add(
|
|
12020
|
-
for (const cron of config.crons ?? []) add(
|
|
12021
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
12022
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
12572
|
+
add(import_types44.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
12573
|
+
for (const cron of config.crons ?? []) add(import_types44.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
12574
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12575
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12023
12576
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
12024
|
-
add(
|
|
12577
|
+
add(import_types44.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
12025
12578
|
}
|
|
12026
12579
|
}
|
|
12027
12580
|
return { nodesAdded, edgesAdded };
|
|
@@ -12030,13 +12583,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12030
12583
|
// src/extract/infra/railway.ts
|
|
12031
12584
|
init_cjs_shims();
|
|
12032
12585
|
var import_node_fs23 = require("fs");
|
|
12033
|
-
var
|
|
12586
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
12034
12587
|
var import_smol_toml3 = require("smol-toml");
|
|
12035
|
-
var
|
|
12588
|
+
var import_types45 = require("@neat.is/types");
|
|
12036
12589
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
12037
12590
|
async function readRailwayConfig(dir) {
|
|
12038
12591
|
for (const filename of RAILWAY_FILENAMES) {
|
|
12039
|
-
const abs =
|
|
12592
|
+
const abs = import_node_path55.default.join(dir, filename);
|
|
12040
12593
|
if (!await exists(abs)) continue;
|
|
12041
12594
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
12042
12595
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -12052,7 +12605,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12052
12605
|
try {
|
|
12053
12606
|
read = await readRailwayConfig(service.dir);
|
|
12054
12607
|
} catch (err) {
|
|
12055
|
-
recordExtractionError("infra railway",
|
|
12608
|
+
recordExtractionError("infra railway", import_node_path55.default.relative(scanPath, service.dir), err);
|
|
12056
12609
|
continue;
|
|
12057
12610
|
}
|
|
12058
12611
|
if (!read) continue;
|
|
@@ -12062,7 +12615,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12062
12615
|
}
|
|
12063
12616
|
const anchorId = service.node.id;
|
|
12064
12617
|
const { config, relFile, raw } = read;
|
|
12065
|
-
const evidenceFile = toPosix(
|
|
12618
|
+
const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
|
|
12066
12619
|
const add = (edgeType, kind, name) => {
|
|
12067
12620
|
if (!name) return;
|
|
12068
12621
|
const result = emitPlatformResourceEdge(
|
|
@@ -12078,9 +12631,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12078
12631
|
nodesAdded += result.nodesAdded;
|
|
12079
12632
|
edgesAdded += result.edgesAdded;
|
|
12080
12633
|
};
|
|
12081
|
-
add(
|
|
12082
|
-
add(
|
|
12083
|
-
add(
|
|
12634
|
+
add(import_types45.EdgeType.RUNS_ON, "railway", "railway");
|
|
12635
|
+
add(import_types45.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
12636
|
+
add(import_types45.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
12084
12637
|
}
|
|
12085
12638
|
return { nodesAdded, edgesAdded };
|
|
12086
12639
|
}
|
|
@@ -12088,12 +12641,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12088
12641
|
// src/extract/infra/supabase.ts
|
|
12089
12642
|
init_cjs_shims();
|
|
12090
12643
|
var import_node_fs24 = require("fs");
|
|
12091
|
-
var
|
|
12644
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
12092
12645
|
var import_smol_toml4 = require("smol-toml");
|
|
12093
|
-
var
|
|
12646
|
+
var import_types46 = require("@neat.is/types");
|
|
12094
12647
|
async function readSupabaseConfig(dir) {
|
|
12095
|
-
const relFile =
|
|
12096
|
-
const abs =
|
|
12648
|
+
const relFile = import_node_path56.default.join("supabase", "config.toml");
|
|
12649
|
+
const abs = import_node_path56.default.join(dir, relFile);
|
|
12097
12650
|
if (!await exists(abs)) return null;
|
|
12098
12651
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
12099
12652
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -12107,7 +12660,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12107
12660
|
try {
|
|
12108
12661
|
read = await readSupabaseConfig(service.dir);
|
|
12109
12662
|
} catch (err) {
|
|
12110
|
-
recordExtractionError("infra supabase",
|
|
12663
|
+
recordExtractionError("infra supabase", import_node_path56.default.relative(scanPath, service.dir), err);
|
|
12111
12664
|
continue;
|
|
12112
12665
|
}
|
|
12113
12666
|
if (!read) continue;
|
|
@@ -12122,7 +12675,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12122
12675
|
});
|
|
12123
12676
|
}
|
|
12124
12677
|
const anchorId = service.node.id;
|
|
12125
|
-
const evidenceFile = toPosix(
|
|
12678
|
+
const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
|
|
12126
12679
|
const add = (edgeType, kind, name) => {
|
|
12127
12680
|
if (!name) return;
|
|
12128
12681
|
const result = emitPlatformResourceEdge(
|
|
@@ -12138,10 +12691,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12138
12691
|
nodesAdded += result.nodesAdded;
|
|
12139
12692
|
edgesAdded += result.edgesAdded;
|
|
12140
12693
|
};
|
|
12141
|
-
add(
|
|
12142
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
12143
|
-
if (config.storage) add(
|
|
12144
|
-
if (config.auth) add(
|
|
12694
|
+
add(import_types46.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
12695
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types46.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
12696
|
+
if (config.storage) add(import_types46.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
12697
|
+
if (config.auth) add(import_types46.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
12145
12698
|
}
|
|
12146
12699
|
return { nodesAdded, edgesAdded };
|
|
12147
12700
|
}
|
|
@@ -12164,14 +12717,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
12164
12717
|
|
|
12165
12718
|
// src/extract/zod-shapes.ts
|
|
12166
12719
|
init_cjs_shims();
|
|
12167
|
-
var
|
|
12168
|
-
var
|
|
12720
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
12721
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
12169
12722
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12170
|
-
var
|
|
12723
|
+
var import_types47 = require("@neat.is/types");
|
|
12171
12724
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
12172
12725
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
12173
12726
|
function parserForExt3(ext) {
|
|
12174
|
-
const p = new
|
|
12727
|
+
const p = new import_tree_sitter16.default();
|
|
12175
12728
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
12176
12729
|
return p;
|
|
12177
12730
|
}
|
|
@@ -12259,7 +12812,7 @@ function topLevelSchemas(root) {
|
|
|
12259
12812
|
}
|
|
12260
12813
|
function zodShapesFromFile(file, serviceDir) {
|
|
12261
12814
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
12262
|
-
const tree = parseSource3(parserForExt3(
|
|
12815
|
+
const tree = parseSource3(parserForExt3(import_node_path57.default.extname(file.path)), file.content);
|
|
12263
12816
|
const out = [];
|
|
12264
12817
|
const seen = /* @__PURE__ */ new Set();
|
|
12265
12818
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -12273,11 +12826,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
12273
12826
|
seen.add(name);
|
|
12274
12827
|
const line = call.startPosition.row + 1;
|
|
12275
12828
|
out.push({
|
|
12276
|
-
infraId: (0,
|
|
12829
|
+
infraId: (0, import_types47.infraId)("zod-schema", name),
|
|
12277
12830
|
name,
|
|
12278
12831
|
fields,
|
|
12279
12832
|
evidence: {
|
|
12280
|
-
file:
|
|
12833
|
+
file: import_node_path57.default.relative(serviceDir, file.path),
|
|
12281
12834
|
line,
|
|
12282
12835
|
snippet: snippet(file.content, line)
|
|
12283
12836
|
}
|
|
@@ -12308,7 +12861,7 @@ async function addZodShapes(graph, services) {
|
|
|
12308
12861
|
if (!graph.hasNode(shape.infraId)) {
|
|
12309
12862
|
const node = {
|
|
12310
12863
|
id: shape.infraId,
|
|
12311
|
-
type:
|
|
12864
|
+
type: import_types47.NodeType.InfraNode,
|
|
12312
12865
|
name: shape.name,
|
|
12313
12866
|
provider: "self",
|
|
12314
12867
|
kind: "zod-schema"
|
|
@@ -12318,14 +12871,14 @@ async function addZodShapes(graph, services) {
|
|
|
12318
12871
|
}
|
|
12319
12872
|
if (shape.fields.length > 0) {
|
|
12320
12873
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
12321
|
-
if (node.type ===
|
|
12874
|
+
if (node.type === import_types47.NodeType.InfraNode) {
|
|
12322
12875
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
12323
12876
|
...node,
|
|
12324
12877
|
columns: foldColumns(
|
|
12325
12878
|
node.columns,
|
|
12326
12879
|
shape.fields,
|
|
12327
|
-
|
|
12328
|
-
(0,
|
|
12880
|
+
import_types47.Provenance.EXTRACTED,
|
|
12881
|
+
(0, import_types47.confidenceForExtracted)("structural")
|
|
12329
12882
|
)
|
|
12330
12883
|
});
|
|
12331
12884
|
}
|
|
@@ -12339,15 +12892,15 @@ async function addZodShapes(graph, services) {
|
|
|
12339
12892
|
);
|
|
12340
12893
|
nodesAdded += n;
|
|
12341
12894
|
edgesAdded += e;
|
|
12342
|
-
const edgeId = (0,
|
|
12895
|
+
const edgeId = (0, import_types47.extractedEdgeId)(fileNodeId, shape.infraId, import_types47.EdgeType.CONTAINS);
|
|
12343
12896
|
if (!graph.hasEdge(edgeId)) {
|
|
12344
12897
|
const edge = {
|
|
12345
12898
|
id: edgeId,
|
|
12346
12899
|
source: fileNodeId,
|
|
12347
12900
|
target: shape.infraId,
|
|
12348
|
-
type:
|
|
12349
|
-
provenance:
|
|
12350
|
-
confidence: (0,
|
|
12901
|
+
type: import_types47.EdgeType.CONTAINS,
|
|
12902
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
12903
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
12351
12904
|
evidence: shape.evidence
|
|
12352
12905
|
};
|
|
12353
12906
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -12361,7 +12914,7 @@ async function addZodShapes(graph, services) {
|
|
|
12361
12914
|
|
|
12362
12915
|
// src/extract/firestore-rules.ts
|
|
12363
12916
|
init_cjs_shims();
|
|
12364
|
-
var
|
|
12917
|
+
var import_types48 = require("@neat.is/types");
|
|
12365
12918
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
12366
12919
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
12367
12920
|
function stripComments(src) {
|
|
@@ -12501,7 +13054,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
12501
13054
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
12502
13055
|
graph.forEachNode((id, attrs) => {
|
|
12503
13056
|
const node = attrs;
|
|
12504
|
-
if (node.type !==
|
|
13057
|
+
if (node.type !== import_types48.NodeType.InfraNode) return;
|
|
12505
13058
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
12506
13059
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
12507
13060
|
if (!fields || fields.size === 0) return;
|
|
@@ -12514,17 +13067,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
12514
13067
|
}
|
|
12515
13068
|
|
|
12516
13069
|
// src/extract/index.ts
|
|
12517
|
-
var
|
|
13070
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
12518
13071
|
|
|
12519
13072
|
// src/extract/retire.ts
|
|
12520
13073
|
init_cjs_shims();
|
|
12521
13074
|
var import_node_fs25 = require("fs");
|
|
12522
|
-
var
|
|
12523
|
-
var
|
|
13075
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13076
|
+
var import_types49 = require("@neat.is/types");
|
|
12524
13077
|
function dropOrphanedFileNodes(graph) {
|
|
12525
13078
|
const orphans = [];
|
|
12526
13079
|
graph.forEachNode((id, attrs) => {
|
|
12527
|
-
if (attrs.type !==
|
|
13080
|
+
if (attrs.type !== import_types49.NodeType.FileNode) return;
|
|
12528
13081
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
12529
13082
|
orphans.push(id);
|
|
12530
13083
|
}
|
|
@@ -12537,14 +13090,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
12537
13090
|
const bases = [scanPath, ...serviceDirs];
|
|
12538
13091
|
graph.forEachEdge((id, attrs) => {
|
|
12539
13092
|
const edge = attrs;
|
|
12540
|
-
if (edge.provenance !==
|
|
13093
|
+
if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
|
|
12541
13094
|
const evidenceFile = edge.evidence?.file;
|
|
12542
13095
|
if (!evidenceFile) return;
|
|
12543
|
-
if (
|
|
13096
|
+
if (import_node_path58.default.isAbsolute(evidenceFile)) {
|
|
12544
13097
|
if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
|
|
12545
13098
|
return;
|
|
12546
13099
|
}
|
|
12547
|
-
const found = bases.some((base) => (0, import_node_fs25.existsSync)(
|
|
13100
|
+
const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path58.default.join(base, evidenceFile)));
|
|
12548
13101
|
if (!found) toDrop.push(id);
|
|
12549
13102
|
});
|
|
12550
13103
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -12601,7 +13154,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12601
13154
|
}
|
|
12602
13155
|
const droppedEntries = drainDroppedExtracted();
|
|
12603
13156
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
12604
|
-
const rejectedPath =
|
|
13157
|
+
const rejectedPath = import_node_path59.default.join(import_node_path59.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
12605
13158
|
try {
|
|
12606
13159
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
12607
13160
|
} catch (err) {
|
|
@@ -12636,8 +13189,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12636
13189
|
// src/persist.ts
|
|
12637
13190
|
init_cjs_shims();
|
|
12638
13191
|
var import_node_fs26 = require("fs");
|
|
12639
|
-
var
|
|
12640
|
-
var
|
|
13192
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
13193
|
+
var import_types50 = require("@neat.is/types");
|
|
12641
13194
|
var SCHEMA_VERSION = 7;
|
|
12642
13195
|
function migrateV1ToV2(payload) {
|
|
12643
13196
|
const nodes = payload.graph.nodes;
|
|
@@ -12661,7 +13214,7 @@ function migrateV5ToV6(payload) {
|
|
|
12661
13214
|
if (Array.isArray(nodes)) {
|
|
12662
13215
|
for (const node of nodes) {
|
|
12663
13216
|
const attrs = node.attributes;
|
|
12664
|
-
if (!attrs || attrs.type !==
|
|
13217
|
+
if (!attrs || attrs.type !== import_types50.NodeType.InfraNode) continue;
|
|
12665
13218
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
12666
13219
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
12667
13220
|
}
|
|
@@ -12677,12 +13230,12 @@ function migrateV2ToV3(payload) {
|
|
|
12677
13230
|
for (const edge of edges) {
|
|
12678
13231
|
const attrs = edge.attributes;
|
|
12679
13232
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
12680
|
-
attrs.provenance =
|
|
13233
|
+
attrs.provenance = import_types50.Provenance.OBSERVED;
|
|
12681
13234
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
12682
13235
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
12683
13236
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
12684
13237
|
if (type && source && target) {
|
|
12685
|
-
const newId = (0,
|
|
13238
|
+
const newId = (0, import_types50.observedEdgeId)(source, target, type);
|
|
12686
13239
|
attrs.id = newId;
|
|
12687
13240
|
if (edge.key) edge.key = newId;
|
|
12688
13241
|
}
|
|
@@ -12691,7 +13244,7 @@ function migrateV2ToV3(payload) {
|
|
|
12691
13244
|
return { ...payload, schemaVersion: 3 };
|
|
12692
13245
|
}
|
|
12693
13246
|
async function ensureDir(filePath) {
|
|
12694
|
-
await import_node_fs26.promises.mkdir(
|
|
13247
|
+
await import_node_fs26.promises.mkdir(import_node_path60.default.dirname(filePath), { recursive: true });
|
|
12695
13248
|
}
|
|
12696
13249
|
async function saveGraphToDisk(graph, outPath) {
|
|
12697
13250
|
await ensureDir(outPath);
|
|
@@ -12783,19 +13336,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
12783
13336
|
init_cjs_shims();
|
|
12784
13337
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
12785
13338
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
12786
|
-
var
|
|
13339
|
+
var import_types80 = require("@neat.is/types");
|
|
12787
13340
|
|
|
12788
13341
|
// src/extend/index.ts
|
|
12789
13342
|
init_cjs_shims();
|
|
12790
13343
|
var import_node_fs28 = require("fs");
|
|
12791
|
-
var
|
|
13344
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
12792
13345
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
12793
13346
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
12794
13347
|
|
|
12795
13348
|
// src/installers/package-manager.ts
|
|
12796
13349
|
init_cjs_shims();
|
|
12797
13350
|
var import_node_fs27 = require("fs");
|
|
12798
|
-
var
|
|
13351
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
12799
13352
|
var import_node_child_process = require("child_process");
|
|
12800
13353
|
var LOCKFILE_PRIORITY = [
|
|
12801
13354
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -12817,22 +13370,22 @@ async function exists2(p) {
|
|
|
12817
13370
|
}
|
|
12818
13371
|
}
|
|
12819
13372
|
async function detectPackageManager(serviceDir) {
|
|
12820
|
-
let dir =
|
|
13373
|
+
let dir = import_node_path61.default.resolve(serviceDir);
|
|
12821
13374
|
const stops = /* @__PURE__ */ new Set();
|
|
12822
13375
|
for (let i = 0; i < 64; i++) {
|
|
12823
13376
|
if (stops.has(dir)) break;
|
|
12824
13377
|
stops.add(dir);
|
|
12825
13378
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
12826
|
-
const lockPath =
|
|
13379
|
+
const lockPath = import_node_path61.default.join(dir, candidate.lockfile);
|
|
12827
13380
|
if (await exists2(lockPath)) {
|
|
12828
13381
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
12829
13382
|
}
|
|
12830
13383
|
}
|
|
12831
|
-
const parent =
|
|
13384
|
+
const parent = import_node_path61.default.dirname(dir);
|
|
12832
13385
|
if (parent === dir) break;
|
|
12833
13386
|
dir = parent;
|
|
12834
13387
|
}
|
|
12835
|
-
return { pm: "npm", cwd:
|
|
13388
|
+
return { pm: "npm", cwd: import_node_path61.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
12836
13389
|
}
|
|
12837
13390
|
async function runPackageManagerInstall(cmd) {
|
|
12838
13391
|
return new Promise((resolve) => {
|
|
@@ -12881,7 +13434,7 @@ async function fileExists2(p) {
|
|
|
12881
13434
|
}
|
|
12882
13435
|
}
|
|
12883
13436
|
async function readPackageJson(scanPath) {
|
|
12884
|
-
const pkgPath =
|
|
13437
|
+
const pkgPath = import_node_path62.default.join(scanPath, "package.json");
|
|
12885
13438
|
const raw = await import_node_fs28.promises.readFile(pkgPath, "utf8");
|
|
12886
13439
|
return JSON.parse(raw);
|
|
12887
13440
|
}
|
|
@@ -12895,27 +13448,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
12895
13448
|
]);
|
|
12896
13449
|
async function findHookFiles(scanPath) {
|
|
12897
13450
|
const found = [];
|
|
12898
|
-
const
|
|
13451
|
+
const walk9 = async (dir) => {
|
|
12899
13452
|
const entries = await import_node_fs28.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
12900
13453
|
for (const entry of entries) {
|
|
12901
13454
|
if (entry.isDirectory()) {
|
|
12902
13455
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
12903
|
-
await
|
|
13456
|
+
await walk9(import_node_path62.default.join(dir, entry.name));
|
|
12904
13457
|
} else if (entry.isFile()) {
|
|
12905
13458
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
12906
|
-
const rel =
|
|
12907
|
-
found.push(rel.split(
|
|
13459
|
+
const rel = import_node_path62.default.relative(scanPath, import_node_path62.default.join(dir, entry.name));
|
|
13460
|
+
found.push(rel.split(import_node_path62.default.sep).join("/"));
|
|
12908
13461
|
}
|
|
12909
13462
|
}
|
|
12910
13463
|
}
|
|
12911
13464
|
};
|
|
12912
|
-
await
|
|
13465
|
+
await walk9(scanPath);
|
|
12913
13466
|
return found.sort();
|
|
12914
13467
|
}
|
|
12915
13468
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
12916
13469
|
let fallback = null;
|
|
12917
13470
|
for (const file of hookFiles) {
|
|
12918
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13471
|
+
const content = await import_node_fs28.promises.readFile(import_node_path62.default.join(scanPath, file), "utf8");
|
|
12919
13472
|
const patched = splicedContent(content, snippet2);
|
|
12920
13473
|
if (patched !== null) return { file, content, patched };
|
|
12921
13474
|
if (fallback === null) fallback = { file, content };
|
|
@@ -12923,11 +13476,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
12923
13476
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
12924
13477
|
}
|
|
12925
13478
|
function extendLogPath() {
|
|
12926
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
13479
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path62.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
12927
13480
|
}
|
|
12928
13481
|
async function appendExtendLog(entry) {
|
|
12929
13482
|
const logPath = extendLogPath();
|
|
12930
|
-
await import_node_fs28.promises.mkdir(
|
|
13483
|
+
await import_node_fs28.promises.mkdir(import_node_path62.default.dirname(logPath), { recursive: true });
|
|
12931
13484
|
await import_node_fs28.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
12932
13485
|
}
|
|
12933
13486
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -12986,7 +13539,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
12986
13539
|
}
|
|
12987
13540
|
async function describeProjectInstrumentation(ctx) {
|
|
12988
13541
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
12989
|
-
const envNeat = await fileExists2(
|
|
13542
|
+
const envNeat = await fileExists2(import_node_path62.default.join(ctx.scanPath, ".env.neat"));
|
|
12990
13543
|
const registryInstrPackages = new Set(
|
|
12991
13544
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
12992
13545
|
);
|
|
@@ -13008,7 +13561,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
13008
13561
|
);
|
|
13009
13562
|
}
|
|
13010
13563
|
for (const file of hookFiles) {
|
|
13011
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13564
|
+
const content = await import_node_fs28.promises.readFile(import_node_path62.default.join(ctx.scanPath, file), "utf8");
|
|
13012
13565
|
if (content.includes(args.registration_snippet)) {
|
|
13013
13566
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
13014
13567
|
}
|
|
@@ -13020,10 +13573,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
13020
13573
|
);
|
|
13021
13574
|
}
|
|
13022
13575
|
const primaryFile = primary.file;
|
|
13023
|
-
const primaryPath =
|
|
13576
|
+
const primaryPath = import_node_path62.default.join(ctx.scanPath, primaryFile);
|
|
13024
13577
|
const filesTouched = [];
|
|
13025
13578
|
const depsAdded = [];
|
|
13026
|
-
const pkgPath =
|
|
13579
|
+
const pkgPath = import_node_path62.default.join(ctx.scanPath, "package.json");
|
|
13027
13580
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13028
13581
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
13029
13582
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -13062,7 +13615,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
13062
13615
|
};
|
|
13063
13616
|
}
|
|
13064
13617
|
for (const file of hookFiles) {
|
|
13065
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13618
|
+
const content = await import_node_fs28.promises.readFile(import_node_path62.default.join(ctx.scanPath, file), "utf8");
|
|
13066
13619
|
if (content.includes(args.registration_snippet)) {
|
|
13067
13620
|
return {
|
|
13068
13621
|
library: args.library,
|
|
@@ -13103,7 +13656,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13103
13656
|
if (!match) {
|
|
13104
13657
|
return { undone: false, message: "no apply found for library" };
|
|
13105
13658
|
}
|
|
13106
|
-
const pkgPath =
|
|
13659
|
+
const pkgPath = import_node_path62.default.join(ctx.scanPath, "package.json");
|
|
13107
13660
|
if (await fileExists2(pkgPath)) {
|
|
13108
13661
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13109
13662
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -13114,7 +13667,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13114
13667
|
}
|
|
13115
13668
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13116
13669
|
for (const file of hookFiles) {
|
|
13117
|
-
const filePath =
|
|
13670
|
+
const filePath = import_node_path62.default.join(ctx.scanPath, file);
|
|
13118
13671
|
const content = await import_node_fs28.promises.readFile(filePath, "utf8");
|
|
13119
13672
|
if (content.includes(match.registration_snippet)) {
|
|
13120
13673
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -13130,39 +13683,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
13130
13683
|
|
|
13131
13684
|
// src/divergences.ts
|
|
13132
13685
|
init_cjs_shims();
|
|
13133
|
-
var
|
|
13686
|
+
var import_types51 = require("@neat.is/types");
|
|
13134
13687
|
function bucketKey(source, target, type) {
|
|
13135
13688
|
return `${type}|${source}|${target}`;
|
|
13136
13689
|
}
|
|
13137
13690
|
function bucketSourceFor(graph, edge) {
|
|
13138
|
-
if (edge.type !==
|
|
13139
|
-
const parsed = (0,
|
|
13691
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) return edge.source;
|
|
13692
|
+
const parsed = (0, import_types51.parseFileId)(edge.source);
|
|
13140
13693
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
13141
13694
|
const target = graph.getNodeAttributes(edge.target);
|
|
13142
|
-
if (target.type !==
|
|
13143
|
-
return (0,
|
|
13695
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) return edge.source;
|
|
13696
|
+
return (0, import_types51.serviceId)(parsed.service);
|
|
13144
13697
|
}
|
|
13145
13698
|
function bucketEdges(graph) {
|
|
13146
13699
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
13147
13700
|
graph.forEachEdge((id, attrs) => {
|
|
13148
13701
|
const e = attrs;
|
|
13149
|
-
const parsed = (0,
|
|
13702
|
+
const parsed = (0, import_types51.parseEdgeId)(id);
|
|
13150
13703
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
13151
13704
|
const source = bucketSourceFor(graph, e);
|
|
13152
13705
|
const key = bucketKey(source, e.target, e.type);
|
|
13153
13706
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
13154
13707
|
switch (provenance) {
|
|
13155
|
-
case
|
|
13708
|
+
case import_types51.Provenance.EXTRACTED:
|
|
13156
13709
|
cur.extracted = e;
|
|
13157
13710
|
break;
|
|
13158
|
-
case
|
|
13711
|
+
case import_types51.Provenance.OBSERVED:
|
|
13159
13712
|
cur.observed = e;
|
|
13160
13713
|
break;
|
|
13161
|
-
case
|
|
13714
|
+
case import_types51.Provenance.INFERRED:
|
|
13162
13715
|
cur.inferred = e;
|
|
13163
13716
|
break;
|
|
13164
13717
|
default:
|
|
13165
|
-
if (e.provenance ===
|
|
13718
|
+
if (e.provenance === import_types51.Provenance.STALE) cur.stale = e;
|
|
13166
13719
|
}
|
|
13167
13720
|
buckets2.set(key, cur);
|
|
13168
13721
|
});
|
|
@@ -13171,22 +13724,22 @@ function bucketEdges(graph) {
|
|
|
13171
13724
|
function nodeIsFrontier(graph, nodeId) {
|
|
13172
13725
|
if (!graph.hasNode(nodeId)) return false;
|
|
13173
13726
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13174
|
-
return attrs.type ===
|
|
13727
|
+
return attrs.type === import_types51.NodeType.FrontierNode;
|
|
13175
13728
|
}
|
|
13176
13729
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
13177
13730
|
if (!graph.hasNode(nodeId)) return false;
|
|
13178
13731
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13179
|
-
return attrs.type ===
|
|
13732
|
+
return attrs.type === import_types51.NodeType.WebSocketChannelNode;
|
|
13180
13733
|
}
|
|
13181
13734
|
function nodeIsServerAction(graph, nodeId) {
|
|
13182
13735
|
if (!graph.hasNode(nodeId)) return false;
|
|
13183
13736
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13184
|
-
return attrs.type ===
|
|
13737
|
+
return attrs.type === import_types51.NodeType.ServerActionNode;
|
|
13185
13738
|
}
|
|
13186
13739
|
function nodeIsSymbol(graph, nodeId) {
|
|
13187
13740
|
if (!graph.hasNode(nodeId)) return false;
|
|
13188
13741
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13189
|
-
return attrs.type ===
|
|
13742
|
+
return attrs.type === import_types51.NodeType.SymbolNode;
|
|
13190
13743
|
}
|
|
13191
13744
|
function clampConfidence(n) {
|
|
13192
13745
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -13206,14 +13759,14 @@ function gradedConfidence(edge) {
|
|
|
13206
13759
|
return clampConfidence(confidenceForEdge(edge));
|
|
13207
13760
|
}
|
|
13208
13761
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13762
|
+
import_types51.EdgeType.CALLS,
|
|
13763
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
13764
|
+
import_types51.EdgeType.PUBLISHES_TO,
|
|
13765
|
+
import_types51.EdgeType.CONSUMES_FROM
|
|
13213
13766
|
]);
|
|
13214
13767
|
function detectMissingDivergences(graph, bucket) {
|
|
13215
13768
|
const out = [];
|
|
13216
|
-
if (bucket.type ===
|
|
13769
|
+
if (bucket.type === import_types51.EdgeType.CONTAINS) return out;
|
|
13217
13770
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
13218
13771
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
13219
13772
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -13255,7 +13808,7 @@ function declaredHostFor(svc) {
|
|
|
13255
13808
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
13256
13809
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13257
13810
|
const e = graph.getEdgeAttributes(edgeId);
|
|
13258
|
-
if (e.type ===
|
|
13811
|
+
if (e.type === import_types51.EdgeType.CONFIGURED_BY && e.provenance === import_types51.Provenance.EXTRACTED) {
|
|
13259
13812
|
return true;
|
|
13260
13813
|
}
|
|
13261
13814
|
}
|
|
@@ -13268,10 +13821,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
13268
13821
|
const out = [];
|
|
13269
13822
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13270
13823
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13271
|
-
if (edge.type !==
|
|
13272
|
-
if (edge.provenance !==
|
|
13824
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13825
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13273
13826
|
const target = graph.getNodeAttributes(edge.target);
|
|
13274
|
-
if (target.type !==
|
|
13827
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13275
13828
|
const observedHost = target.host?.trim();
|
|
13276
13829
|
if (!observedHost) continue;
|
|
13277
13830
|
if (observedHost === declaredHost) continue;
|
|
@@ -13293,10 +13846,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
13293
13846
|
const deps = svc.dependencies ?? {};
|
|
13294
13847
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13295
13848
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13296
|
-
if (edge.type !==
|
|
13297
|
-
if (edge.provenance !==
|
|
13849
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13850
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13298
13851
|
const target = graph.getNodeAttributes(edge.target);
|
|
13299
|
-
if (target.type !==
|
|
13852
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13300
13853
|
for (const pair of compatPairs()) {
|
|
13301
13854
|
if (pair.engine !== target.engine) continue;
|
|
13302
13855
|
const declared = deps[pair.driver];
|
|
@@ -13393,7 +13946,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
13393
13946
|
for (const d of all) {
|
|
13394
13947
|
if (d.type !== "host-mismatch") continue;
|
|
13395
13948
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
13396
|
-
declaredHalf.add((0,
|
|
13949
|
+
declaredHalf.add((0, import_types51.databaseId)(d.extractedHost));
|
|
13397
13950
|
}
|
|
13398
13951
|
if (observedHalf.size === 0) return all;
|
|
13399
13952
|
return all.filter((d) => {
|
|
@@ -13412,13 +13965,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13412
13965
|
}
|
|
13413
13966
|
graph.forEachNode((nodeId, attrs) => {
|
|
13414
13967
|
const n = attrs;
|
|
13415
|
-
if (n.type ===
|
|
13968
|
+
if (n.type === import_types51.NodeType.ServiceNode) {
|
|
13416
13969
|
const svc = n;
|
|
13417
13970
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
13418
13971
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
13419
13972
|
return;
|
|
13420
13973
|
}
|
|
13421
|
-
if (n.type ===
|
|
13974
|
+
if (n.type === import_types51.NodeType.InfraNode && n.kind === "sql-table") {
|
|
13422
13975
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
13423
13976
|
}
|
|
13424
13977
|
});
|
|
@@ -13454,7 +14007,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13454
14007
|
const bc = "column" in b && b.column ? b.column : "";
|
|
13455
14008
|
return ac.localeCompare(bc);
|
|
13456
14009
|
});
|
|
13457
|
-
return
|
|
14010
|
+
return import_types51.DivergenceResultSchema.parse({
|
|
13458
14011
|
divergences: filtered,
|
|
13459
14012
|
totalAffected: filtered.length,
|
|
13460
14013
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -13585,23 +14138,23 @@ function canonicalJson(value) {
|
|
|
13585
14138
|
|
|
13586
14139
|
// src/projects.ts
|
|
13587
14140
|
init_cjs_shims();
|
|
13588
|
-
var
|
|
14141
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
13589
14142
|
function pathsForProject(project, baseDir) {
|
|
13590
14143
|
if (project === DEFAULT_PROJECT) {
|
|
13591
14144
|
return {
|
|
13592
|
-
snapshotPath:
|
|
13593
|
-
errorsPath:
|
|
13594
|
-
staleEventsPath:
|
|
13595
|
-
embeddingsCachePath:
|
|
13596
|
-
policyViolationsPath:
|
|
14145
|
+
snapshotPath: import_node_path63.default.join(baseDir, "graph.json"),
|
|
14146
|
+
errorsPath: import_node_path63.default.join(baseDir, "errors.ndjson"),
|
|
14147
|
+
staleEventsPath: import_node_path63.default.join(baseDir, "stale-events.ndjson"),
|
|
14148
|
+
embeddingsCachePath: import_node_path63.default.join(baseDir, "embeddings.json"),
|
|
14149
|
+
policyViolationsPath: import_node_path63.default.join(baseDir, "policy-violations.ndjson")
|
|
13597
14150
|
};
|
|
13598
14151
|
}
|
|
13599
14152
|
return {
|
|
13600
|
-
snapshotPath:
|
|
13601
|
-
errorsPath:
|
|
13602
|
-
staleEventsPath:
|
|
13603
|
-
embeddingsCachePath:
|
|
13604
|
-
policyViolationsPath:
|
|
14153
|
+
snapshotPath: import_node_path63.default.join(baseDir, `${project}.json`),
|
|
14154
|
+
errorsPath: import_node_path63.default.join(baseDir, `errors.${project}.ndjson`),
|
|
14155
|
+
staleEventsPath: import_node_path63.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
14156
|
+
embeddingsCachePath: import_node_path63.default.join(baseDir, `embeddings.${project}.json`),
|
|
14157
|
+
policyViolationsPath: import_node_path63.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
13605
14158
|
};
|
|
13606
14159
|
}
|
|
13607
14160
|
var Projects = class {
|
|
@@ -13639,26 +14192,26 @@ var Projects = class {
|
|
|
13639
14192
|
init_cjs_shims();
|
|
13640
14193
|
var import_node_fs30 = require("fs");
|
|
13641
14194
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
13642
|
-
var
|
|
13643
|
-
var
|
|
14195
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
14196
|
+
var import_types52 = require("@neat.is/types");
|
|
13644
14197
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
13645
14198
|
var LOCK_RETRY_MS = 50;
|
|
13646
14199
|
function neatHome() {
|
|
13647
14200
|
const override = process.env.NEAT_HOME;
|
|
13648
|
-
if (override && override.length > 0) return
|
|
13649
|
-
return
|
|
14201
|
+
if (override && override.length > 0) return import_node_path64.default.resolve(override);
|
|
14202
|
+
return import_node_path64.default.join(import_node_os3.default.homedir(), ".neat");
|
|
13650
14203
|
}
|
|
13651
14204
|
function registryPath() {
|
|
13652
|
-
return
|
|
14205
|
+
return import_node_path64.default.join(neatHome(), "projects.json");
|
|
13653
14206
|
}
|
|
13654
14207
|
function registryLockPath() {
|
|
13655
|
-
return
|
|
14208
|
+
return import_node_path64.default.join(neatHome(), "projects.json.lock");
|
|
13656
14209
|
}
|
|
13657
14210
|
function daemonPidPath() {
|
|
13658
|
-
return
|
|
14211
|
+
return import_node_path64.default.join(neatHome(), "neatd.pid");
|
|
13659
14212
|
}
|
|
13660
14213
|
function daemonsDir() {
|
|
13661
|
-
return
|
|
14214
|
+
return import_node_path64.default.join(neatHome(), "daemons");
|
|
13662
14215
|
}
|
|
13663
14216
|
function isFiniteInt(v) {
|
|
13664
14217
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -13699,7 +14252,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
13699
14252
|
const out = [];
|
|
13700
14253
|
for (const name of names) {
|
|
13701
14254
|
if (!name.endsWith(".json")) continue;
|
|
13702
|
-
const file =
|
|
14255
|
+
const file = import_node_path64.default.join(dir, name);
|
|
13703
14256
|
let raw;
|
|
13704
14257
|
try {
|
|
13705
14258
|
raw = await import_node_fs30.promises.readFile(file, "utf8");
|
|
@@ -13776,7 +14329,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
13776
14329
|
}
|
|
13777
14330
|
}
|
|
13778
14331
|
async function normalizeProjectPath(input) {
|
|
13779
|
-
const resolved =
|
|
14332
|
+
const resolved = import_node_path64.default.resolve(input);
|
|
13780
14333
|
try {
|
|
13781
14334
|
return await import_node_fs30.promises.realpath(resolved);
|
|
13782
14335
|
} catch {
|
|
@@ -13784,7 +14337,7 @@ async function normalizeProjectPath(input) {
|
|
|
13784
14337
|
}
|
|
13785
14338
|
}
|
|
13786
14339
|
async function writeAtomically(target, contents) {
|
|
13787
|
-
await import_node_fs30.promises.mkdir(
|
|
14340
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(target), { recursive: true });
|
|
13788
14341
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
13789
14342
|
const fd = await import_node_fs30.promises.open(tmp, "w");
|
|
13790
14343
|
try {
|
|
@@ -13797,7 +14350,7 @@ async function writeAtomically(target, contents) {
|
|
|
13797
14350
|
}
|
|
13798
14351
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
13799
14352
|
const deadline = Date.now() + timeoutMs;
|
|
13800
|
-
await import_node_fs30.promises.mkdir(
|
|
14353
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(lockPath), { recursive: true });
|
|
13801
14354
|
let probedHolder = false;
|
|
13802
14355
|
while (true) {
|
|
13803
14356
|
try {
|
|
@@ -13850,10 +14403,10 @@ async function readRegistry() {
|
|
|
13850
14403
|
throw err;
|
|
13851
14404
|
}
|
|
13852
14405
|
const parsed = JSON.parse(raw);
|
|
13853
|
-
return
|
|
14406
|
+
return import_types52.RegistryFileSchema.parse(parsed);
|
|
13854
14407
|
}
|
|
13855
14408
|
async function writeRegistry(reg) {
|
|
13856
|
-
const validated =
|
|
14409
|
+
const validated = import_types52.RegistryFileSchema.parse(reg);
|
|
13857
14410
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
13858
14411
|
}
|
|
13859
14412
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -14048,7 +14601,7 @@ init_auth();
|
|
|
14048
14601
|
// src/connectors-config.ts
|
|
14049
14602
|
init_cjs_shims();
|
|
14050
14603
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
14051
|
-
var
|
|
14604
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
14052
14605
|
var import_node_fs31 = require("fs");
|
|
14053
14606
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
14054
14607
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -14063,11 +14616,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
14063
14616
|
};
|
|
14064
14617
|
function neatHome2() {
|
|
14065
14618
|
const override = process.env.NEAT_HOME;
|
|
14066
|
-
if (override && override.length > 0) return
|
|
14067
|
-
return
|
|
14619
|
+
if (override && override.length > 0) return import_node_path65.default.resolve(override);
|
|
14620
|
+
return import_node_path65.default.join(import_node_os4.default.homedir(), ".neat");
|
|
14068
14621
|
}
|
|
14069
14622
|
function connectorsConfigPath(home = neatHome2()) {
|
|
14070
|
-
return
|
|
14623
|
+
return import_node_path65.default.join(home, "connectors.json");
|
|
14071
14624
|
}
|
|
14072
14625
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
14073
14626
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -14254,15 +14807,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
14254
14807
|
|
|
14255
14808
|
// src/connectors/index.ts
|
|
14256
14809
|
init_cjs_shims();
|
|
14257
|
-
var
|
|
14810
|
+
var import_types53 = require("@neat.is/types");
|
|
14258
14811
|
var NO_ENV = "unknown";
|
|
14259
14812
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
14260
14813
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14261
14814
|
const sites = [];
|
|
14262
14815
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
14263
14816
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
14264
|
-
if (edge.provenance !==
|
|
14265
|
-
const parsed = (0,
|
|
14817
|
+
if (edge.provenance !== import_types53.Provenance.EXTRACTED) continue;
|
|
14818
|
+
const parsed = (0, import_types53.parseFileId)(edge.source);
|
|
14266
14819
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
14267
14820
|
const site = { relPath: edge.evidence.file };
|
|
14268
14821
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -14273,7 +14826,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
14273
14826
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
14274
14827
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14275
14828
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
14276
|
-
if (attrs.type !==
|
|
14829
|
+
if (attrs.type !== import_types53.NodeType.RouteNode || !attrs.path) return void 0;
|
|
14277
14830
|
const site = { relPath: attrs.path };
|
|
14278
14831
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
14279
14832
|
return site;
|
|
@@ -14754,10 +15307,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
14754
15307
|
// src/connectors/supabase/map.ts
|
|
14755
15308
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
14756
15309
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
14757
|
-
function targetFromRestPath(
|
|
14758
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
15310
|
+
function targetFromRestPath(path68) {
|
|
15311
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path68);
|
|
14759
15312
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
14760
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
15313
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path68);
|
|
14761
15314
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
14762
15315
|
return null;
|
|
14763
15316
|
}
|
|
@@ -14868,23 +15421,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
14868
15421
|
|
|
14869
15422
|
// src/connectors/supabase/resolve.ts
|
|
14870
15423
|
init_cjs_shims();
|
|
14871
|
-
var
|
|
15424
|
+
var import_types55 = require("@neat.is/types");
|
|
14872
15425
|
function createSupabaseResolveTarget(graph, config) {
|
|
14873
15426
|
return (signal, _ctx) => {
|
|
14874
15427
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
14875
15428
|
return null;
|
|
14876
15429
|
}
|
|
14877
|
-
const subResourceId = (0,
|
|
15430
|
+
const subResourceId = (0, import_types55.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
14878
15431
|
if (graph.hasNode(subResourceId)) {
|
|
14879
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
15432
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14880
15433
|
}
|
|
14881
|
-
const bareResourceId = (0,
|
|
15434
|
+
const bareResourceId = (0, import_types55.infraId)(signal.targetKind, signal.targetName);
|
|
14882
15435
|
if (graph.hasNode(bareResourceId)) {
|
|
14883
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
15436
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14884
15437
|
}
|
|
14885
|
-
const projectLevelId = (0,
|
|
15438
|
+
const projectLevelId = (0, import_types55.infraId)("supabase", config.nodeRef);
|
|
14886
15439
|
if (graph.hasNode(projectLevelId)) {
|
|
14887
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
15440
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14888
15441
|
}
|
|
14889
15442
|
return null;
|
|
14890
15443
|
};
|
|
@@ -14977,7 +15530,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
14977
15530
|
|
|
14978
15531
|
// src/connectors/railway/index.ts
|
|
14979
15532
|
init_cjs_shims();
|
|
14980
|
-
var
|
|
15533
|
+
var import_types59 = require("@neat.is/types");
|
|
14981
15534
|
|
|
14982
15535
|
// src/connectors/railway/client.ts
|
|
14983
15536
|
init_cjs_shims();
|
|
@@ -15128,7 +15681,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
15128
15681
|
const out = [];
|
|
15129
15682
|
graph.forEachNode((_id, attrs) => {
|
|
15130
15683
|
const node = attrs;
|
|
15131
|
-
if (node.type !==
|
|
15684
|
+
if (node.type !== import_types59.NodeType.RouteNode) return;
|
|
15132
15685
|
const route = attrs;
|
|
15133
15686
|
if (route.service !== serviceName) return;
|
|
15134
15687
|
out.push({
|
|
@@ -15232,12 +15785,12 @@ function createRailwayResolveTarget(config) {
|
|
|
15232
15785
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
15233
15786
|
if (!serviceName) return null;
|
|
15234
15787
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
15235
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
15788
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types59.EdgeType.CALLS };
|
|
15236
15789
|
}
|
|
15237
15790
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
15238
15791
|
const peerName = config.serviceNameById[signal.targetName];
|
|
15239
15792
|
if (!peerName) return null;
|
|
15240
|
-
return { targetNodeId: (0,
|
|
15793
|
+
return { targetNodeId: (0, import_types59.serviceId)(peerName), serviceName, edgeType: import_types59.EdgeType.CONNECTS_TO };
|
|
15241
15794
|
}
|
|
15242
15795
|
return null;
|
|
15243
15796
|
};
|
|
@@ -15361,9 +15914,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
15361
15914
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
15362
15915
|
if (secondSep === -1) return null;
|
|
15363
15916
|
const method = rest.slice(0, secondSep);
|
|
15364
|
-
const
|
|
15365
|
-
if (!resourceName || !method || !
|
|
15366
|
-
return { resourceName, method, path:
|
|
15917
|
+
const path68 = rest.slice(secondSep + 1);
|
|
15918
|
+
if (!resourceName || !method || !path68) return null;
|
|
15919
|
+
return { resourceName, method, path: path68 };
|
|
15367
15920
|
}
|
|
15368
15921
|
function resourceNameFor(type, labels) {
|
|
15369
15922
|
if (!labels) return null;
|
|
@@ -15401,14 +15954,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
15401
15954
|
if (!req) return null;
|
|
15402
15955
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
15403
15956
|
const method = req.requestMethod.toUpperCase();
|
|
15404
|
-
const
|
|
15405
|
-
if (
|
|
15957
|
+
const path68 = pathFromRequestUrl(req.requestUrl);
|
|
15958
|
+
if (path68 === null) return null;
|
|
15406
15959
|
const timestamp = entry.timestamp;
|
|
15407
15960
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15408
15961
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
15409
15962
|
return {
|
|
15410
15963
|
targetKind: resourceType,
|
|
15411
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
15964
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path68 }),
|
|
15412
15965
|
callCount: 1,
|
|
15413
15966
|
errorCount: isError ? 1 : 0,
|
|
15414
15967
|
lastObservedIso: timestamp
|
|
@@ -15425,7 +15978,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
15425
15978
|
|
|
15426
15979
|
// src/connectors/firebase/resolve.ts
|
|
15427
15980
|
init_cjs_shims();
|
|
15428
|
-
var
|
|
15981
|
+
var import_types60 = require("@neat.is/types");
|
|
15429
15982
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
15430
15983
|
switch (resourceType) {
|
|
15431
15984
|
case "cloud_function":
|
|
@@ -15440,7 +15993,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
15440
15993
|
const entries = [];
|
|
15441
15994
|
graph.forEachNode((_id, attrs) => {
|
|
15442
15995
|
const node = attrs;
|
|
15443
|
-
if (node.type !==
|
|
15996
|
+
if (node.type !== import_types60.NodeType.RouteNode) return;
|
|
15444
15997
|
const route = attrs;
|
|
15445
15998
|
if (route.service !== serviceName) return;
|
|
15446
15999
|
entries.push({
|
|
@@ -15472,7 +16025,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
15472
16025
|
return {
|
|
15473
16026
|
targetNodeId: match.routeNodeId,
|
|
15474
16027
|
serviceName,
|
|
15475
|
-
edgeType:
|
|
16028
|
+
edgeType: import_types60.EdgeType.CALLS
|
|
15476
16029
|
};
|
|
15477
16030
|
};
|
|
15478
16031
|
}
|
|
@@ -15499,7 +16052,7 @@ init_cjs_shims();
|
|
|
15499
16052
|
|
|
15500
16053
|
// src/connectors/cloudflare/connector.ts
|
|
15501
16054
|
init_cjs_shims();
|
|
15502
|
-
var
|
|
16055
|
+
var import_types62 = require("@neat.is/types");
|
|
15503
16056
|
|
|
15504
16057
|
// src/connectors/cloudflare/client.ts
|
|
15505
16058
|
init_cjs_shims();
|
|
@@ -15615,7 +16168,7 @@ function mapEventToSignal(event) {
|
|
|
15615
16168
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
15616
16169
|
const statusCode = metadata?.statusCode;
|
|
15617
16170
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
15618
|
-
const
|
|
16171
|
+
const path68 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
15619
16172
|
return {
|
|
15620
16173
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
15621
16174
|
targetName: scriptName,
|
|
@@ -15623,7 +16176,7 @@ function mapEventToSignal(event) {
|
|
|
15623
16176
|
errorCount: isError ? 1 : 0,
|
|
15624
16177
|
lastObservedIso: observedAt.toISOString(),
|
|
15625
16178
|
method,
|
|
15626
|
-
...
|
|
16179
|
+
...path68 ? { path: path68 } : {},
|
|
15627
16180
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
15628
16181
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
15629
16182
|
};
|
|
@@ -15663,19 +16216,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
15663
16216
|
graph.forEachNode((id, attrs) => {
|
|
15664
16217
|
if (found) return;
|
|
15665
16218
|
const a = attrs;
|
|
15666
|
-
if (a.type ===
|
|
16219
|
+
if (a.type === import_types62.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
15667
16220
|
found = id;
|
|
15668
16221
|
}
|
|
15669
16222
|
});
|
|
15670
16223
|
return found;
|
|
15671
16224
|
}
|
|
15672
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
15673
|
-
const normalizedPath = normalizePathTemplate(
|
|
16225
|
+
function findMatchingRouteNode(graph, serviceName, method, path68) {
|
|
16226
|
+
const normalizedPath = normalizePathTemplate(path68);
|
|
15674
16227
|
let found = null;
|
|
15675
16228
|
graph.forEachNode((id, attrs) => {
|
|
15676
16229
|
if (found) return;
|
|
15677
16230
|
const a = attrs;
|
|
15678
|
-
if (a.type !==
|
|
16231
|
+
if (a.type !== import_types62.NodeType.RouteNode || a.service !== serviceName) return;
|
|
15679
16232
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
15680
16233
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
15681
16234
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -15687,18 +16240,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15687
16240
|
return (signal) => {
|
|
15688
16241
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
15689
16242
|
const scriptName = signal.targetName;
|
|
15690
|
-
const { method, path:
|
|
16243
|
+
const { method, path: path68 } = signal;
|
|
15691
16244
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
15692
|
-
if (!method || !
|
|
15693
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
16245
|
+
if (!method || !path68) return wholeFileId;
|
|
16246
|
+
return findMatchingRouteNode(graph, serviceName, method, path68) ?? wholeFileId;
|
|
15694
16247
|
};
|
|
15695
16248
|
const mapping = config.workers?.[scriptName];
|
|
15696
16249
|
if (mapping) {
|
|
15697
|
-
const wholeFileId = (0,
|
|
16250
|
+
const wholeFileId = (0, import_types62.fileId)(mapping.service, mapping.entryFile);
|
|
15698
16251
|
return {
|
|
15699
16252
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
15700
16253
|
serviceName: mapping.service,
|
|
15701
|
-
edgeType:
|
|
16254
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15702
16255
|
};
|
|
15703
16256
|
}
|
|
15704
16257
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -15707,13 +16260,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15707
16260
|
return {
|
|
15708
16261
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
15709
16262
|
serviceName: fileNode.service,
|
|
15710
|
-
edgeType:
|
|
16263
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15711
16264
|
};
|
|
15712
16265
|
}
|
|
15713
16266
|
return {
|
|
15714
|
-
targetNodeId: (0,
|
|
16267
|
+
targetNodeId: (0, import_types62.infraId)("cloudflare-worker", scriptName),
|
|
15715
16268
|
serviceName: scriptName,
|
|
15716
|
-
edgeType:
|
|
16269
|
+
edgeType: import_types62.EdgeType.CALLS,
|
|
15717
16270
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
15718
16271
|
};
|
|
15719
16272
|
};
|
|
@@ -15909,14 +16462,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
15909
16462
|
|
|
15910
16463
|
// src/connectors/neon/resolve.ts
|
|
15911
16464
|
init_cjs_shims();
|
|
15912
|
-
var
|
|
16465
|
+
var import_types66 = require("@neat.is/types");
|
|
15913
16466
|
function createNeonResolveTarget(config) {
|
|
15914
16467
|
return (signal) => {
|
|
15915
16468
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
15916
16469
|
return {
|
|
15917
|
-
targetNodeId: (0,
|
|
16470
|
+
targetNodeId: (0, import_types66.infraId)("sql-table", signal.targetName),
|
|
15918
16471
|
serviceName: config.serviceName,
|
|
15919
|
-
edgeType:
|
|
16472
|
+
edgeType: import_types66.EdgeType.CALLS,
|
|
15920
16473
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
15921
16474
|
};
|
|
15922
16475
|
};
|
|
@@ -16042,9 +16595,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
16042
16595
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
16043
16596
|
if (secondSep === -1) return null;
|
|
16044
16597
|
const method = rest.slice(0, secondSep);
|
|
16045
|
-
const
|
|
16046
|
-
if (!serviceName || !method || !
|
|
16047
|
-
return { serviceName, method, path:
|
|
16598
|
+
const path68 = rest.slice(secondSep + 1);
|
|
16599
|
+
if (!serviceName || !method || !path68) return null;
|
|
16600
|
+
return { serviceName, method, path: path68 };
|
|
16048
16601
|
}
|
|
16049
16602
|
|
|
16050
16603
|
// src/connectors/cloud-run/map.ts
|
|
@@ -16073,14 +16626,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
16073
16626
|
if (!req) return null;
|
|
16074
16627
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
16075
16628
|
const method = req.requestMethod.toUpperCase();
|
|
16076
|
-
const
|
|
16077
|
-
if (
|
|
16629
|
+
const path68 = pathFromRequestUrl2(req.requestUrl);
|
|
16630
|
+
if (path68 === null) return null;
|
|
16078
16631
|
const timestamp = entry.timestamp;
|
|
16079
16632
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
16080
16633
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
16081
16634
|
return {
|
|
16082
16635
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
16083
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
16636
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path68 }),
|
|
16084
16637
|
callCount: 1,
|
|
16085
16638
|
errorCount: isError ? 1 : 0,
|
|
16086
16639
|
lastObservedIso: timestamp
|
|
@@ -16097,14 +16650,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
16097
16650
|
|
|
16098
16651
|
// src/connectors/cloud-run/resolve.ts
|
|
16099
16652
|
init_cjs_shims();
|
|
16100
|
-
var
|
|
16653
|
+
var import_types70 = require("@neat.is/types");
|
|
16101
16654
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
16102
16655
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
16103
16656
|
let found = null;
|
|
16104
16657
|
graph.forEachNode((_id, attrs) => {
|
|
16105
16658
|
if (found) return;
|
|
16106
16659
|
const node = attrs;
|
|
16107
|
-
if (node.type !==
|
|
16660
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
16108
16661
|
const route = attrs;
|
|
16109
16662
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
16110
16663
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -16119,23 +16672,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
16119
16672
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
16120
16673
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
16121
16674
|
if (!identity) return null;
|
|
16122
|
-
const { serviceName: gcpServiceName, method, path:
|
|
16675
|
+
const { serviceName: gcpServiceName, method, path: path68 } = identity;
|
|
16123
16676
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
16124
16677
|
if (mappedService) {
|
|
16125
16678
|
const routeNodeId = findMatchingRouteNode2(
|
|
16126
16679
|
graph,
|
|
16127
16680
|
mappedService,
|
|
16128
16681
|
method,
|
|
16129
|
-
normalizePathTemplate(
|
|
16682
|
+
normalizePathTemplate(path68)
|
|
16130
16683
|
);
|
|
16131
16684
|
if (routeNodeId) {
|
|
16132
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
16685
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types70.EdgeType.CALLS };
|
|
16133
16686
|
}
|
|
16134
16687
|
}
|
|
16135
16688
|
return {
|
|
16136
|
-
targetNodeId: (0,
|
|
16689
|
+
targetNodeId: (0, import_types70.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
16137
16690
|
serviceName: mappedService ?? gcpServiceName,
|
|
16138
|
-
edgeType:
|
|
16691
|
+
edgeType: import_types70.EdgeType.CALLS,
|
|
16139
16692
|
ensureInfraNode: {
|
|
16140
16693
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
16141
16694
|
name: gcpServiceName,
|
|
@@ -16176,7 +16729,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
16176
16729
|
|
|
16177
16730
|
// src/connectors/render/index.ts
|
|
16178
16731
|
init_cjs_shims();
|
|
16179
|
-
var
|
|
16732
|
+
var import_types73 = require("@neat.is/types");
|
|
16180
16733
|
|
|
16181
16734
|
// src/connectors/render/types.ts
|
|
16182
16735
|
init_cjs_shims();
|
|
@@ -16254,7 +16807,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
16254
16807
|
const out = [];
|
|
16255
16808
|
graph.forEachNode((_id, attrs) => {
|
|
16256
16809
|
const node = attrs;
|
|
16257
|
-
if (node.type !==
|
|
16810
|
+
if (node.type !== import_types73.NodeType.RouteNode) return;
|
|
16258
16811
|
const route = attrs;
|
|
16259
16812
|
if (route.service !== serviceName) return;
|
|
16260
16813
|
out.push({
|
|
@@ -16339,7 +16892,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
16339
16892
|
function createRenderResolveTarget(config) {
|
|
16340
16893
|
return (signal) => {
|
|
16341
16894
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
16342
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
16895
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types73.EdgeType.CALLS };
|
|
16343
16896
|
}
|
|
16344
16897
|
return null;
|
|
16345
16898
|
};
|
|
@@ -16477,21 +17030,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
16477
17030
|
|
|
16478
17031
|
// src/connectors/planetscale/resolve.ts
|
|
16479
17032
|
init_cjs_shims();
|
|
16480
|
-
var
|
|
17033
|
+
var import_types77 = require("@neat.is/types");
|
|
16481
17034
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
16482
17035
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
16483
17036
|
const databaseName = `${config.organization}/${config.database}`;
|
|
16484
17037
|
return (signal, _ctx) => {
|
|
16485
17038
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
16486
|
-
const tableId = (0,
|
|
17039
|
+
const tableId = (0, import_types77.infraId)("sql-table", signal.targetName);
|
|
16487
17040
|
if (graph.hasNode(tableId)) {
|
|
16488
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
17041
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types77.EdgeType.CALLS };
|
|
16489
17042
|
}
|
|
16490
|
-
const providerId = (0,
|
|
17043
|
+
const providerId = (0, import_types77.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
16491
17044
|
return {
|
|
16492
17045
|
targetNodeId: providerId,
|
|
16493
17046
|
serviceName: config.serviceName,
|
|
16494
|
-
edgeType:
|
|
17047
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
16495
17048
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
16496
17049
|
};
|
|
16497
17050
|
};
|
|
@@ -17161,11 +17714,11 @@ function registerRoutes(scope, ctx) {
|
|
|
17161
17714
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
17162
17715
|
const parsed = [];
|
|
17163
17716
|
for (const c of candidates) {
|
|
17164
|
-
const r =
|
|
17717
|
+
const r = import_types80.DivergenceTypeSchema.safeParse(c);
|
|
17165
17718
|
if (!r.success) {
|
|
17166
17719
|
return reply.code(400).send({
|
|
17167
17720
|
error: `unknown divergence type "${c}"`,
|
|
17168
|
-
allowed:
|
|
17721
|
+
allowed: import_types80.DivergenceTypeSchema.options
|
|
17169
17722
|
});
|
|
17170
17723
|
}
|
|
17171
17724
|
parsed.push(r.data);
|
|
@@ -17474,7 +18027,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17474
18027
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
17475
18028
|
let violations = await log.readAll();
|
|
17476
18029
|
if (req.query.severity) {
|
|
17477
|
-
const sev =
|
|
18030
|
+
const sev = import_types80.PolicySeveritySchema.safeParse(req.query.severity);
|
|
17478
18031
|
if (!sev.success) {
|
|
17479
18032
|
return reply.code(400).send({
|
|
17480
18033
|
error: "invalid severity",
|
|
@@ -17513,7 +18066,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17513
18066
|
scope.post("/policies/check", async (req, reply) => {
|
|
17514
18067
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
17515
18068
|
if (!proj) return;
|
|
17516
|
-
const parsed =
|
|
18069
|
+
const parsed = import_types80.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
17517
18070
|
if (!parsed.success) {
|
|
17518
18071
|
return reply.code(400).send({
|
|
17519
18072
|
error: "invalid /policies/check body",
|
|
@@ -17835,7 +18388,7 @@ init_otel_grpc();
|
|
|
17835
18388
|
// src/daemon.ts
|
|
17836
18389
|
init_cjs_shims();
|
|
17837
18390
|
var import_node_fs33 = require("fs");
|
|
17838
|
-
var
|
|
18391
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
17839
18392
|
var import_node_module = require("module");
|
|
17840
18393
|
init_otel();
|
|
17841
18394
|
init_auth();
|
|
@@ -17843,7 +18396,7 @@ init_auth();
|
|
|
17843
18396
|
// src/unrouted.ts
|
|
17844
18397
|
init_cjs_shims();
|
|
17845
18398
|
var import_node_fs32 = require("fs");
|
|
17846
|
-
var
|
|
18399
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
17847
18400
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
17848
18401
|
return {
|
|
17849
18402
|
timestamp: now.toISOString(),
|
|
@@ -17853,34 +18406,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
17853
18406
|
};
|
|
17854
18407
|
}
|
|
17855
18408
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
17856
|
-
const target =
|
|
18409
|
+
const target = import_node_path66.default.join(neatHome3, "errors.ndjson");
|
|
17857
18410
|
await import_node_fs32.promises.mkdir(neatHome3, { recursive: true });
|
|
17858
18411
|
await import_node_fs32.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
17859
18412
|
}
|
|
17860
18413
|
function unroutedErrorsPath(neatHome3) {
|
|
17861
|
-
return
|
|
18414
|
+
return import_node_path66.default.join(neatHome3, "errors.ndjson");
|
|
17862
18415
|
}
|
|
17863
18416
|
|
|
17864
18417
|
// src/daemon.ts
|
|
17865
|
-
var
|
|
18418
|
+
var import_types81 = require("@neat.is/types");
|
|
17866
18419
|
function daemonJsonPath(scanPath) {
|
|
17867
|
-
return
|
|
18420
|
+
return import_node_path67.default.join(scanPath, "neat-out", "daemon.json");
|
|
17868
18421
|
}
|
|
17869
18422
|
function daemonsDiscoveryDir(home) {
|
|
17870
18423
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
17871
|
-
return
|
|
18424
|
+
return import_node_path67.default.join(base, "daemons");
|
|
17872
18425
|
}
|
|
17873
18426
|
function daemonDiscoveryPath(project, home) {
|
|
17874
|
-
return
|
|
18427
|
+
return import_node_path67.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
17875
18428
|
}
|
|
17876
18429
|
function sanitizeDiscoveryName(project) {
|
|
17877
18430
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
17878
18431
|
}
|
|
17879
18432
|
function neatHomeFromEnv() {
|
|
17880
18433
|
const env = process.env.NEAT_HOME;
|
|
17881
|
-
if (env && env.length > 0) return
|
|
18434
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17882
18435
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17883
|
-
return
|
|
18436
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17884
18437
|
}
|
|
17885
18438
|
function resolveNeatVersion() {
|
|
17886
18439
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -17935,11 +18488,11 @@ function teardownSlot(slot) {
|
|
|
17935
18488
|
}
|
|
17936
18489
|
}
|
|
17937
18490
|
function neatHomeFor(opts) {
|
|
17938
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
18491
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path67.default.resolve(opts.neatHome);
|
|
17939
18492
|
const env = process.env.NEAT_HOME;
|
|
17940
|
-
if (env && env.length > 0) return
|
|
18493
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17941
18494
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17942
|
-
return
|
|
18495
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17943
18496
|
}
|
|
17944
18497
|
function routeSpanToProject(serviceName, projects) {
|
|
17945
18498
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -17987,11 +18540,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
17987
18540
|
if (!serviceName) return true;
|
|
17988
18541
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
17989
18542
|
return graph.someNode(
|
|
17990
|
-
(_id, attrs) => attrs.type ===
|
|
18543
|
+
(_id, attrs) => attrs.type === import_types81.NodeType.ServiceNode && attrs.name === serviceName
|
|
17991
18544
|
);
|
|
17992
18545
|
}
|
|
17993
18546
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
17994
|
-
const paths = pathsForProject(entry.name,
|
|
18547
|
+
const paths = pathsForProject(entry.name, import_node_path67.default.join(entry.path, "neat-out"));
|
|
17995
18548
|
try {
|
|
17996
18549
|
const stat = await import_node_fs33.promises.stat(entry.path);
|
|
17997
18550
|
if (!stat.isDirectory()) {
|
|
@@ -18107,7 +18660,7 @@ async function startDaemon(opts = {}) {
|
|
|
18107
18660
|
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;
|
|
18108
18661
|
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;
|
|
18109
18662
|
const singleProject = projectArg;
|
|
18110
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
18663
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path67.default.resolve(projectPathArg) : null;
|
|
18111
18664
|
if (singleProject && !singleProjectPath) {
|
|
18112
18665
|
throw new Error(
|
|
18113
18666
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -18122,7 +18675,7 @@ async function startDaemon(opts = {}) {
|
|
|
18122
18675
|
);
|
|
18123
18676
|
}
|
|
18124
18677
|
}
|
|
18125
|
-
const pidPath =
|
|
18678
|
+
const pidPath = import_node_path67.default.join(home, "neatd.pid");
|
|
18126
18679
|
await writeAtomically(pidPath, `${process.pid}
|
|
18127
18680
|
`);
|
|
18128
18681
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -18534,8 +19087,8 @@ async function startDaemon(opts = {}) {
|
|
|
18534
19087
|
let registryWatcher = null;
|
|
18535
19088
|
let reloadTimer = null;
|
|
18536
19089
|
if (!singleProject) try {
|
|
18537
|
-
const regDir =
|
|
18538
|
-
const regBase =
|
|
19090
|
+
const regDir = import_node_path67.default.dirname(regPath);
|
|
19091
|
+
const regBase = import_node_path67.default.basename(regPath);
|
|
18539
19092
|
registryWatcher = (0, import_node_fs33.watch)(regDir, (_eventType, filename) => {
|
|
18540
19093
|
if (filename !== null && filename !== regBase) return;
|
|
18541
19094
|
if (reloadTimer) clearTimeout(reloadTimer);
|