@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/neatd.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req2, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path70 = (req2.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path70) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path70)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -343,7 +343,7 @@ function pickEnv(spanAttrs, resourceAttrs) {
|
|
|
343
343
|
return ENV_FALLBACK;
|
|
344
344
|
}
|
|
345
345
|
function normalizeDbSystem(attrs) {
|
|
346
|
-
const raw = attrs["db.system"];
|
|
346
|
+
const raw = attrs["db.system"] ?? attrs["db.system.name"];
|
|
347
347
|
if (typeof raw !== "string") return void 0;
|
|
348
348
|
return raw === "mongoose" ? "mongodb" : raw;
|
|
349
349
|
}
|
|
@@ -415,8 +415,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
415
415
|
const v = attrs[key];
|
|
416
416
|
if (typeof v === "string" && v.length > 0) {
|
|
417
417
|
const q = v.indexOf("?");
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
418
|
+
const path70 = q === -1 ? v : v.slice(0, q);
|
|
419
|
+
if (path70.length > 0) return path70;
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
return void 0;
|
|
@@ -435,6 +435,9 @@ function parseOtlpRequest(body) {
|
|
|
435
435
|
for (const ss of rs.scopeSpans ?? []) {
|
|
436
436
|
for (const span of ss.spans ?? []) {
|
|
437
437
|
const attrs = attrsToRecord(span.attributes);
|
|
438
|
+
const dbSqlText = typeof attrs["db.statement"] === "string" ? attrs["db.statement"] : typeof attrs["db.query.text"] === "string" ? attrs["db.query.text"] : void 0;
|
|
439
|
+
const dbSystemName = normalizeDbSystem(attrs);
|
|
440
|
+
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;
|
|
438
441
|
const parsed = {
|
|
439
442
|
service,
|
|
440
443
|
resourceServiceNamePresent,
|
|
@@ -449,11 +452,11 @@ function parseOtlpRequest(body) {
|
|
|
449
452
|
durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),
|
|
450
453
|
env: pickEnv(attrs, resourceAttrs),
|
|
451
454
|
attributes: attrs,
|
|
452
|
-
dbSystem:
|
|
455
|
+
dbSystem: dbSystemName,
|
|
453
456
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
454
457
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
455
|
-
dbTable:
|
|
456
|
-
dbColumns:
|
|
458
|
+
dbTable: directDbTable ?? (dbSqlText ? tableFromSqlStatement(dbSqlText) ?? void 0 : void 0),
|
|
459
|
+
dbColumns: dbSqlText ? columnsFromSqlStatement(dbSqlText) : void 0,
|
|
457
460
|
httpRoute: typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0,
|
|
458
461
|
httpMethod: typeof attrs["http.request.method"] === "string" ? attrs["http.request.method"] : typeof attrs["http.method"] === "string" ? attrs["http.method"] : void 0,
|
|
459
462
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
@@ -738,13 +741,13 @@ __export(neatd_exports, {
|
|
|
738
741
|
module.exports = __toCommonJS(neatd_exports);
|
|
739
742
|
init_cjs_shims();
|
|
740
743
|
var import_node_fs35 = require("fs");
|
|
741
|
-
var
|
|
744
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
742
745
|
var import_node_module2 = require("module");
|
|
743
746
|
|
|
744
747
|
// src/daemon.ts
|
|
745
748
|
init_cjs_shims();
|
|
746
749
|
var import_node_fs33 = require("fs");
|
|
747
|
-
var
|
|
750
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
748
751
|
var import_node_module = require("module");
|
|
749
752
|
|
|
750
753
|
// src/graph.ts
|
|
@@ -1277,19 +1280,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1277
1280
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1278
1281
|
let best = { path: [start], edges: [] };
|
|
1279
1282
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1280
|
-
function step(node,
|
|
1281
|
-
if (
|
|
1282
|
-
best = { path: [...
|
|
1283
|
+
function step(node, path70, edges) {
|
|
1284
|
+
if (path70.length > best.path.length) {
|
|
1285
|
+
best = { path: [...path70], edges: [...edges] };
|
|
1283
1286
|
}
|
|
1284
|
-
if (
|
|
1287
|
+
if (path70.length - 1 >= maxDepth) return;
|
|
1285
1288
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1286
1289
|
for (const [srcId, edge] of incoming) {
|
|
1287
1290
|
if (visited.has(srcId)) continue;
|
|
1288
1291
|
visited.add(srcId);
|
|
1289
|
-
|
|
1292
|
+
path70.push(srcId);
|
|
1290
1293
|
edges.push(edge);
|
|
1291
|
-
step(srcId,
|
|
1292
|
-
|
|
1294
|
+
step(srcId, path70, edges);
|
|
1295
|
+
path70.pop();
|
|
1293
1296
|
edges.pop();
|
|
1294
1297
|
visited.delete(srcId);
|
|
1295
1298
|
}
|
|
@@ -1297,11 +1300,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1297
1300
|
step(start, [start], []);
|
|
1298
1301
|
return best;
|
|
1299
1302
|
}
|
|
1300
|
-
function databaseRootCauseShape(graph, origin,
|
|
1303
|
+
function databaseRootCauseShape(graph, origin, walk9) {
|
|
1301
1304
|
const targetDb = origin;
|
|
1302
1305
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1303
1306
|
if (candidatePairs.length === 0) return null;
|
|
1304
|
-
for (const id of
|
|
1307
|
+
for (const id of walk9.path) {
|
|
1305
1308
|
const owner = resolveOwningService(graph, id);
|
|
1306
1309
|
if (!owner) continue;
|
|
1307
1310
|
const { id: serviceId9, svc } = owner;
|
|
@@ -1328,8 +1331,8 @@ function databaseRootCauseShape(graph, origin, walk8) {
|
|
|
1328
1331
|
}
|
|
1329
1332
|
return null;
|
|
1330
1333
|
}
|
|
1331
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1332
|
-
for (const id of
|
|
1334
|
+
function serviceRootCauseShape(graph, _origin, walk9) {
|
|
1335
|
+
for (const id of walk9.path) {
|
|
1333
1336
|
const owner = resolveOwningService(graph, id);
|
|
1334
1337
|
if (!owner) continue;
|
|
1335
1338
|
const { id: serviceId9, svc } = owner;
|
|
@@ -1365,15 +1368,15 @@ function serviceRootCauseShape(graph, _origin, walk8) {
|
|
|
1365
1368
|
}
|
|
1366
1369
|
return null;
|
|
1367
1370
|
}
|
|
1368
|
-
function fileRootCauseShape(graph, origin,
|
|
1371
|
+
function fileRootCauseShape(graph, origin, walk9) {
|
|
1369
1372
|
const owner = resolveOwningService(graph, origin.id);
|
|
1370
1373
|
if (!owner) return null;
|
|
1371
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1374
|
+
return serviceRootCauseShape(graph, owner.svc, walk9);
|
|
1372
1375
|
}
|
|
1373
|
-
function symbolRootCauseShape(graph, origin,
|
|
1376
|
+
function symbolRootCauseShape(graph, origin, walk9) {
|
|
1374
1377
|
const owner = resolveOwningService(graph, origin.id);
|
|
1375
1378
|
if (!owner) return null;
|
|
1376
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1379
|
+
return serviceRootCauseShape(graph, owner.svc, walk9);
|
|
1377
1380
|
}
|
|
1378
1381
|
var rootCauseShapes = {
|
|
1379
1382
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1386,16 +1389,16 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1386
1389
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1387
1390
|
const shape = rootCauseShapes[origin.type];
|
|
1388
1391
|
if (shape) {
|
|
1389
|
-
const
|
|
1390
|
-
const match = shape(graph, origin,
|
|
1392
|
+
const walk9 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1393
|
+
const match = shape(graph, origin, walk9);
|
|
1391
1394
|
if (match) {
|
|
1392
1395
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1393
1396
|
return import_types.RootCauseResultSchema.parse({
|
|
1394
1397
|
rootCauseNode: match.rootCauseNode,
|
|
1395
1398
|
rootCauseReason: reason,
|
|
1396
|
-
traversalPath:
|
|
1397
|
-
edgeProvenances:
|
|
1398
|
-
confidence: confidenceFromMix(
|
|
1399
|
+
traversalPath: walk9.path,
|
|
1400
|
+
edgeProvenances: walk9.edges.map((e) => e.provenance),
|
|
1401
|
+
confidence: confidenceFromMix(walk9.edges),
|
|
1399
1402
|
fixRecommendation: match.fixRecommendation
|
|
1400
1403
|
});
|
|
1401
1404
|
}
|
|
@@ -1496,26 +1499,26 @@ function dominantFailingCall(graph, serviceId9, visited) {
|
|
|
1496
1499
|
return best;
|
|
1497
1500
|
}
|
|
1498
1501
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1499
|
-
const
|
|
1502
|
+
const path70 = [originServiceId];
|
|
1500
1503
|
const edges = [];
|
|
1501
1504
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1502
1505
|
let current = originServiceId;
|
|
1503
1506
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1504
1507
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1505
1508
|
if (!hop) break;
|
|
1506
|
-
|
|
1509
|
+
path70.push(hop.nextService);
|
|
1507
1510
|
edges.push(hop.edge);
|
|
1508
1511
|
visited.add(hop.nextService);
|
|
1509
1512
|
current = hop.nextService;
|
|
1510
1513
|
}
|
|
1511
1514
|
if (edges.length === 0) return null;
|
|
1512
|
-
return { path:
|
|
1515
|
+
return { path: path70, edges, culprit: current };
|
|
1513
1516
|
}
|
|
1514
1517
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1515
1518
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1516
1519
|
if (!chain) return null;
|
|
1517
1520
|
const culprit = chain.culprit;
|
|
1518
|
-
const
|
|
1521
|
+
const path70 = [...chain.path];
|
|
1519
1522
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1520
1523
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1521
1524
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1523,14 +1526,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1523
1526
|
if (loc) {
|
|
1524
1527
|
let rootCauseNode = culprit;
|
|
1525
1528
|
if (loc.fileNode) {
|
|
1526
|
-
|
|
1529
|
+
path70.push(loc.fileNode);
|
|
1527
1530
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1528
1531
|
rootCauseNode = loc.fileNode;
|
|
1529
1532
|
}
|
|
1530
1533
|
return import_types.RootCauseResultSchema.parse({
|
|
1531
1534
|
rootCauseNode,
|
|
1532
1535
|
rootCauseReason: loc.rootCauseReason,
|
|
1533
|
-
traversalPath:
|
|
1536
|
+
traversalPath: path70,
|
|
1534
1537
|
edgeProvenances,
|
|
1535
1538
|
confidence,
|
|
1536
1539
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1542,7 +1545,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1542
1545
|
return import_types.RootCauseResultSchema.parse({
|
|
1543
1546
|
rootCauseNode: culprit,
|
|
1544
1547
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1545
|
-
traversalPath:
|
|
1548
|
+
traversalPath: path70,
|
|
1546
1549
|
edgeProvenances,
|
|
1547
1550
|
confidence,
|
|
1548
1551
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2477,14 +2480,14 @@ function buildServiceHostIndex(services) {
|
|
|
2477
2480
|
}
|
|
2478
2481
|
async function walkSourceFiles(dir) {
|
|
2479
2482
|
const out = [];
|
|
2480
|
-
async function
|
|
2483
|
+
async function walk9(current) {
|
|
2481
2484
|
const entries = await import_node_fs5.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2482
2485
|
for (const entry2 of entries) {
|
|
2483
2486
|
const full = import_node_path5.default.join(current, entry2.name);
|
|
2484
2487
|
if (entry2.isDirectory()) {
|
|
2485
2488
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
2486
2489
|
if (await isPythonVenvDir(full)) continue;
|
|
2487
|
-
await
|
|
2490
|
+
await walk9(full);
|
|
2488
2491
|
} else if (entry2.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path5.default.extname(entry2.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
2489
2492
|
// would attribute our instrumentation imports to the user's service.
|
|
2490
2493
|
!isNeatAuthoredSourceFile(entry2.name)) {
|
|
@@ -2492,7 +2495,7 @@ async function walkSourceFiles(dir) {
|
|
|
2492
2495
|
}
|
|
2493
2496
|
}
|
|
2494
2497
|
}
|
|
2495
|
-
await
|
|
2498
|
+
await walk9(dir);
|
|
2496
2499
|
return out;
|
|
2497
2500
|
}
|
|
2498
2501
|
async function loadSourceFiles(dir) {
|
|
@@ -3005,8 +3008,9 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
3005
3008
|
"all"
|
|
3006
3009
|
]);
|
|
3007
3010
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3011
|
+
var NET_HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3008
3012
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
3009
|
-
function
|
|
3013
|
+
function goRouterRoutesFromSource(source, parser, framework) {
|
|
3010
3014
|
const tree = parseSource2(parser, source);
|
|
3011
3015
|
const prefixes = /* @__PURE__ */ new Map();
|
|
3012
3016
|
const out = [];
|
|
@@ -3016,10 +3020,12 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3016
3020
|
const value = node.childForFieldName("right")?.namedChild(0) ?? node.childForFieldName("value");
|
|
3017
3021
|
if (name && value?.type === "call_expression") {
|
|
3018
3022
|
const fn2 = value.childForFieldName("function");
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
+
if (fn2?.childForFieldName("field")?.text === "Group") {
|
|
3024
|
+
const leaf2 = goStringLiteral(value.childForFieldName("arguments")?.namedChild(0));
|
|
3025
|
+
if (leaf2 !== null) {
|
|
3026
|
+
const parent = fn2.childForFieldName("operand")?.text ?? "";
|
|
3027
|
+
prefixes.set(name, (prefixes.get(parent) ?? "") + leaf2);
|
|
3028
|
+
}
|
|
3023
3029
|
}
|
|
3024
3030
|
}
|
|
3025
3031
|
return;
|
|
@@ -3030,18 +3036,127 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3030
3036
|
const method = fn.childForFieldName("field")?.text?.toUpperCase();
|
|
3031
3037
|
if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return;
|
|
3032
3038
|
const receiver = fn.childForFieldName("operand")?.text ?? "";
|
|
3033
|
-
const
|
|
3034
|
-
if (
|
|
3035
|
-
const leaf = first.text.slice(1, -1);
|
|
3039
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3040
|
+
if (leaf === null) return;
|
|
3036
3041
|
out.push({
|
|
3037
|
-
method
|
|
3042
|
+
method,
|
|
3038
3043
|
pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? "") + leaf),
|
|
3039
3044
|
line: node.startPosition.row + 1,
|
|
3040
|
-
framework
|
|
3045
|
+
framework
|
|
3046
|
+
});
|
|
3047
|
+
});
|
|
3048
|
+
return out;
|
|
3049
|
+
}
|
|
3050
|
+
function goStringLiteral(node) {
|
|
3051
|
+
if (node?.type === "interpreted_string_literal" || node?.type === "raw_string_literal") {
|
|
3052
|
+
return node.text.slice(1, -1);
|
|
3053
|
+
}
|
|
3054
|
+
return null;
|
|
3055
|
+
}
|
|
3056
|
+
function ginRoutesFromSource(source, parser) {
|
|
3057
|
+
return goRouterRoutesFromSource(source, parser, "gin");
|
|
3058
|
+
}
|
|
3059
|
+
function echoRoutesFromSource(source, parser) {
|
|
3060
|
+
return goRouterRoutesFromSource(source, parser, "echo");
|
|
3061
|
+
}
|
|
3062
|
+
function fiberRoutesFromSource(source, parser) {
|
|
3063
|
+
return goRouterRoutesFromSource(source, parser, "fiber");
|
|
3064
|
+
}
|
|
3065
|
+
function chiRoutesFromSource(source, parser) {
|
|
3066
|
+
const tree = parseSource2(parser, source);
|
|
3067
|
+
const out = [];
|
|
3068
|
+
chiWalk(tree.rootNode, "", out);
|
|
3069
|
+
return out;
|
|
3070
|
+
}
|
|
3071
|
+
function stripChiRegex(path70) {
|
|
3072
|
+
return path70.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
3073
|
+
}
|
|
3074
|
+
function chiWalk(node, prefix, out) {
|
|
3075
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3076
|
+
const child = node.namedChild(i);
|
|
3077
|
+
if (child) chiHandle(child, prefix, out);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
function chiHandle(node, prefix, out) {
|
|
3081
|
+
if (node.type === "call_expression") {
|
|
3082
|
+
const fn = node.childForFieldName("function");
|
|
3083
|
+
if (fn?.type === "selector_expression") {
|
|
3084
|
+
const field = fn.childForFieldName("field")?.text;
|
|
3085
|
+
const args = node.childForFieldName("arguments");
|
|
3086
|
+
if (field === "Route") {
|
|
3087
|
+
const leaf = goStringLiteral(args?.namedChild(0));
|
|
3088
|
+
const closure = args?.namedChild(1);
|
|
3089
|
+
if (leaf !== null && closure?.type === "func_literal") {
|
|
3090
|
+
const body = closure.childForFieldName("body");
|
|
3091
|
+
if (body) chiWalk(body, prefix + leaf, out);
|
|
3092
|
+
}
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
if (field === "Group") {
|
|
3096
|
+
const closure = args?.namedChild(0);
|
|
3097
|
+
if (closure?.type === "func_literal") {
|
|
3098
|
+
const body = closure.childForFieldName("body");
|
|
3099
|
+
if (body) chiWalk(body, prefix, out);
|
|
3100
|
+
}
|
|
3101
|
+
return;
|
|
3102
|
+
}
|
|
3103
|
+
if (field === "Mount") {
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
if (field && ROUTER_METHODS.has(field.toLowerCase())) {
|
|
3107
|
+
const leaf = goStringLiteral(args?.namedChild(0));
|
|
3108
|
+
if (leaf !== null) {
|
|
3109
|
+
out.push({
|
|
3110
|
+
method: field.toUpperCase(),
|
|
3111
|
+
pathTemplate: canonicalizeTemplate(stripChiRegex(prefix + leaf)),
|
|
3112
|
+
line: node.startPosition.row + 1,
|
|
3113
|
+
framework: "chi"
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
chiWalk(node, prefix, out);
|
|
3121
|
+
}
|
|
3122
|
+
function netHttpRoutesFromSource(source, parser) {
|
|
3123
|
+
const tree = parseSource2(parser, source);
|
|
3124
|
+
if (!goImportsNetHttp(tree.rootNode)) return [];
|
|
3125
|
+
const out = [];
|
|
3126
|
+
walk(tree.rootNode, (node) => {
|
|
3127
|
+
if (node.type !== "call_expression") return;
|
|
3128
|
+
const fn = node.childForFieldName("function");
|
|
3129
|
+
if (fn?.type !== "selector_expression") return;
|
|
3130
|
+
const field = fn.childForFieldName("field")?.text;
|
|
3131
|
+
if (field !== "HandleFunc" && field !== "Handle") return;
|
|
3132
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3133
|
+
if (leaf === null) return;
|
|
3134
|
+
const sp = leaf.indexOf(" ");
|
|
3135
|
+
if (sp < 0) return;
|
|
3136
|
+
const method = leaf.slice(0, sp);
|
|
3137
|
+
const rest = leaf.slice(sp + 1);
|
|
3138
|
+
if (!NET_HTTP_METHODS.has(method)) return;
|
|
3139
|
+
if (!rest.startsWith("/")) return;
|
|
3140
|
+
out.push({
|
|
3141
|
+
method,
|
|
3142
|
+
pathTemplate: canonicalizeTemplate(rest),
|
|
3143
|
+
line: node.startPosition.row + 1,
|
|
3144
|
+
framework: "net/http"
|
|
3041
3145
|
});
|
|
3042
3146
|
});
|
|
3043
3147
|
return out;
|
|
3044
3148
|
}
|
|
3149
|
+
function goImportsNetHttp(root) {
|
|
3150
|
+
let found = false;
|
|
3151
|
+
walk(root, (node) => {
|
|
3152
|
+
if (found || node.type !== "import_spec") return;
|
|
3153
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3154
|
+
const child = node.namedChild(i);
|
|
3155
|
+
if (goStringLiteral(child) === "net/http") found = true;
|
|
3156
|
+
}
|
|
3157
|
+
});
|
|
3158
|
+
return found;
|
|
3159
|
+
}
|
|
3045
3160
|
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
3046
3161
|
var NESTJS_METHODS = /* @__PURE__ */ new Map([
|
|
3047
3162
|
["Get", "GET"],
|
|
@@ -3626,9 +3741,9 @@ function rubyRocketRoute(args) {
|
|
|
3626
3741
|
if (!pair || pair.type !== "pair") continue;
|
|
3627
3742
|
const k = pair.childForFieldName("key");
|
|
3628
3743
|
if (k?.type !== "string") continue;
|
|
3629
|
-
const
|
|
3630
|
-
if (
|
|
3631
|
-
return { path:
|
|
3744
|
+
const path70 = rubyLiteral(k);
|
|
3745
|
+
if (path70 === null) continue;
|
|
3746
|
+
return { path: path70, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3632
3747
|
}
|
|
3633
3748
|
return null;
|
|
3634
3749
|
}
|
|
@@ -4305,9 +4420,13 @@ async function addRoutes(graph, services) {
|
|
|
4305
4420
|
const hasFlask = deps["flask"] !== void 0;
|
|
4306
4421
|
const hasDjango = deps["django"] !== void 0;
|
|
4307
4422
|
const hasGin = deps["github.com/gin-gonic/gin"] !== void 0;
|
|
4423
|
+
const hasEcho = deps["github.com/labstack/echo/v4"] !== void 0 || deps["github.com/labstack/echo"] !== void 0;
|
|
4424
|
+
const hasFiber = deps["github.com/gofiber/fiber/v2"] !== void 0 || deps["github.com/gofiber/fiber/v3"] !== void 0;
|
|
4425
|
+
const hasChi = deps["github.com/go-chi/chi/v5"] !== void 0 || deps["github.com/go-chi/chi"] !== void 0;
|
|
4426
|
+
const isGoService = service.node.language === "go";
|
|
4308
4427
|
const hasRails = deps["rails"] !== void 0;
|
|
4309
4428
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4310
|
-
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasRails && !hasLaravel)
|
|
4429
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel)
|
|
4311
4430
|
continue;
|
|
4312
4431
|
const files = await loadSourceFiles(service.dir);
|
|
4313
4432
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4331,7 +4450,12 @@ async function addRoutes(graph, services) {
|
|
|
4331
4450
|
} else if (isRb) {
|
|
4332
4451
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4333
4452
|
} else if (isGo) {
|
|
4334
|
-
routes =
|
|
4453
|
+
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4454
|
+
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
4455
|
+
else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser);
|
|
4456
|
+
else if (hasChi) routes = chiRoutesFromSource(file.content, goParser);
|
|
4457
|
+
else routes = [];
|
|
4458
|
+
routes = routes.concat(netHttpRoutesFromSource(file.content, goParser));
|
|
4335
4459
|
} else if (isPy) {
|
|
4336
4460
|
routes = hasFastapi || hasFlask ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? "fastapi" : "flask") : [];
|
|
4337
4461
|
if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser));
|
|
@@ -5938,6 +6062,13 @@ function parseGoMod(source) {
|
|
|
5938
6062
|
}
|
|
5939
6063
|
return { module: module2, ...goVersion ? { goVersion } : {}, dependencies };
|
|
5940
6064
|
}
|
|
6065
|
+
function goFramework(deps) {
|
|
6066
|
+
if (deps["github.com/gin-gonic/gin"]) return "gin";
|
|
6067
|
+
if (deps["github.com/labstack/echo/v4"] || deps["github.com/labstack/echo"]) return "echo";
|
|
6068
|
+
if (deps["github.com/gofiber/fiber/v2"] || deps["github.com/gofiber/fiber/v3"]) return "fiber";
|
|
6069
|
+
if (deps["github.com/go-chi/chi/v5"] || deps["github.com/go-chi/chi"]) return "chi";
|
|
6070
|
+
return void 0;
|
|
6071
|
+
}
|
|
5941
6072
|
async function discoverGoService(scanPath, dir) {
|
|
5942
6073
|
let raw;
|
|
5943
6074
|
try {
|
|
@@ -5949,6 +6080,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5949
6080
|
if (!mod) return null;
|
|
5950
6081
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
5951
6082
|
const pkg = { name, dependencies: mod.dependencies };
|
|
6083
|
+
const framework = goFramework(mod.dependencies);
|
|
5952
6084
|
const node = {
|
|
5953
6085
|
id: (0, import_types9.serviceId)(name),
|
|
5954
6086
|
type: import_types9.NodeType.ServiceNode,
|
|
@@ -5956,7 +6088,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5956
6088
|
language: "go",
|
|
5957
6089
|
dependencies: mod.dependencies,
|
|
5958
6090
|
repoPath: import_node_path10.default.relative(scanPath, dir),
|
|
5959
|
-
...
|
|
6091
|
+
...framework ? { framework } : {}
|
|
5960
6092
|
};
|
|
5961
6093
|
return { pkg, dir, node };
|
|
5962
6094
|
}
|
|
@@ -6856,7 +6988,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
6856
6988
|
return best;
|
|
6857
6989
|
};
|
|
6858
6990
|
const requests = [];
|
|
6859
|
-
const
|
|
6991
|
+
const walk9 = (node) => {
|
|
6860
6992
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
6861
6993
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
6862
6994
|
if (self && self.kind === "class") {
|
|
@@ -6902,10 +7034,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
6902
7034
|
}
|
|
6903
7035
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6904
7036
|
const child = node.namedChild(i);
|
|
6905
|
-
if (child)
|
|
7037
|
+
if (child) walk9(child);
|
|
6906
7038
|
}
|
|
6907
7039
|
};
|
|
6908
|
-
|
|
7040
|
+
walk9(root);
|
|
6909
7041
|
for (const req2 of requests) {
|
|
6910
7042
|
const targetSid = resolveTarget(req2.targetName, req2.wantKind);
|
|
6911
7043
|
if (!targetSid) continue;
|
|
@@ -7918,20 +8050,20 @@ var import_node_path28 = __toESM(require("path"), 1);
|
|
|
7918
8050
|
var import_types18 = require("@neat.is/types");
|
|
7919
8051
|
async function walkConfigFiles(dir) {
|
|
7920
8052
|
const out = [];
|
|
7921
|
-
async function
|
|
8053
|
+
async function walk9(current) {
|
|
7922
8054
|
const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true });
|
|
7923
8055
|
for (const entry2 of entries) {
|
|
7924
8056
|
const full = import_node_path28.default.join(current, entry2.name);
|
|
7925
8057
|
if (entry2.isDirectory()) {
|
|
7926
8058
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
7927
8059
|
if (await isPythonVenvDir(full)) continue;
|
|
7928
|
-
await
|
|
8060
|
+
await walk9(full);
|
|
7929
8061
|
} else if (entry2.isFile() && isConfigFile(entry2.name).match) {
|
|
7930
8062
|
out.push(full);
|
|
7931
8063
|
}
|
|
7932
8064
|
}
|
|
7933
8065
|
}
|
|
7934
|
-
await
|
|
8066
|
+
await walk9(dir);
|
|
7935
8067
|
return out;
|
|
7936
8068
|
}
|
|
7937
8069
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -8021,20 +8153,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
8021
8153
|
}
|
|
8022
8154
|
async function walkProtoFiles(dir) {
|
|
8023
8155
|
const out = [];
|
|
8024
|
-
async function
|
|
8156
|
+
async function walk9(current) {
|
|
8025
8157
|
const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
8026
8158
|
for (const entry2 of entries) {
|
|
8027
8159
|
const full = import_node_path29.default.join(current, entry2.name);
|
|
8028
8160
|
if (entry2.isDirectory()) {
|
|
8029
8161
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
8030
8162
|
if (await isPythonVenvDir(full)) continue;
|
|
8031
|
-
await
|
|
8163
|
+
await walk9(full);
|
|
8032
8164
|
} else if (entry2.isFile() && import_node_path29.default.extname(entry2.name) === PROTO_EXTENSION) {
|
|
8033
8165
|
out.push(full);
|
|
8034
8166
|
}
|
|
8035
8167
|
}
|
|
8036
8168
|
}
|
|
8037
|
-
await
|
|
8169
|
+
await walk9(dir);
|
|
8038
8170
|
return out;
|
|
8039
8171
|
}
|
|
8040
8172
|
async function addGrpcMethods(graph, services) {
|
|
@@ -8102,7 +8234,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
8102
8234
|
|
|
8103
8235
|
// src/extract/calls/index.ts
|
|
8104
8236
|
init_cjs_shims();
|
|
8105
|
-
var
|
|
8237
|
+
var import_types37 = require("@neat.is/types");
|
|
8106
8238
|
|
|
8107
8239
|
// src/extract/calls/http.ts
|
|
8108
8240
|
init_cjs_shims();
|
|
@@ -8856,7 +8988,7 @@ function isFirestoreClientFactory(node) {
|
|
|
8856
8988
|
}
|
|
8857
8989
|
function firestoreClientVars(root) {
|
|
8858
8990
|
const vars = /* @__PURE__ */ new Set();
|
|
8859
|
-
const
|
|
8991
|
+
const walk9 = (node) => {
|
|
8860
8992
|
if (node.type === "variable_declarator") {
|
|
8861
8993
|
const name = node.childForFieldName("name");
|
|
8862
8994
|
let value = node.childForFieldName("value");
|
|
@@ -8865,9 +8997,9 @@ function firestoreClientVars(root) {
|
|
|
8865
8997
|
vars.add(name.text);
|
|
8866
8998
|
}
|
|
8867
8999
|
}
|
|
8868
|
-
for (const c of namedChildren(node))
|
|
9000
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
8869
9001
|
};
|
|
8870
|
-
|
|
9002
|
+
walk9(root);
|
|
8871
9003
|
return vars;
|
|
8872
9004
|
}
|
|
8873
9005
|
function isClientExpr(node, clientVars) {
|
|
@@ -9022,7 +9154,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9022
9154
|
}
|
|
9023
9155
|
s.add(field);
|
|
9024
9156
|
};
|
|
9025
|
-
const
|
|
9157
|
+
const walk9 = (node) => {
|
|
9026
9158
|
if (node.type === "call_expression") {
|
|
9027
9159
|
const fn = node.childForFieldName("function");
|
|
9028
9160
|
const line = node.startPosition.row + 1;
|
|
@@ -9062,9 +9194,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9062
9194
|
}
|
|
9063
9195
|
}
|
|
9064
9196
|
}
|
|
9065
|
-
for (const c of namedChildren(node))
|
|
9197
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
9066
9198
|
};
|
|
9067
|
-
|
|
9199
|
+
walk9(tree.rootNode);
|
|
9068
9200
|
const out = [];
|
|
9069
9201
|
for (const [collPath, line] of collLine) {
|
|
9070
9202
|
const byField = writes.get(collPath);
|
|
@@ -9859,7 +9991,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9859
9991
|
const tree = parseSource3(parserForExt2(import_node_path41.default.extname(file.path)), file.content);
|
|
9860
9992
|
const out = [];
|
|
9861
9993
|
const seen = /* @__PURE__ */ new Set();
|
|
9862
|
-
const
|
|
9994
|
+
const walk9 = (node) => {
|
|
9863
9995
|
if (node.type === "call_expression") {
|
|
9864
9996
|
const fn = node.childForFieldName("function");
|
|
9865
9997
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9887,9 +10019,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9887
10019
|
}
|
|
9888
10020
|
}
|
|
9889
10021
|
}
|
|
9890
|
-
for (const c of namedChildren4(node))
|
|
10022
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9891
10023
|
};
|
|
9892
|
-
|
|
10024
|
+
walk9(tree.rootNode);
|
|
9893
10025
|
return out;
|
|
9894
10026
|
}
|
|
9895
10027
|
function enclosingVarName(call) {
|
|
@@ -9911,7 +10043,7 @@ function enclosingVarName(call) {
|
|
|
9911
10043
|
function collectDrizzleTables(root) {
|
|
9912
10044
|
const tables = [];
|
|
9913
10045
|
const varToTable = /* @__PURE__ */ new Map();
|
|
9914
|
-
const
|
|
10046
|
+
const walk9 = (node) => {
|
|
9915
10047
|
if (node.type === "call_expression") {
|
|
9916
10048
|
const fn = node.childForFieldName("function");
|
|
9917
10049
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9926,9 +10058,9 @@ function collectDrizzleTables(root) {
|
|
|
9926
10058
|
}
|
|
9927
10059
|
}
|
|
9928
10060
|
}
|
|
9929
|
-
for (const c of namedChildren4(node))
|
|
10061
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9930
10062
|
};
|
|
9931
|
-
|
|
10063
|
+
walk9(root);
|
|
9932
10064
|
return { tables, varToTable };
|
|
9933
10065
|
}
|
|
9934
10066
|
function referencesTargetVar(call) {
|
|
@@ -9951,7 +10083,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
9951
10083
|
const seen = /* @__PURE__ */ new Set();
|
|
9952
10084
|
for (const table of tables) {
|
|
9953
10085
|
if (!table.object) continue;
|
|
9954
|
-
const
|
|
10086
|
+
const walk9 = (node) => {
|
|
9955
10087
|
if (node.type === "call_expression") {
|
|
9956
10088
|
const targetVar = referencesTargetVar(node);
|
|
9957
10089
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -9972,9 +10104,9 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
9972
10104
|
}
|
|
9973
10105
|
}
|
|
9974
10106
|
}
|
|
9975
|
-
for (const c of namedChildren4(node))
|
|
10107
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9976
10108
|
};
|
|
9977
|
-
|
|
10109
|
+
walk9(table.object);
|
|
9978
10110
|
}
|
|
9979
10111
|
return out;
|
|
9980
10112
|
}
|
|
@@ -11054,15 +11186,531 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
11054
11186
|
return out;
|
|
11055
11187
|
}
|
|
11056
11188
|
|
|
11189
|
+
// src/extract/calls/gorm.ts
|
|
11190
|
+
init_cjs_shims();
|
|
11191
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11192
|
+
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
11193
|
+
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
11194
|
+
var import_types36 = require("@neat.is/types");
|
|
11195
|
+
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
11196
|
+
var PARSE_CHUNK11 = 16384;
|
|
11197
|
+
function makeGoParser3() {
|
|
11198
|
+
const p = new import_tree_sitter15.default();
|
|
11199
|
+
p.setLanguage(import_tree_sitter_go4.default);
|
|
11200
|
+
return p;
|
|
11201
|
+
}
|
|
11202
|
+
function parseSource10(parser, source) {
|
|
11203
|
+
return parser.parse(
|
|
11204
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
11205
|
+
);
|
|
11206
|
+
}
|
|
11207
|
+
function walk8(node, visit) {
|
|
11208
|
+
visit(node);
|
|
11209
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11210
|
+
const c = node.namedChild(i);
|
|
11211
|
+
if (c) walk8(c, visit);
|
|
11212
|
+
}
|
|
11213
|
+
}
|
|
11214
|
+
var COMMON_INITIALISMS = [
|
|
11215
|
+
"ASCII",
|
|
11216
|
+
"HTTPS",
|
|
11217
|
+
"UTF8",
|
|
11218
|
+
"XSRF",
|
|
11219
|
+
"HTML",
|
|
11220
|
+
"HTTP",
|
|
11221
|
+
"JSON",
|
|
11222
|
+
"UUID",
|
|
11223
|
+
"XMPP",
|
|
11224
|
+
"ACL",
|
|
11225
|
+
"API",
|
|
11226
|
+
"CPU",
|
|
11227
|
+
"CSS",
|
|
11228
|
+
"DNS",
|
|
11229
|
+
"EOF",
|
|
11230
|
+
"GUID",
|
|
11231
|
+
"LHS",
|
|
11232
|
+
"QPS",
|
|
11233
|
+
"RAM",
|
|
11234
|
+
"RHS",
|
|
11235
|
+
"RPC",
|
|
11236
|
+
"SLA",
|
|
11237
|
+
"SQL",
|
|
11238
|
+
"SSH",
|
|
11239
|
+
"TCP",
|
|
11240
|
+
"TLS",
|
|
11241
|
+
"TTL",
|
|
11242
|
+
"UDP",
|
|
11243
|
+
"UID",
|
|
11244
|
+
"URI",
|
|
11245
|
+
"URL",
|
|
11246
|
+
"UID",
|
|
11247
|
+
"XSS",
|
|
11248
|
+
"ID",
|
|
11249
|
+
"IP",
|
|
11250
|
+
"UI",
|
|
11251
|
+
"VM",
|
|
11252
|
+
"XML"
|
|
11253
|
+
].sort((a, b) => b.length - a.length);
|
|
11254
|
+
function titleCase(word) {
|
|
11255
|
+
return word.charAt(0) + word.slice(1).toLowerCase();
|
|
11256
|
+
}
|
|
11257
|
+
function replaceInitialisms(name) {
|
|
11258
|
+
let out = "";
|
|
11259
|
+
let i = 0;
|
|
11260
|
+
while (i < name.length) {
|
|
11261
|
+
let matched = false;
|
|
11262
|
+
for (const init of COMMON_INITIALISMS) {
|
|
11263
|
+
if (name.startsWith(init, i)) {
|
|
11264
|
+
out += titleCase(init);
|
|
11265
|
+
i += init.length;
|
|
11266
|
+
matched = true;
|
|
11267
|
+
break;
|
|
11268
|
+
}
|
|
11269
|
+
}
|
|
11270
|
+
if (!matched) {
|
|
11271
|
+
out += name[i];
|
|
11272
|
+
i++;
|
|
11273
|
+
}
|
|
11274
|
+
}
|
|
11275
|
+
return out;
|
|
11276
|
+
}
|
|
11277
|
+
var isUpper = (c) => c >= "A" && c <= "Z";
|
|
11278
|
+
var isDigit = (c) => c >= "0" && c <= "9";
|
|
11279
|
+
function toDBName(name) {
|
|
11280
|
+
if (name === "") return "";
|
|
11281
|
+
const value = replaceInitialisms(name);
|
|
11282
|
+
if (value.length === 1) return value.toLowerCase();
|
|
11283
|
+
let buf = "";
|
|
11284
|
+
let lastCase = false;
|
|
11285
|
+
let curCase = isUpper(value[0]);
|
|
11286
|
+
for (let i = 0; i < value.length - 1; i++) {
|
|
11287
|
+
const v = value[i];
|
|
11288
|
+
const nextCase = isUpper(value[i + 1]);
|
|
11289
|
+
const nextNumber = isDigit(value[i + 1]);
|
|
11290
|
+
if (curCase) {
|
|
11291
|
+
if (lastCase && (nextCase || nextNumber)) {
|
|
11292
|
+
buf += v.toLowerCase();
|
|
11293
|
+
} else {
|
|
11294
|
+
if (i > 0 && value[i - 1] !== "_" && lastCase !== curCase) buf += "_";
|
|
11295
|
+
buf += v.toLowerCase();
|
|
11296
|
+
}
|
|
11297
|
+
} else {
|
|
11298
|
+
buf += v;
|
|
11299
|
+
}
|
|
11300
|
+
lastCase = curCase;
|
|
11301
|
+
curCase = nextCase;
|
|
11302
|
+
}
|
|
11303
|
+
const last = value[value.length - 1];
|
|
11304
|
+
if (curCase) {
|
|
11305
|
+
if (!lastCase && value.length > 1) buf += "_";
|
|
11306
|
+
buf += last.toLowerCase();
|
|
11307
|
+
} else {
|
|
11308
|
+
buf += last;
|
|
11309
|
+
}
|
|
11310
|
+
return buf;
|
|
11311
|
+
}
|
|
11312
|
+
var UNCOUNTABLE = /* @__PURE__ */ new Set([
|
|
11313
|
+
"equipment",
|
|
11314
|
+
"information",
|
|
11315
|
+
"rice",
|
|
11316
|
+
"money",
|
|
11317
|
+
"species",
|
|
11318
|
+
"series",
|
|
11319
|
+
"fish",
|
|
11320
|
+
"sheep",
|
|
11321
|
+
"jeans",
|
|
11322
|
+
"police"
|
|
11323
|
+
]);
|
|
11324
|
+
var IRREGULAR = [
|
|
11325
|
+
["person", "people"],
|
|
11326
|
+
["man", "men"],
|
|
11327
|
+
["child", "children"],
|
|
11328
|
+
["sex", "sexes"],
|
|
11329
|
+
["move", "moves"]
|
|
11330
|
+
];
|
|
11331
|
+
var PLURAL_RULES = [
|
|
11332
|
+
[/(quiz)$/i, "$1zes"],
|
|
11333
|
+
[/^(ox)$/i, "$1en"],
|
|
11334
|
+
[/([ml])ouse$/i, "$1ice"],
|
|
11335
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"],
|
|
11336
|
+
[/(x|ch|ss|sh)$/i, "$1es"],
|
|
11337
|
+
[/([^aeiouy]|qu)y$/i, "$1ies"],
|
|
11338
|
+
[/(hive)$/i, "$1s"],
|
|
11339
|
+
[/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
|
|
11340
|
+
[/sis$/i, "ses"],
|
|
11341
|
+
[/([ti])um$/i, "$1a"],
|
|
11342
|
+
[/([ti])a$/i, "$1a"],
|
|
11343
|
+
[/(buffal|tomat)o$/i, "$1oes"],
|
|
11344
|
+
[/(bu)s$/i, "$1ses"],
|
|
11345
|
+
[/(alias|status)$/i, "$1es"],
|
|
11346
|
+
[/(octop|vir)i$/i, "$1i"],
|
|
11347
|
+
[/(octop|vir)us$/i, "$1i"],
|
|
11348
|
+
[/(ax|test)is$/i, "$1es"],
|
|
11349
|
+
[/s$/i, "s"]
|
|
11350
|
+
];
|
|
11351
|
+
function pluralize3(word) {
|
|
11352
|
+
if (word === "") return word;
|
|
11353
|
+
const lower = word.toLowerCase();
|
|
11354
|
+
for (const u of UNCOUNTABLE) {
|
|
11355
|
+
if (lower === u || lower.endsWith("_" + u)) return word;
|
|
11356
|
+
}
|
|
11357
|
+
for (const [sing, plur] of IRREGULAR) {
|
|
11358
|
+
const re = new RegExp(sing + "$", "i");
|
|
11359
|
+
if (re.test(word)) return word.replace(re, plur);
|
|
11360
|
+
}
|
|
11361
|
+
for (const [re, rep] of PLURAL_RULES) {
|
|
11362
|
+
if (re.test(word)) return word.replace(re, rep);
|
|
11363
|
+
}
|
|
11364
|
+
return word + "s";
|
|
11365
|
+
}
|
|
11366
|
+
function deriveTableName(structName) {
|
|
11367
|
+
return pluralize3(toDBName(structName));
|
|
11368
|
+
}
|
|
11369
|
+
function stringLiteralValue(node) {
|
|
11370
|
+
if (!node) return null;
|
|
11371
|
+
if (node.type === "interpreted_string_literal" || node.type === "raw_string_literal") {
|
|
11372
|
+
const t = node.text;
|
|
11373
|
+
return t.length >= 2 ? t.slice(1, -1) : "";
|
|
11374
|
+
}
|
|
11375
|
+
return null;
|
|
11376
|
+
}
|
|
11377
|
+
function parseGormTag(tagNode) {
|
|
11378
|
+
const tag = {};
|
|
11379
|
+
if (!tagNode) return tag;
|
|
11380
|
+
let inner = tagNode.text;
|
|
11381
|
+
if (inner.length >= 2) inner = inner.slice(1, -1);
|
|
11382
|
+
if (tagNode.type === "interpreted_string_literal") inner = inner.replace(/\\"/g, '"');
|
|
11383
|
+
const m = inner.match(/gorm:"([^"]*)"/);
|
|
11384
|
+
if (!m) return tag;
|
|
11385
|
+
for (const part of m[1].split(";")) {
|
|
11386
|
+
if (part === "") continue;
|
|
11387
|
+
const idx = part.indexOf(":");
|
|
11388
|
+
const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase();
|
|
11389
|
+
const value = idx >= 0 ? part.slice(idx + 1).trim() : "";
|
|
11390
|
+
if (key === "-") tag.skip = true;
|
|
11391
|
+
else if (key === "column") tag.column = value;
|
|
11392
|
+
else if (key === "primarykey" || key === "primary_key") tag.primaryKey = true;
|
|
11393
|
+
else if (key === "foreignkey") tag.foreignKey = value;
|
|
11394
|
+
else if (key === "many2many") tag.many2many = value;
|
|
11395
|
+
else if (key === "embedded") tag.embedded = true;
|
|
11396
|
+
else if (key === "embeddedprefix") tag.embeddedPrefix = value;
|
|
11397
|
+
}
|
|
11398
|
+
return tag;
|
|
11399
|
+
}
|
|
11400
|
+
function unwrapType(typeNode) {
|
|
11401
|
+
let isSlice = false;
|
|
11402
|
+
let isPointer = false;
|
|
11403
|
+
let n = typeNode;
|
|
11404
|
+
while (n && (n.type === "slice_type" || n.type === "array_type" || n.type === "pointer_type")) {
|
|
11405
|
+
if (n.type === "slice_type" || n.type === "array_type") isSlice = true;
|
|
11406
|
+
if (n.type === "pointer_type") isPointer = true;
|
|
11407
|
+
n = n.childForFieldName("element") ?? n.namedChild(n.namedChildCount - 1);
|
|
11408
|
+
}
|
|
11409
|
+
if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11410
|
+
if (n.type === "type_identifier") {
|
|
11411
|
+
return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11412
|
+
}
|
|
11413
|
+
if (n.type === "qualified_type") {
|
|
11414
|
+
const pkg = n.childForFieldName("package")?.text ?? n.namedChild(0)?.text ?? null;
|
|
11415
|
+
const nm = n.childForFieldName("name")?.text ?? n.namedChild(1)?.text ?? null;
|
|
11416
|
+
return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true };
|
|
11417
|
+
}
|
|
11418
|
+
return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11419
|
+
}
|
|
11420
|
+
function readField(fieldDecl) {
|
|
11421
|
+
const names = [];
|
|
11422
|
+
let tagNode = null;
|
|
11423
|
+
for (let i = 0; i < fieldDecl.namedChildCount; i++) {
|
|
11424
|
+
const c = fieldDecl.namedChild(i);
|
|
11425
|
+
if (!c) continue;
|
|
11426
|
+
if (c.type === "field_identifier") names.push(c.text);
|
|
11427
|
+
else if (c.type === "raw_string_literal" || c.type === "interpreted_string_literal") tagNode = c;
|
|
11428
|
+
}
|
|
11429
|
+
const typeNode = fieldDecl.childForFieldName("type");
|
|
11430
|
+
const t = unwrapType(typeNode);
|
|
11431
|
+
return {
|
|
11432
|
+
names,
|
|
11433
|
+
typeName: t.name,
|
|
11434
|
+
qualifier: t.qualifier,
|
|
11435
|
+
isSlice: t.isSlice,
|
|
11436
|
+
isPointer: t.isPointer,
|
|
11437
|
+
isQualified: t.isQualified,
|
|
11438
|
+
tag: parseGormTag(tagNode),
|
|
11439
|
+
line: fieldDecl.startPosition.row + 1
|
|
11440
|
+
};
|
|
11441
|
+
}
|
|
11442
|
+
function collectStructs(tree) {
|
|
11443
|
+
const structs = /* @__PURE__ */ new Map();
|
|
11444
|
+
walk8(tree.rootNode, (node) => {
|
|
11445
|
+
if (node.type !== "type_spec") return;
|
|
11446
|
+
const nameNode = node.childForFieldName("name");
|
|
11447
|
+
const typeNode = node.childForFieldName("type");
|
|
11448
|
+
if (!nameNode || typeNode?.type !== "struct_type") return;
|
|
11449
|
+
const list = typeNode.childForFieldName("body") ?? typeNode.namedChild(0);
|
|
11450
|
+
const fields = [];
|
|
11451
|
+
if (list && list.type === "field_declaration_list") {
|
|
11452
|
+
for (let i = 0; i < list.namedChildCount; i++) {
|
|
11453
|
+
const fd = list.namedChild(i);
|
|
11454
|
+
if (fd?.type === "field_declaration") fields.push(readField(fd));
|
|
11455
|
+
}
|
|
11456
|
+
}
|
|
11457
|
+
structs.set(nameNode.text, {
|
|
11458
|
+
name: nameNode.text,
|
|
11459
|
+
fields,
|
|
11460
|
+
line: node.startPosition.row + 1
|
|
11461
|
+
});
|
|
11462
|
+
});
|
|
11463
|
+
return structs;
|
|
11464
|
+
}
|
|
11465
|
+
var GORM_MODEL_METHODS = /* @__PURE__ */ new Set([
|
|
11466
|
+
"AutoMigrate",
|
|
11467
|
+
"Model",
|
|
11468
|
+
"Create",
|
|
11469
|
+
"Find",
|
|
11470
|
+
"First",
|
|
11471
|
+
"Take",
|
|
11472
|
+
"Last",
|
|
11473
|
+
"Save",
|
|
11474
|
+
"Delete",
|
|
11475
|
+
"Where",
|
|
11476
|
+
"FirstOrCreate",
|
|
11477
|
+
"FirstOrInit"
|
|
11478
|
+
]);
|
|
11479
|
+
function compositeStructName(arg) {
|
|
11480
|
+
let n = arg;
|
|
11481
|
+
if (n.type === "unary_expression") n = n.childForFieldName("operand") ?? n.namedChild(0);
|
|
11482
|
+
if (!n || n.type !== "composite_literal") return null;
|
|
11483
|
+
const typeNode = n.childForFieldName("type");
|
|
11484
|
+
if (!typeNode) return null;
|
|
11485
|
+
if (typeNode.type === "type_identifier") return typeNode.text;
|
|
11486
|
+
if (typeNode.type === "qualified_type") {
|
|
11487
|
+
return typeNode.childForFieldName("name")?.text ?? typeNode.namedChild(1)?.text ?? null;
|
|
11488
|
+
}
|
|
11489
|
+
return null;
|
|
11490
|
+
}
|
|
11491
|
+
function collectCallModels(tree) {
|
|
11492
|
+
const models = /* @__PURE__ */ new Set();
|
|
11493
|
+
walk8(tree.rootNode, (node) => {
|
|
11494
|
+
if (node.type !== "call_expression") return;
|
|
11495
|
+
const fn = node.childForFieldName("function");
|
|
11496
|
+
if (fn?.type !== "selector_expression") return;
|
|
11497
|
+
const method = fn.childForFieldName("field")?.text;
|
|
11498
|
+
if (!method || !GORM_MODEL_METHODS.has(method)) return;
|
|
11499
|
+
const args = node.childForFieldName("arguments");
|
|
11500
|
+
if (!args) return;
|
|
11501
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
11502
|
+
const arg = args.namedChild(i);
|
|
11503
|
+
if (!arg) continue;
|
|
11504
|
+
const name = compositeStructName(arg);
|
|
11505
|
+
if (name) models.add(name);
|
|
11506
|
+
}
|
|
11507
|
+
});
|
|
11508
|
+
return models;
|
|
11509
|
+
}
|
|
11510
|
+
function collectTableNameOverrides(tree) {
|
|
11511
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
11512
|
+
const declarers = /* @__PURE__ */ new Set();
|
|
11513
|
+
walk8(tree.rootNode, (node) => {
|
|
11514
|
+
if (node.type !== "method_declaration") return;
|
|
11515
|
+
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
11516
|
+
const receiver = node.childForFieldName("receiver");
|
|
11517
|
+
if (!receiver) return;
|
|
11518
|
+
let recvType = null;
|
|
11519
|
+
for (let i = 0; i < receiver.namedChildCount; i++) {
|
|
11520
|
+
const pd = receiver.namedChild(i);
|
|
11521
|
+
if (pd?.type !== "parameter_declaration") continue;
|
|
11522
|
+
const t = unwrapType(pd.childForFieldName("type"));
|
|
11523
|
+
recvType = t.name;
|
|
11524
|
+
}
|
|
11525
|
+
if (!recvType) return;
|
|
11526
|
+
declarers.add(recvType);
|
|
11527
|
+
const body = node.childForFieldName("body");
|
|
11528
|
+
if (!body) return;
|
|
11529
|
+
let literal = null;
|
|
11530
|
+
walk8(body, (n) => {
|
|
11531
|
+
if (literal !== null) return;
|
|
11532
|
+
if (n.type !== "return_statement") return;
|
|
11533
|
+
const exprList = n.namedChild(0);
|
|
11534
|
+
const first = exprList?.namedChild(0) ?? exprList;
|
|
11535
|
+
const v = stringLiteralValue(first);
|
|
11536
|
+
if (v) literal = v;
|
|
11537
|
+
});
|
|
11538
|
+
if (literal !== null) overrides.set(recvType, literal);
|
|
11539
|
+
});
|
|
11540
|
+
return { overrides, declarers };
|
|
11541
|
+
}
|
|
11542
|
+
function isRelationField(field, structs) {
|
|
11543
|
+
if (field.names.length === 0) return false;
|
|
11544
|
+
if (field.isQualified) return false;
|
|
11545
|
+
if (!field.typeName) return false;
|
|
11546
|
+
return structs.has(field.typeName);
|
|
11547
|
+
}
|
|
11548
|
+
function isGormModelEmbed(field) {
|
|
11549
|
+
return field.names.length === 0 && field.qualifier === "gorm" && field.typeName === "Model";
|
|
11550
|
+
}
|
|
11551
|
+
function analyze(tree) {
|
|
11552
|
+
const structs = collectStructs(tree);
|
|
11553
|
+
const { overrides, declarers } = collectTableNameOverrides(tree);
|
|
11554
|
+
const callModels = collectCallModels(tree);
|
|
11555
|
+
const models = /* @__PURE__ */ new Set();
|
|
11556
|
+
for (const [name, info] of structs) {
|
|
11557
|
+
if (info.fields.some(isGormModelEmbed)) models.add(name);
|
|
11558
|
+
}
|
|
11559
|
+
for (const name of callModels) if (structs.has(name)) models.add(name);
|
|
11560
|
+
for (const name of declarers) if (structs.has(name)) models.add(name);
|
|
11561
|
+
let grew = true;
|
|
11562
|
+
while (grew) {
|
|
11563
|
+
grew = false;
|
|
11564
|
+
for (const name of Array.from(models)) {
|
|
11565
|
+
const info = structs.get(name);
|
|
11566
|
+
if (!info) continue;
|
|
11567
|
+
for (const field of info.fields) {
|
|
11568
|
+
if (!isRelationField(field, structs)) continue;
|
|
11569
|
+
const target = field.typeName;
|
|
11570
|
+
if (!models.has(target) && structs.has(target)) {
|
|
11571
|
+
models.add(target);
|
|
11572
|
+
grew = true;
|
|
11573
|
+
}
|
|
11574
|
+
}
|
|
11575
|
+
}
|
|
11576
|
+
}
|
|
11577
|
+
const tableFor = (structName) => overrides.get(structName) ?? deriveTableName(structName);
|
|
11578
|
+
return { structs, models, tableFor };
|
|
11579
|
+
}
|
|
11580
|
+
function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
11581
|
+
if (seen.has(struct.name)) return;
|
|
11582
|
+
seen.add(struct.name);
|
|
11583
|
+
const add = (col) => {
|
|
11584
|
+
const full = prefix + col;
|
|
11585
|
+
if (!emitted.has(full)) {
|
|
11586
|
+
emitted.add(full);
|
|
11587
|
+
out.push(full);
|
|
11588
|
+
}
|
|
11589
|
+
};
|
|
11590
|
+
for (const field of struct.fields) {
|
|
11591
|
+
if (field.tag.skip) continue;
|
|
11592
|
+
if (field.names.length === 0) {
|
|
11593
|
+
if (isGormModelEmbed(field)) {
|
|
11594
|
+
add("id");
|
|
11595
|
+
add("created_at");
|
|
11596
|
+
add("updated_at");
|
|
11597
|
+
add("deleted_at");
|
|
11598
|
+
} else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11599
|
+
collectColumns(structs.get(field.typeName), structs, seen, prefix, out, emitted);
|
|
11600
|
+
}
|
|
11601
|
+
continue;
|
|
11602
|
+
}
|
|
11603
|
+
if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11604
|
+
collectColumns(
|
|
11605
|
+
structs.get(field.typeName),
|
|
11606
|
+
structs,
|
|
11607
|
+
seen,
|
|
11608
|
+
prefix + (field.tag.embeddedPrefix ?? ""),
|
|
11609
|
+
out,
|
|
11610
|
+
emitted
|
|
11611
|
+
);
|
|
11612
|
+
continue;
|
|
11613
|
+
}
|
|
11614
|
+
if (isRelationField(field, structs)) continue;
|
|
11615
|
+
if (field.names.length === 1 && field.tag.column) {
|
|
11616
|
+
add(field.tag.column);
|
|
11617
|
+
} else {
|
|
11618
|
+
for (const n of field.names) add(toDBName(n));
|
|
11619
|
+
}
|
|
11620
|
+
}
|
|
11621
|
+
seen.delete(struct.name);
|
|
11622
|
+
}
|
|
11623
|
+
function gormEndpointsFromFile(file, serviceDir) {
|
|
11624
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11625
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11626
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11627
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11628
|
+
const out = [];
|
|
11629
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
11630
|
+
for (const name of models) {
|
|
11631
|
+
const struct = structs.get(name);
|
|
11632
|
+
if (!struct) continue;
|
|
11633
|
+
const table = tableFor(name);
|
|
11634
|
+
if (seenTables.has(table)) continue;
|
|
11635
|
+
seenTables.add(table);
|
|
11636
|
+
const columns = [];
|
|
11637
|
+
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
11638
|
+
out.push({
|
|
11639
|
+
infraId: (0, import_types36.infraId)("sql-table", table),
|
|
11640
|
+
name: table,
|
|
11641
|
+
kind: "sql-table",
|
|
11642
|
+
edgeType: "CALLS",
|
|
11643
|
+
confidenceKind: "structural",
|
|
11644
|
+
...columns.length > 0 ? { columns } : {},
|
|
11645
|
+
evidence: {
|
|
11646
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11647
|
+
line: struct.line,
|
|
11648
|
+
snippet: snippet(file.content, struct.line)
|
|
11649
|
+
}
|
|
11650
|
+
});
|
|
11651
|
+
}
|
|
11652
|
+
return out;
|
|
11653
|
+
}
|
|
11654
|
+
function gormForeignKeys(file, serviceDir) {
|
|
11655
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11656
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11657
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11658
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11659
|
+
const out = [];
|
|
11660
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11661
|
+
const emit = (childTable, parentTable, line) => {
|
|
11662
|
+
if (!childTable || !parentTable || childTable === parentTable) return;
|
|
11663
|
+
const key = `${childTable}->${parentTable}`;
|
|
11664
|
+
if (seen.has(key)) return;
|
|
11665
|
+
seen.add(key);
|
|
11666
|
+
out.push({
|
|
11667
|
+
childTable,
|
|
11668
|
+
parentTable,
|
|
11669
|
+
evidence: {
|
|
11670
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11671
|
+
line,
|
|
11672
|
+
snippet: snippet(file.content, line)
|
|
11673
|
+
}
|
|
11674
|
+
});
|
|
11675
|
+
};
|
|
11676
|
+
for (const name of models) {
|
|
11677
|
+
const struct = structs.get(name);
|
|
11678
|
+
if (!struct) continue;
|
|
11679
|
+
const thisTable = tableFor(name);
|
|
11680
|
+
const scalarNames = new Set(
|
|
11681
|
+
struct.fields.filter((f) => f.names.length > 0 && !isRelationField(f, structs)).flatMap((f) => f.names)
|
|
11682
|
+
);
|
|
11683
|
+
for (const field of struct.fields) {
|
|
11684
|
+
if (field.tag.skip) continue;
|
|
11685
|
+
if (!isRelationField(field, structs)) continue;
|
|
11686
|
+
const relTable = tableFor(field.typeName);
|
|
11687
|
+
if (field.tag.many2many) {
|
|
11688
|
+
emit(field.tag.many2many, thisTable, field.line);
|
|
11689
|
+
emit(field.tag.many2many, relTable, field.line);
|
|
11690
|
+
continue;
|
|
11691
|
+
}
|
|
11692
|
+
if (field.isSlice) {
|
|
11693
|
+
emit(relTable, thisTable, field.line);
|
|
11694
|
+
continue;
|
|
11695
|
+
}
|
|
11696
|
+
const convFk = field.names[0] + "ID";
|
|
11697
|
+
const belongsTo = scalarNames.has(convFk) || (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false);
|
|
11698
|
+
if (belongsTo) emit(thisTable, relTable, field.line);
|
|
11699
|
+
else emit(relTable, thisTable, field.line);
|
|
11700
|
+
}
|
|
11701
|
+
}
|
|
11702
|
+
return out;
|
|
11703
|
+
}
|
|
11704
|
+
|
|
11057
11705
|
// src/extract/calls/index.ts
|
|
11058
11706
|
function edgeTypeFromEndpoint(ep) {
|
|
11059
11707
|
switch (ep.edgeType) {
|
|
11060
11708
|
case "PUBLISHES_TO":
|
|
11061
|
-
return
|
|
11709
|
+
return import_types37.EdgeType.PUBLISHES_TO;
|
|
11062
11710
|
case "CONSUMES_FROM":
|
|
11063
|
-
return
|
|
11711
|
+
return import_types37.EdgeType.CONSUMES_FROM;
|
|
11064
11712
|
default:
|
|
11065
|
-
return
|
|
11713
|
+
return import_types37.EdgeType.CALLS;
|
|
11066
11714
|
}
|
|
11067
11715
|
}
|
|
11068
11716
|
function isAwsKind(kind) {
|
|
@@ -11095,6 +11743,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11095
11743
|
} catch (err) {
|
|
11096
11744
|
recordExtractionError("go SQL call extraction", file.path, err);
|
|
11097
11745
|
}
|
|
11746
|
+
try {
|
|
11747
|
+
endpoints.push(...gormEndpointsFromFile(file, service.dir));
|
|
11748
|
+
} catch (err) {
|
|
11749
|
+
recordExtractionError("gorm data-axis extraction", file.path, err);
|
|
11750
|
+
}
|
|
11098
11751
|
try {
|
|
11099
11752
|
endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir));
|
|
11100
11753
|
endpoints.push(...railsModelEndpointsFromFile(file, service.dir));
|
|
@@ -11117,7 +11770,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11117
11770
|
if (!graph.hasNode(ep.infraId)) {
|
|
11118
11771
|
const node = {
|
|
11119
11772
|
id: ep.infraId,
|
|
11120
|
-
type:
|
|
11773
|
+
type: import_types37.NodeType.InfraNode,
|
|
11121
11774
|
name: ep.name,
|
|
11122
11775
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
11123
11776
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -11130,21 +11783,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11130
11783
|
}
|
|
11131
11784
|
if (ep.columns && ep.columns.length > 0) {
|
|
11132
11785
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11133
|
-
if (node.type ===
|
|
11786
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11134
11787
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11135
11788
|
...node,
|
|
11136
11789
|
columns: foldColumns(
|
|
11137
11790
|
node.columns,
|
|
11138
11791
|
ep.columns,
|
|
11139
|
-
|
|
11140
|
-
(0,
|
|
11792
|
+
import_types37.Provenance.EXTRACTED,
|
|
11793
|
+
(0, import_types37.confidenceForExtracted)(ep.confidenceKind)
|
|
11141
11794
|
)
|
|
11142
11795
|
});
|
|
11143
11796
|
}
|
|
11144
11797
|
}
|
|
11145
11798
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
11146
11799
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11147
|
-
if (node.type ===
|
|
11800
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11148
11801
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11149
11802
|
...node,
|
|
11150
11803
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -11152,7 +11805,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11152
11805
|
}
|
|
11153
11806
|
}
|
|
11154
11807
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
11155
|
-
const confidence = (0,
|
|
11808
|
+
const confidence = (0, import_types37.confidenceForExtracted)(ep.confidenceKind);
|
|
11156
11809
|
const relFile = toPosix(ep.evidence.file);
|
|
11157
11810
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
11158
11811
|
graph,
|
|
@@ -11162,7 +11815,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11162
11815
|
);
|
|
11163
11816
|
nodesAdded += n;
|
|
11164
11817
|
edgesAdded += e;
|
|
11165
|
-
if (!(0,
|
|
11818
|
+
if (!(0, import_types37.passesExtractedFloor)(confidence)) {
|
|
11166
11819
|
noteExtractedDropped({
|
|
11167
11820
|
source: fileNodeId,
|
|
11168
11821
|
target: ep.infraId,
|
|
@@ -11182,7 +11835,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11182
11835
|
source: fileNodeId,
|
|
11183
11836
|
target: ep.infraId,
|
|
11184
11837
|
type: edgeType,
|
|
11185
|
-
provenance:
|
|
11838
|
+
provenance: import_types37.Provenance.EXTRACTED,
|
|
11186
11839
|
confidence,
|
|
11187
11840
|
evidence: ep.evidence
|
|
11188
11841
|
};
|
|
@@ -11205,7 +11858,7 @@ async function addCallEdges(graph, services) {
|
|
|
11205
11858
|
|
|
11206
11859
|
// src/extract/table-edges.ts
|
|
11207
11860
|
init_cjs_shims();
|
|
11208
|
-
var
|
|
11861
|
+
var import_types38 = require("@neat.is/types");
|
|
11209
11862
|
async function addTableEdges(graph, services) {
|
|
11210
11863
|
let nodesAdded = 0;
|
|
11211
11864
|
let edgesAdded = 0;
|
|
@@ -11219,6 +11872,7 @@ async function addTableEdges(graph, services) {
|
|
|
11219
11872
|
refs.push(...sqlalchemyForeignKeys(file, service.dir));
|
|
11220
11873
|
refs.push(...railsSchemaForeignKeys(file, service.dir));
|
|
11221
11874
|
refs.push(...laravelMigrationForeignKeys(file, service.dir));
|
|
11875
|
+
refs.push(...gormForeignKeys(file, service.dir));
|
|
11222
11876
|
modelRefs.push(...railsModelForeignKeys(file, service.dir));
|
|
11223
11877
|
modelRefs.push(...laravelModelForeignKeys(file, service.dir));
|
|
11224
11878
|
} catch (err) {
|
|
@@ -11232,20 +11886,20 @@ async function addTableEdges(graph, services) {
|
|
|
11232
11886
|
}
|
|
11233
11887
|
refs.push(...modelRefs);
|
|
11234
11888
|
for (const ref of refs) {
|
|
11235
|
-
const childId = (0,
|
|
11236
|
-
const parentId = (0,
|
|
11889
|
+
const childId = (0, import_types38.infraId)("sql-table", ref.childTable);
|
|
11890
|
+
const parentId = (0, import_types38.infraId)("sql-table", ref.parentTable);
|
|
11237
11891
|
if (childId === parentId) continue;
|
|
11238
11892
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
11239
11893
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
11240
|
-
const edgeId = (0,
|
|
11894
|
+
const edgeId = (0, import_types38.extractedEdgeId)(childId, parentId, import_types38.EdgeType.REFERENCES);
|
|
11241
11895
|
if (graph.hasEdge(edgeId)) continue;
|
|
11242
11896
|
const edge = {
|
|
11243
11897
|
id: edgeId,
|
|
11244
11898
|
source: childId,
|
|
11245
11899
|
target: parentId,
|
|
11246
|
-
type:
|
|
11247
|
-
provenance:
|
|
11248
|
-
confidence: (0,
|
|
11900
|
+
type: import_types38.EdgeType.REFERENCES,
|
|
11901
|
+
provenance: import_types38.Provenance.EXTRACTED,
|
|
11902
|
+
confidence: (0, import_types38.confidenceForExtracted)("structural"),
|
|
11249
11903
|
evidence: ref.evidence
|
|
11250
11904
|
};
|
|
11251
11905
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -11258,7 +11912,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
11258
11912
|
if (graph.hasNode(id)) return 0;
|
|
11259
11913
|
const node = {
|
|
11260
11914
|
id,
|
|
11261
|
-
type:
|
|
11915
|
+
type: import_types38.NodeType.InfraNode,
|
|
11262
11916
|
name,
|
|
11263
11917
|
provider: "self",
|
|
11264
11918
|
kind: "sql-table"
|
|
@@ -11272,16 +11926,16 @@ init_cjs_shims();
|
|
|
11272
11926
|
|
|
11273
11927
|
// src/extract/infra/docker-compose.ts
|
|
11274
11928
|
init_cjs_shims();
|
|
11275
|
-
var
|
|
11276
|
-
var
|
|
11929
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11930
|
+
var import_types40 = require("@neat.is/types");
|
|
11277
11931
|
|
|
11278
11932
|
// src/extract/infra/shared.ts
|
|
11279
11933
|
init_cjs_shims();
|
|
11280
|
-
var
|
|
11934
|
+
var import_types39 = require("@neat.is/types");
|
|
11281
11935
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
11282
11936
|
return {
|
|
11283
|
-
id: (0,
|
|
11284
|
-
type:
|
|
11937
|
+
id: (0, import_types39.infraId)(kind, name),
|
|
11938
|
+
type: import_types39.NodeType.InfraNode,
|
|
11285
11939
|
name,
|
|
11286
11940
|
provider,
|
|
11287
11941
|
kind,
|
|
@@ -11325,8 +11979,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
11325
11979
|
source: anchorId,
|
|
11326
11980
|
target: node.id,
|
|
11327
11981
|
type: edgeType,
|
|
11328
|
-
provenance:
|
|
11329
|
-
confidence: (0,
|
|
11982
|
+
provenance: import_types39.Provenance.EXTRACTED,
|
|
11983
|
+
confidence: (0, import_types39.confidenceForExtracted)("structural"),
|
|
11330
11984
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11331
11985
|
};
|
|
11332
11986
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11343,7 +11997,7 @@ function dependsOnList(value) {
|
|
|
11343
11997
|
}
|
|
11344
11998
|
function serviceNameToServiceNode(name, services) {
|
|
11345
11999
|
for (const s of services) {
|
|
11346
|
-
if (s.node.name === name ||
|
|
12000
|
+
if (s.node.name === name || import_node_path49.default.basename(s.dir) === name) return s.node.id;
|
|
11347
12001
|
}
|
|
11348
12002
|
return null;
|
|
11349
12003
|
}
|
|
@@ -11352,7 +12006,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11352
12006
|
let edgesAdded = 0;
|
|
11353
12007
|
let composePath = null;
|
|
11354
12008
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
11355
|
-
const abs =
|
|
12009
|
+
const abs = import_node_path49.default.join(scanPath, name);
|
|
11356
12010
|
if (await exists(abs)) {
|
|
11357
12011
|
composePath = abs;
|
|
11358
12012
|
break;
|
|
@@ -11365,13 +12019,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11365
12019
|
} catch (err) {
|
|
11366
12020
|
recordExtractionError(
|
|
11367
12021
|
"infra docker-compose",
|
|
11368
|
-
|
|
12022
|
+
import_node_path49.default.relative(scanPath, composePath),
|
|
11369
12023
|
err
|
|
11370
12024
|
);
|
|
11371
12025
|
return { nodesAdded, edgesAdded };
|
|
11372
12026
|
}
|
|
11373
12027
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
11374
|
-
const evidenceFile =
|
|
12028
|
+
const evidenceFile = import_node_path49.default.relative(scanPath, composePath).split(import_node_path49.default.sep).join("/");
|
|
11375
12029
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
11376
12030
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
11377
12031
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -11393,15 +12047,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11393
12047
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
11394
12048
|
const targetId = composeNameToNodeId.get(dep);
|
|
11395
12049
|
if (!targetId) continue;
|
|
11396
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
12050
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types40.EdgeType.DEPENDS_ON);
|
|
11397
12051
|
if (graph.hasEdge(edgeId)) continue;
|
|
11398
12052
|
const edge = {
|
|
11399
12053
|
id: edgeId,
|
|
11400
12054
|
source: sourceId,
|
|
11401
12055
|
target: targetId,
|
|
11402
|
-
type:
|
|
11403
|
-
provenance:
|
|
11404
|
-
confidence: (0,
|
|
12056
|
+
type: import_types40.EdgeType.DEPENDS_ON,
|
|
12057
|
+
provenance: import_types40.Provenance.EXTRACTED,
|
|
12058
|
+
confidence: (0, import_types40.confidenceForExtracted)("structural"),
|
|
11405
12059
|
evidence: { file: evidenceFile }
|
|
11406
12060
|
};
|
|
11407
12061
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11413,9 +12067,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11413
12067
|
|
|
11414
12068
|
// src/extract/infra/dockerfile.ts
|
|
11415
12069
|
init_cjs_shims();
|
|
11416
|
-
var
|
|
12070
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11417
12071
|
var import_node_fs18 = require("fs");
|
|
11418
|
-
var
|
|
12072
|
+
var import_types41 = require("@neat.is/types");
|
|
11419
12073
|
function readDockerfile(content) {
|
|
11420
12074
|
let image = null;
|
|
11421
12075
|
const ports = [];
|
|
@@ -11444,7 +12098,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11444
12098
|
let nodesAdded = 0;
|
|
11445
12099
|
let edgesAdded = 0;
|
|
11446
12100
|
for (const service of services) {
|
|
11447
|
-
const dockerfilePath =
|
|
12101
|
+
const dockerfilePath = import_node_path50.default.join(service.dir, "Dockerfile");
|
|
11448
12102
|
if (!await exists(dockerfilePath)) continue;
|
|
11449
12103
|
let content;
|
|
11450
12104
|
try {
|
|
@@ -11452,7 +12106,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11452
12106
|
} catch (err) {
|
|
11453
12107
|
recordExtractionError(
|
|
11454
12108
|
"infra dockerfile",
|
|
11455
|
-
|
|
12109
|
+
import_node_path50.default.relative(scanPath, dockerfilePath),
|
|
11456
12110
|
err
|
|
11457
12111
|
);
|
|
11458
12112
|
continue;
|
|
@@ -11464,8 +12118,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11464
12118
|
graph.addNode(node.id, node);
|
|
11465
12119
|
nodesAdded++;
|
|
11466
12120
|
}
|
|
11467
|
-
const relDockerfile = toPosix(
|
|
11468
|
-
const evidenceFile = toPosix(
|
|
12121
|
+
const relDockerfile = toPosix(import_node_path50.default.relative(service.dir, dockerfilePath));
|
|
12122
|
+
const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, dockerfilePath));
|
|
11469
12123
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11470
12124
|
graph,
|
|
11471
12125
|
service.pkg.name,
|
|
@@ -11474,15 +12128,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11474
12128
|
);
|
|
11475
12129
|
nodesAdded += fn;
|
|
11476
12130
|
edgesAdded += fe;
|
|
11477
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
12131
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types41.EdgeType.RUNS_ON);
|
|
11478
12132
|
if (!graph.hasEdge(edgeId)) {
|
|
11479
12133
|
const edge = {
|
|
11480
12134
|
id: edgeId,
|
|
11481
12135
|
source: fileNodeId,
|
|
11482
12136
|
target: node.id,
|
|
11483
|
-
type:
|
|
11484
|
-
provenance:
|
|
11485
|
-
confidence: (0,
|
|
12137
|
+
type: import_types41.EdgeType.RUNS_ON,
|
|
12138
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12139
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11486
12140
|
evidence: {
|
|
11487
12141
|
file: evidenceFile,
|
|
11488
12142
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -11497,15 +12151,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11497
12151
|
graph.addNode(portNode.id, portNode);
|
|
11498
12152
|
nodesAdded++;
|
|
11499
12153
|
}
|
|
11500
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
12154
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types41.EdgeType.CONNECTS_TO);
|
|
11501
12155
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
11502
12156
|
const portEdge = {
|
|
11503
12157
|
id: portEdgeId,
|
|
11504
12158
|
source: fileNodeId,
|
|
11505
12159
|
target: portNode.id,
|
|
11506
|
-
type:
|
|
11507
|
-
provenance:
|
|
11508
|
-
confidence: (0,
|
|
12160
|
+
type: import_types41.EdgeType.CONNECTS_TO,
|
|
12161
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12162
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11509
12163
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
11510
12164
|
};
|
|
11511
12165
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -11518,8 +12172,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11518
12172
|
// src/extract/infra/terraform.ts
|
|
11519
12173
|
init_cjs_shims();
|
|
11520
12174
|
var import_node_fs19 = require("fs");
|
|
11521
|
-
var
|
|
11522
|
-
var
|
|
12175
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12176
|
+
var import_types42 = require("@neat.is/types");
|
|
11523
12177
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
11524
12178
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
11525
12179
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -11529,11 +12183,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
11529
12183
|
for (const entry2 of entries) {
|
|
11530
12184
|
if (entry2.isDirectory()) {
|
|
11531
12185
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
11532
|
-
const child =
|
|
12186
|
+
const child = import_node_path51.default.join(start, entry2.name);
|
|
11533
12187
|
if (await isPythonVenvDir(child)) continue;
|
|
11534
12188
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
11535
12189
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
11536
|
-
out.push(
|
|
12190
|
+
out.push(import_node_path51.default.join(start, entry2.name));
|
|
11537
12191
|
}
|
|
11538
12192
|
}
|
|
11539
12193
|
return out;
|
|
@@ -11565,7 +12219,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11565
12219
|
const files = await walkTfFiles(scanPath);
|
|
11566
12220
|
for (const file of files) {
|
|
11567
12221
|
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
11568
|
-
const evidenceFile = toPosix(
|
|
12222
|
+
const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, file));
|
|
11569
12223
|
const resources = [];
|
|
11570
12224
|
const byKey = /* @__PURE__ */ new Map();
|
|
11571
12225
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -11600,16 +12254,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11600
12254
|
if (!target) continue;
|
|
11601
12255
|
if (seen.has(target.nodeId)) continue;
|
|
11602
12256
|
seen.add(target.nodeId);
|
|
11603
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
12257
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types42.EdgeType.DEPENDS_ON);
|
|
11604
12258
|
if (graph.hasEdge(edgeId)) continue;
|
|
11605
12259
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
11606
12260
|
const edge = {
|
|
11607
12261
|
id: edgeId,
|
|
11608
12262
|
source: resource.nodeId,
|
|
11609
12263
|
target: target.nodeId,
|
|
11610
|
-
type:
|
|
11611
|
-
provenance:
|
|
11612
|
-
confidence: (0,
|
|
12264
|
+
type: import_types42.EdgeType.DEPENDS_ON,
|
|
12265
|
+
provenance: import_types42.Provenance.EXTRACTED,
|
|
12266
|
+
confidence: (0, import_types42.confidenceForExtracted)("structural"),
|
|
11613
12267
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
11614
12268
|
};
|
|
11615
12269
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11623,7 +12277,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11623
12277
|
// src/extract/infra/k8s.ts
|
|
11624
12278
|
init_cjs_shims();
|
|
11625
12279
|
var import_node_fs20 = require("fs");
|
|
11626
|
-
var
|
|
12280
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
11627
12281
|
var import_yaml3 = require("yaml");
|
|
11628
12282
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
11629
12283
|
Service: "k8s-service",
|
|
@@ -11641,11 +12295,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
11641
12295
|
for (const entry2 of entries) {
|
|
11642
12296
|
if (entry2.isDirectory()) {
|
|
11643
12297
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
11644
|
-
const child =
|
|
12298
|
+
const child = import_node_path52.default.join(start, entry2.name);
|
|
11645
12299
|
if (await isPythonVenvDir(child)) continue;
|
|
11646
12300
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
11647
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
11648
|
-
out.push(
|
|
12301
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path52.default.extname(entry2.name))) {
|
|
12302
|
+
out.push(import_node_path52.default.join(start, entry2.name));
|
|
11649
12303
|
}
|
|
11650
12304
|
}
|
|
11651
12305
|
return out;
|
|
@@ -11679,13 +12333,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
11679
12333
|
// src/extract/infra/cloudflare.ts
|
|
11680
12334
|
init_cjs_shims();
|
|
11681
12335
|
var import_node_fs21 = require("fs");
|
|
11682
|
-
var
|
|
12336
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
11683
12337
|
var import_smol_toml2 = require("smol-toml");
|
|
11684
|
-
var
|
|
12338
|
+
var import_types43 = require("@neat.is/types");
|
|
11685
12339
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
11686
12340
|
async function readWranglerConfig(dir) {
|
|
11687
12341
|
for (const filename of WRANGLER_FILENAMES) {
|
|
11688
|
-
const abs =
|
|
12342
|
+
const abs = import_node_path53.default.join(dir, filename);
|
|
11689
12343
|
if (!await exists(abs)) continue;
|
|
11690
12344
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
11691
12345
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11729,8 +12383,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
11729
12383
|
source: anchorId,
|
|
11730
12384
|
target: node.id,
|
|
11731
12385
|
type: edgeType,
|
|
11732
|
-
provenance:
|
|
11733
|
-
confidence: (0,
|
|
12386
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12387
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11734
12388
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11735
12389
|
};
|
|
11736
12390
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11748,11 +12402,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11748
12402
|
try {
|
|
11749
12403
|
read = await readWranglerConfig(service.dir);
|
|
11750
12404
|
} catch (err) {
|
|
11751
|
-
recordExtractionError("infra cloudflare",
|
|
12405
|
+
recordExtractionError("infra cloudflare", import_node_path53.default.relative(scanPath, service.dir), err);
|
|
11752
12406
|
continue;
|
|
11753
12407
|
}
|
|
11754
12408
|
if (!read || !read.config.name) continue;
|
|
11755
|
-
const evidenceFile = toPosix(
|
|
12409
|
+
const evidenceFile = toPosix(import_node_path53.default.relative(scanPath, import_node_path53.default.join(service.dir, read.relFile)));
|
|
11756
12410
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
11757
12411
|
}
|
|
11758
12412
|
for (const worker of discovered) {
|
|
@@ -11764,7 +12418,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11764
12418
|
}
|
|
11765
12419
|
let anchorId = service.node.id;
|
|
11766
12420
|
if (config.main) {
|
|
11767
|
-
const entryRelPath = toPosix(
|
|
12421
|
+
const entryRelPath = toPosix(import_node_path53.default.normalize(config.main));
|
|
11768
12422
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11769
12423
|
graph,
|
|
11770
12424
|
service.pkg.name,
|
|
@@ -11791,15 +12445,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11791
12445
|
nodesAdded++;
|
|
11792
12446
|
}
|
|
11793
12447
|
if (runtimeNode.id !== anchorId) {
|
|
11794
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
12448
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types43.EdgeType.RUNS_ON);
|
|
11795
12449
|
if (!graph.hasEdge(runsOnId)) {
|
|
11796
12450
|
const edge = {
|
|
11797
12451
|
id: runsOnId,
|
|
11798
12452
|
source: anchorId,
|
|
11799
12453
|
target: runtimeNode.id,
|
|
11800
|
-
type:
|
|
11801
|
-
provenance:
|
|
11802
|
-
confidence: (0,
|
|
12454
|
+
type: import_types43.EdgeType.RUNS_ON,
|
|
12455
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12456
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11803
12457
|
evidence: {
|
|
11804
12458
|
file: evidenceFile,
|
|
11805
12459
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -11813,7 +12467,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11813
12467
|
const result = addResourceEdge(
|
|
11814
12468
|
graph,
|
|
11815
12469
|
anchorId,
|
|
11816
|
-
|
|
12470
|
+
import_types43.EdgeType.CONNECTS_TO,
|
|
11817
12471
|
"cloudflare-route",
|
|
11818
12472
|
route,
|
|
11819
12473
|
evidenceFile,
|
|
@@ -11837,7 +12491,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11837
12491
|
const result = addResourceEdge(
|
|
11838
12492
|
graph,
|
|
11839
12493
|
anchorId,
|
|
11840
|
-
|
|
12494
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11841
12495
|
group.kind,
|
|
11842
12496
|
name,
|
|
11843
12497
|
evidenceFile,
|
|
@@ -11851,7 +12505,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11851
12505
|
const result = addResourceEdge(
|
|
11852
12506
|
graph,
|
|
11853
12507
|
anchorId,
|
|
11854
|
-
|
|
12508
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11855
12509
|
"cloudflare-cron",
|
|
11856
12510
|
cron,
|
|
11857
12511
|
evidenceFile,
|
|
@@ -11864,7 +12518,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11864
12518
|
const result = addResourceEdge(
|
|
11865
12519
|
graph,
|
|
11866
12520
|
anchorId,
|
|
11867
|
-
|
|
12521
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11868
12522
|
"cloudflare-env-var",
|
|
11869
12523
|
varName,
|
|
11870
12524
|
evidenceFile,
|
|
@@ -11877,15 +12531,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11877
12531
|
if (!svc.service) continue;
|
|
11878
12532
|
const target = workerIndex.get(svc.service);
|
|
11879
12533
|
if (target && target.anchorId !== anchorId) {
|
|
11880
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
12534
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types43.EdgeType.CALLS);
|
|
11881
12535
|
if (!graph.hasEdge(edgeId)) {
|
|
11882
12536
|
const edge = {
|
|
11883
12537
|
id: edgeId,
|
|
11884
12538
|
source: anchorId,
|
|
11885
12539
|
target: target.anchorId,
|
|
11886
|
-
type:
|
|
11887
|
-
provenance:
|
|
11888
|
-
confidence: (0,
|
|
12540
|
+
type: import_types43.EdgeType.CALLS,
|
|
12541
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12542
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11889
12543
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
11890
12544
|
};
|
|
11891
12545
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11896,7 +12550,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11896
12550
|
const result = addResourceEdge(
|
|
11897
12551
|
graph,
|
|
11898
12552
|
anchorId,
|
|
11899
|
-
|
|
12553
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11900
12554
|
"cloudflare-service-binding",
|
|
11901
12555
|
svc.service,
|
|
11902
12556
|
evidenceFile,
|
|
@@ -11912,12 +12566,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11912
12566
|
// src/extract/infra/vercel.ts
|
|
11913
12567
|
init_cjs_shims();
|
|
11914
12568
|
var import_node_fs22 = require("fs");
|
|
11915
|
-
var
|
|
11916
|
-
var
|
|
12569
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
12570
|
+
var import_types44 = require("@neat.is/types");
|
|
11917
12571
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
11918
12572
|
async function readVercelConfig(dir) {
|
|
11919
12573
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
11920
|
-
const abs =
|
|
12574
|
+
const abs = import_node_path54.default.join(dir, filename);
|
|
11921
12575
|
if (!await exists(abs)) continue;
|
|
11922
12576
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
11923
12577
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11926,7 +12580,7 @@ async function readVercelConfig(dir) {
|
|
|
11926
12580
|
return null;
|
|
11927
12581
|
}
|
|
11928
12582
|
async function readLinkedProjectName(dir) {
|
|
11929
|
-
const abs =
|
|
12583
|
+
const abs = import_node_path54.default.join(dir, ".vercel", "project.json");
|
|
11930
12584
|
if (!await exists(abs)) return void 0;
|
|
11931
12585
|
const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
|
|
11932
12586
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -11944,7 +12598,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11944
12598
|
read = await readVercelConfig(service.dir);
|
|
11945
12599
|
projectName = await readLinkedProjectName(service.dir);
|
|
11946
12600
|
} catch (err) {
|
|
11947
|
-
recordExtractionError("infra vercel",
|
|
12601
|
+
recordExtractionError("infra vercel", import_node_path54.default.relative(scanPath, service.dir), err);
|
|
11948
12602
|
continue;
|
|
11949
12603
|
}
|
|
11950
12604
|
if (!read && !projectName) continue;
|
|
@@ -11960,7 +12614,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11960
12614
|
const anchorId = service.node.id;
|
|
11961
12615
|
if (!read) continue;
|
|
11962
12616
|
const { config, relFile, raw } = read;
|
|
11963
|
-
const evidenceFile = toPosix(
|
|
12617
|
+
const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, relFile)));
|
|
11964
12618
|
const add = (edgeType, kind, name) => {
|
|
11965
12619
|
if (!name) return;
|
|
11966
12620
|
const result = emitPlatformResourceEdge(
|
|
@@ -11976,12 +12630,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11976
12630
|
nodesAdded += result.nodesAdded;
|
|
11977
12631
|
edgesAdded += result.edgesAdded;
|
|
11978
12632
|
};
|
|
11979
|
-
add(
|
|
11980
|
-
for (const cron of config.crons ?? []) add(
|
|
11981
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
11982
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
12633
|
+
add(import_types44.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
12634
|
+
for (const cron of config.crons ?? []) add(import_types44.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
12635
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12636
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
11983
12637
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
11984
|
-
add(
|
|
12638
|
+
add(import_types44.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
11985
12639
|
}
|
|
11986
12640
|
}
|
|
11987
12641
|
return { nodesAdded, edgesAdded };
|
|
@@ -11990,13 +12644,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11990
12644
|
// src/extract/infra/railway.ts
|
|
11991
12645
|
init_cjs_shims();
|
|
11992
12646
|
var import_node_fs23 = require("fs");
|
|
11993
|
-
var
|
|
12647
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
11994
12648
|
var import_smol_toml3 = require("smol-toml");
|
|
11995
|
-
var
|
|
12649
|
+
var import_types45 = require("@neat.is/types");
|
|
11996
12650
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
11997
12651
|
async function readRailwayConfig(dir) {
|
|
11998
12652
|
for (const filename of RAILWAY_FILENAMES) {
|
|
11999
|
-
const abs =
|
|
12653
|
+
const abs = import_node_path55.default.join(dir, filename);
|
|
12000
12654
|
if (!await exists(abs)) continue;
|
|
12001
12655
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
12002
12656
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -12012,7 +12666,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12012
12666
|
try {
|
|
12013
12667
|
read = await readRailwayConfig(service.dir);
|
|
12014
12668
|
} catch (err) {
|
|
12015
|
-
recordExtractionError("infra railway",
|
|
12669
|
+
recordExtractionError("infra railway", import_node_path55.default.relative(scanPath, service.dir), err);
|
|
12016
12670
|
continue;
|
|
12017
12671
|
}
|
|
12018
12672
|
if (!read) continue;
|
|
@@ -12022,7 +12676,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12022
12676
|
}
|
|
12023
12677
|
const anchorId = service.node.id;
|
|
12024
12678
|
const { config, relFile, raw } = read;
|
|
12025
|
-
const evidenceFile = toPosix(
|
|
12679
|
+
const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
|
|
12026
12680
|
const add = (edgeType, kind, name) => {
|
|
12027
12681
|
if (!name) return;
|
|
12028
12682
|
const result = emitPlatformResourceEdge(
|
|
@@ -12038,9 +12692,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12038
12692
|
nodesAdded += result.nodesAdded;
|
|
12039
12693
|
edgesAdded += result.edgesAdded;
|
|
12040
12694
|
};
|
|
12041
|
-
add(
|
|
12042
|
-
add(
|
|
12043
|
-
add(
|
|
12695
|
+
add(import_types45.EdgeType.RUNS_ON, "railway", "railway");
|
|
12696
|
+
add(import_types45.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
12697
|
+
add(import_types45.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
12044
12698
|
}
|
|
12045
12699
|
return { nodesAdded, edgesAdded };
|
|
12046
12700
|
}
|
|
@@ -12048,12 +12702,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12048
12702
|
// src/extract/infra/supabase.ts
|
|
12049
12703
|
init_cjs_shims();
|
|
12050
12704
|
var import_node_fs24 = require("fs");
|
|
12051
|
-
var
|
|
12705
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
12052
12706
|
var import_smol_toml4 = require("smol-toml");
|
|
12053
|
-
var
|
|
12707
|
+
var import_types46 = require("@neat.is/types");
|
|
12054
12708
|
async function readSupabaseConfig(dir) {
|
|
12055
|
-
const relFile =
|
|
12056
|
-
const abs =
|
|
12709
|
+
const relFile = import_node_path56.default.join("supabase", "config.toml");
|
|
12710
|
+
const abs = import_node_path56.default.join(dir, relFile);
|
|
12057
12711
|
if (!await exists(abs)) return null;
|
|
12058
12712
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
12059
12713
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -12067,7 +12721,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12067
12721
|
try {
|
|
12068
12722
|
read = await readSupabaseConfig(service.dir);
|
|
12069
12723
|
} catch (err) {
|
|
12070
|
-
recordExtractionError("infra supabase",
|
|
12724
|
+
recordExtractionError("infra supabase", import_node_path56.default.relative(scanPath, service.dir), err);
|
|
12071
12725
|
continue;
|
|
12072
12726
|
}
|
|
12073
12727
|
if (!read) continue;
|
|
@@ -12082,7 +12736,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12082
12736
|
});
|
|
12083
12737
|
}
|
|
12084
12738
|
const anchorId = service.node.id;
|
|
12085
|
-
const evidenceFile = toPosix(
|
|
12739
|
+
const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
|
|
12086
12740
|
const add = (edgeType, kind, name) => {
|
|
12087
12741
|
if (!name) return;
|
|
12088
12742
|
const result = emitPlatformResourceEdge(
|
|
@@ -12098,10 +12752,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12098
12752
|
nodesAdded += result.nodesAdded;
|
|
12099
12753
|
edgesAdded += result.edgesAdded;
|
|
12100
12754
|
};
|
|
12101
|
-
add(
|
|
12102
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
12103
|
-
if (config.storage) add(
|
|
12104
|
-
if (config.auth) add(
|
|
12755
|
+
add(import_types46.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
12756
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types46.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
12757
|
+
if (config.storage) add(import_types46.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
12758
|
+
if (config.auth) add(import_types46.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
12105
12759
|
}
|
|
12106
12760
|
return { nodesAdded, edgesAdded };
|
|
12107
12761
|
}
|
|
@@ -12124,14 +12778,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
12124
12778
|
|
|
12125
12779
|
// src/extract/zod-shapes.ts
|
|
12126
12780
|
init_cjs_shims();
|
|
12127
|
-
var
|
|
12128
|
-
var
|
|
12781
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
12782
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
12129
12783
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12130
|
-
var
|
|
12784
|
+
var import_types47 = require("@neat.is/types");
|
|
12131
12785
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
12132
12786
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
12133
12787
|
function parserForExt3(ext) {
|
|
12134
|
-
const p = new
|
|
12788
|
+
const p = new import_tree_sitter16.default();
|
|
12135
12789
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
12136
12790
|
return p;
|
|
12137
12791
|
}
|
|
@@ -12219,7 +12873,7 @@ function topLevelSchemas(root) {
|
|
|
12219
12873
|
}
|
|
12220
12874
|
function zodShapesFromFile(file, serviceDir) {
|
|
12221
12875
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
12222
|
-
const tree = parseSource3(parserForExt3(
|
|
12876
|
+
const tree = parseSource3(parserForExt3(import_node_path57.default.extname(file.path)), file.content);
|
|
12223
12877
|
const out = [];
|
|
12224
12878
|
const seen = /* @__PURE__ */ new Set();
|
|
12225
12879
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -12233,11 +12887,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
12233
12887
|
seen.add(name);
|
|
12234
12888
|
const line = call.startPosition.row + 1;
|
|
12235
12889
|
out.push({
|
|
12236
|
-
infraId: (0,
|
|
12890
|
+
infraId: (0, import_types47.infraId)("zod-schema", name),
|
|
12237
12891
|
name,
|
|
12238
12892
|
fields,
|
|
12239
12893
|
evidence: {
|
|
12240
|
-
file:
|
|
12894
|
+
file: import_node_path57.default.relative(serviceDir, file.path),
|
|
12241
12895
|
line,
|
|
12242
12896
|
snippet: snippet(file.content, line)
|
|
12243
12897
|
}
|
|
@@ -12268,7 +12922,7 @@ async function addZodShapes(graph, services) {
|
|
|
12268
12922
|
if (!graph.hasNode(shape.infraId)) {
|
|
12269
12923
|
const node = {
|
|
12270
12924
|
id: shape.infraId,
|
|
12271
|
-
type:
|
|
12925
|
+
type: import_types47.NodeType.InfraNode,
|
|
12272
12926
|
name: shape.name,
|
|
12273
12927
|
provider: "self",
|
|
12274
12928
|
kind: "zod-schema"
|
|
@@ -12278,14 +12932,14 @@ async function addZodShapes(graph, services) {
|
|
|
12278
12932
|
}
|
|
12279
12933
|
if (shape.fields.length > 0) {
|
|
12280
12934
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
12281
|
-
if (node.type ===
|
|
12935
|
+
if (node.type === import_types47.NodeType.InfraNode) {
|
|
12282
12936
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
12283
12937
|
...node,
|
|
12284
12938
|
columns: foldColumns(
|
|
12285
12939
|
node.columns,
|
|
12286
12940
|
shape.fields,
|
|
12287
|
-
|
|
12288
|
-
(0,
|
|
12941
|
+
import_types47.Provenance.EXTRACTED,
|
|
12942
|
+
(0, import_types47.confidenceForExtracted)("structural")
|
|
12289
12943
|
)
|
|
12290
12944
|
});
|
|
12291
12945
|
}
|
|
@@ -12299,15 +12953,15 @@ async function addZodShapes(graph, services) {
|
|
|
12299
12953
|
);
|
|
12300
12954
|
nodesAdded += n;
|
|
12301
12955
|
edgesAdded += e;
|
|
12302
|
-
const edgeId = (0,
|
|
12956
|
+
const edgeId = (0, import_types47.extractedEdgeId)(fileNodeId, shape.infraId, import_types47.EdgeType.CONTAINS);
|
|
12303
12957
|
if (!graph.hasEdge(edgeId)) {
|
|
12304
12958
|
const edge = {
|
|
12305
12959
|
id: edgeId,
|
|
12306
12960
|
source: fileNodeId,
|
|
12307
12961
|
target: shape.infraId,
|
|
12308
|
-
type:
|
|
12309
|
-
provenance:
|
|
12310
|
-
confidence: (0,
|
|
12962
|
+
type: import_types47.EdgeType.CONTAINS,
|
|
12963
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
12964
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
12311
12965
|
evidence: shape.evidence
|
|
12312
12966
|
};
|
|
12313
12967
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -12321,7 +12975,7 @@ async function addZodShapes(graph, services) {
|
|
|
12321
12975
|
|
|
12322
12976
|
// src/extract/firestore-rules.ts
|
|
12323
12977
|
init_cjs_shims();
|
|
12324
|
-
var
|
|
12978
|
+
var import_types48 = require("@neat.is/types");
|
|
12325
12979
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
12326
12980
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
12327
12981
|
function stripComments(src) {
|
|
@@ -12461,7 +13115,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
12461
13115
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
12462
13116
|
graph.forEachNode((id, attrs) => {
|
|
12463
13117
|
const node = attrs;
|
|
12464
|
-
if (node.type !==
|
|
13118
|
+
if (node.type !== import_types48.NodeType.InfraNode) return;
|
|
12465
13119
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
12466
13120
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
12467
13121
|
if (!fields || fields.size === 0) return;
|
|
@@ -12474,17 +13128,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
12474
13128
|
}
|
|
12475
13129
|
|
|
12476
13130
|
// src/extract/index.ts
|
|
12477
|
-
var
|
|
13131
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
12478
13132
|
|
|
12479
13133
|
// src/extract/retire.ts
|
|
12480
13134
|
init_cjs_shims();
|
|
12481
13135
|
var import_node_fs25 = require("fs");
|
|
12482
|
-
var
|
|
12483
|
-
var
|
|
13136
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13137
|
+
var import_types49 = require("@neat.is/types");
|
|
12484
13138
|
function dropOrphanedFileNodes(graph) {
|
|
12485
13139
|
const orphans = [];
|
|
12486
13140
|
graph.forEachNode((id, attrs) => {
|
|
12487
|
-
if (attrs.type !==
|
|
13141
|
+
if (attrs.type !== import_types49.NodeType.FileNode) return;
|
|
12488
13142
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
12489
13143
|
orphans.push(id);
|
|
12490
13144
|
}
|
|
@@ -12497,14 +13151,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
12497
13151
|
const bases = [scanPath, ...serviceDirs];
|
|
12498
13152
|
graph.forEachEdge((id, attrs) => {
|
|
12499
13153
|
const edge = attrs;
|
|
12500
|
-
if (edge.provenance !==
|
|
13154
|
+
if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
|
|
12501
13155
|
const evidenceFile = edge.evidence?.file;
|
|
12502
13156
|
if (!evidenceFile) return;
|
|
12503
|
-
if (
|
|
13157
|
+
if (import_node_path58.default.isAbsolute(evidenceFile)) {
|
|
12504
13158
|
if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
|
|
12505
13159
|
return;
|
|
12506
13160
|
}
|
|
12507
|
-
const found = bases.some((base) => (0, import_node_fs25.existsSync)(
|
|
13161
|
+
const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path58.default.join(base, evidenceFile)));
|
|
12508
13162
|
if (!found) toDrop.push(id);
|
|
12509
13163
|
});
|
|
12510
13164
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -12561,7 +13215,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12561
13215
|
}
|
|
12562
13216
|
const droppedEntries = drainDroppedExtracted();
|
|
12563
13217
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
12564
|
-
const rejectedPath =
|
|
13218
|
+
const rejectedPath = import_node_path59.default.join(import_node_path59.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
12565
13219
|
try {
|
|
12566
13220
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
12567
13221
|
} catch (err) {
|
|
@@ -12596,8 +13250,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12596
13250
|
// src/persist.ts
|
|
12597
13251
|
init_cjs_shims();
|
|
12598
13252
|
var import_node_fs26 = require("fs");
|
|
12599
|
-
var
|
|
12600
|
-
var
|
|
13253
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
13254
|
+
var import_types50 = require("@neat.is/types");
|
|
12601
13255
|
var SCHEMA_VERSION = 7;
|
|
12602
13256
|
function migrateV1ToV2(payload) {
|
|
12603
13257
|
const nodes = payload.graph.nodes;
|
|
@@ -12621,7 +13275,7 @@ function migrateV5ToV6(payload) {
|
|
|
12621
13275
|
if (Array.isArray(nodes)) {
|
|
12622
13276
|
for (const node of nodes) {
|
|
12623
13277
|
const attrs = node.attributes;
|
|
12624
|
-
if (!attrs || attrs.type !==
|
|
13278
|
+
if (!attrs || attrs.type !== import_types50.NodeType.InfraNode) continue;
|
|
12625
13279
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
12626
13280
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
12627
13281
|
}
|
|
@@ -12637,12 +13291,12 @@ function migrateV2ToV3(payload) {
|
|
|
12637
13291
|
for (const edge of edges) {
|
|
12638
13292
|
const attrs = edge.attributes;
|
|
12639
13293
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
12640
|
-
attrs.provenance =
|
|
13294
|
+
attrs.provenance = import_types50.Provenance.OBSERVED;
|
|
12641
13295
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
12642
13296
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
12643
13297
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
12644
13298
|
if (type && source && target) {
|
|
12645
|
-
const newId = (0,
|
|
13299
|
+
const newId = (0, import_types50.observedEdgeId)(source, target, type);
|
|
12646
13300
|
attrs.id = newId;
|
|
12647
13301
|
if (edge.key) edge.key = newId;
|
|
12648
13302
|
}
|
|
@@ -12651,7 +13305,7 @@ function migrateV2ToV3(payload) {
|
|
|
12651
13305
|
return { ...payload, schemaVersion: 3 };
|
|
12652
13306
|
}
|
|
12653
13307
|
async function ensureDir(filePath) {
|
|
12654
|
-
await import_node_fs26.promises.mkdir(
|
|
13308
|
+
await import_node_fs26.promises.mkdir(import_node_path60.default.dirname(filePath), { recursive: true });
|
|
12655
13309
|
}
|
|
12656
13310
|
async function saveGraphToDisk(graph, outPath) {
|
|
12657
13311
|
await ensureDir(outPath);
|
|
@@ -12741,23 +13395,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
12741
13395
|
|
|
12742
13396
|
// src/projects.ts
|
|
12743
13397
|
init_cjs_shims();
|
|
12744
|
-
var
|
|
13398
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
12745
13399
|
function pathsForProject(project, baseDir) {
|
|
12746
13400
|
if (project === DEFAULT_PROJECT) {
|
|
12747
13401
|
return {
|
|
12748
|
-
snapshotPath:
|
|
12749
|
-
errorsPath:
|
|
12750
|
-
staleEventsPath:
|
|
12751
|
-
embeddingsCachePath:
|
|
12752
|
-
policyViolationsPath:
|
|
13402
|
+
snapshotPath: import_node_path61.default.join(baseDir, "graph.json"),
|
|
13403
|
+
errorsPath: import_node_path61.default.join(baseDir, "errors.ndjson"),
|
|
13404
|
+
staleEventsPath: import_node_path61.default.join(baseDir, "stale-events.ndjson"),
|
|
13405
|
+
embeddingsCachePath: import_node_path61.default.join(baseDir, "embeddings.json"),
|
|
13406
|
+
policyViolationsPath: import_node_path61.default.join(baseDir, "policy-violations.ndjson")
|
|
12753
13407
|
};
|
|
12754
13408
|
}
|
|
12755
13409
|
return {
|
|
12756
|
-
snapshotPath:
|
|
12757
|
-
errorsPath:
|
|
12758
|
-
staleEventsPath:
|
|
12759
|
-
embeddingsCachePath:
|
|
12760
|
-
policyViolationsPath:
|
|
13410
|
+
snapshotPath: import_node_path61.default.join(baseDir, `${project}.json`),
|
|
13411
|
+
errorsPath: import_node_path61.default.join(baseDir, `errors.${project}.ndjson`),
|
|
13412
|
+
staleEventsPath: import_node_path61.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
13413
|
+
embeddingsCachePath: import_node_path61.default.join(baseDir, `embeddings.${project}.json`),
|
|
13414
|
+
policyViolationsPath: import_node_path61.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
12761
13415
|
};
|
|
12762
13416
|
}
|
|
12763
13417
|
var Projects = class {
|
|
@@ -12795,19 +13449,19 @@ var Projects = class {
|
|
|
12795
13449
|
init_cjs_shims();
|
|
12796
13450
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
12797
13451
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
12798
|
-
var
|
|
13452
|
+
var import_types80 = require("@neat.is/types");
|
|
12799
13453
|
|
|
12800
13454
|
// src/extend/index.ts
|
|
12801
13455
|
init_cjs_shims();
|
|
12802
13456
|
var import_node_fs28 = require("fs");
|
|
12803
|
-
var
|
|
13457
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
12804
13458
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
12805
13459
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
12806
13460
|
|
|
12807
13461
|
// src/installers/package-manager.ts
|
|
12808
13462
|
init_cjs_shims();
|
|
12809
13463
|
var import_node_fs27 = require("fs");
|
|
12810
|
-
var
|
|
13464
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
12811
13465
|
var import_node_child_process = require("child_process");
|
|
12812
13466
|
var LOCKFILE_PRIORITY = [
|
|
12813
13467
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -12829,22 +13483,22 @@ async function exists2(p) {
|
|
|
12829
13483
|
}
|
|
12830
13484
|
}
|
|
12831
13485
|
async function detectPackageManager(serviceDir) {
|
|
12832
|
-
let dir =
|
|
13486
|
+
let dir = import_node_path62.default.resolve(serviceDir);
|
|
12833
13487
|
const stops = /* @__PURE__ */ new Set();
|
|
12834
13488
|
for (let i = 0; i < 64; i++) {
|
|
12835
13489
|
if (stops.has(dir)) break;
|
|
12836
13490
|
stops.add(dir);
|
|
12837
13491
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
12838
|
-
const lockPath =
|
|
13492
|
+
const lockPath = import_node_path62.default.join(dir, candidate.lockfile);
|
|
12839
13493
|
if (await exists2(lockPath)) {
|
|
12840
13494
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
12841
13495
|
}
|
|
12842
13496
|
}
|
|
12843
|
-
const parent =
|
|
13497
|
+
const parent = import_node_path62.default.dirname(dir);
|
|
12844
13498
|
if (parent === dir) break;
|
|
12845
13499
|
dir = parent;
|
|
12846
13500
|
}
|
|
12847
|
-
return { pm: "npm", cwd:
|
|
13501
|
+
return { pm: "npm", cwd: import_node_path62.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
12848
13502
|
}
|
|
12849
13503
|
async function runPackageManagerInstall(cmd) {
|
|
12850
13504
|
return new Promise((resolve) => {
|
|
@@ -12893,7 +13547,7 @@ async function fileExists2(p) {
|
|
|
12893
13547
|
}
|
|
12894
13548
|
}
|
|
12895
13549
|
async function readPackageJson(scanPath) {
|
|
12896
|
-
const pkgPath =
|
|
13550
|
+
const pkgPath = import_node_path63.default.join(scanPath, "package.json");
|
|
12897
13551
|
const raw = await import_node_fs28.promises.readFile(pkgPath, "utf8");
|
|
12898
13552
|
return JSON.parse(raw);
|
|
12899
13553
|
}
|
|
@@ -12907,27 +13561,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
12907
13561
|
]);
|
|
12908
13562
|
async function findHookFiles(scanPath) {
|
|
12909
13563
|
const found = [];
|
|
12910
|
-
const
|
|
13564
|
+
const walk9 = async (dir) => {
|
|
12911
13565
|
const entries = await import_node_fs28.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
12912
13566
|
for (const entry2 of entries) {
|
|
12913
13567
|
if (entry2.isDirectory()) {
|
|
12914
13568
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
12915
|
-
await
|
|
13569
|
+
await walk9(import_node_path63.default.join(dir, entry2.name));
|
|
12916
13570
|
} else if (entry2.isFile()) {
|
|
12917
13571
|
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
12918
|
-
const rel =
|
|
12919
|
-
found.push(rel.split(
|
|
13572
|
+
const rel = import_node_path63.default.relative(scanPath, import_node_path63.default.join(dir, entry2.name));
|
|
13573
|
+
found.push(rel.split(import_node_path63.default.sep).join("/"));
|
|
12920
13574
|
}
|
|
12921
13575
|
}
|
|
12922
13576
|
}
|
|
12923
13577
|
};
|
|
12924
|
-
await
|
|
13578
|
+
await walk9(scanPath);
|
|
12925
13579
|
return found.sort();
|
|
12926
13580
|
}
|
|
12927
13581
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
12928
13582
|
let fallback = null;
|
|
12929
13583
|
for (const file of hookFiles) {
|
|
12930
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13584
|
+
const content = await import_node_fs28.promises.readFile(import_node_path63.default.join(scanPath, file), "utf8");
|
|
12931
13585
|
const patched = splicedContent(content, snippet2);
|
|
12932
13586
|
if (patched !== null) return { file, content, patched };
|
|
12933
13587
|
if (fallback === null) fallback = { file, content };
|
|
@@ -12935,11 +13589,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
12935
13589
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
12936
13590
|
}
|
|
12937
13591
|
function extendLogPath() {
|
|
12938
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
13592
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path63.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
12939
13593
|
}
|
|
12940
13594
|
async function appendExtendLog(entry2) {
|
|
12941
13595
|
const logPath = extendLogPath();
|
|
12942
|
-
await import_node_fs28.promises.mkdir(
|
|
13596
|
+
await import_node_fs28.promises.mkdir(import_node_path63.default.dirname(logPath), { recursive: true });
|
|
12943
13597
|
await import_node_fs28.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
12944
13598
|
}
|
|
12945
13599
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -12998,7 +13652,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
12998
13652
|
}
|
|
12999
13653
|
async function describeProjectInstrumentation(ctx) {
|
|
13000
13654
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13001
|
-
const envNeat = await fileExists2(
|
|
13655
|
+
const envNeat = await fileExists2(import_node_path63.default.join(ctx.scanPath, ".env.neat"));
|
|
13002
13656
|
const registryInstrPackages = new Set(
|
|
13003
13657
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
13004
13658
|
);
|
|
@@ -13020,7 +13674,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
13020
13674
|
);
|
|
13021
13675
|
}
|
|
13022
13676
|
for (const file of hookFiles) {
|
|
13023
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13677
|
+
const content = await import_node_fs28.promises.readFile(import_node_path63.default.join(ctx.scanPath, file), "utf8");
|
|
13024
13678
|
if (content.includes(args.registration_snippet)) {
|
|
13025
13679
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
13026
13680
|
}
|
|
@@ -13032,10 +13686,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
13032
13686
|
);
|
|
13033
13687
|
}
|
|
13034
13688
|
const primaryFile = primary.file;
|
|
13035
|
-
const primaryPath =
|
|
13689
|
+
const primaryPath = import_node_path63.default.join(ctx.scanPath, primaryFile);
|
|
13036
13690
|
const filesTouched = [];
|
|
13037
13691
|
const depsAdded = [];
|
|
13038
|
-
const pkgPath =
|
|
13692
|
+
const pkgPath = import_node_path63.default.join(ctx.scanPath, "package.json");
|
|
13039
13693
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13040
13694
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
13041
13695
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -13074,7 +13728,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
13074
13728
|
};
|
|
13075
13729
|
}
|
|
13076
13730
|
for (const file of hookFiles) {
|
|
13077
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13731
|
+
const content = await import_node_fs28.promises.readFile(import_node_path63.default.join(ctx.scanPath, file), "utf8");
|
|
13078
13732
|
if (content.includes(args.registration_snippet)) {
|
|
13079
13733
|
return {
|
|
13080
13734
|
library: args.library,
|
|
@@ -13115,7 +13769,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13115
13769
|
if (!match) {
|
|
13116
13770
|
return { undone: false, message: "no apply found for library" };
|
|
13117
13771
|
}
|
|
13118
|
-
const pkgPath =
|
|
13772
|
+
const pkgPath = import_node_path63.default.join(ctx.scanPath, "package.json");
|
|
13119
13773
|
if (await fileExists2(pkgPath)) {
|
|
13120
13774
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13121
13775
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -13126,7 +13780,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13126
13780
|
}
|
|
13127
13781
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13128
13782
|
for (const file of hookFiles) {
|
|
13129
|
-
const filePath =
|
|
13783
|
+
const filePath = import_node_path63.default.join(ctx.scanPath, file);
|
|
13130
13784
|
const content = await import_node_fs28.promises.readFile(filePath, "utf8");
|
|
13131
13785
|
if (content.includes(match.registration_snippet)) {
|
|
13132
13786
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -13142,39 +13796,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
13142
13796
|
|
|
13143
13797
|
// src/divergences.ts
|
|
13144
13798
|
init_cjs_shims();
|
|
13145
|
-
var
|
|
13799
|
+
var import_types51 = require("@neat.is/types");
|
|
13146
13800
|
function bucketKey(source, target, type) {
|
|
13147
13801
|
return `${type}|${source}|${target}`;
|
|
13148
13802
|
}
|
|
13149
13803
|
function bucketSourceFor(graph, edge) {
|
|
13150
|
-
if (edge.type !==
|
|
13151
|
-
const parsed = (0,
|
|
13804
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) return edge.source;
|
|
13805
|
+
const parsed = (0, import_types51.parseFileId)(edge.source);
|
|
13152
13806
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
13153
13807
|
const target = graph.getNodeAttributes(edge.target);
|
|
13154
|
-
if (target.type !==
|
|
13155
|
-
return (0,
|
|
13808
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) return edge.source;
|
|
13809
|
+
return (0, import_types51.serviceId)(parsed.service);
|
|
13156
13810
|
}
|
|
13157
13811
|
function bucketEdges(graph) {
|
|
13158
13812
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
13159
13813
|
graph.forEachEdge((id, attrs) => {
|
|
13160
13814
|
const e = attrs;
|
|
13161
|
-
const parsed = (0,
|
|
13815
|
+
const parsed = (0, import_types51.parseEdgeId)(id);
|
|
13162
13816
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
13163
13817
|
const source = bucketSourceFor(graph, e);
|
|
13164
13818
|
const key = bucketKey(source, e.target, e.type);
|
|
13165
13819
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
13166
13820
|
switch (provenance) {
|
|
13167
|
-
case
|
|
13821
|
+
case import_types51.Provenance.EXTRACTED:
|
|
13168
13822
|
cur.extracted = e;
|
|
13169
13823
|
break;
|
|
13170
|
-
case
|
|
13824
|
+
case import_types51.Provenance.OBSERVED:
|
|
13171
13825
|
cur.observed = e;
|
|
13172
13826
|
break;
|
|
13173
|
-
case
|
|
13827
|
+
case import_types51.Provenance.INFERRED:
|
|
13174
13828
|
cur.inferred = e;
|
|
13175
13829
|
break;
|
|
13176
13830
|
default:
|
|
13177
|
-
if (e.provenance ===
|
|
13831
|
+
if (e.provenance === import_types51.Provenance.STALE) cur.stale = e;
|
|
13178
13832
|
}
|
|
13179
13833
|
buckets2.set(key, cur);
|
|
13180
13834
|
});
|
|
@@ -13183,22 +13837,22 @@ function bucketEdges(graph) {
|
|
|
13183
13837
|
function nodeIsFrontier(graph, nodeId) {
|
|
13184
13838
|
if (!graph.hasNode(nodeId)) return false;
|
|
13185
13839
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13186
|
-
return attrs.type ===
|
|
13840
|
+
return attrs.type === import_types51.NodeType.FrontierNode;
|
|
13187
13841
|
}
|
|
13188
13842
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
13189
13843
|
if (!graph.hasNode(nodeId)) return false;
|
|
13190
13844
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13191
|
-
return attrs.type ===
|
|
13845
|
+
return attrs.type === import_types51.NodeType.WebSocketChannelNode;
|
|
13192
13846
|
}
|
|
13193
13847
|
function nodeIsServerAction(graph, nodeId) {
|
|
13194
13848
|
if (!graph.hasNode(nodeId)) return false;
|
|
13195
13849
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13196
|
-
return attrs.type ===
|
|
13850
|
+
return attrs.type === import_types51.NodeType.ServerActionNode;
|
|
13197
13851
|
}
|
|
13198
13852
|
function nodeIsSymbol(graph, nodeId) {
|
|
13199
13853
|
if (!graph.hasNode(nodeId)) return false;
|
|
13200
13854
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13201
|
-
return attrs.type ===
|
|
13855
|
+
return attrs.type === import_types51.NodeType.SymbolNode;
|
|
13202
13856
|
}
|
|
13203
13857
|
function clampConfidence(n) {
|
|
13204
13858
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -13218,14 +13872,14 @@ function gradedConfidence(edge) {
|
|
|
13218
13872
|
return clampConfidence(confidenceForEdge(edge));
|
|
13219
13873
|
}
|
|
13220
13874
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13875
|
+
import_types51.EdgeType.CALLS,
|
|
13876
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
13877
|
+
import_types51.EdgeType.PUBLISHES_TO,
|
|
13878
|
+
import_types51.EdgeType.CONSUMES_FROM
|
|
13225
13879
|
]);
|
|
13226
13880
|
function detectMissingDivergences(graph, bucket) {
|
|
13227
13881
|
const out = [];
|
|
13228
|
-
if (bucket.type ===
|
|
13882
|
+
if (bucket.type === import_types51.EdgeType.CONTAINS) return out;
|
|
13229
13883
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
13230
13884
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
13231
13885
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -13267,7 +13921,7 @@ function declaredHostFor(svc) {
|
|
|
13267
13921
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
13268
13922
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13269
13923
|
const e = graph.getEdgeAttributes(edgeId);
|
|
13270
|
-
if (e.type ===
|
|
13924
|
+
if (e.type === import_types51.EdgeType.CONFIGURED_BY && e.provenance === import_types51.Provenance.EXTRACTED) {
|
|
13271
13925
|
return true;
|
|
13272
13926
|
}
|
|
13273
13927
|
}
|
|
@@ -13280,10 +13934,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
13280
13934
|
const out = [];
|
|
13281
13935
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13282
13936
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13283
|
-
if (edge.type !==
|
|
13284
|
-
if (edge.provenance !==
|
|
13937
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13938
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13285
13939
|
const target = graph.getNodeAttributes(edge.target);
|
|
13286
|
-
if (target.type !==
|
|
13940
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13287
13941
|
const observedHost = target.host?.trim();
|
|
13288
13942
|
if (!observedHost) continue;
|
|
13289
13943
|
if (observedHost === declaredHost) continue;
|
|
@@ -13305,10 +13959,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
13305
13959
|
const deps = svc.dependencies ?? {};
|
|
13306
13960
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13307
13961
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13308
|
-
if (edge.type !==
|
|
13309
|
-
if (edge.provenance !==
|
|
13962
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13963
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13310
13964
|
const target = graph.getNodeAttributes(edge.target);
|
|
13311
|
-
if (target.type !==
|
|
13965
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13312
13966
|
for (const pair of compatPairs()) {
|
|
13313
13967
|
if (pair.engine !== target.engine) continue;
|
|
13314
13968
|
const declared = deps[pair.driver];
|
|
@@ -13405,7 +14059,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
13405
14059
|
for (const d of all) {
|
|
13406
14060
|
if (d.type !== "host-mismatch") continue;
|
|
13407
14061
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
13408
|
-
declaredHalf.add((0,
|
|
14062
|
+
declaredHalf.add((0, import_types51.databaseId)(d.extractedHost));
|
|
13409
14063
|
}
|
|
13410
14064
|
if (observedHalf.size === 0) return all;
|
|
13411
14065
|
return all.filter((d) => {
|
|
@@ -13424,13 +14078,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13424
14078
|
}
|
|
13425
14079
|
graph.forEachNode((nodeId, attrs) => {
|
|
13426
14080
|
const n = attrs;
|
|
13427
|
-
if (n.type ===
|
|
14081
|
+
if (n.type === import_types51.NodeType.ServiceNode) {
|
|
13428
14082
|
const svc = n;
|
|
13429
14083
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
13430
14084
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
13431
14085
|
return;
|
|
13432
14086
|
}
|
|
13433
|
-
if (n.type ===
|
|
14087
|
+
if (n.type === import_types51.NodeType.InfraNode && n.kind === "sql-table") {
|
|
13434
14088
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
13435
14089
|
}
|
|
13436
14090
|
});
|
|
@@ -13466,7 +14120,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13466
14120
|
const bc = "column" in b && b.column ? b.column : "";
|
|
13467
14121
|
return ac.localeCompare(bc);
|
|
13468
14122
|
});
|
|
13469
|
-
return
|
|
14123
|
+
return import_types51.DivergenceResultSchema.parse({
|
|
13470
14124
|
divergences: filtered,
|
|
13471
14125
|
totalAffected: filtered.length,
|
|
13472
14126
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -13599,26 +14253,26 @@ function canonicalJson(value) {
|
|
|
13599
14253
|
init_cjs_shims();
|
|
13600
14254
|
var import_node_fs30 = require("fs");
|
|
13601
14255
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
13602
|
-
var
|
|
13603
|
-
var
|
|
14256
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
14257
|
+
var import_types52 = require("@neat.is/types");
|
|
13604
14258
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
13605
14259
|
var LOCK_RETRY_MS = 50;
|
|
13606
14260
|
function neatHome() {
|
|
13607
14261
|
const override = process.env.NEAT_HOME;
|
|
13608
|
-
if (override && override.length > 0) return
|
|
13609
|
-
return
|
|
14262
|
+
if (override && override.length > 0) return import_node_path64.default.resolve(override);
|
|
14263
|
+
return import_node_path64.default.join(import_node_os3.default.homedir(), ".neat");
|
|
13610
14264
|
}
|
|
13611
14265
|
function registryPath() {
|
|
13612
|
-
return
|
|
14266
|
+
return import_node_path64.default.join(neatHome(), "projects.json");
|
|
13613
14267
|
}
|
|
13614
14268
|
function registryLockPath() {
|
|
13615
|
-
return
|
|
14269
|
+
return import_node_path64.default.join(neatHome(), "projects.json.lock");
|
|
13616
14270
|
}
|
|
13617
14271
|
function daemonPidPath() {
|
|
13618
|
-
return
|
|
14272
|
+
return import_node_path64.default.join(neatHome(), "neatd.pid");
|
|
13619
14273
|
}
|
|
13620
14274
|
function daemonsDir() {
|
|
13621
|
-
return
|
|
14275
|
+
return import_node_path64.default.join(neatHome(), "daemons");
|
|
13622
14276
|
}
|
|
13623
14277
|
function isFiniteInt(v) {
|
|
13624
14278
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -13659,7 +14313,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
13659
14313
|
const out = [];
|
|
13660
14314
|
for (const name of names) {
|
|
13661
14315
|
if (!name.endsWith(".json")) continue;
|
|
13662
|
-
const file =
|
|
14316
|
+
const file = import_node_path64.default.join(dir, name);
|
|
13663
14317
|
let raw;
|
|
13664
14318
|
try {
|
|
13665
14319
|
raw = await import_node_fs30.promises.readFile(file, "utf8");
|
|
@@ -13736,7 +14390,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
13736
14390
|
}
|
|
13737
14391
|
}
|
|
13738
14392
|
async function writeAtomically(target, contents) {
|
|
13739
|
-
await import_node_fs30.promises.mkdir(
|
|
14393
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(target), { recursive: true });
|
|
13740
14394
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
13741
14395
|
const fd = await import_node_fs30.promises.open(tmp, "w");
|
|
13742
14396
|
try {
|
|
@@ -13749,7 +14403,7 @@ async function writeAtomically(target, contents) {
|
|
|
13749
14403
|
}
|
|
13750
14404
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
13751
14405
|
const deadline = Date.now() + timeoutMs;
|
|
13752
|
-
await import_node_fs30.promises.mkdir(
|
|
14406
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(lockPath), { recursive: true });
|
|
13753
14407
|
let probedHolder = false;
|
|
13754
14408
|
while (true) {
|
|
13755
14409
|
try {
|
|
@@ -13802,10 +14456,10 @@ async function readRegistry() {
|
|
|
13802
14456
|
throw err;
|
|
13803
14457
|
}
|
|
13804
14458
|
const parsed = JSON.parse(raw);
|
|
13805
|
-
return
|
|
14459
|
+
return import_types52.RegistryFileSchema.parse(parsed);
|
|
13806
14460
|
}
|
|
13807
14461
|
async function writeRegistry(reg) {
|
|
13808
|
-
const validated =
|
|
14462
|
+
const validated = import_types52.RegistryFileSchema.parse(reg);
|
|
13809
14463
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
13810
14464
|
}
|
|
13811
14465
|
async function getProject(name) {
|
|
@@ -13950,7 +14604,7 @@ init_auth();
|
|
|
13950
14604
|
// src/connectors-config.ts
|
|
13951
14605
|
init_cjs_shims();
|
|
13952
14606
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
13953
|
-
var
|
|
14607
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
13954
14608
|
var import_node_fs31 = require("fs");
|
|
13955
14609
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
13956
14610
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -13965,11 +14619,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
13965
14619
|
};
|
|
13966
14620
|
function neatHome2() {
|
|
13967
14621
|
const override = process.env.NEAT_HOME;
|
|
13968
|
-
if (override && override.length > 0) return
|
|
13969
|
-
return
|
|
14622
|
+
if (override && override.length > 0) return import_node_path65.default.resolve(override);
|
|
14623
|
+
return import_node_path65.default.join(import_node_os4.default.homedir(), ".neat");
|
|
13970
14624
|
}
|
|
13971
14625
|
function connectorsConfigPath(home = neatHome2()) {
|
|
13972
|
-
return
|
|
14626
|
+
return import_node_path65.default.join(home, "connectors.json");
|
|
13973
14627
|
}
|
|
13974
14628
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
13975
14629
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -14156,15 +14810,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
14156
14810
|
|
|
14157
14811
|
// src/connectors/index.ts
|
|
14158
14812
|
init_cjs_shims();
|
|
14159
|
-
var
|
|
14813
|
+
var import_types53 = require("@neat.is/types");
|
|
14160
14814
|
var NO_ENV = "unknown";
|
|
14161
14815
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
14162
14816
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14163
14817
|
const sites = [];
|
|
14164
14818
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
14165
14819
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
14166
|
-
if (edge.provenance !==
|
|
14167
|
-
const parsed = (0,
|
|
14820
|
+
if (edge.provenance !== import_types53.Provenance.EXTRACTED) continue;
|
|
14821
|
+
const parsed = (0, import_types53.parseFileId)(edge.source);
|
|
14168
14822
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
14169
14823
|
const site = { relPath: edge.evidence.file };
|
|
14170
14824
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -14175,7 +14829,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
14175
14829
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
14176
14830
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14177
14831
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
14178
|
-
if (attrs.type !==
|
|
14832
|
+
if (attrs.type !== import_types53.NodeType.RouteNode || !attrs.path) return void 0;
|
|
14179
14833
|
const site = { relPath: attrs.path };
|
|
14180
14834
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
14181
14835
|
return site;
|
|
@@ -14656,10 +15310,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
14656
15310
|
// src/connectors/supabase/map.ts
|
|
14657
15311
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
14658
15312
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
14659
|
-
function targetFromRestPath(
|
|
14660
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
15313
|
+
function targetFromRestPath(path70) {
|
|
15314
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path70);
|
|
14661
15315
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
14662
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
15316
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path70);
|
|
14663
15317
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
14664
15318
|
return null;
|
|
14665
15319
|
}
|
|
@@ -14770,23 +15424,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
14770
15424
|
|
|
14771
15425
|
// src/connectors/supabase/resolve.ts
|
|
14772
15426
|
init_cjs_shims();
|
|
14773
|
-
var
|
|
15427
|
+
var import_types55 = require("@neat.is/types");
|
|
14774
15428
|
function createSupabaseResolveTarget(graph, config) {
|
|
14775
15429
|
return (signal, _ctx) => {
|
|
14776
15430
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
14777
15431
|
return null;
|
|
14778
15432
|
}
|
|
14779
|
-
const subResourceId = (0,
|
|
15433
|
+
const subResourceId = (0, import_types55.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
14780
15434
|
if (graph.hasNode(subResourceId)) {
|
|
14781
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
15435
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14782
15436
|
}
|
|
14783
|
-
const bareResourceId = (0,
|
|
15437
|
+
const bareResourceId = (0, import_types55.infraId)(signal.targetKind, signal.targetName);
|
|
14784
15438
|
if (graph.hasNode(bareResourceId)) {
|
|
14785
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
15439
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14786
15440
|
}
|
|
14787
|
-
const projectLevelId = (0,
|
|
15441
|
+
const projectLevelId = (0, import_types55.infraId)("supabase", config.nodeRef);
|
|
14788
15442
|
if (graph.hasNode(projectLevelId)) {
|
|
14789
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
15443
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14790
15444
|
}
|
|
14791
15445
|
return null;
|
|
14792
15446
|
};
|
|
@@ -14879,7 +15533,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
14879
15533
|
|
|
14880
15534
|
// src/connectors/railway/index.ts
|
|
14881
15535
|
init_cjs_shims();
|
|
14882
|
-
var
|
|
15536
|
+
var import_types59 = require("@neat.is/types");
|
|
14883
15537
|
|
|
14884
15538
|
// src/connectors/railway/client.ts
|
|
14885
15539
|
init_cjs_shims();
|
|
@@ -15030,7 +15684,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
15030
15684
|
const out = [];
|
|
15031
15685
|
graph.forEachNode((_id, attrs) => {
|
|
15032
15686
|
const node = attrs;
|
|
15033
|
-
if (node.type !==
|
|
15687
|
+
if (node.type !== import_types59.NodeType.RouteNode) return;
|
|
15034
15688
|
const route = attrs;
|
|
15035
15689
|
if (route.service !== serviceName) return;
|
|
15036
15690
|
out.push({
|
|
@@ -15134,12 +15788,12 @@ function createRailwayResolveTarget(config) {
|
|
|
15134
15788
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
15135
15789
|
if (!serviceName) return null;
|
|
15136
15790
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
15137
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
15791
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types59.EdgeType.CALLS };
|
|
15138
15792
|
}
|
|
15139
15793
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
15140
15794
|
const peerName = config.serviceNameById[signal.targetName];
|
|
15141
15795
|
if (!peerName) return null;
|
|
15142
|
-
return { targetNodeId: (0,
|
|
15796
|
+
return { targetNodeId: (0, import_types59.serviceId)(peerName), serviceName, edgeType: import_types59.EdgeType.CONNECTS_TO };
|
|
15143
15797
|
}
|
|
15144
15798
|
return null;
|
|
15145
15799
|
};
|
|
@@ -15263,9 +15917,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
15263
15917
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
15264
15918
|
if (secondSep === -1) return null;
|
|
15265
15919
|
const method = rest.slice(0, secondSep);
|
|
15266
|
-
const
|
|
15267
|
-
if (!resourceName || !method || !
|
|
15268
|
-
return { resourceName, method, path:
|
|
15920
|
+
const path70 = rest.slice(secondSep + 1);
|
|
15921
|
+
if (!resourceName || !method || !path70) return null;
|
|
15922
|
+
return { resourceName, method, path: path70 };
|
|
15269
15923
|
}
|
|
15270
15924
|
function resourceNameFor(type, labels) {
|
|
15271
15925
|
if (!labels) return null;
|
|
@@ -15303,14 +15957,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
15303
15957
|
if (!req2) return null;
|
|
15304
15958
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
15305
15959
|
const method = req2.requestMethod.toUpperCase();
|
|
15306
|
-
const
|
|
15307
|
-
if (
|
|
15960
|
+
const path70 = pathFromRequestUrl(req2.requestUrl);
|
|
15961
|
+
if (path70 === null) return null;
|
|
15308
15962
|
const timestamp = entry2.timestamp;
|
|
15309
15963
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15310
15964
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD2;
|
|
15311
15965
|
return {
|
|
15312
15966
|
targetKind: resourceType,
|
|
15313
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
15967
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path70 }),
|
|
15314
15968
|
callCount: 1,
|
|
15315
15969
|
errorCount: isError ? 1 : 0,
|
|
15316
15970
|
lastObservedIso: timestamp
|
|
@@ -15327,7 +15981,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
15327
15981
|
|
|
15328
15982
|
// src/connectors/firebase/resolve.ts
|
|
15329
15983
|
init_cjs_shims();
|
|
15330
|
-
var
|
|
15984
|
+
var import_types60 = require("@neat.is/types");
|
|
15331
15985
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
15332
15986
|
switch (resourceType) {
|
|
15333
15987
|
case "cloud_function":
|
|
@@ -15342,7 +15996,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
15342
15996
|
const entries = [];
|
|
15343
15997
|
graph.forEachNode((_id, attrs) => {
|
|
15344
15998
|
const node = attrs;
|
|
15345
|
-
if (node.type !==
|
|
15999
|
+
if (node.type !== import_types60.NodeType.RouteNode) return;
|
|
15346
16000
|
const route = attrs;
|
|
15347
16001
|
if (route.service !== serviceName) return;
|
|
15348
16002
|
entries.push({
|
|
@@ -15374,7 +16028,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
15374
16028
|
return {
|
|
15375
16029
|
targetNodeId: match.routeNodeId,
|
|
15376
16030
|
serviceName,
|
|
15377
|
-
edgeType:
|
|
16031
|
+
edgeType: import_types60.EdgeType.CALLS
|
|
15378
16032
|
};
|
|
15379
16033
|
};
|
|
15380
16034
|
}
|
|
@@ -15401,7 +16055,7 @@ init_cjs_shims();
|
|
|
15401
16055
|
|
|
15402
16056
|
// src/connectors/cloudflare/connector.ts
|
|
15403
16057
|
init_cjs_shims();
|
|
15404
|
-
var
|
|
16058
|
+
var import_types62 = require("@neat.is/types");
|
|
15405
16059
|
|
|
15406
16060
|
// src/connectors/cloudflare/client.ts
|
|
15407
16061
|
init_cjs_shims();
|
|
@@ -15517,7 +16171,7 @@ function mapEventToSignal(event) {
|
|
|
15517
16171
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
15518
16172
|
const statusCode = metadata?.statusCode;
|
|
15519
16173
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
15520
|
-
const
|
|
16174
|
+
const path70 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
15521
16175
|
return {
|
|
15522
16176
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
15523
16177
|
targetName: scriptName,
|
|
@@ -15525,7 +16179,7 @@ function mapEventToSignal(event) {
|
|
|
15525
16179
|
errorCount: isError ? 1 : 0,
|
|
15526
16180
|
lastObservedIso: observedAt.toISOString(),
|
|
15527
16181
|
method,
|
|
15528
|
-
...
|
|
16182
|
+
...path70 ? { path: path70 } : {},
|
|
15529
16183
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
15530
16184
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
15531
16185
|
};
|
|
@@ -15565,19 +16219,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
15565
16219
|
graph.forEachNode((id, attrs) => {
|
|
15566
16220
|
if (found) return;
|
|
15567
16221
|
const a = attrs;
|
|
15568
|
-
if (a.type ===
|
|
16222
|
+
if (a.type === import_types62.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
15569
16223
|
found = id;
|
|
15570
16224
|
}
|
|
15571
16225
|
});
|
|
15572
16226
|
return found;
|
|
15573
16227
|
}
|
|
15574
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
15575
|
-
const normalizedPath = normalizePathTemplate(
|
|
16228
|
+
function findMatchingRouteNode(graph, serviceName, method, path70) {
|
|
16229
|
+
const normalizedPath = normalizePathTemplate(path70);
|
|
15576
16230
|
let found = null;
|
|
15577
16231
|
graph.forEachNode((id, attrs) => {
|
|
15578
16232
|
if (found) return;
|
|
15579
16233
|
const a = attrs;
|
|
15580
|
-
if (a.type !==
|
|
16234
|
+
if (a.type !== import_types62.NodeType.RouteNode || a.service !== serviceName) return;
|
|
15581
16235
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
15582
16236
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
15583
16237
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -15589,18 +16243,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15589
16243
|
return (signal) => {
|
|
15590
16244
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
15591
16245
|
const scriptName = signal.targetName;
|
|
15592
|
-
const { method, path:
|
|
16246
|
+
const { method, path: path70 } = signal;
|
|
15593
16247
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
15594
|
-
if (!method || !
|
|
15595
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
16248
|
+
if (!method || !path70) return wholeFileId;
|
|
16249
|
+
return findMatchingRouteNode(graph, serviceName, method, path70) ?? wholeFileId;
|
|
15596
16250
|
};
|
|
15597
16251
|
const mapping = config.workers?.[scriptName];
|
|
15598
16252
|
if (mapping) {
|
|
15599
|
-
const wholeFileId = (0,
|
|
16253
|
+
const wholeFileId = (0, import_types62.fileId)(mapping.service, mapping.entryFile);
|
|
15600
16254
|
return {
|
|
15601
16255
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
15602
16256
|
serviceName: mapping.service,
|
|
15603
|
-
edgeType:
|
|
16257
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15604
16258
|
};
|
|
15605
16259
|
}
|
|
15606
16260
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -15609,13 +16263,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15609
16263
|
return {
|
|
15610
16264
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
15611
16265
|
serviceName: fileNode.service,
|
|
15612
|
-
edgeType:
|
|
16266
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15613
16267
|
};
|
|
15614
16268
|
}
|
|
15615
16269
|
return {
|
|
15616
|
-
targetNodeId: (0,
|
|
16270
|
+
targetNodeId: (0, import_types62.infraId)("cloudflare-worker", scriptName),
|
|
15617
16271
|
serviceName: scriptName,
|
|
15618
|
-
edgeType:
|
|
16272
|
+
edgeType: import_types62.EdgeType.CALLS,
|
|
15619
16273
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
15620
16274
|
};
|
|
15621
16275
|
};
|
|
@@ -15811,14 +16465,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
15811
16465
|
|
|
15812
16466
|
// src/connectors/neon/resolve.ts
|
|
15813
16467
|
init_cjs_shims();
|
|
15814
|
-
var
|
|
16468
|
+
var import_types66 = require("@neat.is/types");
|
|
15815
16469
|
function createNeonResolveTarget(config) {
|
|
15816
16470
|
return (signal) => {
|
|
15817
16471
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
15818
16472
|
return {
|
|
15819
|
-
targetNodeId: (0,
|
|
16473
|
+
targetNodeId: (0, import_types66.infraId)("sql-table", signal.targetName),
|
|
15820
16474
|
serviceName: config.serviceName,
|
|
15821
|
-
edgeType:
|
|
16475
|
+
edgeType: import_types66.EdgeType.CALLS,
|
|
15822
16476
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
15823
16477
|
};
|
|
15824
16478
|
};
|
|
@@ -15944,9 +16598,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
15944
16598
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
15945
16599
|
if (secondSep === -1) return null;
|
|
15946
16600
|
const method = rest.slice(0, secondSep);
|
|
15947
|
-
const
|
|
15948
|
-
if (!serviceName || !method || !
|
|
15949
|
-
return { serviceName, method, path:
|
|
16601
|
+
const path70 = rest.slice(secondSep + 1);
|
|
16602
|
+
if (!serviceName || !method || !path70) return null;
|
|
16603
|
+
return { serviceName, method, path: path70 };
|
|
15950
16604
|
}
|
|
15951
16605
|
|
|
15952
16606
|
// src/connectors/cloud-run/map.ts
|
|
@@ -15975,14 +16629,14 @@ function mapLogEntryToSignal2(entry2) {
|
|
|
15975
16629
|
if (!req2) return null;
|
|
15976
16630
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
15977
16631
|
const method = req2.requestMethod.toUpperCase();
|
|
15978
|
-
const
|
|
15979
|
-
if (
|
|
16632
|
+
const path70 = pathFromRequestUrl2(req2.requestUrl);
|
|
16633
|
+
if (path70 === null) return null;
|
|
15980
16634
|
const timestamp = entry2.timestamp;
|
|
15981
16635
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15982
16636
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD4;
|
|
15983
16637
|
return {
|
|
15984
16638
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
15985
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
16639
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path70 }),
|
|
15986
16640
|
callCount: 1,
|
|
15987
16641
|
errorCount: isError ? 1 : 0,
|
|
15988
16642
|
lastObservedIso: timestamp
|
|
@@ -15999,14 +16653,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
15999
16653
|
|
|
16000
16654
|
// src/connectors/cloud-run/resolve.ts
|
|
16001
16655
|
init_cjs_shims();
|
|
16002
|
-
var
|
|
16656
|
+
var import_types70 = require("@neat.is/types");
|
|
16003
16657
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
16004
16658
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
16005
16659
|
let found = null;
|
|
16006
16660
|
graph.forEachNode((_id, attrs) => {
|
|
16007
16661
|
if (found) return;
|
|
16008
16662
|
const node = attrs;
|
|
16009
|
-
if (node.type !==
|
|
16663
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
16010
16664
|
const route = attrs;
|
|
16011
16665
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
16012
16666
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -16021,23 +16675,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
16021
16675
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
16022
16676
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
16023
16677
|
if (!identity) return null;
|
|
16024
|
-
const { serviceName: gcpServiceName, method, path:
|
|
16678
|
+
const { serviceName: gcpServiceName, method, path: path70 } = identity;
|
|
16025
16679
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
16026
16680
|
if (mappedService) {
|
|
16027
16681
|
const routeNodeId = findMatchingRouteNode2(
|
|
16028
16682
|
graph,
|
|
16029
16683
|
mappedService,
|
|
16030
16684
|
method,
|
|
16031
|
-
normalizePathTemplate(
|
|
16685
|
+
normalizePathTemplate(path70)
|
|
16032
16686
|
);
|
|
16033
16687
|
if (routeNodeId) {
|
|
16034
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
16688
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types70.EdgeType.CALLS };
|
|
16035
16689
|
}
|
|
16036
16690
|
}
|
|
16037
16691
|
return {
|
|
16038
|
-
targetNodeId: (0,
|
|
16692
|
+
targetNodeId: (0, import_types70.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
16039
16693
|
serviceName: mappedService ?? gcpServiceName,
|
|
16040
|
-
edgeType:
|
|
16694
|
+
edgeType: import_types70.EdgeType.CALLS,
|
|
16041
16695
|
ensureInfraNode: {
|
|
16042
16696
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
16043
16697
|
name: gcpServiceName,
|
|
@@ -16078,7 +16732,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
16078
16732
|
|
|
16079
16733
|
// src/connectors/render/index.ts
|
|
16080
16734
|
init_cjs_shims();
|
|
16081
|
-
var
|
|
16735
|
+
var import_types73 = require("@neat.is/types");
|
|
16082
16736
|
|
|
16083
16737
|
// src/connectors/render/types.ts
|
|
16084
16738
|
init_cjs_shims();
|
|
@@ -16156,7 +16810,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
16156
16810
|
const out = [];
|
|
16157
16811
|
graph.forEachNode((_id, attrs) => {
|
|
16158
16812
|
const node = attrs;
|
|
16159
|
-
if (node.type !==
|
|
16813
|
+
if (node.type !== import_types73.NodeType.RouteNode) return;
|
|
16160
16814
|
const route = attrs;
|
|
16161
16815
|
if (route.service !== serviceName) return;
|
|
16162
16816
|
out.push({
|
|
@@ -16241,7 +16895,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
16241
16895
|
function createRenderResolveTarget(config) {
|
|
16242
16896
|
return (signal) => {
|
|
16243
16897
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
16244
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
16898
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types73.EdgeType.CALLS };
|
|
16245
16899
|
}
|
|
16246
16900
|
return null;
|
|
16247
16901
|
};
|
|
@@ -16379,21 +17033,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
16379
17033
|
|
|
16380
17034
|
// src/connectors/planetscale/resolve.ts
|
|
16381
17035
|
init_cjs_shims();
|
|
16382
|
-
var
|
|
17036
|
+
var import_types77 = require("@neat.is/types");
|
|
16383
17037
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
16384
17038
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
16385
17039
|
const databaseName = `${config.organization}/${config.database}`;
|
|
16386
17040
|
return (signal, _ctx) => {
|
|
16387
17041
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
16388
|
-
const tableId = (0,
|
|
17042
|
+
const tableId = (0, import_types77.infraId)("sql-table", signal.targetName);
|
|
16389
17043
|
if (graph.hasNode(tableId)) {
|
|
16390
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
17044
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types77.EdgeType.CALLS };
|
|
16391
17045
|
}
|
|
16392
|
-
const providerId = (0,
|
|
17046
|
+
const providerId = (0, import_types77.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
16393
17047
|
return {
|
|
16394
17048
|
targetNodeId: providerId,
|
|
16395
17049
|
serviceName: config.serviceName,
|
|
16396
|
-
edgeType:
|
|
17050
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
16397
17051
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
16398
17052
|
};
|
|
16399
17053
|
};
|
|
@@ -17063,11 +17717,11 @@ function registerRoutes(scope, ctx) {
|
|
|
17063
17717
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
17064
17718
|
const parsed = [];
|
|
17065
17719
|
for (const c of candidates) {
|
|
17066
|
-
const r =
|
|
17720
|
+
const r = import_types80.DivergenceTypeSchema.safeParse(c);
|
|
17067
17721
|
if (!r.success) {
|
|
17068
17722
|
return reply.code(400).send({
|
|
17069
17723
|
error: `unknown divergence type "${c}"`,
|
|
17070
|
-
allowed:
|
|
17724
|
+
allowed: import_types80.DivergenceTypeSchema.options
|
|
17071
17725
|
});
|
|
17072
17726
|
}
|
|
17073
17727
|
parsed.push(r.data);
|
|
@@ -17376,7 +18030,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17376
18030
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
17377
18031
|
let violations = await log.readAll();
|
|
17378
18032
|
if (req2.query.severity) {
|
|
17379
|
-
const sev =
|
|
18033
|
+
const sev = import_types80.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
17380
18034
|
if (!sev.success) {
|
|
17381
18035
|
return reply.code(400).send({
|
|
17382
18036
|
error: "invalid severity",
|
|
@@ -17415,7 +18069,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17415
18069
|
scope.post("/policies/check", async (req2, reply) => {
|
|
17416
18070
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
17417
18071
|
if (!proj) return;
|
|
17418
|
-
const parsed =
|
|
18072
|
+
const parsed = import_types80.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
17419
18073
|
if (!parsed.success) {
|
|
17420
18074
|
return reply.code(400).send({
|
|
17421
18075
|
error: "invalid /policies/check body",
|
|
@@ -17737,7 +18391,7 @@ init_auth();
|
|
|
17737
18391
|
// src/unrouted.ts
|
|
17738
18392
|
init_cjs_shims();
|
|
17739
18393
|
var import_node_fs32 = require("fs");
|
|
17740
|
-
var
|
|
18394
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
17741
18395
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
17742
18396
|
return {
|
|
17743
18397
|
timestamp: now.toISOString(),
|
|
@@ -17747,34 +18401,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
17747
18401
|
};
|
|
17748
18402
|
}
|
|
17749
18403
|
async function appendUnroutedSpan(neatHome4, record) {
|
|
17750
|
-
const target =
|
|
18404
|
+
const target = import_node_path66.default.join(neatHome4, "errors.ndjson");
|
|
17751
18405
|
await import_node_fs32.promises.mkdir(neatHome4, { recursive: true });
|
|
17752
18406
|
await import_node_fs32.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
17753
18407
|
}
|
|
17754
18408
|
function unroutedErrorsPath(neatHome4) {
|
|
17755
|
-
return
|
|
18409
|
+
return import_node_path66.default.join(neatHome4, "errors.ndjson");
|
|
17756
18410
|
}
|
|
17757
18411
|
|
|
17758
18412
|
// src/daemon.ts
|
|
17759
|
-
var
|
|
18413
|
+
var import_types81 = require("@neat.is/types");
|
|
17760
18414
|
function daemonJsonPath(scanPath) {
|
|
17761
|
-
return
|
|
18415
|
+
return import_node_path67.default.join(scanPath, "neat-out", "daemon.json");
|
|
17762
18416
|
}
|
|
17763
18417
|
function daemonsDiscoveryDir(home) {
|
|
17764
18418
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
17765
|
-
return
|
|
18419
|
+
return import_node_path67.default.join(base, "daemons");
|
|
17766
18420
|
}
|
|
17767
18421
|
function daemonDiscoveryPath(project, home) {
|
|
17768
|
-
return
|
|
18422
|
+
return import_node_path67.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
17769
18423
|
}
|
|
17770
18424
|
function sanitizeDiscoveryName(project) {
|
|
17771
18425
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
17772
18426
|
}
|
|
17773
18427
|
function neatHomeFromEnv() {
|
|
17774
18428
|
const env = process.env.NEAT_HOME;
|
|
17775
|
-
if (env && env.length > 0) return
|
|
18429
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17776
18430
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17777
|
-
return
|
|
18431
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17778
18432
|
}
|
|
17779
18433
|
function resolveNeatVersion() {
|
|
17780
18434
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -17843,11 +18497,11 @@ function teardownSlot(slot) {
|
|
|
17843
18497
|
}
|
|
17844
18498
|
}
|
|
17845
18499
|
function neatHomeFor(opts) {
|
|
17846
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
18500
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path67.default.resolve(opts.neatHome);
|
|
17847
18501
|
const env = process.env.NEAT_HOME;
|
|
17848
|
-
if (env && env.length > 0) return
|
|
18502
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17849
18503
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17850
|
-
return
|
|
18504
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17851
18505
|
}
|
|
17852
18506
|
function routeSpanToProject(serviceName, projects) {
|
|
17853
18507
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -17895,11 +18549,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
17895
18549
|
if (!serviceName) return true;
|
|
17896
18550
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
17897
18551
|
return graph.someNode(
|
|
17898
|
-
(_id, attrs) => attrs.type ===
|
|
18552
|
+
(_id, attrs) => attrs.type === import_types81.NodeType.ServiceNode && attrs.name === serviceName
|
|
17899
18553
|
);
|
|
17900
18554
|
}
|
|
17901
18555
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
17902
|
-
const paths = pathsForProject(entry2.name,
|
|
18556
|
+
const paths = pathsForProject(entry2.name, import_node_path67.default.join(entry2.path, "neat-out"));
|
|
17903
18557
|
try {
|
|
17904
18558
|
const stat = await import_node_fs33.promises.stat(entry2.path);
|
|
17905
18559
|
if (!stat.isDirectory()) {
|
|
@@ -18015,7 +18669,7 @@ async function startDaemon(opts = {}) {
|
|
|
18015
18669
|
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;
|
|
18016
18670
|
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;
|
|
18017
18671
|
const singleProject = projectArg;
|
|
18018
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
18672
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path67.default.resolve(projectPathArg) : null;
|
|
18019
18673
|
if (singleProject && !singleProjectPath) {
|
|
18020
18674
|
throw new Error(
|
|
18021
18675
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -18030,7 +18684,7 @@ async function startDaemon(opts = {}) {
|
|
|
18030
18684
|
);
|
|
18031
18685
|
}
|
|
18032
18686
|
}
|
|
18033
|
-
const pidPath =
|
|
18687
|
+
const pidPath = import_node_path67.default.join(home, "neatd.pid");
|
|
18034
18688
|
await writeAtomically(pidPath, `${process.pid}
|
|
18035
18689
|
`);
|
|
18036
18690
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -18442,8 +19096,8 @@ async function startDaemon(opts = {}) {
|
|
|
18442
19096
|
let registryWatcher = null;
|
|
18443
19097
|
let reloadTimer = null;
|
|
18444
19098
|
if (!singleProject) try {
|
|
18445
|
-
const regDir =
|
|
18446
|
-
const regBase =
|
|
19099
|
+
const regDir = import_node_path67.default.dirname(regPath);
|
|
19100
|
+
const regBase = import_node_path67.default.basename(regPath);
|
|
18447
19101
|
registryWatcher = (0, import_node_fs33.watch)(regDir, (_eventType, filename) => {
|
|
18448
19102
|
if (filename !== null && filename !== regBase) return;
|
|
18449
19103
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
@@ -18518,7 +19172,7 @@ init_cjs_shims();
|
|
|
18518
19172
|
var import_node_child_process2 = require("child_process");
|
|
18519
19173
|
var import_node_fs34 = require("fs");
|
|
18520
19174
|
var import_node_net = __toESM(require("net"), 1);
|
|
18521
|
-
var
|
|
19175
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
18522
19176
|
var DEFAULT_WEB_PORT = 6328;
|
|
18523
19177
|
var DEFAULT_REST_PORT = 8080;
|
|
18524
19178
|
function asValidPort(value) {
|
|
@@ -18527,11 +19181,11 @@ function asValidPort(value) {
|
|
|
18527
19181
|
}
|
|
18528
19182
|
function projectRoot() {
|
|
18529
19183
|
const fromEnv = process.env.NEAT_SCAN_PATH;
|
|
18530
|
-
return
|
|
19184
|
+
return import_node_path68.default.resolve(fromEnv && fromEnv.length > 0 ? fromEnv : process.cwd());
|
|
18531
19185
|
}
|
|
18532
19186
|
async function readDaemonPorts(root) {
|
|
18533
19187
|
try {
|
|
18534
|
-
const raw = await import_node_fs34.promises.readFile(
|
|
19188
|
+
const raw = await import_node_fs34.promises.readFile(import_node_path68.default.join(root, "neat-out", "daemon.json"), "utf8");
|
|
18535
19189
|
const parsed = JSON.parse(raw);
|
|
18536
19190
|
const ports = parsed?.ports ?? {};
|
|
18537
19191
|
return { web: asValidPort(ports.web), rest: asValidPort(ports.rest) };
|
|
@@ -18576,10 +19230,10 @@ function resolveWebPackageDir() {
|
|
|
18576
19230
|
eval("require")
|
|
18577
19231
|
);
|
|
18578
19232
|
const pkgJsonPath = req.resolve("@neat.is/web/package.json");
|
|
18579
|
-
return
|
|
19233
|
+
return import_node_path68.default.dirname(pkgJsonPath);
|
|
18580
19234
|
}
|
|
18581
19235
|
function resolveStandaloneServerEntry(webDir) {
|
|
18582
|
-
return
|
|
19236
|
+
return import_node_path68.default.join(webDir, ".next/standalone/packages/web/server.js");
|
|
18583
19237
|
}
|
|
18584
19238
|
async function pickInternalPort() {
|
|
18585
19239
|
return new Promise((resolve, reject) => {
|
|
@@ -18632,7 +19286,7 @@ async function spawnWebUI(restPort, opts = {}) {
|
|
|
18632
19286
|
NEAT_API_URL: apiUrl
|
|
18633
19287
|
};
|
|
18634
19288
|
child = (0, import_node_child_process2.spawn)(process.execPath, [serverEntry], {
|
|
18635
|
-
cwd:
|
|
19289
|
+
cwd: import_node_path68.default.dirname(serverEntry),
|
|
18636
19290
|
env,
|
|
18637
19291
|
stdio: ["ignore", "inherit", "inherit"],
|
|
18638
19292
|
detached: false
|
|
@@ -18808,14 +19462,14 @@ function localVersion() {
|
|
|
18808
19462
|
}
|
|
18809
19463
|
function neatHome3() {
|
|
18810
19464
|
if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {
|
|
18811
|
-
return
|
|
19465
|
+
return import_node_path69.default.resolve(process.env.NEAT_HOME);
|
|
18812
19466
|
}
|
|
18813
19467
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
18814
|
-
return
|
|
19468
|
+
return import_node_path69.default.join(home, ".neat");
|
|
18815
19469
|
}
|
|
18816
19470
|
async function readPid() {
|
|
18817
19471
|
try {
|
|
18818
|
-
const raw = await import_node_fs35.promises.readFile(
|
|
19472
|
+
const raw = await import_node_fs35.promises.readFile(import_node_path69.default.join(neatHome3(), "neatd.pid"), "utf8");
|
|
18819
19473
|
const n = Number.parseInt(raw.trim(), 10);
|
|
18820
19474
|
return Number.isFinite(n) ? n : null;
|
|
18821
19475
|
} catch {
|