@neat.is/core 0.7.6 → 0.7.8
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-LN75Z624.js} +866 -216
- package/dist/chunk-LN75Z624.js.map +1 -0
- package/dist/{chunk-XHSK4BGL.js → chunk-OVRVDSUO.js} +3 -3
- package/dist/{chunk-P2ZEKJ35.js → chunk-Y43UCVZS.js} +9 -6
- package/dist/chunk-Y43UCVZS.js.map +1 -0
- package/dist/cli.cjs +1244 -590
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +1046 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +1055 -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 +978 -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-OVRVDSUO.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) {
|
|
@@ -3042,8 +3045,9 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
3042
3045
|
"all"
|
|
3043
3046
|
]);
|
|
3044
3047
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3048
|
+
var NET_HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3045
3049
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
3046
|
-
function
|
|
3050
|
+
function goRouterRoutesFromSource(source, parser, framework) {
|
|
3047
3051
|
const tree = parseSource2(parser, source);
|
|
3048
3052
|
const prefixes = /* @__PURE__ */ new Map();
|
|
3049
3053
|
const out = [];
|
|
@@ -3053,10 +3057,12 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3053
3057
|
const value = node.childForFieldName("right")?.namedChild(0) ?? node.childForFieldName("value");
|
|
3054
3058
|
if (name && value?.type === "call_expression") {
|
|
3055
3059
|
const fn2 = value.childForFieldName("function");
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
+
if (fn2?.childForFieldName("field")?.text === "Group") {
|
|
3061
|
+
const leaf2 = goStringLiteral(value.childForFieldName("arguments")?.namedChild(0));
|
|
3062
|
+
if (leaf2 !== null) {
|
|
3063
|
+
const parent = fn2.childForFieldName("operand")?.text ?? "";
|
|
3064
|
+
prefixes.set(name, (prefixes.get(parent) ?? "") + leaf2);
|
|
3065
|
+
}
|
|
3060
3066
|
}
|
|
3061
3067
|
}
|
|
3062
3068
|
return;
|
|
@@ -3067,18 +3073,127 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3067
3073
|
const method = fn.childForFieldName("field")?.text?.toUpperCase();
|
|
3068
3074
|
if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return;
|
|
3069
3075
|
const receiver = fn.childForFieldName("operand")?.text ?? "";
|
|
3070
|
-
const
|
|
3071
|
-
if (
|
|
3072
|
-
const leaf = first.text.slice(1, -1);
|
|
3076
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3077
|
+
if (leaf === null) return;
|
|
3073
3078
|
out.push({
|
|
3074
|
-
method
|
|
3079
|
+
method,
|
|
3075
3080
|
pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? "") + leaf),
|
|
3076
3081
|
line: node.startPosition.row + 1,
|
|
3077
|
-
framework
|
|
3082
|
+
framework
|
|
3078
3083
|
});
|
|
3079
3084
|
});
|
|
3080
3085
|
return out;
|
|
3081
3086
|
}
|
|
3087
|
+
function goStringLiteral(node) {
|
|
3088
|
+
if (node?.type === "interpreted_string_literal" || node?.type === "raw_string_literal") {
|
|
3089
|
+
return node.text.slice(1, -1);
|
|
3090
|
+
}
|
|
3091
|
+
return null;
|
|
3092
|
+
}
|
|
3093
|
+
function ginRoutesFromSource(source, parser) {
|
|
3094
|
+
return goRouterRoutesFromSource(source, parser, "gin");
|
|
3095
|
+
}
|
|
3096
|
+
function echoRoutesFromSource(source, parser) {
|
|
3097
|
+
return goRouterRoutesFromSource(source, parser, "echo");
|
|
3098
|
+
}
|
|
3099
|
+
function fiberRoutesFromSource(source, parser) {
|
|
3100
|
+
return goRouterRoutesFromSource(source, parser, "fiber");
|
|
3101
|
+
}
|
|
3102
|
+
function chiRoutesFromSource(source, parser) {
|
|
3103
|
+
const tree = parseSource2(parser, source);
|
|
3104
|
+
const out = [];
|
|
3105
|
+
chiWalk(tree.rootNode, "", out);
|
|
3106
|
+
return out;
|
|
3107
|
+
}
|
|
3108
|
+
function stripChiRegex(path68) {
|
|
3109
|
+
return path68.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
3110
|
+
}
|
|
3111
|
+
function chiWalk(node, prefix, out) {
|
|
3112
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3113
|
+
const child = node.namedChild(i);
|
|
3114
|
+
if (child) chiHandle(child, prefix, out);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
function chiHandle(node, prefix, out) {
|
|
3118
|
+
if (node.type === "call_expression") {
|
|
3119
|
+
const fn = node.childForFieldName("function");
|
|
3120
|
+
if (fn?.type === "selector_expression") {
|
|
3121
|
+
const field = fn.childForFieldName("field")?.text;
|
|
3122
|
+
const args = node.childForFieldName("arguments");
|
|
3123
|
+
if (field === "Route") {
|
|
3124
|
+
const leaf = goStringLiteral(args?.namedChild(0));
|
|
3125
|
+
const closure = args?.namedChild(1);
|
|
3126
|
+
if (leaf !== null && closure?.type === "func_literal") {
|
|
3127
|
+
const body = closure.childForFieldName("body");
|
|
3128
|
+
if (body) chiWalk(body, prefix + leaf, out);
|
|
3129
|
+
}
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
if (field === "Group") {
|
|
3133
|
+
const closure = args?.namedChild(0);
|
|
3134
|
+
if (closure?.type === "func_literal") {
|
|
3135
|
+
const body = closure.childForFieldName("body");
|
|
3136
|
+
if (body) chiWalk(body, prefix, out);
|
|
3137
|
+
}
|
|
3138
|
+
return;
|
|
3139
|
+
}
|
|
3140
|
+
if (field === "Mount") {
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
if (field && ROUTER_METHODS.has(field.toLowerCase())) {
|
|
3144
|
+
const leaf = goStringLiteral(args?.namedChild(0));
|
|
3145
|
+
if (leaf !== null) {
|
|
3146
|
+
out.push({
|
|
3147
|
+
method: field.toUpperCase(),
|
|
3148
|
+
pathTemplate: canonicalizeTemplate(stripChiRegex(prefix + leaf)),
|
|
3149
|
+
line: node.startPosition.row + 1,
|
|
3150
|
+
framework: "chi"
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
return;
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
chiWalk(node, prefix, out);
|
|
3158
|
+
}
|
|
3159
|
+
function netHttpRoutesFromSource(source, parser) {
|
|
3160
|
+
const tree = parseSource2(parser, source);
|
|
3161
|
+
if (!goImportsNetHttp(tree.rootNode)) return [];
|
|
3162
|
+
const out = [];
|
|
3163
|
+
walk(tree.rootNode, (node) => {
|
|
3164
|
+
if (node.type !== "call_expression") return;
|
|
3165
|
+
const fn = node.childForFieldName("function");
|
|
3166
|
+
if (fn?.type !== "selector_expression") return;
|
|
3167
|
+
const field = fn.childForFieldName("field")?.text;
|
|
3168
|
+
if (field !== "HandleFunc" && field !== "Handle") return;
|
|
3169
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3170
|
+
if (leaf === null) return;
|
|
3171
|
+
const sp = leaf.indexOf(" ");
|
|
3172
|
+
if (sp < 0) return;
|
|
3173
|
+
const method = leaf.slice(0, sp);
|
|
3174
|
+
const rest = leaf.slice(sp + 1);
|
|
3175
|
+
if (!NET_HTTP_METHODS.has(method)) return;
|
|
3176
|
+
if (!rest.startsWith("/")) return;
|
|
3177
|
+
out.push({
|
|
3178
|
+
method,
|
|
3179
|
+
pathTemplate: canonicalizeTemplate(rest),
|
|
3180
|
+
line: node.startPosition.row + 1,
|
|
3181
|
+
framework: "net/http"
|
|
3182
|
+
});
|
|
3183
|
+
});
|
|
3184
|
+
return out;
|
|
3185
|
+
}
|
|
3186
|
+
function goImportsNetHttp(root) {
|
|
3187
|
+
let found = false;
|
|
3188
|
+
walk(root, (node) => {
|
|
3189
|
+
if (found || node.type !== "import_spec") return;
|
|
3190
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3191
|
+
const child = node.namedChild(i);
|
|
3192
|
+
if (goStringLiteral(child) === "net/http") found = true;
|
|
3193
|
+
}
|
|
3194
|
+
});
|
|
3195
|
+
return found;
|
|
3196
|
+
}
|
|
3082
3197
|
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
3083
3198
|
var NESTJS_METHODS = /* @__PURE__ */ new Map([
|
|
3084
3199
|
["Get", "GET"],
|
|
@@ -3663,9 +3778,9 @@ function rubyRocketRoute(args) {
|
|
|
3663
3778
|
if (!pair || pair.type !== "pair") continue;
|
|
3664
3779
|
const k = pair.childForFieldName("key");
|
|
3665
3780
|
if (k?.type !== "string") continue;
|
|
3666
|
-
const
|
|
3667
|
-
if (
|
|
3668
|
-
return { path:
|
|
3781
|
+
const path68 = rubyLiteral(k);
|
|
3782
|
+
if (path68 === null) continue;
|
|
3783
|
+
return { path: path68, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3669
3784
|
}
|
|
3670
3785
|
return null;
|
|
3671
3786
|
}
|
|
@@ -4342,9 +4457,13 @@ async function addRoutes(graph, services) {
|
|
|
4342
4457
|
const hasFlask = deps["flask"] !== void 0;
|
|
4343
4458
|
const hasDjango = deps["django"] !== void 0;
|
|
4344
4459
|
const hasGin = deps["github.com/gin-gonic/gin"] !== void 0;
|
|
4460
|
+
const hasEcho = deps["github.com/labstack/echo/v4"] !== void 0 || deps["github.com/labstack/echo"] !== void 0;
|
|
4461
|
+
const hasFiber = deps["github.com/gofiber/fiber/v2"] !== void 0 || deps["github.com/gofiber/fiber/v3"] !== void 0;
|
|
4462
|
+
const hasChi = deps["github.com/go-chi/chi/v5"] !== void 0 || deps["github.com/go-chi/chi"] !== void 0;
|
|
4463
|
+
const isGoService = service.node.language === "go";
|
|
4345
4464
|
const hasRails = deps["rails"] !== void 0;
|
|
4346
4465
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4347
|
-
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasRails && !hasLaravel)
|
|
4466
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel)
|
|
4348
4467
|
continue;
|
|
4349
4468
|
const files = await loadSourceFiles(service.dir);
|
|
4350
4469
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4368,7 +4487,12 @@ async function addRoutes(graph, services) {
|
|
|
4368
4487
|
} else if (isRb) {
|
|
4369
4488
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4370
4489
|
} else if (isGo) {
|
|
4371
|
-
routes =
|
|
4490
|
+
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4491
|
+
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
4492
|
+
else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser);
|
|
4493
|
+
else if (hasChi) routes = chiRoutesFromSource(file.content, goParser);
|
|
4494
|
+
else routes = [];
|
|
4495
|
+
routes = routes.concat(netHttpRoutesFromSource(file.content, goParser));
|
|
4372
4496
|
} else if (isPy) {
|
|
4373
4497
|
routes = hasFastapi || hasFlask ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? "fastapi" : "flask") : [];
|
|
4374
4498
|
if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser));
|
|
@@ -5978,6 +6102,13 @@ function parseGoMod(source) {
|
|
|
5978
6102
|
}
|
|
5979
6103
|
return { module: module2, ...goVersion ? { goVersion } : {}, dependencies };
|
|
5980
6104
|
}
|
|
6105
|
+
function goFramework(deps) {
|
|
6106
|
+
if (deps["github.com/gin-gonic/gin"]) return "gin";
|
|
6107
|
+
if (deps["github.com/labstack/echo/v4"] || deps["github.com/labstack/echo"]) return "echo";
|
|
6108
|
+
if (deps["github.com/gofiber/fiber/v2"] || deps["github.com/gofiber/fiber/v3"]) return "fiber";
|
|
6109
|
+
if (deps["github.com/go-chi/chi/v5"] || deps["github.com/go-chi/chi"]) return "chi";
|
|
6110
|
+
return void 0;
|
|
6111
|
+
}
|
|
5981
6112
|
async function discoverGoService(scanPath, dir) {
|
|
5982
6113
|
let raw;
|
|
5983
6114
|
try {
|
|
@@ -5989,6 +6120,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5989
6120
|
if (!mod) return null;
|
|
5990
6121
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
5991
6122
|
const pkg = { name, dependencies: mod.dependencies };
|
|
6123
|
+
const framework = goFramework(mod.dependencies);
|
|
5992
6124
|
const node = {
|
|
5993
6125
|
id: (0, import_types9.serviceId)(name),
|
|
5994
6126
|
type: import_types9.NodeType.ServiceNode,
|
|
@@ -5996,7 +6128,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5996
6128
|
language: "go",
|
|
5997
6129
|
dependencies: mod.dependencies,
|
|
5998
6130
|
repoPath: import_node_path10.default.relative(scanPath, dir),
|
|
5999
|
-
...
|
|
6131
|
+
...framework ? { framework } : {}
|
|
6000
6132
|
};
|
|
6001
6133
|
return { pkg, dir, node };
|
|
6002
6134
|
}
|
|
@@ -6896,7 +7028,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
6896
7028
|
return best;
|
|
6897
7029
|
};
|
|
6898
7030
|
const requests = [];
|
|
6899
|
-
const
|
|
7031
|
+
const walk9 = (node) => {
|
|
6900
7032
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
6901
7033
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
6902
7034
|
if (self && self.kind === "class") {
|
|
@@ -6942,10 +7074,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
6942
7074
|
}
|
|
6943
7075
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6944
7076
|
const child = node.namedChild(i);
|
|
6945
|
-
if (child)
|
|
7077
|
+
if (child) walk9(child);
|
|
6946
7078
|
}
|
|
6947
7079
|
};
|
|
6948
|
-
|
|
7080
|
+
walk9(root);
|
|
6949
7081
|
for (const req of requests) {
|
|
6950
7082
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
6951
7083
|
if (!targetSid) continue;
|
|
@@ -7958,20 +8090,20 @@ var import_node_path28 = __toESM(require("path"), 1);
|
|
|
7958
8090
|
var import_types18 = require("@neat.is/types");
|
|
7959
8091
|
async function walkConfigFiles(dir) {
|
|
7960
8092
|
const out = [];
|
|
7961
|
-
async function
|
|
8093
|
+
async function walk9(current) {
|
|
7962
8094
|
const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true });
|
|
7963
8095
|
for (const entry of entries) {
|
|
7964
8096
|
const full = import_node_path28.default.join(current, entry.name);
|
|
7965
8097
|
if (entry.isDirectory()) {
|
|
7966
8098
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
7967
8099
|
if (await isPythonVenvDir(full)) continue;
|
|
7968
|
-
await
|
|
8100
|
+
await walk9(full);
|
|
7969
8101
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
7970
8102
|
out.push(full);
|
|
7971
8103
|
}
|
|
7972
8104
|
}
|
|
7973
8105
|
}
|
|
7974
|
-
await
|
|
8106
|
+
await walk9(dir);
|
|
7975
8107
|
return out;
|
|
7976
8108
|
}
|
|
7977
8109
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -8061,20 +8193,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
8061
8193
|
}
|
|
8062
8194
|
async function walkProtoFiles(dir) {
|
|
8063
8195
|
const out = [];
|
|
8064
|
-
async function
|
|
8196
|
+
async function walk9(current) {
|
|
8065
8197
|
const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
8066
8198
|
for (const entry of entries) {
|
|
8067
8199
|
const full = import_node_path29.default.join(current, entry.name);
|
|
8068
8200
|
if (entry.isDirectory()) {
|
|
8069
8201
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
8070
8202
|
if (await isPythonVenvDir(full)) continue;
|
|
8071
|
-
await
|
|
8203
|
+
await walk9(full);
|
|
8072
8204
|
} else if (entry.isFile() && import_node_path29.default.extname(entry.name) === PROTO_EXTENSION) {
|
|
8073
8205
|
out.push(full);
|
|
8074
8206
|
}
|
|
8075
8207
|
}
|
|
8076
8208
|
}
|
|
8077
|
-
await
|
|
8209
|
+
await walk9(dir);
|
|
8078
8210
|
return out;
|
|
8079
8211
|
}
|
|
8080
8212
|
async function addGrpcMethods(graph, services) {
|
|
@@ -8142,7 +8274,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
8142
8274
|
|
|
8143
8275
|
// src/extract/calls/index.ts
|
|
8144
8276
|
init_cjs_shims();
|
|
8145
|
-
var
|
|
8277
|
+
var import_types37 = require("@neat.is/types");
|
|
8146
8278
|
|
|
8147
8279
|
// src/extract/calls/http.ts
|
|
8148
8280
|
init_cjs_shims();
|
|
@@ -8896,7 +9028,7 @@ function isFirestoreClientFactory(node) {
|
|
|
8896
9028
|
}
|
|
8897
9029
|
function firestoreClientVars(root) {
|
|
8898
9030
|
const vars = /* @__PURE__ */ new Set();
|
|
8899
|
-
const
|
|
9031
|
+
const walk9 = (node) => {
|
|
8900
9032
|
if (node.type === "variable_declarator") {
|
|
8901
9033
|
const name = node.childForFieldName("name");
|
|
8902
9034
|
let value = node.childForFieldName("value");
|
|
@@ -8905,9 +9037,9 @@ function firestoreClientVars(root) {
|
|
|
8905
9037
|
vars.add(name.text);
|
|
8906
9038
|
}
|
|
8907
9039
|
}
|
|
8908
|
-
for (const c of namedChildren(node))
|
|
9040
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
8909
9041
|
};
|
|
8910
|
-
|
|
9042
|
+
walk9(root);
|
|
8911
9043
|
return vars;
|
|
8912
9044
|
}
|
|
8913
9045
|
function isClientExpr(node, clientVars) {
|
|
@@ -9062,7 +9194,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9062
9194
|
}
|
|
9063
9195
|
s.add(field);
|
|
9064
9196
|
};
|
|
9065
|
-
const
|
|
9197
|
+
const walk9 = (node) => {
|
|
9066
9198
|
if (node.type === "call_expression") {
|
|
9067
9199
|
const fn = node.childForFieldName("function");
|
|
9068
9200
|
const line = node.startPosition.row + 1;
|
|
@@ -9102,9 +9234,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9102
9234
|
}
|
|
9103
9235
|
}
|
|
9104
9236
|
}
|
|
9105
|
-
for (const c of namedChildren(node))
|
|
9237
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
9106
9238
|
};
|
|
9107
|
-
|
|
9239
|
+
walk9(tree.rootNode);
|
|
9108
9240
|
const out = [];
|
|
9109
9241
|
for (const [collPath, line] of collLine) {
|
|
9110
9242
|
const byField = writes.get(collPath);
|
|
@@ -9899,7 +10031,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9899
10031
|
const tree = parseSource3(parserForExt2(import_node_path41.default.extname(file.path)), file.content);
|
|
9900
10032
|
const out = [];
|
|
9901
10033
|
const seen = /* @__PURE__ */ new Set();
|
|
9902
|
-
const
|
|
10034
|
+
const walk9 = (node) => {
|
|
9903
10035
|
if (node.type === "call_expression") {
|
|
9904
10036
|
const fn = node.childForFieldName("function");
|
|
9905
10037
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9927,9 +10059,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9927
10059
|
}
|
|
9928
10060
|
}
|
|
9929
10061
|
}
|
|
9930
|
-
for (const c of namedChildren4(node))
|
|
10062
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9931
10063
|
};
|
|
9932
|
-
|
|
10064
|
+
walk9(tree.rootNode);
|
|
9933
10065
|
return out;
|
|
9934
10066
|
}
|
|
9935
10067
|
function enclosingVarName(call) {
|
|
@@ -9951,7 +10083,7 @@ function enclosingVarName(call) {
|
|
|
9951
10083
|
function collectDrizzleTables(root) {
|
|
9952
10084
|
const tables = [];
|
|
9953
10085
|
const varToTable = /* @__PURE__ */ new Map();
|
|
9954
|
-
const
|
|
10086
|
+
const walk9 = (node) => {
|
|
9955
10087
|
if (node.type === "call_expression") {
|
|
9956
10088
|
const fn = node.childForFieldName("function");
|
|
9957
10089
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9966,9 +10098,9 @@ function collectDrizzleTables(root) {
|
|
|
9966
10098
|
}
|
|
9967
10099
|
}
|
|
9968
10100
|
}
|
|
9969
|
-
for (const c of namedChildren4(node))
|
|
10101
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9970
10102
|
};
|
|
9971
|
-
|
|
10103
|
+
walk9(root);
|
|
9972
10104
|
return { tables, varToTable };
|
|
9973
10105
|
}
|
|
9974
10106
|
function referencesTargetVar(call) {
|
|
@@ -9991,7 +10123,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
9991
10123
|
const seen = /* @__PURE__ */ new Set();
|
|
9992
10124
|
for (const table of tables) {
|
|
9993
10125
|
if (!table.object) continue;
|
|
9994
|
-
const
|
|
10126
|
+
const walk9 = (node) => {
|
|
9995
10127
|
if (node.type === "call_expression") {
|
|
9996
10128
|
const targetVar = referencesTargetVar(node);
|
|
9997
10129
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -10012,9 +10144,9 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
10012
10144
|
}
|
|
10013
10145
|
}
|
|
10014
10146
|
}
|
|
10015
|
-
for (const c of namedChildren4(node))
|
|
10147
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
10016
10148
|
};
|
|
10017
|
-
|
|
10149
|
+
walk9(table.object);
|
|
10018
10150
|
}
|
|
10019
10151
|
return out;
|
|
10020
10152
|
}
|
|
@@ -11094,15 +11226,531 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
11094
11226
|
return out;
|
|
11095
11227
|
}
|
|
11096
11228
|
|
|
11229
|
+
// src/extract/calls/gorm.ts
|
|
11230
|
+
init_cjs_shims();
|
|
11231
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11232
|
+
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
11233
|
+
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
11234
|
+
var import_types36 = require("@neat.is/types");
|
|
11235
|
+
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
11236
|
+
var PARSE_CHUNK11 = 16384;
|
|
11237
|
+
function makeGoParser3() {
|
|
11238
|
+
const p = new import_tree_sitter15.default();
|
|
11239
|
+
p.setLanguage(import_tree_sitter_go4.default);
|
|
11240
|
+
return p;
|
|
11241
|
+
}
|
|
11242
|
+
function parseSource10(parser, source) {
|
|
11243
|
+
return parser.parse(
|
|
11244
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
11245
|
+
);
|
|
11246
|
+
}
|
|
11247
|
+
function walk8(node, visit) {
|
|
11248
|
+
visit(node);
|
|
11249
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11250
|
+
const c = node.namedChild(i);
|
|
11251
|
+
if (c) walk8(c, visit);
|
|
11252
|
+
}
|
|
11253
|
+
}
|
|
11254
|
+
var COMMON_INITIALISMS = [
|
|
11255
|
+
"ASCII",
|
|
11256
|
+
"HTTPS",
|
|
11257
|
+
"UTF8",
|
|
11258
|
+
"XSRF",
|
|
11259
|
+
"HTML",
|
|
11260
|
+
"HTTP",
|
|
11261
|
+
"JSON",
|
|
11262
|
+
"UUID",
|
|
11263
|
+
"XMPP",
|
|
11264
|
+
"ACL",
|
|
11265
|
+
"API",
|
|
11266
|
+
"CPU",
|
|
11267
|
+
"CSS",
|
|
11268
|
+
"DNS",
|
|
11269
|
+
"EOF",
|
|
11270
|
+
"GUID",
|
|
11271
|
+
"LHS",
|
|
11272
|
+
"QPS",
|
|
11273
|
+
"RAM",
|
|
11274
|
+
"RHS",
|
|
11275
|
+
"RPC",
|
|
11276
|
+
"SLA",
|
|
11277
|
+
"SQL",
|
|
11278
|
+
"SSH",
|
|
11279
|
+
"TCP",
|
|
11280
|
+
"TLS",
|
|
11281
|
+
"TTL",
|
|
11282
|
+
"UDP",
|
|
11283
|
+
"UID",
|
|
11284
|
+
"URI",
|
|
11285
|
+
"URL",
|
|
11286
|
+
"UID",
|
|
11287
|
+
"XSS",
|
|
11288
|
+
"ID",
|
|
11289
|
+
"IP",
|
|
11290
|
+
"UI",
|
|
11291
|
+
"VM",
|
|
11292
|
+
"XML"
|
|
11293
|
+
].sort((a, b) => b.length - a.length);
|
|
11294
|
+
function titleCase(word) {
|
|
11295
|
+
return word.charAt(0) + word.slice(1).toLowerCase();
|
|
11296
|
+
}
|
|
11297
|
+
function replaceInitialisms(name) {
|
|
11298
|
+
let out = "";
|
|
11299
|
+
let i = 0;
|
|
11300
|
+
while (i < name.length) {
|
|
11301
|
+
let matched = false;
|
|
11302
|
+
for (const init of COMMON_INITIALISMS) {
|
|
11303
|
+
if (name.startsWith(init, i)) {
|
|
11304
|
+
out += titleCase(init);
|
|
11305
|
+
i += init.length;
|
|
11306
|
+
matched = true;
|
|
11307
|
+
break;
|
|
11308
|
+
}
|
|
11309
|
+
}
|
|
11310
|
+
if (!matched) {
|
|
11311
|
+
out += name[i];
|
|
11312
|
+
i++;
|
|
11313
|
+
}
|
|
11314
|
+
}
|
|
11315
|
+
return out;
|
|
11316
|
+
}
|
|
11317
|
+
var isUpper = (c) => c >= "A" && c <= "Z";
|
|
11318
|
+
var isDigit = (c) => c >= "0" && c <= "9";
|
|
11319
|
+
function toDBName(name) {
|
|
11320
|
+
if (name === "") return "";
|
|
11321
|
+
const value = replaceInitialisms(name);
|
|
11322
|
+
if (value.length === 1) return value.toLowerCase();
|
|
11323
|
+
let buf = "";
|
|
11324
|
+
let lastCase = false;
|
|
11325
|
+
let curCase = isUpper(value[0]);
|
|
11326
|
+
for (let i = 0; i < value.length - 1; i++) {
|
|
11327
|
+
const v = value[i];
|
|
11328
|
+
const nextCase = isUpper(value[i + 1]);
|
|
11329
|
+
const nextNumber = isDigit(value[i + 1]);
|
|
11330
|
+
if (curCase) {
|
|
11331
|
+
if (lastCase && (nextCase || nextNumber)) {
|
|
11332
|
+
buf += v.toLowerCase();
|
|
11333
|
+
} else {
|
|
11334
|
+
if (i > 0 && value[i - 1] !== "_" && lastCase !== curCase) buf += "_";
|
|
11335
|
+
buf += v.toLowerCase();
|
|
11336
|
+
}
|
|
11337
|
+
} else {
|
|
11338
|
+
buf += v;
|
|
11339
|
+
}
|
|
11340
|
+
lastCase = curCase;
|
|
11341
|
+
curCase = nextCase;
|
|
11342
|
+
}
|
|
11343
|
+
const last = value[value.length - 1];
|
|
11344
|
+
if (curCase) {
|
|
11345
|
+
if (!lastCase && value.length > 1) buf += "_";
|
|
11346
|
+
buf += last.toLowerCase();
|
|
11347
|
+
} else {
|
|
11348
|
+
buf += last;
|
|
11349
|
+
}
|
|
11350
|
+
return buf;
|
|
11351
|
+
}
|
|
11352
|
+
var UNCOUNTABLE = /* @__PURE__ */ new Set([
|
|
11353
|
+
"equipment",
|
|
11354
|
+
"information",
|
|
11355
|
+
"rice",
|
|
11356
|
+
"money",
|
|
11357
|
+
"species",
|
|
11358
|
+
"series",
|
|
11359
|
+
"fish",
|
|
11360
|
+
"sheep",
|
|
11361
|
+
"jeans",
|
|
11362
|
+
"police"
|
|
11363
|
+
]);
|
|
11364
|
+
var IRREGULAR = [
|
|
11365
|
+
["person", "people"],
|
|
11366
|
+
["man", "men"],
|
|
11367
|
+
["child", "children"],
|
|
11368
|
+
["sex", "sexes"],
|
|
11369
|
+
["move", "moves"]
|
|
11370
|
+
];
|
|
11371
|
+
var PLURAL_RULES = [
|
|
11372
|
+
[/(quiz)$/i, "$1zes"],
|
|
11373
|
+
[/^(ox)$/i, "$1en"],
|
|
11374
|
+
[/([ml])ouse$/i, "$1ice"],
|
|
11375
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"],
|
|
11376
|
+
[/(x|ch|ss|sh)$/i, "$1es"],
|
|
11377
|
+
[/([^aeiouy]|qu)y$/i, "$1ies"],
|
|
11378
|
+
[/(hive)$/i, "$1s"],
|
|
11379
|
+
[/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
|
|
11380
|
+
[/sis$/i, "ses"],
|
|
11381
|
+
[/([ti])um$/i, "$1a"],
|
|
11382
|
+
[/([ti])a$/i, "$1a"],
|
|
11383
|
+
[/(buffal|tomat)o$/i, "$1oes"],
|
|
11384
|
+
[/(bu)s$/i, "$1ses"],
|
|
11385
|
+
[/(alias|status)$/i, "$1es"],
|
|
11386
|
+
[/(octop|vir)i$/i, "$1i"],
|
|
11387
|
+
[/(octop|vir)us$/i, "$1i"],
|
|
11388
|
+
[/(ax|test)is$/i, "$1es"],
|
|
11389
|
+
[/s$/i, "s"]
|
|
11390
|
+
];
|
|
11391
|
+
function pluralize3(word) {
|
|
11392
|
+
if (word === "") return word;
|
|
11393
|
+
const lower = word.toLowerCase();
|
|
11394
|
+
for (const u of UNCOUNTABLE) {
|
|
11395
|
+
if (lower === u || lower.endsWith("_" + u)) return word;
|
|
11396
|
+
}
|
|
11397
|
+
for (const [sing, plur] of IRREGULAR) {
|
|
11398
|
+
const re = new RegExp(sing + "$", "i");
|
|
11399
|
+
if (re.test(word)) return word.replace(re, plur);
|
|
11400
|
+
}
|
|
11401
|
+
for (const [re, rep] of PLURAL_RULES) {
|
|
11402
|
+
if (re.test(word)) return word.replace(re, rep);
|
|
11403
|
+
}
|
|
11404
|
+
return word + "s";
|
|
11405
|
+
}
|
|
11406
|
+
function deriveTableName(structName) {
|
|
11407
|
+
return pluralize3(toDBName(structName));
|
|
11408
|
+
}
|
|
11409
|
+
function stringLiteralValue(node) {
|
|
11410
|
+
if (!node) return null;
|
|
11411
|
+
if (node.type === "interpreted_string_literal" || node.type === "raw_string_literal") {
|
|
11412
|
+
const t = node.text;
|
|
11413
|
+
return t.length >= 2 ? t.slice(1, -1) : "";
|
|
11414
|
+
}
|
|
11415
|
+
return null;
|
|
11416
|
+
}
|
|
11417
|
+
function parseGormTag(tagNode) {
|
|
11418
|
+
const tag = {};
|
|
11419
|
+
if (!tagNode) return tag;
|
|
11420
|
+
let inner = tagNode.text;
|
|
11421
|
+
if (inner.length >= 2) inner = inner.slice(1, -1);
|
|
11422
|
+
if (tagNode.type === "interpreted_string_literal") inner = inner.replace(/\\"/g, '"');
|
|
11423
|
+
const m = inner.match(/gorm:"([^"]*)"/);
|
|
11424
|
+
if (!m) return tag;
|
|
11425
|
+
for (const part of m[1].split(";")) {
|
|
11426
|
+
if (part === "") continue;
|
|
11427
|
+
const idx = part.indexOf(":");
|
|
11428
|
+
const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase();
|
|
11429
|
+
const value = idx >= 0 ? part.slice(idx + 1).trim() : "";
|
|
11430
|
+
if (key === "-") tag.skip = true;
|
|
11431
|
+
else if (key === "column") tag.column = value;
|
|
11432
|
+
else if (key === "primarykey" || key === "primary_key") tag.primaryKey = true;
|
|
11433
|
+
else if (key === "foreignkey") tag.foreignKey = value;
|
|
11434
|
+
else if (key === "many2many") tag.many2many = value;
|
|
11435
|
+
else if (key === "embedded") tag.embedded = true;
|
|
11436
|
+
else if (key === "embeddedprefix") tag.embeddedPrefix = value;
|
|
11437
|
+
}
|
|
11438
|
+
return tag;
|
|
11439
|
+
}
|
|
11440
|
+
function unwrapType(typeNode) {
|
|
11441
|
+
let isSlice = false;
|
|
11442
|
+
let isPointer = false;
|
|
11443
|
+
let n = typeNode;
|
|
11444
|
+
while (n && (n.type === "slice_type" || n.type === "array_type" || n.type === "pointer_type")) {
|
|
11445
|
+
if (n.type === "slice_type" || n.type === "array_type") isSlice = true;
|
|
11446
|
+
if (n.type === "pointer_type") isPointer = true;
|
|
11447
|
+
n = n.childForFieldName("element") ?? n.namedChild(n.namedChildCount - 1);
|
|
11448
|
+
}
|
|
11449
|
+
if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11450
|
+
if (n.type === "type_identifier") {
|
|
11451
|
+
return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11452
|
+
}
|
|
11453
|
+
if (n.type === "qualified_type") {
|
|
11454
|
+
const pkg = n.childForFieldName("package")?.text ?? n.namedChild(0)?.text ?? null;
|
|
11455
|
+
const nm = n.childForFieldName("name")?.text ?? n.namedChild(1)?.text ?? null;
|
|
11456
|
+
return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true };
|
|
11457
|
+
}
|
|
11458
|
+
return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11459
|
+
}
|
|
11460
|
+
function readField(fieldDecl) {
|
|
11461
|
+
const names = [];
|
|
11462
|
+
let tagNode = null;
|
|
11463
|
+
for (let i = 0; i < fieldDecl.namedChildCount; i++) {
|
|
11464
|
+
const c = fieldDecl.namedChild(i);
|
|
11465
|
+
if (!c) continue;
|
|
11466
|
+
if (c.type === "field_identifier") names.push(c.text);
|
|
11467
|
+
else if (c.type === "raw_string_literal" || c.type === "interpreted_string_literal") tagNode = c;
|
|
11468
|
+
}
|
|
11469
|
+
const typeNode = fieldDecl.childForFieldName("type");
|
|
11470
|
+
const t = unwrapType(typeNode);
|
|
11471
|
+
return {
|
|
11472
|
+
names,
|
|
11473
|
+
typeName: t.name,
|
|
11474
|
+
qualifier: t.qualifier,
|
|
11475
|
+
isSlice: t.isSlice,
|
|
11476
|
+
isPointer: t.isPointer,
|
|
11477
|
+
isQualified: t.isQualified,
|
|
11478
|
+
tag: parseGormTag(tagNode),
|
|
11479
|
+
line: fieldDecl.startPosition.row + 1
|
|
11480
|
+
};
|
|
11481
|
+
}
|
|
11482
|
+
function collectStructs(tree) {
|
|
11483
|
+
const structs = /* @__PURE__ */ new Map();
|
|
11484
|
+
walk8(tree.rootNode, (node) => {
|
|
11485
|
+
if (node.type !== "type_spec") return;
|
|
11486
|
+
const nameNode = node.childForFieldName("name");
|
|
11487
|
+
const typeNode = node.childForFieldName("type");
|
|
11488
|
+
if (!nameNode || typeNode?.type !== "struct_type") return;
|
|
11489
|
+
const list = typeNode.childForFieldName("body") ?? typeNode.namedChild(0);
|
|
11490
|
+
const fields = [];
|
|
11491
|
+
if (list && list.type === "field_declaration_list") {
|
|
11492
|
+
for (let i = 0; i < list.namedChildCount; i++) {
|
|
11493
|
+
const fd = list.namedChild(i);
|
|
11494
|
+
if (fd?.type === "field_declaration") fields.push(readField(fd));
|
|
11495
|
+
}
|
|
11496
|
+
}
|
|
11497
|
+
structs.set(nameNode.text, {
|
|
11498
|
+
name: nameNode.text,
|
|
11499
|
+
fields,
|
|
11500
|
+
line: node.startPosition.row + 1
|
|
11501
|
+
});
|
|
11502
|
+
});
|
|
11503
|
+
return structs;
|
|
11504
|
+
}
|
|
11505
|
+
var GORM_MODEL_METHODS = /* @__PURE__ */ new Set([
|
|
11506
|
+
"AutoMigrate",
|
|
11507
|
+
"Model",
|
|
11508
|
+
"Create",
|
|
11509
|
+
"Find",
|
|
11510
|
+
"First",
|
|
11511
|
+
"Take",
|
|
11512
|
+
"Last",
|
|
11513
|
+
"Save",
|
|
11514
|
+
"Delete",
|
|
11515
|
+
"Where",
|
|
11516
|
+
"FirstOrCreate",
|
|
11517
|
+
"FirstOrInit"
|
|
11518
|
+
]);
|
|
11519
|
+
function compositeStructName(arg) {
|
|
11520
|
+
let n = arg;
|
|
11521
|
+
if (n.type === "unary_expression") n = n.childForFieldName("operand") ?? n.namedChild(0);
|
|
11522
|
+
if (!n || n.type !== "composite_literal") return null;
|
|
11523
|
+
const typeNode = n.childForFieldName("type");
|
|
11524
|
+
if (!typeNode) return null;
|
|
11525
|
+
if (typeNode.type === "type_identifier") return typeNode.text;
|
|
11526
|
+
if (typeNode.type === "qualified_type") {
|
|
11527
|
+
return typeNode.childForFieldName("name")?.text ?? typeNode.namedChild(1)?.text ?? null;
|
|
11528
|
+
}
|
|
11529
|
+
return null;
|
|
11530
|
+
}
|
|
11531
|
+
function collectCallModels(tree) {
|
|
11532
|
+
const models = /* @__PURE__ */ new Set();
|
|
11533
|
+
walk8(tree.rootNode, (node) => {
|
|
11534
|
+
if (node.type !== "call_expression") return;
|
|
11535
|
+
const fn = node.childForFieldName("function");
|
|
11536
|
+
if (fn?.type !== "selector_expression") return;
|
|
11537
|
+
const method = fn.childForFieldName("field")?.text;
|
|
11538
|
+
if (!method || !GORM_MODEL_METHODS.has(method)) return;
|
|
11539
|
+
const args = node.childForFieldName("arguments");
|
|
11540
|
+
if (!args) return;
|
|
11541
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
11542
|
+
const arg = args.namedChild(i);
|
|
11543
|
+
if (!arg) continue;
|
|
11544
|
+
const name = compositeStructName(arg);
|
|
11545
|
+
if (name) models.add(name);
|
|
11546
|
+
}
|
|
11547
|
+
});
|
|
11548
|
+
return models;
|
|
11549
|
+
}
|
|
11550
|
+
function collectTableNameOverrides(tree) {
|
|
11551
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
11552
|
+
const declarers = /* @__PURE__ */ new Set();
|
|
11553
|
+
walk8(tree.rootNode, (node) => {
|
|
11554
|
+
if (node.type !== "method_declaration") return;
|
|
11555
|
+
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
11556
|
+
const receiver = node.childForFieldName("receiver");
|
|
11557
|
+
if (!receiver) return;
|
|
11558
|
+
let recvType = null;
|
|
11559
|
+
for (let i = 0; i < receiver.namedChildCount; i++) {
|
|
11560
|
+
const pd = receiver.namedChild(i);
|
|
11561
|
+
if (pd?.type !== "parameter_declaration") continue;
|
|
11562
|
+
const t = unwrapType(pd.childForFieldName("type"));
|
|
11563
|
+
recvType = t.name;
|
|
11564
|
+
}
|
|
11565
|
+
if (!recvType) return;
|
|
11566
|
+
declarers.add(recvType);
|
|
11567
|
+
const body = node.childForFieldName("body");
|
|
11568
|
+
if (!body) return;
|
|
11569
|
+
let literal = null;
|
|
11570
|
+
walk8(body, (n) => {
|
|
11571
|
+
if (literal !== null) return;
|
|
11572
|
+
if (n.type !== "return_statement") return;
|
|
11573
|
+
const exprList = n.namedChild(0);
|
|
11574
|
+
const first = exprList?.namedChild(0) ?? exprList;
|
|
11575
|
+
const v = stringLiteralValue(first);
|
|
11576
|
+
if (v) literal = v;
|
|
11577
|
+
});
|
|
11578
|
+
if (literal !== null) overrides.set(recvType, literal);
|
|
11579
|
+
});
|
|
11580
|
+
return { overrides, declarers };
|
|
11581
|
+
}
|
|
11582
|
+
function isRelationField(field, structs) {
|
|
11583
|
+
if (field.names.length === 0) return false;
|
|
11584
|
+
if (field.isQualified) return false;
|
|
11585
|
+
if (!field.typeName) return false;
|
|
11586
|
+
return structs.has(field.typeName);
|
|
11587
|
+
}
|
|
11588
|
+
function isGormModelEmbed(field) {
|
|
11589
|
+
return field.names.length === 0 && field.qualifier === "gorm" && field.typeName === "Model";
|
|
11590
|
+
}
|
|
11591
|
+
function analyze(tree) {
|
|
11592
|
+
const structs = collectStructs(tree);
|
|
11593
|
+
const { overrides, declarers } = collectTableNameOverrides(tree);
|
|
11594
|
+
const callModels = collectCallModels(tree);
|
|
11595
|
+
const models = /* @__PURE__ */ new Set();
|
|
11596
|
+
for (const [name, info] of structs) {
|
|
11597
|
+
if (info.fields.some(isGormModelEmbed)) models.add(name);
|
|
11598
|
+
}
|
|
11599
|
+
for (const name of callModels) if (structs.has(name)) models.add(name);
|
|
11600
|
+
for (const name of declarers) if (structs.has(name)) models.add(name);
|
|
11601
|
+
let grew = true;
|
|
11602
|
+
while (grew) {
|
|
11603
|
+
grew = false;
|
|
11604
|
+
for (const name of Array.from(models)) {
|
|
11605
|
+
const info = structs.get(name);
|
|
11606
|
+
if (!info) continue;
|
|
11607
|
+
for (const field of info.fields) {
|
|
11608
|
+
if (!isRelationField(field, structs)) continue;
|
|
11609
|
+
const target = field.typeName;
|
|
11610
|
+
if (!models.has(target) && structs.has(target)) {
|
|
11611
|
+
models.add(target);
|
|
11612
|
+
grew = true;
|
|
11613
|
+
}
|
|
11614
|
+
}
|
|
11615
|
+
}
|
|
11616
|
+
}
|
|
11617
|
+
const tableFor = (structName) => overrides.get(structName) ?? deriveTableName(structName);
|
|
11618
|
+
return { structs, models, tableFor };
|
|
11619
|
+
}
|
|
11620
|
+
function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
11621
|
+
if (seen.has(struct.name)) return;
|
|
11622
|
+
seen.add(struct.name);
|
|
11623
|
+
const add = (col) => {
|
|
11624
|
+
const full = prefix + col;
|
|
11625
|
+
if (!emitted.has(full)) {
|
|
11626
|
+
emitted.add(full);
|
|
11627
|
+
out.push(full);
|
|
11628
|
+
}
|
|
11629
|
+
};
|
|
11630
|
+
for (const field of struct.fields) {
|
|
11631
|
+
if (field.tag.skip) continue;
|
|
11632
|
+
if (field.names.length === 0) {
|
|
11633
|
+
if (isGormModelEmbed(field)) {
|
|
11634
|
+
add("id");
|
|
11635
|
+
add("created_at");
|
|
11636
|
+
add("updated_at");
|
|
11637
|
+
add("deleted_at");
|
|
11638
|
+
} else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11639
|
+
collectColumns(structs.get(field.typeName), structs, seen, prefix, out, emitted);
|
|
11640
|
+
}
|
|
11641
|
+
continue;
|
|
11642
|
+
}
|
|
11643
|
+
if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11644
|
+
collectColumns(
|
|
11645
|
+
structs.get(field.typeName),
|
|
11646
|
+
structs,
|
|
11647
|
+
seen,
|
|
11648
|
+
prefix + (field.tag.embeddedPrefix ?? ""),
|
|
11649
|
+
out,
|
|
11650
|
+
emitted
|
|
11651
|
+
);
|
|
11652
|
+
continue;
|
|
11653
|
+
}
|
|
11654
|
+
if (isRelationField(field, structs)) continue;
|
|
11655
|
+
if (field.names.length === 1 && field.tag.column) {
|
|
11656
|
+
add(field.tag.column);
|
|
11657
|
+
} else {
|
|
11658
|
+
for (const n of field.names) add(toDBName(n));
|
|
11659
|
+
}
|
|
11660
|
+
}
|
|
11661
|
+
seen.delete(struct.name);
|
|
11662
|
+
}
|
|
11663
|
+
function gormEndpointsFromFile(file, serviceDir) {
|
|
11664
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11665
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11666
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11667
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11668
|
+
const out = [];
|
|
11669
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
11670
|
+
for (const name of models) {
|
|
11671
|
+
const struct = structs.get(name);
|
|
11672
|
+
if (!struct) continue;
|
|
11673
|
+
const table = tableFor(name);
|
|
11674
|
+
if (seenTables.has(table)) continue;
|
|
11675
|
+
seenTables.add(table);
|
|
11676
|
+
const columns = [];
|
|
11677
|
+
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
11678
|
+
out.push({
|
|
11679
|
+
infraId: (0, import_types36.infraId)("sql-table", table),
|
|
11680
|
+
name: table,
|
|
11681
|
+
kind: "sql-table",
|
|
11682
|
+
edgeType: "CALLS",
|
|
11683
|
+
confidenceKind: "structural",
|
|
11684
|
+
...columns.length > 0 ? { columns } : {},
|
|
11685
|
+
evidence: {
|
|
11686
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11687
|
+
line: struct.line,
|
|
11688
|
+
snippet: snippet(file.content, struct.line)
|
|
11689
|
+
}
|
|
11690
|
+
});
|
|
11691
|
+
}
|
|
11692
|
+
return out;
|
|
11693
|
+
}
|
|
11694
|
+
function gormForeignKeys(file, serviceDir) {
|
|
11695
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11696
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11697
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11698
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11699
|
+
const out = [];
|
|
11700
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11701
|
+
const emit = (childTable, parentTable, line) => {
|
|
11702
|
+
if (!childTable || !parentTable || childTable === parentTable) return;
|
|
11703
|
+
const key = `${childTable}->${parentTable}`;
|
|
11704
|
+
if (seen.has(key)) return;
|
|
11705
|
+
seen.add(key);
|
|
11706
|
+
out.push({
|
|
11707
|
+
childTable,
|
|
11708
|
+
parentTable,
|
|
11709
|
+
evidence: {
|
|
11710
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11711
|
+
line,
|
|
11712
|
+
snippet: snippet(file.content, line)
|
|
11713
|
+
}
|
|
11714
|
+
});
|
|
11715
|
+
};
|
|
11716
|
+
for (const name of models) {
|
|
11717
|
+
const struct = structs.get(name);
|
|
11718
|
+
if (!struct) continue;
|
|
11719
|
+
const thisTable = tableFor(name);
|
|
11720
|
+
const scalarNames = new Set(
|
|
11721
|
+
struct.fields.filter((f) => f.names.length > 0 && !isRelationField(f, structs)).flatMap((f) => f.names)
|
|
11722
|
+
);
|
|
11723
|
+
for (const field of struct.fields) {
|
|
11724
|
+
if (field.tag.skip) continue;
|
|
11725
|
+
if (!isRelationField(field, structs)) continue;
|
|
11726
|
+
const relTable = tableFor(field.typeName);
|
|
11727
|
+
if (field.tag.many2many) {
|
|
11728
|
+
emit(field.tag.many2many, thisTable, field.line);
|
|
11729
|
+
emit(field.tag.many2many, relTable, field.line);
|
|
11730
|
+
continue;
|
|
11731
|
+
}
|
|
11732
|
+
if (field.isSlice) {
|
|
11733
|
+
emit(relTable, thisTable, field.line);
|
|
11734
|
+
continue;
|
|
11735
|
+
}
|
|
11736
|
+
const convFk = field.names[0] + "ID";
|
|
11737
|
+
const belongsTo = scalarNames.has(convFk) || (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false);
|
|
11738
|
+
if (belongsTo) emit(thisTable, relTable, field.line);
|
|
11739
|
+
else emit(relTable, thisTable, field.line);
|
|
11740
|
+
}
|
|
11741
|
+
}
|
|
11742
|
+
return out;
|
|
11743
|
+
}
|
|
11744
|
+
|
|
11097
11745
|
// src/extract/calls/index.ts
|
|
11098
11746
|
function edgeTypeFromEndpoint(ep) {
|
|
11099
11747
|
switch (ep.edgeType) {
|
|
11100
11748
|
case "PUBLISHES_TO":
|
|
11101
|
-
return
|
|
11749
|
+
return import_types37.EdgeType.PUBLISHES_TO;
|
|
11102
11750
|
case "CONSUMES_FROM":
|
|
11103
|
-
return
|
|
11751
|
+
return import_types37.EdgeType.CONSUMES_FROM;
|
|
11104
11752
|
default:
|
|
11105
|
-
return
|
|
11753
|
+
return import_types37.EdgeType.CALLS;
|
|
11106
11754
|
}
|
|
11107
11755
|
}
|
|
11108
11756
|
function isAwsKind(kind) {
|
|
@@ -11135,6 +11783,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11135
11783
|
} catch (err) {
|
|
11136
11784
|
recordExtractionError("go SQL call extraction", file.path, err);
|
|
11137
11785
|
}
|
|
11786
|
+
try {
|
|
11787
|
+
endpoints.push(...gormEndpointsFromFile(file, service.dir));
|
|
11788
|
+
} catch (err) {
|
|
11789
|
+
recordExtractionError("gorm data-axis extraction", file.path, err);
|
|
11790
|
+
}
|
|
11138
11791
|
try {
|
|
11139
11792
|
endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir));
|
|
11140
11793
|
endpoints.push(...railsModelEndpointsFromFile(file, service.dir));
|
|
@@ -11157,7 +11810,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11157
11810
|
if (!graph.hasNode(ep.infraId)) {
|
|
11158
11811
|
const node = {
|
|
11159
11812
|
id: ep.infraId,
|
|
11160
|
-
type:
|
|
11813
|
+
type: import_types37.NodeType.InfraNode,
|
|
11161
11814
|
name: ep.name,
|
|
11162
11815
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
11163
11816
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -11170,21 +11823,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11170
11823
|
}
|
|
11171
11824
|
if (ep.columns && ep.columns.length > 0) {
|
|
11172
11825
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11173
|
-
if (node.type ===
|
|
11826
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11174
11827
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11175
11828
|
...node,
|
|
11176
11829
|
columns: foldColumns(
|
|
11177
11830
|
node.columns,
|
|
11178
11831
|
ep.columns,
|
|
11179
|
-
|
|
11180
|
-
(0,
|
|
11832
|
+
import_types37.Provenance.EXTRACTED,
|
|
11833
|
+
(0, import_types37.confidenceForExtracted)(ep.confidenceKind)
|
|
11181
11834
|
)
|
|
11182
11835
|
});
|
|
11183
11836
|
}
|
|
11184
11837
|
}
|
|
11185
11838
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
11186
11839
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11187
|
-
if (node.type ===
|
|
11840
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11188
11841
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11189
11842
|
...node,
|
|
11190
11843
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -11192,7 +11845,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11192
11845
|
}
|
|
11193
11846
|
}
|
|
11194
11847
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
11195
|
-
const confidence = (0,
|
|
11848
|
+
const confidence = (0, import_types37.confidenceForExtracted)(ep.confidenceKind);
|
|
11196
11849
|
const relFile = toPosix(ep.evidence.file);
|
|
11197
11850
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
11198
11851
|
graph,
|
|
@@ -11202,7 +11855,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11202
11855
|
);
|
|
11203
11856
|
nodesAdded += n;
|
|
11204
11857
|
edgesAdded += e;
|
|
11205
|
-
if (!(0,
|
|
11858
|
+
if (!(0, import_types37.passesExtractedFloor)(confidence)) {
|
|
11206
11859
|
noteExtractedDropped({
|
|
11207
11860
|
source: fileNodeId,
|
|
11208
11861
|
target: ep.infraId,
|
|
@@ -11222,7 +11875,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11222
11875
|
source: fileNodeId,
|
|
11223
11876
|
target: ep.infraId,
|
|
11224
11877
|
type: edgeType,
|
|
11225
|
-
provenance:
|
|
11878
|
+
provenance: import_types37.Provenance.EXTRACTED,
|
|
11226
11879
|
confidence,
|
|
11227
11880
|
evidence: ep.evidence
|
|
11228
11881
|
};
|
|
@@ -11245,7 +11898,7 @@ async function addCallEdges(graph, services) {
|
|
|
11245
11898
|
|
|
11246
11899
|
// src/extract/table-edges.ts
|
|
11247
11900
|
init_cjs_shims();
|
|
11248
|
-
var
|
|
11901
|
+
var import_types38 = require("@neat.is/types");
|
|
11249
11902
|
async function addTableEdges(graph, services) {
|
|
11250
11903
|
let nodesAdded = 0;
|
|
11251
11904
|
let edgesAdded = 0;
|
|
@@ -11259,6 +11912,7 @@ async function addTableEdges(graph, services) {
|
|
|
11259
11912
|
refs.push(...sqlalchemyForeignKeys(file, service.dir));
|
|
11260
11913
|
refs.push(...railsSchemaForeignKeys(file, service.dir));
|
|
11261
11914
|
refs.push(...laravelMigrationForeignKeys(file, service.dir));
|
|
11915
|
+
refs.push(...gormForeignKeys(file, service.dir));
|
|
11262
11916
|
modelRefs.push(...railsModelForeignKeys(file, service.dir));
|
|
11263
11917
|
modelRefs.push(...laravelModelForeignKeys(file, service.dir));
|
|
11264
11918
|
} catch (err) {
|
|
@@ -11272,20 +11926,20 @@ async function addTableEdges(graph, services) {
|
|
|
11272
11926
|
}
|
|
11273
11927
|
refs.push(...modelRefs);
|
|
11274
11928
|
for (const ref of refs) {
|
|
11275
|
-
const childId = (0,
|
|
11276
|
-
const parentId = (0,
|
|
11929
|
+
const childId = (0, import_types38.infraId)("sql-table", ref.childTable);
|
|
11930
|
+
const parentId = (0, import_types38.infraId)("sql-table", ref.parentTable);
|
|
11277
11931
|
if (childId === parentId) continue;
|
|
11278
11932
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
11279
11933
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
11280
|
-
const edgeId = (0,
|
|
11934
|
+
const edgeId = (0, import_types38.extractedEdgeId)(childId, parentId, import_types38.EdgeType.REFERENCES);
|
|
11281
11935
|
if (graph.hasEdge(edgeId)) continue;
|
|
11282
11936
|
const edge = {
|
|
11283
11937
|
id: edgeId,
|
|
11284
11938
|
source: childId,
|
|
11285
11939
|
target: parentId,
|
|
11286
|
-
type:
|
|
11287
|
-
provenance:
|
|
11288
|
-
confidence: (0,
|
|
11940
|
+
type: import_types38.EdgeType.REFERENCES,
|
|
11941
|
+
provenance: import_types38.Provenance.EXTRACTED,
|
|
11942
|
+
confidence: (0, import_types38.confidenceForExtracted)("structural"),
|
|
11289
11943
|
evidence: ref.evidence
|
|
11290
11944
|
};
|
|
11291
11945
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -11298,7 +11952,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
11298
11952
|
if (graph.hasNode(id)) return 0;
|
|
11299
11953
|
const node = {
|
|
11300
11954
|
id,
|
|
11301
|
-
type:
|
|
11955
|
+
type: import_types38.NodeType.InfraNode,
|
|
11302
11956
|
name,
|
|
11303
11957
|
provider: "self",
|
|
11304
11958
|
kind: "sql-table"
|
|
@@ -11312,16 +11966,16 @@ init_cjs_shims();
|
|
|
11312
11966
|
|
|
11313
11967
|
// src/extract/infra/docker-compose.ts
|
|
11314
11968
|
init_cjs_shims();
|
|
11315
|
-
var
|
|
11316
|
-
var
|
|
11969
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11970
|
+
var import_types40 = require("@neat.is/types");
|
|
11317
11971
|
|
|
11318
11972
|
// src/extract/infra/shared.ts
|
|
11319
11973
|
init_cjs_shims();
|
|
11320
|
-
var
|
|
11974
|
+
var import_types39 = require("@neat.is/types");
|
|
11321
11975
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
11322
11976
|
return {
|
|
11323
|
-
id: (0,
|
|
11324
|
-
type:
|
|
11977
|
+
id: (0, import_types39.infraId)(kind, name),
|
|
11978
|
+
type: import_types39.NodeType.InfraNode,
|
|
11325
11979
|
name,
|
|
11326
11980
|
provider,
|
|
11327
11981
|
kind,
|
|
@@ -11365,8 +12019,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
11365
12019
|
source: anchorId,
|
|
11366
12020
|
target: node.id,
|
|
11367
12021
|
type: edgeType,
|
|
11368
|
-
provenance:
|
|
11369
|
-
confidence: (0,
|
|
12022
|
+
provenance: import_types39.Provenance.EXTRACTED,
|
|
12023
|
+
confidence: (0, import_types39.confidenceForExtracted)("structural"),
|
|
11370
12024
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11371
12025
|
};
|
|
11372
12026
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11383,7 +12037,7 @@ function dependsOnList(value) {
|
|
|
11383
12037
|
}
|
|
11384
12038
|
function serviceNameToServiceNode(name, services) {
|
|
11385
12039
|
for (const s of services) {
|
|
11386
|
-
if (s.node.name === name ||
|
|
12040
|
+
if (s.node.name === name || import_node_path49.default.basename(s.dir) === name) return s.node.id;
|
|
11387
12041
|
}
|
|
11388
12042
|
return null;
|
|
11389
12043
|
}
|
|
@@ -11392,7 +12046,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11392
12046
|
let edgesAdded = 0;
|
|
11393
12047
|
let composePath = null;
|
|
11394
12048
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
11395
|
-
const abs =
|
|
12049
|
+
const abs = import_node_path49.default.join(scanPath, name);
|
|
11396
12050
|
if (await exists(abs)) {
|
|
11397
12051
|
composePath = abs;
|
|
11398
12052
|
break;
|
|
@@ -11405,13 +12059,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11405
12059
|
} catch (err) {
|
|
11406
12060
|
recordExtractionError(
|
|
11407
12061
|
"infra docker-compose",
|
|
11408
|
-
|
|
12062
|
+
import_node_path49.default.relative(scanPath, composePath),
|
|
11409
12063
|
err
|
|
11410
12064
|
);
|
|
11411
12065
|
return { nodesAdded, edgesAdded };
|
|
11412
12066
|
}
|
|
11413
12067
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
11414
|
-
const evidenceFile =
|
|
12068
|
+
const evidenceFile = import_node_path49.default.relative(scanPath, composePath).split(import_node_path49.default.sep).join("/");
|
|
11415
12069
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
11416
12070
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
11417
12071
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -11433,15 +12087,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11433
12087
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
11434
12088
|
const targetId = composeNameToNodeId.get(dep);
|
|
11435
12089
|
if (!targetId) continue;
|
|
11436
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
12090
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types40.EdgeType.DEPENDS_ON);
|
|
11437
12091
|
if (graph.hasEdge(edgeId)) continue;
|
|
11438
12092
|
const edge = {
|
|
11439
12093
|
id: edgeId,
|
|
11440
12094
|
source: sourceId,
|
|
11441
12095
|
target: targetId,
|
|
11442
|
-
type:
|
|
11443
|
-
provenance:
|
|
11444
|
-
confidence: (0,
|
|
12096
|
+
type: import_types40.EdgeType.DEPENDS_ON,
|
|
12097
|
+
provenance: import_types40.Provenance.EXTRACTED,
|
|
12098
|
+
confidence: (0, import_types40.confidenceForExtracted)("structural"),
|
|
11445
12099
|
evidence: { file: evidenceFile }
|
|
11446
12100
|
};
|
|
11447
12101
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11453,9 +12107,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11453
12107
|
|
|
11454
12108
|
// src/extract/infra/dockerfile.ts
|
|
11455
12109
|
init_cjs_shims();
|
|
11456
|
-
var
|
|
12110
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11457
12111
|
var import_node_fs18 = require("fs");
|
|
11458
|
-
var
|
|
12112
|
+
var import_types41 = require("@neat.is/types");
|
|
11459
12113
|
function readDockerfile(content) {
|
|
11460
12114
|
let image = null;
|
|
11461
12115
|
const ports = [];
|
|
@@ -11484,7 +12138,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11484
12138
|
let nodesAdded = 0;
|
|
11485
12139
|
let edgesAdded = 0;
|
|
11486
12140
|
for (const service of services) {
|
|
11487
|
-
const dockerfilePath =
|
|
12141
|
+
const dockerfilePath = import_node_path50.default.join(service.dir, "Dockerfile");
|
|
11488
12142
|
if (!await exists(dockerfilePath)) continue;
|
|
11489
12143
|
let content;
|
|
11490
12144
|
try {
|
|
@@ -11492,7 +12146,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11492
12146
|
} catch (err) {
|
|
11493
12147
|
recordExtractionError(
|
|
11494
12148
|
"infra dockerfile",
|
|
11495
|
-
|
|
12149
|
+
import_node_path50.default.relative(scanPath, dockerfilePath),
|
|
11496
12150
|
err
|
|
11497
12151
|
);
|
|
11498
12152
|
continue;
|
|
@@ -11504,8 +12158,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11504
12158
|
graph.addNode(node.id, node);
|
|
11505
12159
|
nodesAdded++;
|
|
11506
12160
|
}
|
|
11507
|
-
const relDockerfile = toPosix(
|
|
11508
|
-
const evidenceFile = toPosix(
|
|
12161
|
+
const relDockerfile = toPosix(import_node_path50.default.relative(service.dir, dockerfilePath));
|
|
12162
|
+
const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, dockerfilePath));
|
|
11509
12163
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11510
12164
|
graph,
|
|
11511
12165
|
service.pkg.name,
|
|
@@ -11514,15 +12168,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11514
12168
|
);
|
|
11515
12169
|
nodesAdded += fn;
|
|
11516
12170
|
edgesAdded += fe;
|
|
11517
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
12171
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types41.EdgeType.RUNS_ON);
|
|
11518
12172
|
if (!graph.hasEdge(edgeId)) {
|
|
11519
12173
|
const edge = {
|
|
11520
12174
|
id: edgeId,
|
|
11521
12175
|
source: fileNodeId,
|
|
11522
12176
|
target: node.id,
|
|
11523
|
-
type:
|
|
11524
|
-
provenance:
|
|
11525
|
-
confidence: (0,
|
|
12177
|
+
type: import_types41.EdgeType.RUNS_ON,
|
|
12178
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12179
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11526
12180
|
evidence: {
|
|
11527
12181
|
file: evidenceFile,
|
|
11528
12182
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -11537,15 +12191,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11537
12191
|
graph.addNode(portNode.id, portNode);
|
|
11538
12192
|
nodesAdded++;
|
|
11539
12193
|
}
|
|
11540
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
12194
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types41.EdgeType.CONNECTS_TO);
|
|
11541
12195
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
11542
12196
|
const portEdge = {
|
|
11543
12197
|
id: portEdgeId,
|
|
11544
12198
|
source: fileNodeId,
|
|
11545
12199
|
target: portNode.id,
|
|
11546
|
-
type:
|
|
11547
|
-
provenance:
|
|
11548
|
-
confidence: (0,
|
|
12200
|
+
type: import_types41.EdgeType.CONNECTS_TO,
|
|
12201
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12202
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11549
12203
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
11550
12204
|
};
|
|
11551
12205
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -11558,8 +12212,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11558
12212
|
// src/extract/infra/terraform.ts
|
|
11559
12213
|
init_cjs_shims();
|
|
11560
12214
|
var import_node_fs19 = require("fs");
|
|
11561
|
-
var
|
|
11562
|
-
var
|
|
12215
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12216
|
+
var import_types42 = require("@neat.is/types");
|
|
11563
12217
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
11564
12218
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
11565
12219
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -11569,11 +12223,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
11569
12223
|
for (const entry of entries) {
|
|
11570
12224
|
if (entry.isDirectory()) {
|
|
11571
12225
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
11572
|
-
const child =
|
|
12226
|
+
const child = import_node_path51.default.join(start, entry.name);
|
|
11573
12227
|
if (await isPythonVenvDir(child)) continue;
|
|
11574
12228
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
11575
12229
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
11576
|
-
out.push(
|
|
12230
|
+
out.push(import_node_path51.default.join(start, entry.name));
|
|
11577
12231
|
}
|
|
11578
12232
|
}
|
|
11579
12233
|
return out;
|
|
@@ -11605,7 +12259,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11605
12259
|
const files = await walkTfFiles(scanPath);
|
|
11606
12260
|
for (const file of files) {
|
|
11607
12261
|
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
11608
|
-
const evidenceFile = toPosix(
|
|
12262
|
+
const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, file));
|
|
11609
12263
|
const resources = [];
|
|
11610
12264
|
const byKey = /* @__PURE__ */ new Map();
|
|
11611
12265
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -11640,16 +12294,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11640
12294
|
if (!target) continue;
|
|
11641
12295
|
if (seen.has(target.nodeId)) continue;
|
|
11642
12296
|
seen.add(target.nodeId);
|
|
11643
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
12297
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types42.EdgeType.DEPENDS_ON);
|
|
11644
12298
|
if (graph.hasEdge(edgeId)) continue;
|
|
11645
12299
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
11646
12300
|
const edge = {
|
|
11647
12301
|
id: edgeId,
|
|
11648
12302
|
source: resource.nodeId,
|
|
11649
12303
|
target: target.nodeId,
|
|
11650
|
-
type:
|
|
11651
|
-
provenance:
|
|
11652
|
-
confidence: (0,
|
|
12304
|
+
type: import_types42.EdgeType.DEPENDS_ON,
|
|
12305
|
+
provenance: import_types42.Provenance.EXTRACTED,
|
|
12306
|
+
confidence: (0, import_types42.confidenceForExtracted)("structural"),
|
|
11653
12307
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
11654
12308
|
};
|
|
11655
12309
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11663,7 +12317,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11663
12317
|
// src/extract/infra/k8s.ts
|
|
11664
12318
|
init_cjs_shims();
|
|
11665
12319
|
var import_node_fs20 = require("fs");
|
|
11666
|
-
var
|
|
12320
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
11667
12321
|
var import_yaml3 = require("yaml");
|
|
11668
12322
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
11669
12323
|
Service: "k8s-service",
|
|
@@ -11681,11 +12335,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
11681
12335
|
for (const entry of entries) {
|
|
11682
12336
|
if (entry.isDirectory()) {
|
|
11683
12337
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
11684
|
-
const child =
|
|
12338
|
+
const child = import_node_path52.default.join(start, entry.name);
|
|
11685
12339
|
if (await isPythonVenvDir(child)) continue;
|
|
11686
12340
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
11687
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
11688
|
-
out.push(
|
|
12341
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path52.default.extname(entry.name))) {
|
|
12342
|
+
out.push(import_node_path52.default.join(start, entry.name));
|
|
11689
12343
|
}
|
|
11690
12344
|
}
|
|
11691
12345
|
return out;
|
|
@@ -11719,13 +12373,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
11719
12373
|
// src/extract/infra/cloudflare.ts
|
|
11720
12374
|
init_cjs_shims();
|
|
11721
12375
|
var import_node_fs21 = require("fs");
|
|
11722
|
-
var
|
|
12376
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
11723
12377
|
var import_smol_toml2 = require("smol-toml");
|
|
11724
|
-
var
|
|
12378
|
+
var import_types43 = require("@neat.is/types");
|
|
11725
12379
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
11726
12380
|
async function readWranglerConfig(dir) {
|
|
11727
12381
|
for (const filename of WRANGLER_FILENAMES) {
|
|
11728
|
-
const abs =
|
|
12382
|
+
const abs = import_node_path53.default.join(dir, filename);
|
|
11729
12383
|
if (!await exists(abs)) continue;
|
|
11730
12384
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
11731
12385
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11769,8 +12423,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
11769
12423
|
source: anchorId,
|
|
11770
12424
|
target: node.id,
|
|
11771
12425
|
type: edgeType,
|
|
11772
|
-
provenance:
|
|
11773
|
-
confidence: (0,
|
|
12426
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12427
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11774
12428
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11775
12429
|
};
|
|
11776
12430
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11788,11 +12442,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11788
12442
|
try {
|
|
11789
12443
|
read = await readWranglerConfig(service.dir);
|
|
11790
12444
|
} catch (err) {
|
|
11791
|
-
recordExtractionError("infra cloudflare",
|
|
12445
|
+
recordExtractionError("infra cloudflare", import_node_path53.default.relative(scanPath, service.dir), err);
|
|
11792
12446
|
continue;
|
|
11793
12447
|
}
|
|
11794
12448
|
if (!read || !read.config.name) continue;
|
|
11795
|
-
const evidenceFile = toPosix(
|
|
12449
|
+
const evidenceFile = toPosix(import_node_path53.default.relative(scanPath, import_node_path53.default.join(service.dir, read.relFile)));
|
|
11796
12450
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
11797
12451
|
}
|
|
11798
12452
|
for (const worker of discovered) {
|
|
@@ -11804,7 +12458,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11804
12458
|
}
|
|
11805
12459
|
let anchorId = service.node.id;
|
|
11806
12460
|
if (config.main) {
|
|
11807
|
-
const entryRelPath = toPosix(
|
|
12461
|
+
const entryRelPath = toPosix(import_node_path53.default.normalize(config.main));
|
|
11808
12462
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11809
12463
|
graph,
|
|
11810
12464
|
service.pkg.name,
|
|
@@ -11831,15 +12485,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11831
12485
|
nodesAdded++;
|
|
11832
12486
|
}
|
|
11833
12487
|
if (runtimeNode.id !== anchorId) {
|
|
11834
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
12488
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types43.EdgeType.RUNS_ON);
|
|
11835
12489
|
if (!graph.hasEdge(runsOnId)) {
|
|
11836
12490
|
const edge = {
|
|
11837
12491
|
id: runsOnId,
|
|
11838
12492
|
source: anchorId,
|
|
11839
12493
|
target: runtimeNode.id,
|
|
11840
|
-
type:
|
|
11841
|
-
provenance:
|
|
11842
|
-
confidence: (0,
|
|
12494
|
+
type: import_types43.EdgeType.RUNS_ON,
|
|
12495
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12496
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11843
12497
|
evidence: {
|
|
11844
12498
|
file: evidenceFile,
|
|
11845
12499
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -11853,7 +12507,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11853
12507
|
const result = addResourceEdge(
|
|
11854
12508
|
graph,
|
|
11855
12509
|
anchorId,
|
|
11856
|
-
|
|
12510
|
+
import_types43.EdgeType.CONNECTS_TO,
|
|
11857
12511
|
"cloudflare-route",
|
|
11858
12512
|
route,
|
|
11859
12513
|
evidenceFile,
|
|
@@ -11877,7 +12531,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11877
12531
|
const result = addResourceEdge(
|
|
11878
12532
|
graph,
|
|
11879
12533
|
anchorId,
|
|
11880
|
-
|
|
12534
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11881
12535
|
group.kind,
|
|
11882
12536
|
name,
|
|
11883
12537
|
evidenceFile,
|
|
@@ -11891,7 +12545,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11891
12545
|
const result = addResourceEdge(
|
|
11892
12546
|
graph,
|
|
11893
12547
|
anchorId,
|
|
11894
|
-
|
|
12548
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11895
12549
|
"cloudflare-cron",
|
|
11896
12550
|
cron,
|
|
11897
12551
|
evidenceFile,
|
|
@@ -11904,7 +12558,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11904
12558
|
const result = addResourceEdge(
|
|
11905
12559
|
graph,
|
|
11906
12560
|
anchorId,
|
|
11907
|
-
|
|
12561
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11908
12562
|
"cloudflare-env-var",
|
|
11909
12563
|
varName,
|
|
11910
12564
|
evidenceFile,
|
|
@@ -11917,15 +12571,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11917
12571
|
if (!svc.service) continue;
|
|
11918
12572
|
const target = workerIndex.get(svc.service);
|
|
11919
12573
|
if (target && target.anchorId !== anchorId) {
|
|
11920
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
12574
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types43.EdgeType.CALLS);
|
|
11921
12575
|
if (!graph.hasEdge(edgeId)) {
|
|
11922
12576
|
const edge = {
|
|
11923
12577
|
id: edgeId,
|
|
11924
12578
|
source: anchorId,
|
|
11925
12579
|
target: target.anchorId,
|
|
11926
|
-
type:
|
|
11927
|
-
provenance:
|
|
11928
|
-
confidence: (0,
|
|
12580
|
+
type: import_types43.EdgeType.CALLS,
|
|
12581
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12582
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11929
12583
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
11930
12584
|
};
|
|
11931
12585
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11936,7 +12590,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11936
12590
|
const result = addResourceEdge(
|
|
11937
12591
|
graph,
|
|
11938
12592
|
anchorId,
|
|
11939
|
-
|
|
12593
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11940
12594
|
"cloudflare-service-binding",
|
|
11941
12595
|
svc.service,
|
|
11942
12596
|
evidenceFile,
|
|
@@ -11952,12 +12606,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11952
12606
|
// src/extract/infra/vercel.ts
|
|
11953
12607
|
init_cjs_shims();
|
|
11954
12608
|
var import_node_fs22 = require("fs");
|
|
11955
|
-
var
|
|
11956
|
-
var
|
|
12609
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
12610
|
+
var import_types44 = require("@neat.is/types");
|
|
11957
12611
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
11958
12612
|
async function readVercelConfig(dir) {
|
|
11959
12613
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
11960
|
-
const abs =
|
|
12614
|
+
const abs = import_node_path54.default.join(dir, filename);
|
|
11961
12615
|
if (!await exists(abs)) continue;
|
|
11962
12616
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
11963
12617
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11966,7 +12620,7 @@ async function readVercelConfig(dir) {
|
|
|
11966
12620
|
return null;
|
|
11967
12621
|
}
|
|
11968
12622
|
async function readLinkedProjectName(dir) {
|
|
11969
|
-
const abs =
|
|
12623
|
+
const abs = import_node_path54.default.join(dir, ".vercel", "project.json");
|
|
11970
12624
|
if (!await exists(abs)) return void 0;
|
|
11971
12625
|
const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
|
|
11972
12626
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -11984,7 +12638,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11984
12638
|
read = await readVercelConfig(service.dir);
|
|
11985
12639
|
projectName = await readLinkedProjectName(service.dir);
|
|
11986
12640
|
} catch (err) {
|
|
11987
|
-
recordExtractionError("infra vercel",
|
|
12641
|
+
recordExtractionError("infra vercel", import_node_path54.default.relative(scanPath, service.dir), err);
|
|
11988
12642
|
continue;
|
|
11989
12643
|
}
|
|
11990
12644
|
if (!read && !projectName) continue;
|
|
@@ -12000,7 +12654,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12000
12654
|
const anchorId = service.node.id;
|
|
12001
12655
|
if (!read) continue;
|
|
12002
12656
|
const { config, relFile, raw } = read;
|
|
12003
|
-
const evidenceFile = toPosix(
|
|
12657
|
+
const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, relFile)));
|
|
12004
12658
|
const add = (edgeType, kind, name) => {
|
|
12005
12659
|
if (!name) return;
|
|
12006
12660
|
const result = emitPlatformResourceEdge(
|
|
@@ -12016,12 +12670,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12016
12670
|
nodesAdded += result.nodesAdded;
|
|
12017
12671
|
edgesAdded += result.edgesAdded;
|
|
12018
12672
|
};
|
|
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(
|
|
12673
|
+
add(import_types44.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
12674
|
+
for (const cron of config.crons ?? []) add(import_types44.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
12675
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12676
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12023
12677
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
12024
|
-
add(
|
|
12678
|
+
add(import_types44.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
12025
12679
|
}
|
|
12026
12680
|
}
|
|
12027
12681
|
return { nodesAdded, edgesAdded };
|
|
@@ -12030,13 +12684,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
12030
12684
|
// src/extract/infra/railway.ts
|
|
12031
12685
|
init_cjs_shims();
|
|
12032
12686
|
var import_node_fs23 = require("fs");
|
|
12033
|
-
var
|
|
12687
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
12034
12688
|
var import_smol_toml3 = require("smol-toml");
|
|
12035
|
-
var
|
|
12689
|
+
var import_types45 = require("@neat.is/types");
|
|
12036
12690
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
12037
12691
|
async function readRailwayConfig(dir) {
|
|
12038
12692
|
for (const filename of RAILWAY_FILENAMES) {
|
|
12039
|
-
const abs =
|
|
12693
|
+
const abs = import_node_path55.default.join(dir, filename);
|
|
12040
12694
|
if (!await exists(abs)) continue;
|
|
12041
12695
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
12042
12696
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -12052,7 +12706,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12052
12706
|
try {
|
|
12053
12707
|
read = await readRailwayConfig(service.dir);
|
|
12054
12708
|
} catch (err) {
|
|
12055
|
-
recordExtractionError("infra railway",
|
|
12709
|
+
recordExtractionError("infra railway", import_node_path55.default.relative(scanPath, service.dir), err);
|
|
12056
12710
|
continue;
|
|
12057
12711
|
}
|
|
12058
12712
|
if (!read) continue;
|
|
@@ -12062,7 +12716,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12062
12716
|
}
|
|
12063
12717
|
const anchorId = service.node.id;
|
|
12064
12718
|
const { config, relFile, raw } = read;
|
|
12065
|
-
const evidenceFile = toPosix(
|
|
12719
|
+
const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
|
|
12066
12720
|
const add = (edgeType, kind, name) => {
|
|
12067
12721
|
if (!name) return;
|
|
12068
12722
|
const result = emitPlatformResourceEdge(
|
|
@@ -12078,9 +12732,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12078
12732
|
nodesAdded += result.nodesAdded;
|
|
12079
12733
|
edgesAdded += result.edgesAdded;
|
|
12080
12734
|
};
|
|
12081
|
-
add(
|
|
12082
|
-
add(
|
|
12083
|
-
add(
|
|
12735
|
+
add(import_types45.EdgeType.RUNS_ON, "railway", "railway");
|
|
12736
|
+
add(import_types45.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
12737
|
+
add(import_types45.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
12084
12738
|
}
|
|
12085
12739
|
return { nodesAdded, edgesAdded };
|
|
12086
12740
|
}
|
|
@@ -12088,12 +12742,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12088
12742
|
// src/extract/infra/supabase.ts
|
|
12089
12743
|
init_cjs_shims();
|
|
12090
12744
|
var import_node_fs24 = require("fs");
|
|
12091
|
-
var
|
|
12745
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
12092
12746
|
var import_smol_toml4 = require("smol-toml");
|
|
12093
|
-
var
|
|
12747
|
+
var import_types46 = require("@neat.is/types");
|
|
12094
12748
|
async function readSupabaseConfig(dir) {
|
|
12095
|
-
const relFile =
|
|
12096
|
-
const abs =
|
|
12749
|
+
const relFile = import_node_path56.default.join("supabase", "config.toml");
|
|
12750
|
+
const abs = import_node_path56.default.join(dir, relFile);
|
|
12097
12751
|
if (!await exists(abs)) return null;
|
|
12098
12752
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
12099
12753
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -12107,7 +12761,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12107
12761
|
try {
|
|
12108
12762
|
read = await readSupabaseConfig(service.dir);
|
|
12109
12763
|
} catch (err) {
|
|
12110
|
-
recordExtractionError("infra supabase",
|
|
12764
|
+
recordExtractionError("infra supabase", import_node_path56.default.relative(scanPath, service.dir), err);
|
|
12111
12765
|
continue;
|
|
12112
12766
|
}
|
|
12113
12767
|
if (!read) continue;
|
|
@@ -12122,7 +12776,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12122
12776
|
});
|
|
12123
12777
|
}
|
|
12124
12778
|
const anchorId = service.node.id;
|
|
12125
|
-
const evidenceFile = toPosix(
|
|
12779
|
+
const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
|
|
12126
12780
|
const add = (edgeType, kind, name) => {
|
|
12127
12781
|
if (!name) return;
|
|
12128
12782
|
const result = emitPlatformResourceEdge(
|
|
@@ -12138,10 +12792,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12138
12792
|
nodesAdded += result.nodesAdded;
|
|
12139
12793
|
edgesAdded += result.edgesAdded;
|
|
12140
12794
|
};
|
|
12141
|
-
add(
|
|
12142
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
12143
|
-
if (config.storage) add(
|
|
12144
|
-
if (config.auth) add(
|
|
12795
|
+
add(import_types46.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
12796
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types46.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
12797
|
+
if (config.storage) add(import_types46.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
12798
|
+
if (config.auth) add(import_types46.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
12145
12799
|
}
|
|
12146
12800
|
return { nodesAdded, edgesAdded };
|
|
12147
12801
|
}
|
|
@@ -12164,14 +12818,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
12164
12818
|
|
|
12165
12819
|
// src/extract/zod-shapes.ts
|
|
12166
12820
|
init_cjs_shims();
|
|
12167
|
-
var
|
|
12168
|
-
var
|
|
12821
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
12822
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
12169
12823
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12170
|
-
var
|
|
12824
|
+
var import_types47 = require("@neat.is/types");
|
|
12171
12825
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
12172
12826
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
12173
12827
|
function parserForExt3(ext) {
|
|
12174
|
-
const p = new
|
|
12828
|
+
const p = new import_tree_sitter16.default();
|
|
12175
12829
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
12176
12830
|
return p;
|
|
12177
12831
|
}
|
|
@@ -12259,7 +12913,7 @@ function topLevelSchemas(root) {
|
|
|
12259
12913
|
}
|
|
12260
12914
|
function zodShapesFromFile(file, serviceDir) {
|
|
12261
12915
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
12262
|
-
const tree = parseSource3(parserForExt3(
|
|
12916
|
+
const tree = parseSource3(parserForExt3(import_node_path57.default.extname(file.path)), file.content);
|
|
12263
12917
|
const out = [];
|
|
12264
12918
|
const seen = /* @__PURE__ */ new Set();
|
|
12265
12919
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -12273,11 +12927,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
12273
12927
|
seen.add(name);
|
|
12274
12928
|
const line = call.startPosition.row + 1;
|
|
12275
12929
|
out.push({
|
|
12276
|
-
infraId: (0,
|
|
12930
|
+
infraId: (0, import_types47.infraId)("zod-schema", name),
|
|
12277
12931
|
name,
|
|
12278
12932
|
fields,
|
|
12279
12933
|
evidence: {
|
|
12280
|
-
file:
|
|
12934
|
+
file: import_node_path57.default.relative(serviceDir, file.path),
|
|
12281
12935
|
line,
|
|
12282
12936
|
snippet: snippet(file.content, line)
|
|
12283
12937
|
}
|
|
@@ -12308,7 +12962,7 @@ async function addZodShapes(graph, services) {
|
|
|
12308
12962
|
if (!graph.hasNode(shape.infraId)) {
|
|
12309
12963
|
const node = {
|
|
12310
12964
|
id: shape.infraId,
|
|
12311
|
-
type:
|
|
12965
|
+
type: import_types47.NodeType.InfraNode,
|
|
12312
12966
|
name: shape.name,
|
|
12313
12967
|
provider: "self",
|
|
12314
12968
|
kind: "zod-schema"
|
|
@@ -12318,14 +12972,14 @@ async function addZodShapes(graph, services) {
|
|
|
12318
12972
|
}
|
|
12319
12973
|
if (shape.fields.length > 0) {
|
|
12320
12974
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
12321
|
-
if (node.type ===
|
|
12975
|
+
if (node.type === import_types47.NodeType.InfraNode) {
|
|
12322
12976
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
12323
12977
|
...node,
|
|
12324
12978
|
columns: foldColumns(
|
|
12325
12979
|
node.columns,
|
|
12326
12980
|
shape.fields,
|
|
12327
|
-
|
|
12328
|
-
(0,
|
|
12981
|
+
import_types47.Provenance.EXTRACTED,
|
|
12982
|
+
(0, import_types47.confidenceForExtracted)("structural")
|
|
12329
12983
|
)
|
|
12330
12984
|
});
|
|
12331
12985
|
}
|
|
@@ -12339,15 +12993,15 @@ async function addZodShapes(graph, services) {
|
|
|
12339
12993
|
);
|
|
12340
12994
|
nodesAdded += n;
|
|
12341
12995
|
edgesAdded += e;
|
|
12342
|
-
const edgeId = (0,
|
|
12996
|
+
const edgeId = (0, import_types47.extractedEdgeId)(fileNodeId, shape.infraId, import_types47.EdgeType.CONTAINS);
|
|
12343
12997
|
if (!graph.hasEdge(edgeId)) {
|
|
12344
12998
|
const edge = {
|
|
12345
12999
|
id: edgeId,
|
|
12346
13000
|
source: fileNodeId,
|
|
12347
13001
|
target: shape.infraId,
|
|
12348
|
-
type:
|
|
12349
|
-
provenance:
|
|
12350
|
-
confidence: (0,
|
|
13002
|
+
type: import_types47.EdgeType.CONTAINS,
|
|
13003
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
13004
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
12351
13005
|
evidence: shape.evidence
|
|
12352
13006
|
};
|
|
12353
13007
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -12361,7 +13015,7 @@ async function addZodShapes(graph, services) {
|
|
|
12361
13015
|
|
|
12362
13016
|
// src/extract/firestore-rules.ts
|
|
12363
13017
|
init_cjs_shims();
|
|
12364
|
-
var
|
|
13018
|
+
var import_types48 = require("@neat.is/types");
|
|
12365
13019
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
12366
13020
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
12367
13021
|
function stripComments(src) {
|
|
@@ -12501,7 +13155,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
12501
13155
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
12502
13156
|
graph.forEachNode((id, attrs) => {
|
|
12503
13157
|
const node = attrs;
|
|
12504
|
-
if (node.type !==
|
|
13158
|
+
if (node.type !== import_types48.NodeType.InfraNode) return;
|
|
12505
13159
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
12506
13160
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
12507
13161
|
if (!fields || fields.size === 0) return;
|
|
@@ -12514,17 +13168,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
12514
13168
|
}
|
|
12515
13169
|
|
|
12516
13170
|
// src/extract/index.ts
|
|
12517
|
-
var
|
|
13171
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
12518
13172
|
|
|
12519
13173
|
// src/extract/retire.ts
|
|
12520
13174
|
init_cjs_shims();
|
|
12521
13175
|
var import_node_fs25 = require("fs");
|
|
12522
|
-
var
|
|
12523
|
-
var
|
|
13176
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13177
|
+
var import_types49 = require("@neat.is/types");
|
|
12524
13178
|
function dropOrphanedFileNodes(graph) {
|
|
12525
13179
|
const orphans = [];
|
|
12526
13180
|
graph.forEachNode((id, attrs) => {
|
|
12527
|
-
if (attrs.type !==
|
|
13181
|
+
if (attrs.type !== import_types49.NodeType.FileNode) return;
|
|
12528
13182
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
12529
13183
|
orphans.push(id);
|
|
12530
13184
|
}
|
|
@@ -12537,14 +13191,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
12537
13191
|
const bases = [scanPath, ...serviceDirs];
|
|
12538
13192
|
graph.forEachEdge((id, attrs) => {
|
|
12539
13193
|
const edge = attrs;
|
|
12540
|
-
if (edge.provenance !==
|
|
13194
|
+
if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
|
|
12541
13195
|
const evidenceFile = edge.evidence?.file;
|
|
12542
13196
|
if (!evidenceFile) return;
|
|
12543
|
-
if (
|
|
13197
|
+
if (import_node_path58.default.isAbsolute(evidenceFile)) {
|
|
12544
13198
|
if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
|
|
12545
13199
|
return;
|
|
12546
13200
|
}
|
|
12547
|
-
const found = bases.some((base) => (0, import_node_fs25.existsSync)(
|
|
13201
|
+
const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path58.default.join(base, evidenceFile)));
|
|
12548
13202
|
if (!found) toDrop.push(id);
|
|
12549
13203
|
});
|
|
12550
13204
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -12601,7 +13255,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12601
13255
|
}
|
|
12602
13256
|
const droppedEntries = drainDroppedExtracted();
|
|
12603
13257
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
12604
|
-
const rejectedPath =
|
|
13258
|
+
const rejectedPath = import_node_path59.default.join(import_node_path59.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
12605
13259
|
try {
|
|
12606
13260
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
12607
13261
|
} catch (err) {
|
|
@@ -12636,8 +13290,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12636
13290
|
// src/persist.ts
|
|
12637
13291
|
init_cjs_shims();
|
|
12638
13292
|
var import_node_fs26 = require("fs");
|
|
12639
|
-
var
|
|
12640
|
-
var
|
|
13293
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
13294
|
+
var import_types50 = require("@neat.is/types");
|
|
12641
13295
|
var SCHEMA_VERSION = 7;
|
|
12642
13296
|
function migrateV1ToV2(payload) {
|
|
12643
13297
|
const nodes = payload.graph.nodes;
|
|
@@ -12661,7 +13315,7 @@ function migrateV5ToV6(payload) {
|
|
|
12661
13315
|
if (Array.isArray(nodes)) {
|
|
12662
13316
|
for (const node of nodes) {
|
|
12663
13317
|
const attrs = node.attributes;
|
|
12664
|
-
if (!attrs || attrs.type !==
|
|
13318
|
+
if (!attrs || attrs.type !== import_types50.NodeType.InfraNode) continue;
|
|
12665
13319
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
12666
13320
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
12667
13321
|
}
|
|
@@ -12677,12 +13331,12 @@ function migrateV2ToV3(payload) {
|
|
|
12677
13331
|
for (const edge of edges) {
|
|
12678
13332
|
const attrs = edge.attributes;
|
|
12679
13333
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
12680
|
-
attrs.provenance =
|
|
13334
|
+
attrs.provenance = import_types50.Provenance.OBSERVED;
|
|
12681
13335
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
12682
13336
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
12683
13337
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
12684
13338
|
if (type && source && target) {
|
|
12685
|
-
const newId = (0,
|
|
13339
|
+
const newId = (0, import_types50.observedEdgeId)(source, target, type);
|
|
12686
13340
|
attrs.id = newId;
|
|
12687
13341
|
if (edge.key) edge.key = newId;
|
|
12688
13342
|
}
|
|
@@ -12691,7 +13345,7 @@ function migrateV2ToV3(payload) {
|
|
|
12691
13345
|
return { ...payload, schemaVersion: 3 };
|
|
12692
13346
|
}
|
|
12693
13347
|
async function ensureDir(filePath) {
|
|
12694
|
-
await import_node_fs26.promises.mkdir(
|
|
13348
|
+
await import_node_fs26.promises.mkdir(import_node_path60.default.dirname(filePath), { recursive: true });
|
|
12695
13349
|
}
|
|
12696
13350
|
async function saveGraphToDisk(graph, outPath) {
|
|
12697
13351
|
await ensureDir(outPath);
|
|
@@ -12783,19 +13437,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
12783
13437
|
init_cjs_shims();
|
|
12784
13438
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
12785
13439
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
12786
|
-
var
|
|
13440
|
+
var import_types80 = require("@neat.is/types");
|
|
12787
13441
|
|
|
12788
13442
|
// src/extend/index.ts
|
|
12789
13443
|
init_cjs_shims();
|
|
12790
13444
|
var import_node_fs28 = require("fs");
|
|
12791
|
-
var
|
|
13445
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
12792
13446
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
12793
13447
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
12794
13448
|
|
|
12795
13449
|
// src/installers/package-manager.ts
|
|
12796
13450
|
init_cjs_shims();
|
|
12797
13451
|
var import_node_fs27 = require("fs");
|
|
12798
|
-
var
|
|
13452
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
12799
13453
|
var import_node_child_process = require("child_process");
|
|
12800
13454
|
var LOCKFILE_PRIORITY = [
|
|
12801
13455
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -12817,22 +13471,22 @@ async function exists2(p) {
|
|
|
12817
13471
|
}
|
|
12818
13472
|
}
|
|
12819
13473
|
async function detectPackageManager(serviceDir) {
|
|
12820
|
-
let dir =
|
|
13474
|
+
let dir = import_node_path61.default.resolve(serviceDir);
|
|
12821
13475
|
const stops = /* @__PURE__ */ new Set();
|
|
12822
13476
|
for (let i = 0; i < 64; i++) {
|
|
12823
13477
|
if (stops.has(dir)) break;
|
|
12824
13478
|
stops.add(dir);
|
|
12825
13479
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
12826
|
-
const lockPath =
|
|
13480
|
+
const lockPath = import_node_path61.default.join(dir, candidate.lockfile);
|
|
12827
13481
|
if (await exists2(lockPath)) {
|
|
12828
13482
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
12829
13483
|
}
|
|
12830
13484
|
}
|
|
12831
|
-
const parent =
|
|
13485
|
+
const parent = import_node_path61.default.dirname(dir);
|
|
12832
13486
|
if (parent === dir) break;
|
|
12833
13487
|
dir = parent;
|
|
12834
13488
|
}
|
|
12835
|
-
return { pm: "npm", cwd:
|
|
13489
|
+
return { pm: "npm", cwd: import_node_path61.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
12836
13490
|
}
|
|
12837
13491
|
async function runPackageManagerInstall(cmd) {
|
|
12838
13492
|
return new Promise((resolve) => {
|
|
@@ -12881,7 +13535,7 @@ async function fileExists2(p) {
|
|
|
12881
13535
|
}
|
|
12882
13536
|
}
|
|
12883
13537
|
async function readPackageJson(scanPath) {
|
|
12884
|
-
const pkgPath =
|
|
13538
|
+
const pkgPath = import_node_path62.default.join(scanPath, "package.json");
|
|
12885
13539
|
const raw = await import_node_fs28.promises.readFile(pkgPath, "utf8");
|
|
12886
13540
|
return JSON.parse(raw);
|
|
12887
13541
|
}
|
|
@@ -12895,27 +13549,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
12895
13549
|
]);
|
|
12896
13550
|
async function findHookFiles(scanPath) {
|
|
12897
13551
|
const found = [];
|
|
12898
|
-
const
|
|
13552
|
+
const walk9 = async (dir) => {
|
|
12899
13553
|
const entries = await import_node_fs28.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
12900
13554
|
for (const entry of entries) {
|
|
12901
13555
|
if (entry.isDirectory()) {
|
|
12902
13556
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
12903
|
-
await
|
|
13557
|
+
await walk9(import_node_path62.default.join(dir, entry.name));
|
|
12904
13558
|
} else if (entry.isFile()) {
|
|
12905
13559
|
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(
|
|
13560
|
+
const rel = import_node_path62.default.relative(scanPath, import_node_path62.default.join(dir, entry.name));
|
|
13561
|
+
found.push(rel.split(import_node_path62.default.sep).join("/"));
|
|
12908
13562
|
}
|
|
12909
13563
|
}
|
|
12910
13564
|
}
|
|
12911
13565
|
};
|
|
12912
|
-
await
|
|
13566
|
+
await walk9(scanPath);
|
|
12913
13567
|
return found.sort();
|
|
12914
13568
|
}
|
|
12915
13569
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
12916
13570
|
let fallback = null;
|
|
12917
13571
|
for (const file of hookFiles) {
|
|
12918
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13572
|
+
const content = await import_node_fs28.promises.readFile(import_node_path62.default.join(scanPath, file), "utf8");
|
|
12919
13573
|
const patched = splicedContent(content, snippet2);
|
|
12920
13574
|
if (patched !== null) return { file, content, patched };
|
|
12921
13575
|
if (fallback === null) fallback = { file, content };
|
|
@@ -12923,11 +13577,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
12923
13577
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
12924
13578
|
}
|
|
12925
13579
|
function extendLogPath() {
|
|
12926
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
13580
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path62.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
12927
13581
|
}
|
|
12928
13582
|
async function appendExtendLog(entry) {
|
|
12929
13583
|
const logPath = extendLogPath();
|
|
12930
|
-
await import_node_fs28.promises.mkdir(
|
|
13584
|
+
await import_node_fs28.promises.mkdir(import_node_path62.default.dirname(logPath), { recursive: true });
|
|
12931
13585
|
await import_node_fs28.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
12932
13586
|
}
|
|
12933
13587
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -12986,7 +13640,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
12986
13640
|
}
|
|
12987
13641
|
async function describeProjectInstrumentation(ctx) {
|
|
12988
13642
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
12989
|
-
const envNeat = await fileExists2(
|
|
13643
|
+
const envNeat = await fileExists2(import_node_path62.default.join(ctx.scanPath, ".env.neat"));
|
|
12990
13644
|
const registryInstrPackages = new Set(
|
|
12991
13645
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
12992
13646
|
);
|
|
@@ -13008,7 +13662,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
13008
13662
|
);
|
|
13009
13663
|
}
|
|
13010
13664
|
for (const file of hookFiles) {
|
|
13011
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13665
|
+
const content = await import_node_fs28.promises.readFile(import_node_path62.default.join(ctx.scanPath, file), "utf8");
|
|
13012
13666
|
if (content.includes(args.registration_snippet)) {
|
|
13013
13667
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
13014
13668
|
}
|
|
@@ -13020,10 +13674,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
13020
13674
|
);
|
|
13021
13675
|
}
|
|
13022
13676
|
const primaryFile = primary.file;
|
|
13023
|
-
const primaryPath =
|
|
13677
|
+
const primaryPath = import_node_path62.default.join(ctx.scanPath, primaryFile);
|
|
13024
13678
|
const filesTouched = [];
|
|
13025
13679
|
const depsAdded = [];
|
|
13026
|
-
const pkgPath =
|
|
13680
|
+
const pkgPath = import_node_path62.default.join(ctx.scanPath, "package.json");
|
|
13027
13681
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13028
13682
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
13029
13683
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -13062,7 +13716,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
13062
13716
|
};
|
|
13063
13717
|
}
|
|
13064
13718
|
for (const file of hookFiles) {
|
|
13065
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13719
|
+
const content = await import_node_fs28.promises.readFile(import_node_path62.default.join(ctx.scanPath, file), "utf8");
|
|
13066
13720
|
if (content.includes(args.registration_snippet)) {
|
|
13067
13721
|
return {
|
|
13068
13722
|
library: args.library,
|
|
@@ -13103,7 +13757,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13103
13757
|
if (!match) {
|
|
13104
13758
|
return { undone: false, message: "no apply found for library" };
|
|
13105
13759
|
}
|
|
13106
|
-
const pkgPath =
|
|
13760
|
+
const pkgPath = import_node_path62.default.join(ctx.scanPath, "package.json");
|
|
13107
13761
|
if (await fileExists2(pkgPath)) {
|
|
13108
13762
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13109
13763
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -13114,7 +13768,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13114
13768
|
}
|
|
13115
13769
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13116
13770
|
for (const file of hookFiles) {
|
|
13117
|
-
const filePath =
|
|
13771
|
+
const filePath = import_node_path62.default.join(ctx.scanPath, file);
|
|
13118
13772
|
const content = await import_node_fs28.promises.readFile(filePath, "utf8");
|
|
13119
13773
|
if (content.includes(match.registration_snippet)) {
|
|
13120
13774
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -13130,39 +13784,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
13130
13784
|
|
|
13131
13785
|
// src/divergences.ts
|
|
13132
13786
|
init_cjs_shims();
|
|
13133
|
-
var
|
|
13787
|
+
var import_types51 = require("@neat.is/types");
|
|
13134
13788
|
function bucketKey(source, target, type) {
|
|
13135
13789
|
return `${type}|${source}|${target}`;
|
|
13136
13790
|
}
|
|
13137
13791
|
function bucketSourceFor(graph, edge) {
|
|
13138
|
-
if (edge.type !==
|
|
13139
|
-
const parsed = (0,
|
|
13792
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) return edge.source;
|
|
13793
|
+
const parsed = (0, import_types51.parseFileId)(edge.source);
|
|
13140
13794
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
13141
13795
|
const target = graph.getNodeAttributes(edge.target);
|
|
13142
|
-
if (target.type !==
|
|
13143
|
-
return (0,
|
|
13796
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) return edge.source;
|
|
13797
|
+
return (0, import_types51.serviceId)(parsed.service);
|
|
13144
13798
|
}
|
|
13145
13799
|
function bucketEdges(graph) {
|
|
13146
13800
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
13147
13801
|
graph.forEachEdge((id, attrs) => {
|
|
13148
13802
|
const e = attrs;
|
|
13149
|
-
const parsed = (0,
|
|
13803
|
+
const parsed = (0, import_types51.parseEdgeId)(id);
|
|
13150
13804
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
13151
13805
|
const source = bucketSourceFor(graph, e);
|
|
13152
13806
|
const key = bucketKey(source, e.target, e.type);
|
|
13153
13807
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
13154
13808
|
switch (provenance) {
|
|
13155
|
-
case
|
|
13809
|
+
case import_types51.Provenance.EXTRACTED:
|
|
13156
13810
|
cur.extracted = e;
|
|
13157
13811
|
break;
|
|
13158
|
-
case
|
|
13812
|
+
case import_types51.Provenance.OBSERVED:
|
|
13159
13813
|
cur.observed = e;
|
|
13160
13814
|
break;
|
|
13161
|
-
case
|
|
13815
|
+
case import_types51.Provenance.INFERRED:
|
|
13162
13816
|
cur.inferred = e;
|
|
13163
13817
|
break;
|
|
13164
13818
|
default:
|
|
13165
|
-
if (e.provenance ===
|
|
13819
|
+
if (e.provenance === import_types51.Provenance.STALE) cur.stale = e;
|
|
13166
13820
|
}
|
|
13167
13821
|
buckets2.set(key, cur);
|
|
13168
13822
|
});
|
|
@@ -13171,22 +13825,22 @@ function bucketEdges(graph) {
|
|
|
13171
13825
|
function nodeIsFrontier(graph, nodeId) {
|
|
13172
13826
|
if (!graph.hasNode(nodeId)) return false;
|
|
13173
13827
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13174
|
-
return attrs.type ===
|
|
13828
|
+
return attrs.type === import_types51.NodeType.FrontierNode;
|
|
13175
13829
|
}
|
|
13176
13830
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
13177
13831
|
if (!graph.hasNode(nodeId)) return false;
|
|
13178
13832
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13179
|
-
return attrs.type ===
|
|
13833
|
+
return attrs.type === import_types51.NodeType.WebSocketChannelNode;
|
|
13180
13834
|
}
|
|
13181
13835
|
function nodeIsServerAction(graph, nodeId) {
|
|
13182
13836
|
if (!graph.hasNode(nodeId)) return false;
|
|
13183
13837
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13184
|
-
return attrs.type ===
|
|
13838
|
+
return attrs.type === import_types51.NodeType.ServerActionNode;
|
|
13185
13839
|
}
|
|
13186
13840
|
function nodeIsSymbol(graph, nodeId) {
|
|
13187
13841
|
if (!graph.hasNode(nodeId)) return false;
|
|
13188
13842
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13189
|
-
return attrs.type ===
|
|
13843
|
+
return attrs.type === import_types51.NodeType.SymbolNode;
|
|
13190
13844
|
}
|
|
13191
13845
|
function clampConfidence(n) {
|
|
13192
13846
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -13206,14 +13860,14 @@ function gradedConfidence(edge) {
|
|
|
13206
13860
|
return clampConfidence(confidenceForEdge(edge));
|
|
13207
13861
|
}
|
|
13208
13862
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13863
|
+
import_types51.EdgeType.CALLS,
|
|
13864
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
13865
|
+
import_types51.EdgeType.PUBLISHES_TO,
|
|
13866
|
+
import_types51.EdgeType.CONSUMES_FROM
|
|
13213
13867
|
]);
|
|
13214
13868
|
function detectMissingDivergences(graph, bucket) {
|
|
13215
13869
|
const out = [];
|
|
13216
|
-
if (bucket.type ===
|
|
13870
|
+
if (bucket.type === import_types51.EdgeType.CONTAINS) return out;
|
|
13217
13871
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
13218
13872
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
13219
13873
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -13255,7 +13909,7 @@ function declaredHostFor(svc) {
|
|
|
13255
13909
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
13256
13910
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13257
13911
|
const e = graph.getEdgeAttributes(edgeId);
|
|
13258
|
-
if (e.type ===
|
|
13912
|
+
if (e.type === import_types51.EdgeType.CONFIGURED_BY && e.provenance === import_types51.Provenance.EXTRACTED) {
|
|
13259
13913
|
return true;
|
|
13260
13914
|
}
|
|
13261
13915
|
}
|
|
@@ -13268,10 +13922,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
13268
13922
|
const out = [];
|
|
13269
13923
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13270
13924
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13271
|
-
if (edge.type !==
|
|
13272
|
-
if (edge.provenance !==
|
|
13925
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13926
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13273
13927
|
const target = graph.getNodeAttributes(edge.target);
|
|
13274
|
-
if (target.type !==
|
|
13928
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13275
13929
|
const observedHost = target.host?.trim();
|
|
13276
13930
|
if (!observedHost) continue;
|
|
13277
13931
|
if (observedHost === declaredHost) continue;
|
|
@@ -13293,10 +13947,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
13293
13947
|
const deps = svc.dependencies ?? {};
|
|
13294
13948
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13295
13949
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13296
|
-
if (edge.type !==
|
|
13297
|
-
if (edge.provenance !==
|
|
13950
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13951
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13298
13952
|
const target = graph.getNodeAttributes(edge.target);
|
|
13299
|
-
if (target.type !==
|
|
13953
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13300
13954
|
for (const pair of compatPairs()) {
|
|
13301
13955
|
if (pair.engine !== target.engine) continue;
|
|
13302
13956
|
const declared = deps[pair.driver];
|
|
@@ -13393,7 +14047,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
13393
14047
|
for (const d of all) {
|
|
13394
14048
|
if (d.type !== "host-mismatch") continue;
|
|
13395
14049
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
13396
|
-
declaredHalf.add((0,
|
|
14050
|
+
declaredHalf.add((0, import_types51.databaseId)(d.extractedHost));
|
|
13397
14051
|
}
|
|
13398
14052
|
if (observedHalf.size === 0) return all;
|
|
13399
14053
|
return all.filter((d) => {
|
|
@@ -13412,13 +14066,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13412
14066
|
}
|
|
13413
14067
|
graph.forEachNode((nodeId, attrs) => {
|
|
13414
14068
|
const n = attrs;
|
|
13415
|
-
if (n.type ===
|
|
14069
|
+
if (n.type === import_types51.NodeType.ServiceNode) {
|
|
13416
14070
|
const svc = n;
|
|
13417
14071
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
13418
14072
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
13419
14073
|
return;
|
|
13420
14074
|
}
|
|
13421
|
-
if (n.type ===
|
|
14075
|
+
if (n.type === import_types51.NodeType.InfraNode && n.kind === "sql-table") {
|
|
13422
14076
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
13423
14077
|
}
|
|
13424
14078
|
});
|
|
@@ -13454,7 +14108,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13454
14108
|
const bc = "column" in b && b.column ? b.column : "";
|
|
13455
14109
|
return ac.localeCompare(bc);
|
|
13456
14110
|
});
|
|
13457
|
-
return
|
|
14111
|
+
return import_types51.DivergenceResultSchema.parse({
|
|
13458
14112
|
divergences: filtered,
|
|
13459
14113
|
totalAffected: filtered.length,
|
|
13460
14114
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -13585,23 +14239,23 @@ function canonicalJson(value) {
|
|
|
13585
14239
|
|
|
13586
14240
|
// src/projects.ts
|
|
13587
14241
|
init_cjs_shims();
|
|
13588
|
-
var
|
|
14242
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
13589
14243
|
function pathsForProject(project, baseDir) {
|
|
13590
14244
|
if (project === DEFAULT_PROJECT) {
|
|
13591
14245
|
return {
|
|
13592
|
-
snapshotPath:
|
|
13593
|
-
errorsPath:
|
|
13594
|
-
staleEventsPath:
|
|
13595
|
-
embeddingsCachePath:
|
|
13596
|
-
policyViolationsPath:
|
|
14246
|
+
snapshotPath: import_node_path63.default.join(baseDir, "graph.json"),
|
|
14247
|
+
errorsPath: import_node_path63.default.join(baseDir, "errors.ndjson"),
|
|
14248
|
+
staleEventsPath: import_node_path63.default.join(baseDir, "stale-events.ndjson"),
|
|
14249
|
+
embeddingsCachePath: import_node_path63.default.join(baseDir, "embeddings.json"),
|
|
14250
|
+
policyViolationsPath: import_node_path63.default.join(baseDir, "policy-violations.ndjson")
|
|
13597
14251
|
};
|
|
13598
14252
|
}
|
|
13599
14253
|
return {
|
|
13600
|
-
snapshotPath:
|
|
13601
|
-
errorsPath:
|
|
13602
|
-
staleEventsPath:
|
|
13603
|
-
embeddingsCachePath:
|
|
13604
|
-
policyViolationsPath:
|
|
14254
|
+
snapshotPath: import_node_path63.default.join(baseDir, `${project}.json`),
|
|
14255
|
+
errorsPath: import_node_path63.default.join(baseDir, `errors.${project}.ndjson`),
|
|
14256
|
+
staleEventsPath: import_node_path63.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
14257
|
+
embeddingsCachePath: import_node_path63.default.join(baseDir, `embeddings.${project}.json`),
|
|
14258
|
+
policyViolationsPath: import_node_path63.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
13605
14259
|
};
|
|
13606
14260
|
}
|
|
13607
14261
|
var Projects = class {
|
|
@@ -13639,26 +14293,26 @@ var Projects = class {
|
|
|
13639
14293
|
init_cjs_shims();
|
|
13640
14294
|
var import_node_fs30 = require("fs");
|
|
13641
14295
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
13642
|
-
var
|
|
13643
|
-
var
|
|
14296
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
14297
|
+
var import_types52 = require("@neat.is/types");
|
|
13644
14298
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
13645
14299
|
var LOCK_RETRY_MS = 50;
|
|
13646
14300
|
function neatHome() {
|
|
13647
14301
|
const override = process.env.NEAT_HOME;
|
|
13648
|
-
if (override && override.length > 0) return
|
|
13649
|
-
return
|
|
14302
|
+
if (override && override.length > 0) return import_node_path64.default.resolve(override);
|
|
14303
|
+
return import_node_path64.default.join(import_node_os3.default.homedir(), ".neat");
|
|
13650
14304
|
}
|
|
13651
14305
|
function registryPath() {
|
|
13652
|
-
return
|
|
14306
|
+
return import_node_path64.default.join(neatHome(), "projects.json");
|
|
13653
14307
|
}
|
|
13654
14308
|
function registryLockPath() {
|
|
13655
|
-
return
|
|
14309
|
+
return import_node_path64.default.join(neatHome(), "projects.json.lock");
|
|
13656
14310
|
}
|
|
13657
14311
|
function daemonPidPath() {
|
|
13658
|
-
return
|
|
14312
|
+
return import_node_path64.default.join(neatHome(), "neatd.pid");
|
|
13659
14313
|
}
|
|
13660
14314
|
function daemonsDir() {
|
|
13661
|
-
return
|
|
14315
|
+
return import_node_path64.default.join(neatHome(), "daemons");
|
|
13662
14316
|
}
|
|
13663
14317
|
function isFiniteInt(v) {
|
|
13664
14318
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -13699,7 +14353,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
13699
14353
|
const out = [];
|
|
13700
14354
|
for (const name of names) {
|
|
13701
14355
|
if (!name.endsWith(".json")) continue;
|
|
13702
|
-
const file =
|
|
14356
|
+
const file = import_node_path64.default.join(dir, name);
|
|
13703
14357
|
let raw;
|
|
13704
14358
|
try {
|
|
13705
14359
|
raw = await import_node_fs30.promises.readFile(file, "utf8");
|
|
@@ -13776,7 +14430,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
13776
14430
|
}
|
|
13777
14431
|
}
|
|
13778
14432
|
async function normalizeProjectPath(input) {
|
|
13779
|
-
const resolved =
|
|
14433
|
+
const resolved = import_node_path64.default.resolve(input);
|
|
13780
14434
|
try {
|
|
13781
14435
|
return await import_node_fs30.promises.realpath(resolved);
|
|
13782
14436
|
} catch {
|
|
@@ -13784,7 +14438,7 @@ async function normalizeProjectPath(input) {
|
|
|
13784
14438
|
}
|
|
13785
14439
|
}
|
|
13786
14440
|
async function writeAtomically(target, contents) {
|
|
13787
|
-
await import_node_fs30.promises.mkdir(
|
|
14441
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(target), { recursive: true });
|
|
13788
14442
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
13789
14443
|
const fd = await import_node_fs30.promises.open(tmp, "w");
|
|
13790
14444
|
try {
|
|
@@ -13797,7 +14451,7 @@ async function writeAtomically(target, contents) {
|
|
|
13797
14451
|
}
|
|
13798
14452
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
13799
14453
|
const deadline = Date.now() + timeoutMs;
|
|
13800
|
-
await import_node_fs30.promises.mkdir(
|
|
14454
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(lockPath), { recursive: true });
|
|
13801
14455
|
let probedHolder = false;
|
|
13802
14456
|
while (true) {
|
|
13803
14457
|
try {
|
|
@@ -13850,10 +14504,10 @@ async function readRegistry() {
|
|
|
13850
14504
|
throw err;
|
|
13851
14505
|
}
|
|
13852
14506
|
const parsed = JSON.parse(raw);
|
|
13853
|
-
return
|
|
14507
|
+
return import_types52.RegistryFileSchema.parse(parsed);
|
|
13854
14508
|
}
|
|
13855
14509
|
async function writeRegistry(reg) {
|
|
13856
|
-
const validated =
|
|
14510
|
+
const validated = import_types52.RegistryFileSchema.parse(reg);
|
|
13857
14511
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
13858
14512
|
}
|
|
13859
14513
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -14048,7 +14702,7 @@ init_auth();
|
|
|
14048
14702
|
// src/connectors-config.ts
|
|
14049
14703
|
init_cjs_shims();
|
|
14050
14704
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
14051
|
-
var
|
|
14705
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
14052
14706
|
var import_node_fs31 = require("fs");
|
|
14053
14707
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
14054
14708
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -14063,11 +14717,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
14063
14717
|
};
|
|
14064
14718
|
function neatHome2() {
|
|
14065
14719
|
const override = process.env.NEAT_HOME;
|
|
14066
|
-
if (override && override.length > 0) return
|
|
14067
|
-
return
|
|
14720
|
+
if (override && override.length > 0) return import_node_path65.default.resolve(override);
|
|
14721
|
+
return import_node_path65.default.join(import_node_os4.default.homedir(), ".neat");
|
|
14068
14722
|
}
|
|
14069
14723
|
function connectorsConfigPath(home = neatHome2()) {
|
|
14070
|
-
return
|
|
14724
|
+
return import_node_path65.default.join(home, "connectors.json");
|
|
14071
14725
|
}
|
|
14072
14726
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
14073
14727
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -14254,15 +14908,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
14254
14908
|
|
|
14255
14909
|
// src/connectors/index.ts
|
|
14256
14910
|
init_cjs_shims();
|
|
14257
|
-
var
|
|
14911
|
+
var import_types53 = require("@neat.is/types");
|
|
14258
14912
|
var NO_ENV = "unknown";
|
|
14259
14913
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
14260
14914
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14261
14915
|
const sites = [];
|
|
14262
14916
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
14263
14917
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
14264
|
-
if (edge.provenance !==
|
|
14265
|
-
const parsed = (0,
|
|
14918
|
+
if (edge.provenance !== import_types53.Provenance.EXTRACTED) continue;
|
|
14919
|
+
const parsed = (0, import_types53.parseFileId)(edge.source);
|
|
14266
14920
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
14267
14921
|
const site = { relPath: edge.evidence.file };
|
|
14268
14922
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -14273,7 +14927,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
14273
14927
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
14274
14928
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14275
14929
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
14276
|
-
if (attrs.type !==
|
|
14930
|
+
if (attrs.type !== import_types53.NodeType.RouteNode || !attrs.path) return void 0;
|
|
14277
14931
|
const site = { relPath: attrs.path };
|
|
14278
14932
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
14279
14933
|
return site;
|
|
@@ -14754,10 +15408,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
14754
15408
|
// src/connectors/supabase/map.ts
|
|
14755
15409
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
14756
15410
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
14757
|
-
function targetFromRestPath(
|
|
14758
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
15411
|
+
function targetFromRestPath(path68) {
|
|
15412
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path68);
|
|
14759
15413
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
14760
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
15414
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path68);
|
|
14761
15415
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
14762
15416
|
return null;
|
|
14763
15417
|
}
|
|
@@ -14868,23 +15522,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
14868
15522
|
|
|
14869
15523
|
// src/connectors/supabase/resolve.ts
|
|
14870
15524
|
init_cjs_shims();
|
|
14871
|
-
var
|
|
15525
|
+
var import_types55 = require("@neat.is/types");
|
|
14872
15526
|
function createSupabaseResolveTarget(graph, config) {
|
|
14873
15527
|
return (signal, _ctx) => {
|
|
14874
15528
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
14875
15529
|
return null;
|
|
14876
15530
|
}
|
|
14877
|
-
const subResourceId = (0,
|
|
15531
|
+
const subResourceId = (0, import_types55.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
14878
15532
|
if (graph.hasNode(subResourceId)) {
|
|
14879
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
15533
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14880
15534
|
}
|
|
14881
|
-
const bareResourceId = (0,
|
|
15535
|
+
const bareResourceId = (0, import_types55.infraId)(signal.targetKind, signal.targetName);
|
|
14882
15536
|
if (graph.hasNode(bareResourceId)) {
|
|
14883
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
15537
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14884
15538
|
}
|
|
14885
|
-
const projectLevelId = (0,
|
|
15539
|
+
const projectLevelId = (0, import_types55.infraId)("supabase", config.nodeRef);
|
|
14886
15540
|
if (graph.hasNode(projectLevelId)) {
|
|
14887
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
15541
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14888
15542
|
}
|
|
14889
15543
|
return null;
|
|
14890
15544
|
};
|
|
@@ -14977,7 +15631,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
14977
15631
|
|
|
14978
15632
|
// src/connectors/railway/index.ts
|
|
14979
15633
|
init_cjs_shims();
|
|
14980
|
-
var
|
|
15634
|
+
var import_types59 = require("@neat.is/types");
|
|
14981
15635
|
|
|
14982
15636
|
// src/connectors/railway/client.ts
|
|
14983
15637
|
init_cjs_shims();
|
|
@@ -15128,7 +15782,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
15128
15782
|
const out = [];
|
|
15129
15783
|
graph.forEachNode((_id, attrs) => {
|
|
15130
15784
|
const node = attrs;
|
|
15131
|
-
if (node.type !==
|
|
15785
|
+
if (node.type !== import_types59.NodeType.RouteNode) return;
|
|
15132
15786
|
const route = attrs;
|
|
15133
15787
|
if (route.service !== serviceName) return;
|
|
15134
15788
|
out.push({
|
|
@@ -15232,12 +15886,12 @@ function createRailwayResolveTarget(config) {
|
|
|
15232
15886
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
15233
15887
|
if (!serviceName) return null;
|
|
15234
15888
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
15235
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
15889
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types59.EdgeType.CALLS };
|
|
15236
15890
|
}
|
|
15237
15891
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
15238
15892
|
const peerName = config.serviceNameById[signal.targetName];
|
|
15239
15893
|
if (!peerName) return null;
|
|
15240
|
-
return { targetNodeId: (0,
|
|
15894
|
+
return { targetNodeId: (0, import_types59.serviceId)(peerName), serviceName, edgeType: import_types59.EdgeType.CONNECTS_TO };
|
|
15241
15895
|
}
|
|
15242
15896
|
return null;
|
|
15243
15897
|
};
|
|
@@ -15361,9 +16015,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
15361
16015
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
15362
16016
|
if (secondSep === -1) return null;
|
|
15363
16017
|
const method = rest.slice(0, secondSep);
|
|
15364
|
-
const
|
|
15365
|
-
if (!resourceName || !method || !
|
|
15366
|
-
return { resourceName, method, path:
|
|
16018
|
+
const path68 = rest.slice(secondSep + 1);
|
|
16019
|
+
if (!resourceName || !method || !path68) return null;
|
|
16020
|
+
return { resourceName, method, path: path68 };
|
|
15367
16021
|
}
|
|
15368
16022
|
function resourceNameFor(type, labels) {
|
|
15369
16023
|
if (!labels) return null;
|
|
@@ -15401,14 +16055,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
15401
16055
|
if (!req) return null;
|
|
15402
16056
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
15403
16057
|
const method = req.requestMethod.toUpperCase();
|
|
15404
|
-
const
|
|
15405
|
-
if (
|
|
16058
|
+
const path68 = pathFromRequestUrl(req.requestUrl);
|
|
16059
|
+
if (path68 === null) return null;
|
|
15406
16060
|
const timestamp = entry.timestamp;
|
|
15407
16061
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15408
16062
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
15409
16063
|
return {
|
|
15410
16064
|
targetKind: resourceType,
|
|
15411
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
16065
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path68 }),
|
|
15412
16066
|
callCount: 1,
|
|
15413
16067
|
errorCount: isError ? 1 : 0,
|
|
15414
16068
|
lastObservedIso: timestamp
|
|
@@ -15425,7 +16079,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
15425
16079
|
|
|
15426
16080
|
// src/connectors/firebase/resolve.ts
|
|
15427
16081
|
init_cjs_shims();
|
|
15428
|
-
var
|
|
16082
|
+
var import_types60 = require("@neat.is/types");
|
|
15429
16083
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
15430
16084
|
switch (resourceType) {
|
|
15431
16085
|
case "cloud_function":
|
|
@@ -15440,7 +16094,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
15440
16094
|
const entries = [];
|
|
15441
16095
|
graph.forEachNode((_id, attrs) => {
|
|
15442
16096
|
const node = attrs;
|
|
15443
|
-
if (node.type !==
|
|
16097
|
+
if (node.type !== import_types60.NodeType.RouteNode) return;
|
|
15444
16098
|
const route = attrs;
|
|
15445
16099
|
if (route.service !== serviceName) return;
|
|
15446
16100
|
entries.push({
|
|
@@ -15472,7 +16126,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
15472
16126
|
return {
|
|
15473
16127
|
targetNodeId: match.routeNodeId,
|
|
15474
16128
|
serviceName,
|
|
15475
|
-
edgeType:
|
|
16129
|
+
edgeType: import_types60.EdgeType.CALLS
|
|
15476
16130
|
};
|
|
15477
16131
|
};
|
|
15478
16132
|
}
|
|
@@ -15499,7 +16153,7 @@ init_cjs_shims();
|
|
|
15499
16153
|
|
|
15500
16154
|
// src/connectors/cloudflare/connector.ts
|
|
15501
16155
|
init_cjs_shims();
|
|
15502
|
-
var
|
|
16156
|
+
var import_types62 = require("@neat.is/types");
|
|
15503
16157
|
|
|
15504
16158
|
// src/connectors/cloudflare/client.ts
|
|
15505
16159
|
init_cjs_shims();
|
|
@@ -15615,7 +16269,7 @@ function mapEventToSignal(event) {
|
|
|
15615
16269
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
15616
16270
|
const statusCode = metadata?.statusCode;
|
|
15617
16271
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
15618
|
-
const
|
|
16272
|
+
const path68 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
15619
16273
|
return {
|
|
15620
16274
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
15621
16275
|
targetName: scriptName,
|
|
@@ -15623,7 +16277,7 @@ function mapEventToSignal(event) {
|
|
|
15623
16277
|
errorCount: isError ? 1 : 0,
|
|
15624
16278
|
lastObservedIso: observedAt.toISOString(),
|
|
15625
16279
|
method,
|
|
15626
|
-
...
|
|
16280
|
+
...path68 ? { path: path68 } : {},
|
|
15627
16281
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
15628
16282
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
15629
16283
|
};
|
|
@@ -15663,19 +16317,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
15663
16317
|
graph.forEachNode((id, attrs) => {
|
|
15664
16318
|
if (found) return;
|
|
15665
16319
|
const a = attrs;
|
|
15666
|
-
if (a.type ===
|
|
16320
|
+
if (a.type === import_types62.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
15667
16321
|
found = id;
|
|
15668
16322
|
}
|
|
15669
16323
|
});
|
|
15670
16324
|
return found;
|
|
15671
16325
|
}
|
|
15672
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
15673
|
-
const normalizedPath = normalizePathTemplate(
|
|
16326
|
+
function findMatchingRouteNode(graph, serviceName, method, path68) {
|
|
16327
|
+
const normalizedPath = normalizePathTemplate(path68);
|
|
15674
16328
|
let found = null;
|
|
15675
16329
|
graph.forEachNode((id, attrs) => {
|
|
15676
16330
|
if (found) return;
|
|
15677
16331
|
const a = attrs;
|
|
15678
|
-
if (a.type !==
|
|
16332
|
+
if (a.type !== import_types62.NodeType.RouteNode || a.service !== serviceName) return;
|
|
15679
16333
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
15680
16334
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
15681
16335
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -15687,18 +16341,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15687
16341
|
return (signal) => {
|
|
15688
16342
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
15689
16343
|
const scriptName = signal.targetName;
|
|
15690
|
-
const { method, path:
|
|
16344
|
+
const { method, path: path68 } = signal;
|
|
15691
16345
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
15692
|
-
if (!method || !
|
|
15693
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
16346
|
+
if (!method || !path68) return wholeFileId;
|
|
16347
|
+
return findMatchingRouteNode(graph, serviceName, method, path68) ?? wholeFileId;
|
|
15694
16348
|
};
|
|
15695
16349
|
const mapping = config.workers?.[scriptName];
|
|
15696
16350
|
if (mapping) {
|
|
15697
|
-
const wholeFileId = (0,
|
|
16351
|
+
const wholeFileId = (0, import_types62.fileId)(mapping.service, mapping.entryFile);
|
|
15698
16352
|
return {
|
|
15699
16353
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
15700
16354
|
serviceName: mapping.service,
|
|
15701
|
-
edgeType:
|
|
16355
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15702
16356
|
};
|
|
15703
16357
|
}
|
|
15704
16358
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -15707,13 +16361,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15707
16361
|
return {
|
|
15708
16362
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
15709
16363
|
serviceName: fileNode.service,
|
|
15710
|
-
edgeType:
|
|
16364
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15711
16365
|
};
|
|
15712
16366
|
}
|
|
15713
16367
|
return {
|
|
15714
|
-
targetNodeId: (0,
|
|
16368
|
+
targetNodeId: (0, import_types62.infraId)("cloudflare-worker", scriptName),
|
|
15715
16369
|
serviceName: scriptName,
|
|
15716
|
-
edgeType:
|
|
16370
|
+
edgeType: import_types62.EdgeType.CALLS,
|
|
15717
16371
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
15718
16372
|
};
|
|
15719
16373
|
};
|
|
@@ -15909,14 +16563,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
15909
16563
|
|
|
15910
16564
|
// src/connectors/neon/resolve.ts
|
|
15911
16565
|
init_cjs_shims();
|
|
15912
|
-
var
|
|
16566
|
+
var import_types66 = require("@neat.is/types");
|
|
15913
16567
|
function createNeonResolveTarget(config) {
|
|
15914
16568
|
return (signal) => {
|
|
15915
16569
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
15916
16570
|
return {
|
|
15917
|
-
targetNodeId: (0,
|
|
16571
|
+
targetNodeId: (0, import_types66.infraId)("sql-table", signal.targetName),
|
|
15918
16572
|
serviceName: config.serviceName,
|
|
15919
|
-
edgeType:
|
|
16573
|
+
edgeType: import_types66.EdgeType.CALLS,
|
|
15920
16574
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
15921
16575
|
};
|
|
15922
16576
|
};
|
|
@@ -16042,9 +16696,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
16042
16696
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
16043
16697
|
if (secondSep === -1) return null;
|
|
16044
16698
|
const method = rest.slice(0, secondSep);
|
|
16045
|
-
const
|
|
16046
|
-
if (!serviceName || !method || !
|
|
16047
|
-
return { serviceName, method, path:
|
|
16699
|
+
const path68 = rest.slice(secondSep + 1);
|
|
16700
|
+
if (!serviceName || !method || !path68) return null;
|
|
16701
|
+
return { serviceName, method, path: path68 };
|
|
16048
16702
|
}
|
|
16049
16703
|
|
|
16050
16704
|
// src/connectors/cloud-run/map.ts
|
|
@@ -16073,14 +16727,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
16073
16727
|
if (!req) return null;
|
|
16074
16728
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
16075
16729
|
const method = req.requestMethod.toUpperCase();
|
|
16076
|
-
const
|
|
16077
|
-
if (
|
|
16730
|
+
const path68 = pathFromRequestUrl2(req.requestUrl);
|
|
16731
|
+
if (path68 === null) return null;
|
|
16078
16732
|
const timestamp = entry.timestamp;
|
|
16079
16733
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
16080
16734
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
16081
16735
|
return {
|
|
16082
16736
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
16083
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
16737
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path68 }),
|
|
16084
16738
|
callCount: 1,
|
|
16085
16739
|
errorCount: isError ? 1 : 0,
|
|
16086
16740
|
lastObservedIso: timestamp
|
|
@@ -16097,14 +16751,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
16097
16751
|
|
|
16098
16752
|
// src/connectors/cloud-run/resolve.ts
|
|
16099
16753
|
init_cjs_shims();
|
|
16100
|
-
var
|
|
16754
|
+
var import_types70 = require("@neat.is/types");
|
|
16101
16755
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
16102
16756
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
16103
16757
|
let found = null;
|
|
16104
16758
|
graph.forEachNode((_id, attrs) => {
|
|
16105
16759
|
if (found) return;
|
|
16106
16760
|
const node = attrs;
|
|
16107
|
-
if (node.type !==
|
|
16761
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
16108
16762
|
const route = attrs;
|
|
16109
16763
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
16110
16764
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -16119,23 +16773,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
16119
16773
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
16120
16774
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
16121
16775
|
if (!identity) return null;
|
|
16122
|
-
const { serviceName: gcpServiceName, method, path:
|
|
16776
|
+
const { serviceName: gcpServiceName, method, path: path68 } = identity;
|
|
16123
16777
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
16124
16778
|
if (mappedService) {
|
|
16125
16779
|
const routeNodeId = findMatchingRouteNode2(
|
|
16126
16780
|
graph,
|
|
16127
16781
|
mappedService,
|
|
16128
16782
|
method,
|
|
16129
|
-
normalizePathTemplate(
|
|
16783
|
+
normalizePathTemplate(path68)
|
|
16130
16784
|
);
|
|
16131
16785
|
if (routeNodeId) {
|
|
16132
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
16786
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types70.EdgeType.CALLS };
|
|
16133
16787
|
}
|
|
16134
16788
|
}
|
|
16135
16789
|
return {
|
|
16136
|
-
targetNodeId: (0,
|
|
16790
|
+
targetNodeId: (0, import_types70.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
16137
16791
|
serviceName: mappedService ?? gcpServiceName,
|
|
16138
|
-
edgeType:
|
|
16792
|
+
edgeType: import_types70.EdgeType.CALLS,
|
|
16139
16793
|
ensureInfraNode: {
|
|
16140
16794
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
16141
16795
|
name: gcpServiceName,
|
|
@@ -16176,7 +16830,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
16176
16830
|
|
|
16177
16831
|
// src/connectors/render/index.ts
|
|
16178
16832
|
init_cjs_shims();
|
|
16179
|
-
var
|
|
16833
|
+
var import_types73 = require("@neat.is/types");
|
|
16180
16834
|
|
|
16181
16835
|
// src/connectors/render/types.ts
|
|
16182
16836
|
init_cjs_shims();
|
|
@@ -16254,7 +16908,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
16254
16908
|
const out = [];
|
|
16255
16909
|
graph.forEachNode((_id, attrs) => {
|
|
16256
16910
|
const node = attrs;
|
|
16257
|
-
if (node.type !==
|
|
16911
|
+
if (node.type !== import_types73.NodeType.RouteNode) return;
|
|
16258
16912
|
const route = attrs;
|
|
16259
16913
|
if (route.service !== serviceName) return;
|
|
16260
16914
|
out.push({
|
|
@@ -16339,7 +16993,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
16339
16993
|
function createRenderResolveTarget(config) {
|
|
16340
16994
|
return (signal) => {
|
|
16341
16995
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
16342
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
16996
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types73.EdgeType.CALLS };
|
|
16343
16997
|
}
|
|
16344
16998
|
return null;
|
|
16345
16999
|
};
|
|
@@ -16477,21 +17131,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
16477
17131
|
|
|
16478
17132
|
// src/connectors/planetscale/resolve.ts
|
|
16479
17133
|
init_cjs_shims();
|
|
16480
|
-
var
|
|
17134
|
+
var import_types77 = require("@neat.is/types");
|
|
16481
17135
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
16482
17136
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
16483
17137
|
const databaseName = `${config.organization}/${config.database}`;
|
|
16484
17138
|
return (signal, _ctx) => {
|
|
16485
17139
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
16486
|
-
const tableId = (0,
|
|
17140
|
+
const tableId = (0, import_types77.infraId)("sql-table", signal.targetName);
|
|
16487
17141
|
if (graph.hasNode(tableId)) {
|
|
16488
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
17142
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types77.EdgeType.CALLS };
|
|
16489
17143
|
}
|
|
16490
|
-
const providerId = (0,
|
|
17144
|
+
const providerId = (0, import_types77.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
16491
17145
|
return {
|
|
16492
17146
|
targetNodeId: providerId,
|
|
16493
17147
|
serviceName: config.serviceName,
|
|
16494
|
-
edgeType:
|
|
17148
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
16495
17149
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
16496
17150
|
};
|
|
16497
17151
|
};
|
|
@@ -17161,11 +17815,11 @@ function registerRoutes(scope, ctx) {
|
|
|
17161
17815
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
17162
17816
|
const parsed = [];
|
|
17163
17817
|
for (const c of candidates) {
|
|
17164
|
-
const r =
|
|
17818
|
+
const r = import_types80.DivergenceTypeSchema.safeParse(c);
|
|
17165
17819
|
if (!r.success) {
|
|
17166
17820
|
return reply.code(400).send({
|
|
17167
17821
|
error: `unknown divergence type "${c}"`,
|
|
17168
|
-
allowed:
|
|
17822
|
+
allowed: import_types80.DivergenceTypeSchema.options
|
|
17169
17823
|
});
|
|
17170
17824
|
}
|
|
17171
17825
|
parsed.push(r.data);
|
|
@@ -17474,7 +18128,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17474
18128
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
17475
18129
|
let violations = await log.readAll();
|
|
17476
18130
|
if (req.query.severity) {
|
|
17477
|
-
const sev =
|
|
18131
|
+
const sev = import_types80.PolicySeveritySchema.safeParse(req.query.severity);
|
|
17478
18132
|
if (!sev.success) {
|
|
17479
18133
|
return reply.code(400).send({
|
|
17480
18134
|
error: "invalid severity",
|
|
@@ -17513,7 +18167,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17513
18167
|
scope.post("/policies/check", async (req, reply) => {
|
|
17514
18168
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
17515
18169
|
if (!proj) return;
|
|
17516
|
-
const parsed =
|
|
18170
|
+
const parsed = import_types80.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
17517
18171
|
if (!parsed.success) {
|
|
17518
18172
|
return reply.code(400).send({
|
|
17519
18173
|
error: "invalid /policies/check body",
|
|
@@ -17835,7 +18489,7 @@ init_otel_grpc();
|
|
|
17835
18489
|
// src/daemon.ts
|
|
17836
18490
|
init_cjs_shims();
|
|
17837
18491
|
var import_node_fs33 = require("fs");
|
|
17838
|
-
var
|
|
18492
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
17839
18493
|
var import_node_module = require("module");
|
|
17840
18494
|
init_otel();
|
|
17841
18495
|
init_auth();
|
|
@@ -17843,7 +18497,7 @@ init_auth();
|
|
|
17843
18497
|
// src/unrouted.ts
|
|
17844
18498
|
init_cjs_shims();
|
|
17845
18499
|
var import_node_fs32 = require("fs");
|
|
17846
|
-
var
|
|
18500
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
17847
18501
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
17848
18502
|
return {
|
|
17849
18503
|
timestamp: now.toISOString(),
|
|
@@ -17853,34 +18507,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
17853
18507
|
};
|
|
17854
18508
|
}
|
|
17855
18509
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
17856
|
-
const target =
|
|
18510
|
+
const target = import_node_path66.default.join(neatHome3, "errors.ndjson");
|
|
17857
18511
|
await import_node_fs32.promises.mkdir(neatHome3, { recursive: true });
|
|
17858
18512
|
await import_node_fs32.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
17859
18513
|
}
|
|
17860
18514
|
function unroutedErrorsPath(neatHome3) {
|
|
17861
|
-
return
|
|
18515
|
+
return import_node_path66.default.join(neatHome3, "errors.ndjson");
|
|
17862
18516
|
}
|
|
17863
18517
|
|
|
17864
18518
|
// src/daemon.ts
|
|
17865
|
-
var
|
|
18519
|
+
var import_types81 = require("@neat.is/types");
|
|
17866
18520
|
function daemonJsonPath(scanPath) {
|
|
17867
|
-
return
|
|
18521
|
+
return import_node_path67.default.join(scanPath, "neat-out", "daemon.json");
|
|
17868
18522
|
}
|
|
17869
18523
|
function daemonsDiscoveryDir(home) {
|
|
17870
18524
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
17871
|
-
return
|
|
18525
|
+
return import_node_path67.default.join(base, "daemons");
|
|
17872
18526
|
}
|
|
17873
18527
|
function daemonDiscoveryPath(project, home) {
|
|
17874
|
-
return
|
|
18528
|
+
return import_node_path67.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
17875
18529
|
}
|
|
17876
18530
|
function sanitizeDiscoveryName(project) {
|
|
17877
18531
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
17878
18532
|
}
|
|
17879
18533
|
function neatHomeFromEnv() {
|
|
17880
18534
|
const env = process.env.NEAT_HOME;
|
|
17881
|
-
if (env && env.length > 0) return
|
|
18535
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17882
18536
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17883
|
-
return
|
|
18537
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17884
18538
|
}
|
|
17885
18539
|
function resolveNeatVersion() {
|
|
17886
18540
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -17935,11 +18589,11 @@ function teardownSlot(slot) {
|
|
|
17935
18589
|
}
|
|
17936
18590
|
}
|
|
17937
18591
|
function neatHomeFor(opts) {
|
|
17938
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
18592
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path67.default.resolve(opts.neatHome);
|
|
17939
18593
|
const env = process.env.NEAT_HOME;
|
|
17940
|
-
if (env && env.length > 0) return
|
|
18594
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17941
18595
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17942
|
-
return
|
|
18596
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17943
18597
|
}
|
|
17944
18598
|
function routeSpanToProject(serviceName, projects) {
|
|
17945
18599
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -17987,11 +18641,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
17987
18641
|
if (!serviceName) return true;
|
|
17988
18642
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
17989
18643
|
return graph.someNode(
|
|
17990
|
-
(_id, attrs) => attrs.type ===
|
|
18644
|
+
(_id, attrs) => attrs.type === import_types81.NodeType.ServiceNode && attrs.name === serviceName
|
|
17991
18645
|
);
|
|
17992
18646
|
}
|
|
17993
18647
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
17994
|
-
const paths = pathsForProject(entry.name,
|
|
18648
|
+
const paths = pathsForProject(entry.name, import_node_path67.default.join(entry.path, "neat-out"));
|
|
17995
18649
|
try {
|
|
17996
18650
|
const stat = await import_node_fs33.promises.stat(entry.path);
|
|
17997
18651
|
if (!stat.isDirectory()) {
|
|
@@ -18107,7 +18761,7 @@ async function startDaemon(opts = {}) {
|
|
|
18107
18761
|
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
18762
|
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
18763
|
const singleProject = projectArg;
|
|
18110
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
18764
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path67.default.resolve(projectPathArg) : null;
|
|
18111
18765
|
if (singleProject && !singleProjectPath) {
|
|
18112
18766
|
throw new Error(
|
|
18113
18767
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -18122,7 +18776,7 @@ async function startDaemon(opts = {}) {
|
|
|
18122
18776
|
);
|
|
18123
18777
|
}
|
|
18124
18778
|
}
|
|
18125
|
-
const pidPath =
|
|
18779
|
+
const pidPath = import_node_path67.default.join(home, "neatd.pid");
|
|
18126
18780
|
await writeAtomically(pidPath, `${process.pid}
|
|
18127
18781
|
`);
|
|
18128
18782
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -18534,8 +19188,8 @@ async function startDaemon(opts = {}) {
|
|
|
18534
19188
|
let registryWatcher = null;
|
|
18535
19189
|
let reloadTimer = null;
|
|
18536
19190
|
if (!singleProject) try {
|
|
18537
|
-
const regDir =
|
|
18538
|
-
const regBase =
|
|
19191
|
+
const regDir = import_node_path67.default.dirname(regPath);
|
|
19192
|
+
const regBase = import_node_path67.default.basename(regPath);
|
|
18539
19193
|
registryWatcher = (0, import_node_fs33.watch)(regDir, (_eventType, filename) => {
|
|
18540
19194
|
if (filename !== null && filename !== regBase) return;
|
|
18541
19195
|
if (reloadTimer) clearTimeout(reloadTimer);
|