@neat.is/core 0.7.6 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-6H757ZNM.js → chunk-4GCV46AP.js} +2 -2
- package/dist/{chunk-XT4NNFH6.js → chunk-UI3AFJAF.js} +765 -216
- package/dist/chunk-UI3AFJAF.js.map +1 -0
- package/dist/{chunk-P2ZEKJ35.js → chunk-Y43UCVZS.js} +9 -6
- package/dist/chunk-Y43UCVZS.js.map +1 -0
- package/dist/{chunk-XHSK4BGL.js → chunk-YVZRBT4C.js} +3 -3
- package/dist/cli.cjs +1143 -590
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +945 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +954 -401
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-APVZSB6W.js → otel-grpc-DPSAGRUU.js} +3 -3
- package/dist/server.cjs +877 -324
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-P2ZEKJ35.js.map +0 -1
- package/dist/chunk-XT4NNFH6.js.map +0 -1
- /package/dist/{chunk-6H757ZNM.js.map → chunk-4GCV46AP.js.map} +0 -0
- /package/dist/{chunk-XHSK4BGL.js.map → chunk-YVZRBT4C.js.map} +0 -0
- /package/dist/{otel-grpc-APVZSB6W.js.map → otel-grpc-DPSAGRUU.js.map} +0 -0
package/dist/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) {
|
|
@@ -3006,7 +3009,7 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
3006
3009
|
]);
|
|
3007
3010
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
3008
3011
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
3009
|
-
function
|
|
3012
|
+
function goRouterRoutesFromSource(source, parser, framework) {
|
|
3010
3013
|
const tree = parseSource2(parser, source);
|
|
3011
3014
|
const prefixes = /* @__PURE__ */ new Map();
|
|
3012
3015
|
const out = [];
|
|
@@ -3016,10 +3019,12 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3016
3019
|
const value = node.childForFieldName("right")?.namedChild(0) ?? node.childForFieldName("value");
|
|
3017
3020
|
if (name && value?.type === "call_expression") {
|
|
3018
3021
|
const fn2 = value.childForFieldName("function");
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3022
|
+
if (fn2?.childForFieldName("field")?.text === "Group") {
|
|
3023
|
+
const leaf2 = goStringLiteral(value.childForFieldName("arguments")?.namedChild(0));
|
|
3024
|
+
if (leaf2 !== null) {
|
|
3025
|
+
const parent = fn2.childForFieldName("operand")?.text ?? "";
|
|
3026
|
+
prefixes.set(name, (prefixes.get(parent) ?? "") + leaf2);
|
|
3027
|
+
}
|
|
3023
3028
|
}
|
|
3024
3029
|
}
|
|
3025
3030
|
return;
|
|
@@ -3030,18 +3035,32 @@ function ginRoutesFromSource(source, parser) {
|
|
|
3030
3035
|
const method = fn.childForFieldName("field")?.text?.toUpperCase();
|
|
3031
3036
|
if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return;
|
|
3032
3037
|
const receiver = fn.childForFieldName("operand")?.text ?? "";
|
|
3033
|
-
const
|
|
3034
|
-
if (
|
|
3035
|
-
const leaf = first.text.slice(1, -1);
|
|
3038
|
+
const leaf = goStringLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3039
|
+
if (leaf === null) return;
|
|
3036
3040
|
out.push({
|
|
3037
|
-
method
|
|
3041
|
+
method,
|
|
3038
3042
|
pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? "") + leaf),
|
|
3039
3043
|
line: node.startPosition.row + 1,
|
|
3040
|
-
framework
|
|
3044
|
+
framework
|
|
3041
3045
|
});
|
|
3042
3046
|
});
|
|
3043
3047
|
return out;
|
|
3044
3048
|
}
|
|
3049
|
+
function goStringLiteral(node) {
|
|
3050
|
+
if (node?.type === "interpreted_string_literal" || node?.type === "raw_string_literal") {
|
|
3051
|
+
return node.text.slice(1, -1);
|
|
3052
|
+
}
|
|
3053
|
+
return null;
|
|
3054
|
+
}
|
|
3055
|
+
function ginRoutesFromSource(source, parser) {
|
|
3056
|
+
return goRouterRoutesFromSource(source, parser, "gin");
|
|
3057
|
+
}
|
|
3058
|
+
function echoRoutesFromSource(source, parser) {
|
|
3059
|
+
return goRouterRoutesFromSource(source, parser, "echo");
|
|
3060
|
+
}
|
|
3061
|
+
function fiberRoutesFromSource(source, parser) {
|
|
3062
|
+
return goRouterRoutesFromSource(source, parser, "fiber");
|
|
3063
|
+
}
|
|
3045
3064
|
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
3046
3065
|
var NESTJS_METHODS = /* @__PURE__ */ new Map([
|
|
3047
3066
|
["Get", "GET"],
|
|
@@ -3626,9 +3645,9 @@ function rubyRocketRoute(args) {
|
|
|
3626
3645
|
if (!pair || pair.type !== "pair") continue;
|
|
3627
3646
|
const k = pair.childForFieldName("key");
|
|
3628
3647
|
if (k?.type !== "string") continue;
|
|
3629
|
-
const
|
|
3630
|
-
if (
|
|
3631
|
-
return { path:
|
|
3648
|
+
const path70 = rubyLiteral(k);
|
|
3649
|
+
if (path70 === null) continue;
|
|
3650
|
+
return { path: path70, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3632
3651
|
}
|
|
3633
3652
|
return null;
|
|
3634
3653
|
}
|
|
@@ -4305,9 +4324,11 @@ async function addRoutes(graph, services) {
|
|
|
4305
4324
|
const hasFlask = deps["flask"] !== void 0;
|
|
4306
4325
|
const hasDjango = deps["django"] !== void 0;
|
|
4307
4326
|
const hasGin = deps["github.com/gin-gonic/gin"] !== void 0;
|
|
4327
|
+
const hasEcho = deps["github.com/labstack/echo/v4"] !== void 0 || deps["github.com/labstack/echo"] !== void 0;
|
|
4328
|
+
const hasFiber = deps["github.com/gofiber/fiber/v2"] !== void 0 || deps["github.com/gofiber/fiber/v3"] !== void 0;
|
|
4308
4329
|
const hasRails = deps["rails"] !== void 0;
|
|
4309
4330
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4310
|
-
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasRails && !hasLaravel)
|
|
4331
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasRails && !hasLaravel)
|
|
4311
4332
|
continue;
|
|
4312
4333
|
const files = await loadSourceFiles(service.dir);
|
|
4313
4334
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4331,7 +4352,10 @@ async function addRoutes(graph, services) {
|
|
|
4331
4352
|
} else if (isRb) {
|
|
4332
4353
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4333
4354
|
} else if (isGo) {
|
|
4334
|
-
routes =
|
|
4355
|
+
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4356
|
+
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
4357
|
+
else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser);
|
|
4358
|
+
else routes = [];
|
|
4335
4359
|
} else if (isPy) {
|
|
4336
4360
|
routes = hasFastapi || hasFlask ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? "fastapi" : "flask") : [];
|
|
4337
4361
|
if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser));
|
|
@@ -5938,6 +5962,12 @@ function parseGoMod(source) {
|
|
|
5938
5962
|
}
|
|
5939
5963
|
return { module: module2, ...goVersion ? { goVersion } : {}, dependencies };
|
|
5940
5964
|
}
|
|
5965
|
+
function goFramework(deps) {
|
|
5966
|
+
if (deps["github.com/gin-gonic/gin"]) return "gin";
|
|
5967
|
+
if (deps["github.com/labstack/echo/v4"] || deps["github.com/labstack/echo"]) return "echo";
|
|
5968
|
+
if (deps["github.com/gofiber/fiber/v2"] || deps["github.com/gofiber/fiber/v3"]) return "fiber";
|
|
5969
|
+
return void 0;
|
|
5970
|
+
}
|
|
5941
5971
|
async function discoverGoService(scanPath, dir) {
|
|
5942
5972
|
let raw;
|
|
5943
5973
|
try {
|
|
@@ -5949,6 +5979,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5949
5979
|
if (!mod) return null;
|
|
5950
5980
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
5951
5981
|
const pkg = { name, dependencies: mod.dependencies };
|
|
5982
|
+
const framework = goFramework(mod.dependencies);
|
|
5952
5983
|
const node = {
|
|
5953
5984
|
id: (0, import_types9.serviceId)(name),
|
|
5954
5985
|
type: import_types9.NodeType.ServiceNode,
|
|
@@ -5956,7 +5987,7 @@ async function discoverGoService(scanPath, dir) {
|
|
|
5956
5987
|
language: "go",
|
|
5957
5988
|
dependencies: mod.dependencies,
|
|
5958
5989
|
repoPath: import_node_path10.default.relative(scanPath, dir),
|
|
5959
|
-
...
|
|
5990
|
+
...framework ? { framework } : {}
|
|
5960
5991
|
};
|
|
5961
5992
|
return { pkg, dir, node };
|
|
5962
5993
|
}
|
|
@@ -6856,7 +6887,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
6856
6887
|
return best;
|
|
6857
6888
|
};
|
|
6858
6889
|
const requests = [];
|
|
6859
|
-
const
|
|
6890
|
+
const walk9 = (node) => {
|
|
6860
6891
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
6861
6892
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
6862
6893
|
if (self && self.kind === "class") {
|
|
@@ -6902,10 +6933,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
6902
6933
|
}
|
|
6903
6934
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6904
6935
|
const child = node.namedChild(i);
|
|
6905
|
-
if (child)
|
|
6936
|
+
if (child) walk9(child);
|
|
6906
6937
|
}
|
|
6907
6938
|
};
|
|
6908
|
-
|
|
6939
|
+
walk9(root);
|
|
6909
6940
|
for (const req2 of requests) {
|
|
6910
6941
|
const targetSid = resolveTarget(req2.targetName, req2.wantKind);
|
|
6911
6942
|
if (!targetSid) continue;
|
|
@@ -7918,20 +7949,20 @@ var import_node_path28 = __toESM(require("path"), 1);
|
|
|
7918
7949
|
var import_types18 = require("@neat.is/types");
|
|
7919
7950
|
async function walkConfigFiles(dir) {
|
|
7920
7951
|
const out = [];
|
|
7921
|
-
async function
|
|
7952
|
+
async function walk9(current) {
|
|
7922
7953
|
const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true });
|
|
7923
7954
|
for (const entry2 of entries) {
|
|
7924
7955
|
const full = import_node_path28.default.join(current, entry2.name);
|
|
7925
7956
|
if (entry2.isDirectory()) {
|
|
7926
7957
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
7927
7958
|
if (await isPythonVenvDir(full)) continue;
|
|
7928
|
-
await
|
|
7959
|
+
await walk9(full);
|
|
7929
7960
|
} else if (entry2.isFile() && isConfigFile(entry2.name).match) {
|
|
7930
7961
|
out.push(full);
|
|
7931
7962
|
}
|
|
7932
7963
|
}
|
|
7933
7964
|
}
|
|
7934
|
-
await
|
|
7965
|
+
await walk9(dir);
|
|
7935
7966
|
return out;
|
|
7936
7967
|
}
|
|
7937
7968
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -8021,20 +8052,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
8021
8052
|
}
|
|
8022
8053
|
async function walkProtoFiles(dir) {
|
|
8023
8054
|
const out = [];
|
|
8024
|
-
async function
|
|
8055
|
+
async function walk9(current) {
|
|
8025
8056
|
const entries = await import_node_fs17.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
8026
8057
|
for (const entry2 of entries) {
|
|
8027
8058
|
const full = import_node_path29.default.join(current, entry2.name);
|
|
8028
8059
|
if (entry2.isDirectory()) {
|
|
8029
8060
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
8030
8061
|
if (await isPythonVenvDir(full)) continue;
|
|
8031
|
-
await
|
|
8062
|
+
await walk9(full);
|
|
8032
8063
|
} else if (entry2.isFile() && import_node_path29.default.extname(entry2.name) === PROTO_EXTENSION) {
|
|
8033
8064
|
out.push(full);
|
|
8034
8065
|
}
|
|
8035
8066
|
}
|
|
8036
8067
|
}
|
|
8037
|
-
await
|
|
8068
|
+
await walk9(dir);
|
|
8038
8069
|
return out;
|
|
8039
8070
|
}
|
|
8040
8071
|
async function addGrpcMethods(graph, services) {
|
|
@@ -8102,7 +8133,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
8102
8133
|
|
|
8103
8134
|
// src/extract/calls/index.ts
|
|
8104
8135
|
init_cjs_shims();
|
|
8105
|
-
var
|
|
8136
|
+
var import_types37 = require("@neat.is/types");
|
|
8106
8137
|
|
|
8107
8138
|
// src/extract/calls/http.ts
|
|
8108
8139
|
init_cjs_shims();
|
|
@@ -8856,7 +8887,7 @@ function isFirestoreClientFactory(node) {
|
|
|
8856
8887
|
}
|
|
8857
8888
|
function firestoreClientVars(root) {
|
|
8858
8889
|
const vars = /* @__PURE__ */ new Set();
|
|
8859
|
-
const
|
|
8890
|
+
const walk9 = (node) => {
|
|
8860
8891
|
if (node.type === "variable_declarator") {
|
|
8861
8892
|
const name = node.childForFieldName("name");
|
|
8862
8893
|
let value = node.childForFieldName("value");
|
|
@@ -8865,9 +8896,9 @@ function firestoreClientVars(root) {
|
|
|
8865
8896
|
vars.add(name.text);
|
|
8866
8897
|
}
|
|
8867
8898
|
}
|
|
8868
|
-
for (const c of namedChildren(node))
|
|
8899
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
8869
8900
|
};
|
|
8870
|
-
|
|
8901
|
+
walk9(root);
|
|
8871
8902
|
return vars;
|
|
8872
8903
|
}
|
|
8873
8904
|
function isClientExpr(node, clientVars) {
|
|
@@ -9022,7 +9053,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9022
9053
|
}
|
|
9023
9054
|
s.add(field);
|
|
9024
9055
|
};
|
|
9025
|
-
const
|
|
9056
|
+
const walk9 = (node) => {
|
|
9026
9057
|
if (node.type === "call_expression") {
|
|
9027
9058
|
const fn = node.childForFieldName("function");
|
|
9028
9059
|
const line = node.startPosition.row + 1;
|
|
@@ -9062,9 +9093,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
9062
9093
|
}
|
|
9063
9094
|
}
|
|
9064
9095
|
}
|
|
9065
|
-
for (const c of namedChildren(node))
|
|
9096
|
+
for (const c of namedChildren(node)) walk9(c);
|
|
9066
9097
|
};
|
|
9067
|
-
|
|
9098
|
+
walk9(tree.rootNode);
|
|
9068
9099
|
const out = [];
|
|
9069
9100
|
for (const [collPath, line] of collLine) {
|
|
9070
9101
|
const byField = writes.get(collPath);
|
|
@@ -9859,7 +9890,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9859
9890
|
const tree = parseSource3(parserForExt2(import_node_path41.default.extname(file.path)), file.content);
|
|
9860
9891
|
const out = [];
|
|
9861
9892
|
const seen = /* @__PURE__ */ new Set();
|
|
9862
|
-
const
|
|
9893
|
+
const walk9 = (node) => {
|
|
9863
9894
|
if (node.type === "call_expression") {
|
|
9864
9895
|
const fn = node.childForFieldName("function");
|
|
9865
9896
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9887,9 +9918,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
9887
9918
|
}
|
|
9888
9919
|
}
|
|
9889
9920
|
}
|
|
9890
|
-
for (const c of namedChildren4(node))
|
|
9921
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9891
9922
|
};
|
|
9892
|
-
|
|
9923
|
+
walk9(tree.rootNode);
|
|
9893
9924
|
return out;
|
|
9894
9925
|
}
|
|
9895
9926
|
function enclosingVarName(call) {
|
|
@@ -9911,7 +9942,7 @@ function enclosingVarName(call) {
|
|
|
9911
9942
|
function collectDrizzleTables(root) {
|
|
9912
9943
|
const tables = [];
|
|
9913
9944
|
const varToTable = /* @__PURE__ */ new Map();
|
|
9914
|
-
const
|
|
9945
|
+
const walk9 = (node) => {
|
|
9915
9946
|
if (node.type === "call_expression") {
|
|
9916
9947
|
const fn = node.childForFieldName("function");
|
|
9917
9948
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -9926,9 +9957,9 @@ function collectDrizzleTables(root) {
|
|
|
9926
9957
|
}
|
|
9927
9958
|
}
|
|
9928
9959
|
}
|
|
9929
|
-
for (const c of namedChildren4(node))
|
|
9960
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9930
9961
|
};
|
|
9931
|
-
|
|
9962
|
+
walk9(root);
|
|
9932
9963
|
return { tables, varToTable };
|
|
9933
9964
|
}
|
|
9934
9965
|
function referencesTargetVar(call) {
|
|
@@ -9951,7 +9982,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
9951
9982
|
const seen = /* @__PURE__ */ new Set();
|
|
9952
9983
|
for (const table of tables) {
|
|
9953
9984
|
if (!table.object) continue;
|
|
9954
|
-
const
|
|
9985
|
+
const walk9 = (node) => {
|
|
9955
9986
|
if (node.type === "call_expression") {
|
|
9956
9987
|
const targetVar = referencesTargetVar(node);
|
|
9957
9988
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -9972,9 +10003,9 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
9972
10003
|
}
|
|
9973
10004
|
}
|
|
9974
10005
|
}
|
|
9975
|
-
for (const c of namedChildren4(node))
|
|
10006
|
+
for (const c of namedChildren4(node)) walk9(c);
|
|
9976
10007
|
};
|
|
9977
|
-
|
|
10008
|
+
walk9(table.object);
|
|
9978
10009
|
}
|
|
9979
10010
|
return out;
|
|
9980
10011
|
}
|
|
@@ -11054,15 +11085,531 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
11054
11085
|
return out;
|
|
11055
11086
|
}
|
|
11056
11087
|
|
|
11088
|
+
// src/extract/calls/gorm.ts
|
|
11089
|
+
init_cjs_shims();
|
|
11090
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11091
|
+
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
11092
|
+
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
11093
|
+
var import_types36 = require("@neat.is/types");
|
|
11094
|
+
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
11095
|
+
var PARSE_CHUNK11 = 16384;
|
|
11096
|
+
function makeGoParser3() {
|
|
11097
|
+
const p = new import_tree_sitter15.default();
|
|
11098
|
+
p.setLanguage(import_tree_sitter_go4.default);
|
|
11099
|
+
return p;
|
|
11100
|
+
}
|
|
11101
|
+
function parseSource10(parser, source) {
|
|
11102
|
+
return parser.parse(
|
|
11103
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
11104
|
+
);
|
|
11105
|
+
}
|
|
11106
|
+
function walk8(node, visit) {
|
|
11107
|
+
visit(node);
|
|
11108
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11109
|
+
const c = node.namedChild(i);
|
|
11110
|
+
if (c) walk8(c, visit);
|
|
11111
|
+
}
|
|
11112
|
+
}
|
|
11113
|
+
var COMMON_INITIALISMS = [
|
|
11114
|
+
"ASCII",
|
|
11115
|
+
"HTTPS",
|
|
11116
|
+
"UTF8",
|
|
11117
|
+
"XSRF",
|
|
11118
|
+
"HTML",
|
|
11119
|
+
"HTTP",
|
|
11120
|
+
"JSON",
|
|
11121
|
+
"UUID",
|
|
11122
|
+
"XMPP",
|
|
11123
|
+
"ACL",
|
|
11124
|
+
"API",
|
|
11125
|
+
"CPU",
|
|
11126
|
+
"CSS",
|
|
11127
|
+
"DNS",
|
|
11128
|
+
"EOF",
|
|
11129
|
+
"GUID",
|
|
11130
|
+
"LHS",
|
|
11131
|
+
"QPS",
|
|
11132
|
+
"RAM",
|
|
11133
|
+
"RHS",
|
|
11134
|
+
"RPC",
|
|
11135
|
+
"SLA",
|
|
11136
|
+
"SQL",
|
|
11137
|
+
"SSH",
|
|
11138
|
+
"TCP",
|
|
11139
|
+
"TLS",
|
|
11140
|
+
"TTL",
|
|
11141
|
+
"UDP",
|
|
11142
|
+
"UID",
|
|
11143
|
+
"URI",
|
|
11144
|
+
"URL",
|
|
11145
|
+
"UID",
|
|
11146
|
+
"XSS",
|
|
11147
|
+
"ID",
|
|
11148
|
+
"IP",
|
|
11149
|
+
"UI",
|
|
11150
|
+
"VM",
|
|
11151
|
+
"XML"
|
|
11152
|
+
].sort((a, b) => b.length - a.length);
|
|
11153
|
+
function titleCase(word) {
|
|
11154
|
+
return word.charAt(0) + word.slice(1).toLowerCase();
|
|
11155
|
+
}
|
|
11156
|
+
function replaceInitialisms(name) {
|
|
11157
|
+
let out = "";
|
|
11158
|
+
let i = 0;
|
|
11159
|
+
while (i < name.length) {
|
|
11160
|
+
let matched = false;
|
|
11161
|
+
for (const init of COMMON_INITIALISMS) {
|
|
11162
|
+
if (name.startsWith(init, i)) {
|
|
11163
|
+
out += titleCase(init);
|
|
11164
|
+
i += init.length;
|
|
11165
|
+
matched = true;
|
|
11166
|
+
break;
|
|
11167
|
+
}
|
|
11168
|
+
}
|
|
11169
|
+
if (!matched) {
|
|
11170
|
+
out += name[i];
|
|
11171
|
+
i++;
|
|
11172
|
+
}
|
|
11173
|
+
}
|
|
11174
|
+
return out;
|
|
11175
|
+
}
|
|
11176
|
+
var isUpper = (c) => c >= "A" && c <= "Z";
|
|
11177
|
+
var isDigit = (c) => c >= "0" && c <= "9";
|
|
11178
|
+
function toDBName(name) {
|
|
11179
|
+
if (name === "") return "";
|
|
11180
|
+
const value = replaceInitialisms(name);
|
|
11181
|
+
if (value.length === 1) return value.toLowerCase();
|
|
11182
|
+
let buf = "";
|
|
11183
|
+
let lastCase = false;
|
|
11184
|
+
let curCase = isUpper(value[0]);
|
|
11185
|
+
for (let i = 0; i < value.length - 1; i++) {
|
|
11186
|
+
const v = value[i];
|
|
11187
|
+
const nextCase = isUpper(value[i + 1]);
|
|
11188
|
+
const nextNumber = isDigit(value[i + 1]);
|
|
11189
|
+
if (curCase) {
|
|
11190
|
+
if (lastCase && (nextCase || nextNumber)) {
|
|
11191
|
+
buf += v.toLowerCase();
|
|
11192
|
+
} else {
|
|
11193
|
+
if (i > 0 && value[i - 1] !== "_" && lastCase !== curCase) buf += "_";
|
|
11194
|
+
buf += v.toLowerCase();
|
|
11195
|
+
}
|
|
11196
|
+
} else {
|
|
11197
|
+
buf += v;
|
|
11198
|
+
}
|
|
11199
|
+
lastCase = curCase;
|
|
11200
|
+
curCase = nextCase;
|
|
11201
|
+
}
|
|
11202
|
+
const last = value[value.length - 1];
|
|
11203
|
+
if (curCase) {
|
|
11204
|
+
if (!lastCase && value.length > 1) buf += "_";
|
|
11205
|
+
buf += last.toLowerCase();
|
|
11206
|
+
} else {
|
|
11207
|
+
buf += last;
|
|
11208
|
+
}
|
|
11209
|
+
return buf;
|
|
11210
|
+
}
|
|
11211
|
+
var UNCOUNTABLE = /* @__PURE__ */ new Set([
|
|
11212
|
+
"equipment",
|
|
11213
|
+
"information",
|
|
11214
|
+
"rice",
|
|
11215
|
+
"money",
|
|
11216
|
+
"species",
|
|
11217
|
+
"series",
|
|
11218
|
+
"fish",
|
|
11219
|
+
"sheep",
|
|
11220
|
+
"jeans",
|
|
11221
|
+
"police"
|
|
11222
|
+
]);
|
|
11223
|
+
var IRREGULAR = [
|
|
11224
|
+
["person", "people"],
|
|
11225
|
+
["man", "men"],
|
|
11226
|
+
["child", "children"],
|
|
11227
|
+
["sex", "sexes"],
|
|
11228
|
+
["move", "moves"]
|
|
11229
|
+
];
|
|
11230
|
+
var PLURAL_RULES = [
|
|
11231
|
+
[/(quiz)$/i, "$1zes"],
|
|
11232
|
+
[/^(ox)$/i, "$1en"],
|
|
11233
|
+
[/([ml])ouse$/i, "$1ice"],
|
|
11234
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"],
|
|
11235
|
+
[/(x|ch|ss|sh)$/i, "$1es"],
|
|
11236
|
+
[/([^aeiouy]|qu)y$/i, "$1ies"],
|
|
11237
|
+
[/(hive)$/i, "$1s"],
|
|
11238
|
+
[/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
|
|
11239
|
+
[/sis$/i, "ses"],
|
|
11240
|
+
[/([ti])um$/i, "$1a"],
|
|
11241
|
+
[/([ti])a$/i, "$1a"],
|
|
11242
|
+
[/(buffal|tomat)o$/i, "$1oes"],
|
|
11243
|
+
[/(bu)s$/i, "$1ses"],
|
|
11244
|
+
[/(alias|status)$/i, "$1es"],
|
|
11245
|
+
[/(octop|vir)i$/i, "$1i"],
|
|
11246
|
+
[/(octop|vir)us$/i, "$1i"],
|
|
11247
|
+
[/(ax|test)is$/i, "$1es"],
|
|
11248
|
+
[/s$/i, "s"]
|
|
11249
|
+
];
|
|
11250
|
+
function pluralize3(word) {
|
|
11251
|
+
if (word === "") return word;
|
|
11252
|
+
const lower = word.toLowerCase();
|
|
11253
|
+
for (const u of UNCOUNTABLE) {
|
|
11254
|
+
if (lower === u || lower.endsWith("_" + u)) return word;
|
|
11255
|
+
}
|
|
11256
|
+
for (const [sing, plur] of IRREGULAR) {
|
|
11257
|
+
const re = new RegExp(sing + "$", "i");
|
|
11258
|
+
if (re.test(word)) return word.replace(re, plur);
|
|
11259
|
+
}
|
|
11260
|
+
for (const [re, rep] of PLURAL_RULES) {
|
|
11261
|
+
if (re.test(word)) return word.replace(re, rep);
|
|
11262
|
+
}
|
|
11263
|
+
return word + "s";
|
|
11264
|
+
}
|
|
11265
|
+
function deriveTableName(structName) {
|
|
11266
|
+
return pluralize3(toDBName(structName));
|
|
11267
|
+
}
|
|
11268
|
+
function stringLiteralValue(node) {
|
|
11269
|
+
if (!node) return null;
|
|
11270
|
+
if (node.type === "interpreted_string_literal" || node.type === "raw_string_literal") {
|
|
11271
|
+
const t = node.text;
|
|
11272
|
+
return t.length >= 2 ? t.slice(1, -1) : "";
|
|
11273
|
+
}
|
|
11274
|
+
return null;
|
|
11275
|
+
}
|
|
11276
|
+
function parseGormTag(tagNode) {
|
|
11277
|
+
const tag = {};
|
|
11278
|
+
if (!tagNode) return tag;
|
|
11279
|
+
let inner = tagNode.text;
|
|
11280
|
+
if (inner.length >= 2) inner = inner.slice(1, -1);
|
|
11281
|
+
if (tagNode.type === "interpreted_string_literal") inner = inner.replace(/\\"/g, '"');
|
|
11282
|
+
const m = inner.match(/gorm:"([^"]*)"/);
|
|
11283
|
+
if (!m) return tag;
|
|
11284
|
+
for (const part of m[1].split(";")) {
|
|
11285
|
+
if (part === "") continue;
|
|
11286
|
+
const idx = part.indexOf(":");
|
|
11287
|
+
const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase();
|
|
11288
|
+
const value = idx >= 0 ? part.slice(idx + 1).trim() : "";
|
|
11289
|
+
if (key === "-") tag.skip = true;
|
|
11290
|
+
else if (key === "column") tag.column = value;
|
|
11291
|
+
else if (key === "primarykey" || key === "primary_key") tag.primaryKey = true;
|
|
11292
|
+
else if (key === "foreignkey") tag.foreignKey = value;
|
|
11293
|
+
else if (key === "many2many") tag.many2many = value;
|
|
11294
|
+
else if (key === "embedded") tag.embedded = true;
|
|
11295
|
+
else if (key === "embeddedprefix") tag.embeddedPrefix = value;
|
|
11296
|
+
}
|
|
11297
|
+
return tag;
|
|
11298
|
+
}
|
|
11299
|
+
function unwrapType(typeNode) {
|
|
11300
|
+
let isSlice = false;
|
|
11301
|
+
let isPointer = false;
|
|
11302
|
+
let n = typeNode;
|
|
11303
|
+
while (n && (n.type === "slice_type" || n.type === "array_type" || n.type === "pointer_type")) {
|
|
11304
|
+
if (n.type === "slice_type" || n.type === "array_type") isSlice = true;
|
|
11305
|
+
if (n.type === "pointer_type") isPointer = true;
|
|
11306
|
+
n = n.childForFieldName("element") ?? n.namedChild(n.namedChildCount - 1);
|
|
11307
|
+
}
|
|
11308
|
+
if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11309
|
+
if (n.type === "type_identifier") {
|
|
11310
|
+
return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11311
|
+
}
|
|
11312
|
+
if (n.type === "qualified_type") {
|
|
11313
|
+
const pkg = n.childForFieldName("package")?.text ?? n.namedChild(0)?.text ?? null;
|
|
11314
|
+
const nm = n.childForFieldName("name")?.text ?? n.namedChild(1)?.text ?? null;
|
|
11315
|
+
return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true };
|
|
11316
|
+
}
|
|
11317
|
+
return { name: null, qualifier: null, isSlice, isPointer, isQualified: false };
|
|
11318
|
+
}
|
|
11319
|
+
function readField(fieldDecl) {
|
|
11320
|
+
const names = [];
|
|
11321
|
+
let tagNode = null;
|
|
11322
|
+
for (let i = 0; i < fieldDecl.namedChildCount; i++) {
|
|
11323
|
+
const c = fieldDecl.namedChild(i);
|
|
11324
|
+
if (!c) continue;
|
|
11325
|
+
if (c.type === "field_identifier") names.push(c.text);
|
|
11326
|
+
else if (c.type === "raw_string_literal" || c.type === "interpreted_string_literal") tagNode = c;
|
|
11327
|
+
}
|
|
11328
|
+
const typeNode = fieldDecl.childForFieldName("type");
|
|
11329
|
+
const t = unwrapType(typeNode);
|
|
11330
|
+
return {
|
|
11331
|
+
names,
|
|
11332
|
+
typeName: t.name,
|
|
11333
|
+
qualifier: t.qualifier,
|
|
11334
|
+
isSlice: t.isSlice,
|
|
11335
|
+
isPointer: t.isPointer,
|
|
11336
|
+
isQualified: t.isQualified,
|
|
11337
|
+
tag: parseGormTag(tagNode),
|
|
11338
|
+
line: fieldDecl.startPosition.row + 1
|
|
11339
|
+
};
|
|
11340
|
+
}
|
|
11341
|
+
function collectStructs(tree) {
|
|
11342
|
+
const structs = /* @__PURE__ */ new Map();
|
|
11343
|
+
walk8(tree.rootNode, (node) => {
|
|
11344
|
+
if (node.type !== "type_spec") return;
|
|
11345
|
+
const nameNode = node.childForFieldName("name");
|
|
11346
|
+
const typeNode = node.childForFieldName("type");
|
|
11347
|
+
if (!nameNode || typeNode?.type !== "struct_type") return;
|
|
11348
|
+
const list = typeNode.childForFieldName("body") ?? typeNode.namedChild(0);
|
|
11349
|
+
const fields = [];
|
|
11350
|
+
if (list && list.type === "field_declaration_list") {
|
|
11351
|
+
for (let i = 0; i < list.namedChildCount; i++) {
|
|
11352
|
+
const fd = list.namedChild(i);
|
|
11353
|
+
if (fd?.type === "field_declaration") fields.push(readField(fd));
|
|
11354
|
+
}
|
|
11355
|
+
}
|
|
11356
|
+
structs.set(nameNode.text, {
|
|
11357
|
+
name: nameNode.text,
|
|
11358
|
+
fields,
|
|
11359
|
+
line: node.startPosition.row + 1
|
|
11360
|
+
});
|
|
11361
|
+
});
|
|
11362
|
+
return structs;
|
|
11363
|
+
}
|
|
11364
|
+
var GORM_MODEL_METHODS = /* @__PURE__ */ new Set([
|
|
11365
|
+
"AutoMigrate",
|
|
11366
|
+
"Model",
|
|
11367
|
+
"Create",
|
|
11368
|
+
"Find",
|
|
11369
|
+
"First",
|
|
11370
|
+
"Take",
|
|
11371
|
+
"Last",
|
|
11372
|
+
"Save",
|
|
11373
|
+
"Delete",
|
|
11374
|
+
"Where",
|
|
11375
|
+
"FirstOrCreate",
|
|
11376
|
+
"FirstOrInit"
|
|
11377
|
+
]);
|
|
11378
|
+
function compositeStructName(arg) {
|
|
11379
|
+
let n = arg;
|
|
11380
|
+
if (n.type === "unary_expression") n = n.childForFieldName("operand") ?? n.namedChild(0);
|
|
11381
|
+
if (!n || n.type !== "composite_literal") return null;
|
|
11382
|
+
const typeNode = n.childForFieldName("type");
|
|
11383
|
+
if (!typeNode) return null;
|
|
11384
|
+
if (typeNode.type === "type_identifier") return typeNode.text;
|
|
11385
|
+
if (typeNode.type === "qualified_type") {
|
|
11386
|
+
return typeNode.childForFieldName("name")?.text ?? typeNode.namedChild(1)?.text ?? null;
|
|
11387
|
+
}
|
|
11388
|
+
return null;
|
|
11389
|
+
}
|
|
11390
|
+
function collectCallModels(tree) {
|
|
11391
|
+
const models = /* @__PURE__ */ new Set();
|
|
11392
|
+
walk8(tree.rootNode, (node) => {
|
|
11393
|
+
if (node.type !== "call_expression") return;
|
|
11394
|
+
const fn = node.childForFieldName("function");
|
|
11395
|
+
if (fn?.type !== "selector_expression") return;
|
|
11396
|
+
const method = fn.childForFieldName("field")?.text;
|
|
11397
|
+
if (!method || !GORM_MODEL_METHODS.has(method)) return;
|
|
11398
|
+
const args = node.childForFieldName("arguments");
|
|
11399
|
+
if (!args) return;
|
|
11400
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
11401
|
+
const arg = args.namedChild(i);
|
|
11402
|
+
if (!arg) continue;
|
|
11403
|
+
const name = compositeStructName(arg);
|
|
11404
|
+
if (name) models.add(name);
|
|
11405
|
+
}
|
|
11406
|
+
});
|
|
11407
|
+
return models;
|
|
11408
|
+
}
|
|
11409
|
+
function collectTableNameOverrides(tree) {
|
|
11410
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
11411
|
+
const declarers = /* @__PURE__ */ new Set();
|
|
11412
|
+
walk8(tree.rootNode, (node) => {
|
|
11413
|
+
if (node.type !== "method_declaration") return;
|
|
11414
|
+
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
11415
|
+
const receiver = node.childForFieldName("receiver");
|
|
11416
|
+
if (!receiver) return;
|
|
11417
|
+
let recvType = null;
|
|
11418
|
+
for (let i = 0; i < receiver.namedChildCount; i++) {
|
|
11419
|
+
const pd = receiver.namedChild(i);
|
|
11420
|
+
if (pd?.type !== "parameter_declaration") continue;
|
|
11421
|
+
const t = unwrapType(pd.childForFieldName("type"));
|
|
11422
|
+
recvType = t.name;
|
|
11423
|
+
}
|
|
11424
|
+
if (!recvType) return;
|
|
11425
|
+
declarers.add(recvType);
|
|
11426
|
+
const body = node.childForFieldName("body");
|
|
11427
|
+
if (!body) return;
|
|
11428
|
+
let literal = null;
|
|
11429
|
+
walk8(body, (n) => {
|
|
11430
|
+
if (literal !== null) return;
|
|
11431
|
+
if (n.type !== "return_statement") return;
|
|
11432
|
+
const exprList = n.namedChild(0);
|
|
11433
|
+
const first = exprList?.namedChild(0) ?? exprList;
|
|
11434
|
+
const v = stringLiteralValue(first);
|
|
11435
|
+
if (v) literal = v;
|
|
11436
|
+
});
|
|
11437
|
+
if (literal !== null) overrides.set(recvType, literal);
|
|
11438
|
+
});
|
|
11439
|
+
return { overrides, declarers };
|
|
11440
|
+
}
|
|
11441
|
+
function isRelationField(field, structs) {
|
|
11442
|
+
if (field.names.length === 0) return false;
|
|
11443
|
+
if (field.isQualified) return false;
|
|
11444
|
+
if (!field.typeName) return false;
|
|
11445
|
+
return structs.has(field.typeName);
|
|
11446
|
+
}
|
|
11447
|
+
function isGormModelEmbed(field) {
|
|
11448
|
+
return field.names.length === 0 && field.qualifier === "gorm" && field.typeName === "Model";
|
|
11449
|
+
}
|
|
11450
|
+
function analyze(tree) {
|
|
11451
|
+
const structs = collectStructs(tree);
|
|
11452
|
+
const { overrides, declarers } = collectTableNameOverrides(tree);
|
|
11453
|
+
const callModels = collectCallModels(tree);
|
|
11454
|
+
const models = /* @__PURE__ */ new Set();
|
|
11455
|
+
for (const [name, info] of structs) {
|
|
11456
|
+
if (info.fields.some(isGormModelEmbed)) models.add(name);
|
|
11457
|
+
}
|
|
11458
|
+
for (const name of callModels) if (structs.has(name)) models.add(name);
|
|
11459
|
+
for (const name of declarers) if (structs.has(name)) models.add(name);
|
|
11460
|
+
let grew = true;
|
|
11461
|
+
while (grew) {
|
|
11462
|
+
grew = false;
|
|
11463
|
+
for (const name of Array.from(models)) {
|
|
11464
|
+
const info = structs.get(name);
|
|
11465
|
+
if (!info) continue;
|
|
11466
|
+
for (const field of info.fields) {
|
|
11467
|
+
if (!isRelationField(field, structs)) continue;
|
|
11468
|
+
const target = field.typeName;
|
|
11469
|
+
if (!models.has(target) && structs.has(target)) {
|
|
11470
|
+
models.add(target);
|
|
11471
|
+
grew = true;
|
|
11472
|
+
}
|
|
11473
|
+
}
|
|
11474
|
+
}
|
|
11475
|
+
}
|
|
11476
|
+
const tableFor = (structName) => overrides.get(structName) ?? deriveTableName(structName);
|
|
11477
|
+
return { structs, models, tableFor };
|
|
11478
|
+
}
|
|
11479
|
+
function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
11480
|
+
if (seen.has(struct.name)) return;
|
|
11481
|
+
seen.add(struct.name);
|
|
11482
|
+
const add = (col) => {
|
|
11483
|
+
const full = prefix + col;
|
|
11484
|
+
if (!emitted.has(full)) {
|
|
11485
|
+
emitted.add(full);
|
|
11486
|
+
out.push(full);
|
|
11487
|
+
}
|
|
11488
|
+
};
|
|
11489
|
+
for (const field of struct.fields) {
|
|
11490
|
+
if (field.tag.skip) continue;
|
|
11491
|
+
if (field.names.length === 0) {
|
|
11492
|
+
if (isGormModelEmbed(field)) {
|
|
11493
|
+
add("id");
|
|
11494
|
+
add("created_at");
|
|
11495
|
+
add("updated_at");
|
|
11496
|
+
add("deleted_at");
|
|
11497
|
+
} else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11498
|
+
collectColumns(structs.get(field.typeName), structs, seen, prefix, out, emitted);
|
|
11499
|
+
}
|
|
11500
|
+
continue;
|
|
11501
|
+
}
|
|
11502
|
+
if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {
|
|
11503
|
+
collectColumns(
|
|
11504
|
+
structs.get(field.typeName),
|
|
11505
|
+
structs,
|
|
11506
|
+
seen,
|
|
11507
|
+
prefix + (field.tag.embeddedPrefix ?? ""),
|
|
11508
|
+
out,
|
|
11509
|
+
emitted
|
|
11510
|
+
);
|
|
11511
|
+
continue;
|
|
11512
|
+
}
|
|
11513
|
+
if (isRelationField(field, structs)) continue;
|
|
11514
|
+
if (field.names.length === 1 && field.tag.column) {
|
|
11515
|
+
add(field.tag.column);
|
|
11516
|
+
} else {
|
|
11517
|
+
for (const n of field.names) add(toDBName(n));
|
|
11518
|
+
}
|
|
11519
|
+
}
|
|
11520
|
+
seen.delete(struct.name);
|
|
11521
|
+
}
|
|
11522
|
+
function gormEndpointsFromFile(file, serviceDir) {
|
|
11523
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11524
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11525
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11526
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11527
|
+
const out = [];
|
|
11528
|
+
const seenTables = /* @__PURE__ */ new Set();
|
|
11529
|
+
for (const name of models) {
|
|
11530
|
+
const struct = structs.get(name);
|
|
11531
|
+
if (!struct) continue;
|
|
11532
|
+
const table = tableFor(name);
|
|
11533
|
+
if (seenTables.has(table)) continue;
|
|
11534
|
+
seenTables.add(table);
|
|
11535
|
+
const columns = [];
|
|
11536
|
+
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
11537
|
+
out.push({
|
|
11538
|
+
infraId: (0, import_types36.infraId)("sql-table", table),
|
|
11539
|
+
name: table,
|
|
11540
|
+
kind: "sql-table",
|
|
11541
|
+
edgeType: "CALLS",
|
|
11542
|
+
confidenceKind: "structural",
|
|
11543
|
+
...columns.length > 0 ? { columns } : {},
|
|
11544
|
+
evidence: {
|
|
11545
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11546
|
+
line: struct.line,
|
|
11547
|
+
snippet: snippet(file.content, struct.line)
|
|
11548
|
+
}
|
|
11549
|
+
});
|
|
11550
|
+
}
|
|
11551
|
+
return out;
|
|
11552
|
+
}
|
|
11553
|
+
function gormForeignKeys(file, serviceDir) {
|
|
11554
|
+
if (import_node_path48.default.extname(file.path) !== ".go") return [];
|
|
11555
|
+
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
11556
|
+
const tree = parseSource10(makeGoParser3(), file.content);
|
|
11557
|
+
const { structs, models, tableFor } = analyze(tree);
|
|
11558
|
+
const out = [];
|
|
11559
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11560
|
+
const emit = (childTable, parentTable, line) => {
|
|
11561
|
+
if (!childTable || !parentTable || childTable === parentTable) return;
|
|
11562
|
+
const key = `${childTable}->${parentTable}`;
|
|
11563
|
+
if (seen.has(key)) return;
|
|
11564
|
+
seen.add(key);
|
|
11565
|
+
out.push({
|
|
11566
|
+
childTable,
|
|
11567
|
+
parentTable,
|
|
11568
|
+
evidence: {
|
|
11569
|
+
file: toPosix(import_node_path48.default.relative(serviceDir, file.path)),
|
|
11570
|
+
line,
|
|
11571
|
+
snippet: snippet(file.content, line)
|
|
11572
|
+
}
|
|
11573
|
+
});
|
|
11574
|
+
};
|
|
11575
|
+
for (const name of models) {
|
|
11576
|
+
const struct = structs.get(name);
|
|
11577
|
+
if (!struct) continue;
|
|
11578
|
+
const thisTable = tableFor(name);
|
|
11579
|
+
const scalarNames = new Set(
|
|
11580
|
+
struct.fields.filter((f) => f.names.length > 0 && !isRelationField(f, structs)).flatMap((f) => f.names)
|
|
11581
|
+
);
|
|
11582
|
+
for (const field of struct.fields) {
|
|
11583
|
+
if (field.tag.skip) continue;
|
|
11584
|
+
if (!isRelationField(field, structs)) continue;
|
|
11585
|
+
const relTable = tableFor(field.typeName);
|
|
11586
|
+
if (field.tag.many2many) {
|
|
11587
|
+
emit(field.tag.many2many, thisTable, field.line);
|
|
11588
|
+
emit(field.tag.many2many, relTable, field.line);
|
|
11589
|
+
continue;
|
|
11590
|
+
}
|
|
11591
|
+
if (field.isSlice) {
|
|
11592
|
+
emit(relTable, thisTable, field.line);
|
|
11593
|
+
continue;
|
|
11594
|
+
}
|
|
11595
|
+
const convFk = field.names[0] + "ID";
|
|
11596
|
+
const belongsTo = scalarNames.has(convFk) || (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false);
|
|
11597
|
+
if (belongsTo) emit(thisTable, relTable, field.line);
|
|
11598
|
+
else emit(relTable, thisTable, field.line);
|
|
11599
|
+
}
|
|
11600
|
+
}
|
|
11601
|
+
return out;
|
|
11602
|
+
}
|
|
11603
|
+
|
|
11057
11604
|
// src/extract/calls/index.ts
|
|
11058
11605
|
function edgeTypeFromEndpoint(ep) {
|
|
11059
11606
|
switch (ep.edgeType) {
|
|
11060
11607
|
case "PUBLISHES_TO":
|
|
11061
|
-
return
|
|
11608
|
+
return import_types37.EdgeType.PUBLISHES_TO;
|
|
11062
11609
|
case "CONSUMES_FROM":
|
|
11063
|
-
return
|
|
11610
|
+
return import_types37.EdgeType.CONSUMES_FROM;
|
|
11064
11611
|
default:
|
|
11065
|
-
return
|
|
11612
|
+
return import_types37.EdgeType.CALLS;
|
|
11066
11613
|
}
|
|
11067
11614
|
}
|
|
11068
11615
|
function isAwsKind(kind) {
|
|
@@ -11095,6 +11642,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11095
11642
|
} catch (err) {
|
|
11096
11643
|
recordExtractionError("go SQL call extraction", file.path, err);
|
|
11097
11644
|
}
|
|
11645
|
+
try {
|
|
11646
|
+
endpoints.push(...gormEndpointsFromFile(file, service.dir));
|
|
11647
|
+
} catch (err) {
|
|
11648
|
+
recordExtractionError("gorm data-axis extraction", file.path, err);
|
|
11649
|
+
}
|
|
11098
11650
|
try {
|
|
11099
11651
|
endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir));
|
|
11100
11652
|
endpoints.push(...railsModelEndpointsFromFile(file, service.dir));
|
|
@@ -11117,7 +11669,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11117
11669
|
if (!graph.hasNode(ep.infraId)) {
|
|
11118
11670
|
const node = {
|
|
11119
11671
|
id: ep.infraId,
|
|
11120
|
-
type:
|
|
11672
|
+
type: import_types37.NodeType.InfraNode,
|
|
11121
11673
|
name: ep.name,
|
|
11122
11674
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
11123
11675
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -11130,21 +11682,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11130
11682
|
}
|
|
11131
11683
|
if (ep.columns && ep.columns.length > 0) {
|
|
11132
11684
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11133
|
-
if (node.type ===
|
|
11685
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11134
11686
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11135
11687
|
...node,
|
|
11136
11688
|
columns: foldColumns(
|
|
11137
11689
|
node.columns,
|
|
11138
11690
|
ep.columns,
|
|
11139
|
-
|
|
11140
|
-
(0,
|
|
11691
|
+
import_types37.Provenance.EXTRACTED,
|
|
11692
|
+
(0, import_types37.confidenceForExtracted)(ep.confidenceKind)
|
|
11141
11693
|
)
|
|
11142
11694
|
});
|
|
11143
11695
|
}
|
|
11144
11696
|
}
|
|
11145
11697
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
11146
11698
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
11147
|
-
if (node.type ===
|
|
11699
|
+
if (node.type === import_types37.NodeType.InfraNode) {
|
|
11148
11700
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
11149
11701
|
...node,
|
|
11150
11702
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -11152,7 +11704,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11152
11704
|
}
|
|
11153
11705
|
}
|
|
11154
11706
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
11155
|
-
const confidence = (0,
|
|
11707
|
+
const confidence = (0, import_types37.confidenceForExtracted)(ep.confidenceKind);
|
|
11156
11708
|
const relFile = toPosix(ep.evidence.file);
|
|
11157
11709
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
11158
11710
|
graph,
|
|
@@ -11162,7 +11714,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11162
11714
|
);
|
|
11163
11715
|
nodesAdded += n;
|
|
11164
11716
|
edgesAdded += e;
|
|
11165
|
-
if (!(0,
|
|
11717
|
+
if (!(0, import_types37.passesExtractedFloor)(confidence)) {
|
|
11166
11718
|
noteExtractedDropped({
|
|
11167
11719
|
source: fileNodeId,
|
|
11168
11720
|
target: ep.infraId,
|
|
@@ -11182,7 +11734,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
11182
11734
|
source: fileNodeId,
|
|
11183
11735
|
target: ep.infraId,
|
|
11184
11736
|
type: edgeType,
|
|
11185
|
-
provenance:
|
|
11737
|
+
provenance: import_types37.Provenance.EXTRACTED,
|
|
11186
11738
|
confidence,
|
|
11187
11739
|
evidence: ep.evidence
|
|
11188
11740
|
};
|
|
@@ -11205,7 +11757,7 @@ async function addCallEdges(graph, services) {
|
|
|
11205
11757
|
|
|
11206
11758
|
// src/extract/table-edges.ts
|
|
11207
11759
|
init_cjs_shims();
|
|
11208
|
-
var
|
|
11760
|
+
var import_types38 = require("@neat.is/types");
|
|
11209
11761
|
async function addTableEdges(graph, services) {
|
|
11210
11762
|
let nodesAdded = 0;
|
|
11211
11763
|
let edgesAdded = 0;
|
|
@@ -11219,6 +11771,7 @@ async function addTableEdges(graph, services) {
|
|
|
11219
11771
|
refs.push(...sqlalchemyForeignKeys(file, service.dir));
|
|
11220
11772
|
refs.push(...railsSchemaForeignKeys(file, service.dir));
|
|
11221
11773
|
refs.push(...laravelMigrationForeignKeys(file, service.dir));
|
|
11774
|
+
refs.push(...gormForeignKeys(file, service.dir));
|
|
11222
11775
|
modelRefs.push(...railsModelForeignKeys(file, service.dir));
|
|
11223
11776
|
modelRefs.push(...laravelModelForeignKeys(file, service.dir));
|
|
11224
11777
|
} catch (err) {
|
|
@@ -11232,20 +11785,20 @@ async function addTableEdges(graph, services) {
|
|
|
11232
11785
|
}
|
|
11233
11786
|
refs.push(...modelRefs);
|
|
11234
11787
|
for (const ref of refs) {
|
|
11235
|
-
const childId = (0,
|
|
11236
|
-
const parentId = (0,
|
|
11788
|
+
const childId = (0, import_types38.infraId)("sql-table", ref.childTable);
|
|
11789
|
+
const parentId = (0, import_types38.infraId)("sql-table", ref.parentTable);
|
|
11237
11790
|
if (childId === parentId) continue;
|
|
11238
11791
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
11239
11792
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
11240
|
-
const edgeId = (0,
|
|
11793
|
+
const edgeId = (0, import_types38.extractedEdgeId)(childId, parentId, import_types38.EdgeType.REFERENCES);
|
|
11241
11794
|
if (graph.hasEdge(edgeId)) continue;
|
|
11242
11795
|
const edge = {
|
|
11243
11796
|
id: edgeId,
|
|
11244
11797
|
source: childId,
|
|
11245
11798
|
target: parentId,
|
|
11246
|
-
type:
|
|
11247
|
-
provenance:
|
|
11248
|
-
confidence: (0,
|
|
11799
|
+
type: import_types38.EdgeType.REFERENCES,
|
|
11800
|
+
provenance: import_types38.Provenance.EXTRACTED,
|
|
11801
|
+
confidence: (0, import_types38.confidenceForExtracted)("structural"),
|
|
11249
11802
|
evidence: ref.evidence
|
|
11250
11803
|
};
|
|
11251
11804
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -11258,7 +11811,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
11258
11811
|
if (graph.hasNode(id)) return 0;
|
|
11259
11812
|
const node = {
|
|
11260
11813
|
id,
|
|
11261
|
-
type:
|
|
11814
|
+
type: import_types38.NodeType.InfraNode,
|
|
11262
11815
|
name,
|
|
11263
11816
|
provider: "self",
|
|
11264
11817
|
kind: "sql-table"
|
|
@@ -11272,16 +11825,16 @@ init_cjs_shims();
|
|
|
11272
11825
|
|
|
11273
11826
|
// src/extract/infra/docker-compose.ts
|
|
11274
11827
|
init_cjs_shims();
|
|
11275
|
-
var
|
|
11276
|
-
var
|
|
11828
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11829
|
+
var import_types40 = require("@neat.is/types");
|
|
11277
11830
|
|
|
11278
11831
|
// src/extract/infra/shared.ts
|
|
11279
11832
|
init_cjs_shims();
|
|
11280
|
-
var
|
|
11833
|
+
var import_types39 = require("@neat.is/types");
|
|
11281
11834
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
11282
11835
|
return {
|
|
11283
|
-
id: (0,
|
|
11284
|
-
type:
|
|
11836
|
+
id: (0, import_types39.infraId)(kind, name),
|
|
11837
|
+
type: import_types39.NodeType.InfraNode,
|
|
11285
11838
|
name,
|
|
11286
11839
|
provider,
|
|
11287
11840
|
kind,
|
|
@@ -11325,8 +11878,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
11325
11878
|
source: anchorId,
|
|
11326
11879
|
target: node.id,
|
|
11327
11880
|
type: edgeType,
|
|
11328
|
-
provenance:
|
|
11329
|
-
confidence: (0,
|
|
11881
|
+
provenance: import_types39.Provenance.EXTRACTED,
|
|
11882
|
+
confidence: (0, import_types39.confidenceForExtracted)("structural"),
|
|
11330
11883
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11331
11884
|
};
|
|
11332
11885
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11343,7 +11896,7 @@ function dependsOnList(value) {
|
|
|
11343
11896
|
}
|
|
11344
11897
|
function serviceNameToServiceNode(name, services) {
|
|
11345
11898
|
for (const s of services) {
|
|
11346
|
-
if (s.node.name === name ||
|
|
11899
|
+
if (s.node.name === name || import_node_path49.default.basename(s.dir) === name) return s.node.id;
|
|
11347
11900
|
}
|
|
11348
11901
|
return null;
|
|
11349
11902
|
}
|
|
@@ -11352,7 +11905,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11352
11905
|
let edgesAdded = 0;
|
|
11353
11906
|
let composePath = null;
|
|
11354
11907
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
11355
|
-
const abs =
|
|
11908
|
+
const abs = import_node_path49.default.join(scanPath, name);
|
|
11356
11909
|
if (await exists(abs)) {
|
|
11357
11910
|
composePath = abs;
|
|
11358
11911
|
break;
|
|
@@ -11365,13 +11918,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11365
11918
|
} catch (err) {
|
|
11366
11919
|
recordExtractionError(
|
|
11367
11920
|
"infra docker-compose",
|
|
11368
|
-
|
|
11921
|
+
import_node_path49.default.relative(scanPath, composePath),
|
|
11369
11922
|
err
|
|
11370
11923
|
);
|
|
11371
11924
|
return { nodesAdded, edgesAdded };
|
|
11372
11925
|
}
|
|
11373
11926
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
11374
|
-
const evidenceFile =
|
|
11927
|
+
const evidenceFile = import_node_path49.default.relative(scanPath, composePath).split(import_node_path49.default.sep).join("/");
|
|
11375
11928
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
11376
11929
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
11377
11930
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -11393,15 +11946,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11393
11946
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
11394
11947
|
const targetId = composeNameToNodeId.get(dep);
|
|
11395
11948
|
if (!targetId) continue;
|
|
11396
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
11949
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types40.EdgeType.DEPENDS_ON);
|
|
11397
11950
|
if (graph.hasEdge(edgeId)) continue;
|
|
11398
11951
|
const edge = {
|
|
11399
11952
|
id: edgeId,
|
|
11400
11953
|
source: sourceId,
|
|
11401
11954
|
target: targetId,
|
|
11402
|
-
type:
|
|
11403
|
-
provenance:
|
|
11404
|
-
confidence: (0,
|
|
11955
|
+
type: import_types40.EdgeType.DEPENDS_ON,
|
|
11956
|
+
provenance: import_types40.Provenance.EXTRACTED,
|
|
11957
|
+
confidence: (0, import_types40.confidenceForExtracted)("structural"),
|
|
11405
11958
|
evidence: { file: evidenceFile }
|
|
11406
11959
|
};
|
|
11407
11960
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11413,9 +11966,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
11413
11966
|
|
|
11414
11967
|
// src/extract/infra/dockerfile.ts
|
|
11415
11968
|
init_cjs_shims();
|
|
11416
|
-
var
|
|
11969
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11417
11970
|
var import_node_fs18 = require("fs");
|
|
11418
|
-
var
|
|
11971
|
+
var import_types41 = require("@neat.is/types");
|
|
11419
11972
|
function readDockerfile(content) {
|
|
11420
11973
|
let image = null;
|
|
11421
11974
|
const ports = [];
|
|
@@ -11444,7 +11997,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11444
11997
|
let nodesAdded = 0;
|
|
11445
11998
|
let edgesAdded = 0;
|
|
11446
11999
|
for (const service of services) {
|
|
11447
|
-
const dockerfilePath =
|
|
12000
|
+
const dockerfilePath = import_node_path50.default.join(service.dir, "Dockerfile");
|
|
11448
12001
|
if (!await exists(dockerfilePath)) continue;
|
|
11449
12002
|
let content;
|
|
11450
12003
|
try {
|
|
@@ -11452,7 +12005,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11452
12005
|
} catch (err) {
|
|
11453
12006
|
recordExtractionError(
|
|
11454
12007
|
"infra dockerfile",
|
|
11455
|
-
|
|
12008
|
+
import_node_path50.default.relative(scanPath, dockerfilePath),
|
|
11456
12009
|
err
|
|
11457
12010
|
);
|
|
11458
12011
|
continue;
|
|
@@ -11464,8 +12017,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11464
12017
|
graph.addNode(node.id, node);
|
|
11465
12018
|
nodesAdded++;
|
|
11466
12019
|
}
|
|
11467
|
-
const relDockerfile = toPosix(
|
|
11468
|
-
const evidenceFile = toPosix(
|
|
12020
|
+
const relDockerfile = toPosix(import_node_path50.default.relative(service.dir, dockerfilePath));
|
|
12021
|
+
const evidenceFile = toPosix(import_node_path50.default.relative(scanPath, dockerfilePath));
|
|
11469
12022
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11470
12023
|
graph,
|
|
11471
12024
|
service.pkg.name,
|
|
@@ -11474,15 +12027,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11474
12027
|
);
|
|
11475
12028
|
nodesAdded += fn;
|
|
11476
12029
|
edgesAdded += fe;
|
|
11477
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
12030
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types41.EdgeType.RUNS_ON);
|
|
11478
12031
|
if (!graph.hasEdge(edgeId)) {
|
|
11479
12032
|
const edge = {
|
|
11480
12033
|
id: edgeId,
|
|
11481
12034
|
source: fileNodeId,
|
|
11482
12035
|
target: node.id,
|
|
11483
|
-
type:
|
|
11484
|
-
provenance:
|
|
11485
|
-
confidence: (0,
|
|
12036
|
+
type: import_types41.EdgeType.RUNS_ON,
|
|
12037
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12038
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11486
12039
|
evidence: {
|
|
11487
12040
|
file: evidenceFile,
|
|
11488
12041
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -11497,15 +12050,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11497
12050
|
graph.addNode(portNode.id, portNode);
|
|
11498
12051
|
nodesAdded++;
|
|
11499
12052
|
}
|
|
11500
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
12053
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types41.EdgeType.CONNECTS_TO);
|
|
11501
12054
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
11502
12055
|
const portEdge = {
|
|
11503
12056
|
id: portEdgeId,
|
|
11504
12057
|
source: fileNodeId,
|
|
11505
12058
|
target: portNode.id,
|
|
11506
|
-
type:
|
|
11507
|
-
provenance:
|
|
11508
|
-
confidence: (0,
|
|
12059
|
+
type: import_types41.EdgeType.CONNECTS_TO,
|
|
12060
|
+
provenance: import_types41.Provenance.EXTRACTED,
|
|
12061
|
+
confidence: (0, import_types41.confidenceForExtracted)("structural"),
|
|
11509
12062
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
11510
12063
|
};
|
|
11511
12064
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -11518,8 +12071,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
11518
12071
|
// src/extract/infra/terraform.ts
|
|
11519
12072
|
init_cjs_shims();
|
|
11520
12073
|
var import_node_fs19 = require("fs");
|
|
11521
|
-
var
|
|
11522
|
-
var
|
|
12074
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12075
|
+
var import_types42 = require("@neat.is/types");
|
|
11523
12076
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
11524
12077
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
11525
12078
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -11529,11 +12082,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
11529
12082
|
for (const entry2 of entries) {
|
|
11530
12083
|
if (entry2.isDirectory()) {
|
|
11531
12084
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
11532
|
-
const child =
|
|
12085
|
+
const child = import_node_path51.default.join(start, entry2.name);
|
|
11533
12086
|
if (await isPythonVenvDir(child)) continue;
|
|
11534
12087
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
11535
12088
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
11536
|
-
out.push(
|
|
12089
|
+
out.push(import_node_path51.default.join(start, entry2.name));
|
|
11537
12090
|
}
|
|
11538
12091
|
}
|
|
11539
12092
|
return out;
|
|
@@ -11565,7 +12118,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11565
12118
|
const files = await walkTfFiles(scanPath);
|
|
11566
12119
|
for (const file of files) {
|
|
11567
12120
|
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
11568
|
-
const evidenceFile = toPosix(
|
|
12121
|
+
const evidenceFile = toPosix(import_node_path51.default.relative(scanPath, file));
|
|
11569
12122
|
const resources = [];
|
|
11570
12123
|
const byKey = /* @__PURE__ */ new Map();
|
|
11571
12124
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -11600,16 +12153,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11600
12153
|
if (!target) continue;
|
|
11601
12154
|
if (seen.has(target.nodeId)) continue;
|
|
11602
12155
|
seen.add(target.nodeId);
|
|
11603
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
12156
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types42.EdgeType.DEPENDS_ON);
|
|
11604
12157
|
if (graph.hasEdge(edgeId)) continue;
|
|
11605
12158
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
11606
12159
|
const edge = {
|
|
11607
12160
|
id: edgeId,
|
|
11608
12161
|
source: resource.nodeId,
|
|
11609
12162
|
target: target.nodeId,
|
|
11610
|
-
type:
|
|
11611
|
-
provenance:
|
|
11612
|
-
confidence: (0,
|
|
12163
|
+
type: import_types42.EdgeType.DEPENDS_ON,
|
|
12164
|
+
provenance: import_types42.Provenance.EXTRACTED,
|
|
12165
|
+
confidence: (0, import_types42.confidenceForExtracted)("structural"),
|
|
11613
12166
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
11614
12167
|
};
|
|
11615
12168
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11623,7 +12176,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
11623
12176
|
// src/extract/infra/k8s.ts
|
|
11624
12177
|
init_cjs_shims();
|
|
11625
12178
|
var import_node_fs20 = require("fs");
|
|
11626
|
-
var
|
|
12179
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
11627
12180
|
var import_yaml3 = require("yaml");
|
|
11628
12181
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
11629
12182
|
Service: "k8s-service",
|
|
@@ -11641,11 +12194,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
11641
12194
|
for (const entry2 of entries) {
|
|
11642
12195
|
if (entry2.isDirectory()) {
|
|
11643
12196
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
11644
|
-
const child =
|
|
12197
|
+
const child = import_node_path52.default.join(start, entry2.name);
|
|
11645
12198
|
if (await isPythonVenvDir(child)) continue;
|
|
11646
12199
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
11647
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
11648
|
-
out.push(
|
|
12200
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path52.default.extname(entry2.name))) {
|
|
12201
|
+
out.push(import_node_path52.default.join(start, entry2.name));
|
|
11649
12202
|
}
|
|
11650
12203
|
}
|
|
11651
12204
|
return out;
|
|
@@ -11679,13 +12232,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
11679
12232
|
// src/extract/infra/cloudflare.ts
|
|
11680
12233
|
init_cjs_shims();
|
|
11681
12234
|
var import_node_fs21 = require("fs");
|
|
11682
|
-
var
|
|
12235
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
11683
12236
|
var import_smol_toml2 = require("smol-toml");
|
|
11684
|
-
var
|
|
12237
|
+
var import_types43 = require("@neat.is/types");
|
|
11685
12238
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
11686
12239
|
async function readWranglerConfig(dir) {
|
|
11687
12240
|
for (const filename of WRANGLER_FILENAMES) {
|
|
11688
|
-
const abs =
|
|
12241
|
+
const abs = import_node_path53.default.join(dir, filename);
|
|
11689
12242
|
if (!await exists(abs)) continue;
|
|
11690
12243
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
11691
12244
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11729,8 +12282,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
11729
12282
|
source: anchorId,
|
|
11730
12283
|
target: node.id,
|
|
11731
12284
|
type: edgeType,
|
|
11732
|
-
provenance:
|
|
11733
|
-
confidence: (0,
|
|
12285
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12286
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11734
12287
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
11735
12288
|
};
|
|
11736
12289
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11748,11 +12301,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11748
12301
|
try {
|
|
11749
12302
|
read = await readWranglerConfig(service.dir);
|
|
11750
12303
|
} catch (err) {
|
|
11751
|
-
recordExtractionError("infra cloudflare",
|
|
12304
|
+
recordExtractionError("infra cloudflare", import_node_path53.default.relative(scanPath, service.dir), err);
|
|
11752
12305
|
continue;
|
|
11753
12306
|
}
|
|
11754
12307
|
if (!read || !read.config.name) continue;
|
|
11755
|
-
const evidenceFile = toPosix(
|
|
12308
|
+
const evidenceFile = toPosix(import_node_path53.default.relative(scanPath, import_node_path53.default.join(service.dir, read.relFile)));
|
|
11756
12309
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
11757
12310
|
}
|
|
11758
12311
|
for (const worker of discovered) {
|
|
@@ -11764,7 +12317,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11764
12317
|
}
|
|
11765
12318
|
let anchorId = service.node.id;
|
|
11766
12319
|
if (config.main) {
|
|
11767
|
-
const entryRelPath = toPosix(
|
|
12320
|
+
const entryRelPath = toPosix(import_node_path53.default.normalize(config.main));
|
|
11768
12321
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
11769
12322
|
graph,
|
|
11770
12323
|
service.pkg.name,
|
|
@@ -11791,15 +12344,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11791
12344
|
nodesAdded++;
|
|
11792
12345
|
}
|
|
11793
12346
|
if (runtimeNode.id !== anchorId) {
|
|
11794
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
12347
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types43.EdgeType.RUNS_ON);
|
|
11795
12348
|
if (!graph.hasEdge(runsOnId)) {
|
|
11796
12349
|
const edge = {
|
|
11797
12350
|
id: runsOnId,
|
|
11798
12351
|
source: anchorId,
|
|
11799
12352
|
target: runtimeNode.id,
|
|
11800
|
-
type:
|
|
11801
|
-
provenance:
|
|
11802
|
-
confidence: (0,
|
|
12353
|
+
type: import_types43.EdgeType.RUNS_ON,
|
|
12354
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12355
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11803
12356
|
evidence: {
|
|
11804
12357
|
file: evidenceFile,
|
|
11805
12358
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -11813,7 +12366,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11813
12366
|
const result = addResourceEdge(
|
|
11814
12367
|
graph,
|
|
11815
12368
|
anchorId,
|
|
11816
|
-
|
|
12369
|
+
import_types43.EdgeType.CONNECTS_TO,
|
|
11817
12370
|
"cloudflare-route",
|
|
11818
12371
|
route,
|
|
11819
12372
|
evidenceFile,
|
|
@@ -11837,7 +12390,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11837
12390
|
const result = addResourceEdge(
|
|
11838
12391
|
graph,
|
|
11839
12392
|
anchorId,
|
|
11840
|
-
|
|
12393
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11841
12394
|
group.kind,
|
|
11842
12395
|
name,
|
|
11843
12396
|
evidenceFile,
|
|
@@ -11851,7 +12404,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11851
12404
|
const result = addResourceEdge(
|
|
11852
12405
|
graph,
|
|
11853
12406
|
anchorId,
|
|
11854
|
-
|
|
12407
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11855
12408
|
"cloudflare-cron",
|
|
11856
12409
|
cron,
|
|
11857
12410
|
evidenceFile,
|
|
@@ -11864,7 +12417,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11864
12417
|
const result = addResourceEdge(
|
|
11865
12418
|
graph,
|
|
11866
12419
|
anchorId,
|
|
11867
|
-
|
|
12420
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11868
12421
|
"cloudflare-env-var",
|
|
11869
12422
|
varName,
|
|
11870
12423
|
evidenceFile,
|
|
@@ -11877,15 +12430,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11877
12430
|
if (!svc.service) continue;
|
|
11878
12431
|
const target = workerIndex.get(svc.service);
|
|
11879
12432
|
if (target && target.anchorId !== anchorId) {
|
|
11880
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
12433
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types43.EdgeType.CALLS);
|
|
11881
12434
|
if (!graph.hasEdge(edgeId)) {
|
|
11882
12435
|
const edge = {
|
|
11883
12436
|
id: edgeId,
|
|
11884
12437
|
source: anchorId,
|
|
11885
12438
|
target: target.anchorId,
|
|
11886
|
-
type:
|
|
11887
|
-
provenance:
|
|
11888
|
-
confidence: (0,
|
|
12439
|
+
type: import_types43.EdgeType.CALLS,
|
|
12440
|
+
provenance: import_types43.Provenance.EXTRACTED,
|
|
12441
|
+
confidence: (0, import_types43.confidenceForExtracted)("structural"),
|
|
11889
12442
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
11890
12443
|
};
|
|
11891
12444
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -11896,7 +12449,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11896
12449
|
const result = addResourceEdge(
|
|
11897
12450
|
graph,
|
|
11898
12451
|
anchorId,
|
|
11899
|
-
|
|
12452
|
+
import_types43.EdgeType.DEPENDS_ON,
|
|
11900
12453
|
"cloudflare-service-binding",
|
|
11901
12454
|
svc.service,
|
|
11902
12455
|
evidenceFile,
|
|
@@ -11912,12 +12465,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
11912
12465
|
// src/extract/infra/vercel.ts
|
|
11913
12466
|
init_cjs_shims();
|
|
11914
12467
|
var import_node_fs22 = require("fs");
|
|
11915
|
-
var
|
|
11916
|
-
var
|
|
12468
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
12469
|
+
var import_types44 = require("@neat.is/types");
|
|
11917
12470
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
11918
12471
|
async function readVercelConfig(dir) {
|
|
11919
12472
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
11920
|
-
const abs =
|
|
12473
|
+
const abs = import_node_path54.default.join(dir, filename);
|
|
11921
12474
|
if (!await exists(abs)) continue;
|
|
11922
12475
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
11923
12476
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -11926,7 +12479,7 @@ async function readVercelConfig(dir) {
|
|
|
11926
12479
|
return null;
|
|
11927
12480
|
}
|
|
11928
12481
|
async function readLinkedProjectName(dir) {
|
|
11929
|
-
const abs =
|
|
12482
|
+
const abs = import_node_path54.default.join(dir, ".vercel", "project.json");
|
|
11930
12483
|
if (!await exists(abs)) return void 0;
|
|
11931
12484
|
const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
|
|
11932
12485
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -11944,7 +12497,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11944
12497
|
read = await readVercelConfig(service.dir);
|
|
11945
12498
|
projectName = await readLinkedProjectName(service.dir);
|
|
11946
12499
|
} catch (err) {
|
|
11947
|
-
recordExtractionError("infra vercel",
|
|
12500
|
+
recordExtractionError("infra vercel", import_node_path54.default.relative(scanPath, service.dir), err);
|
|
11948
12501
|
continue;
|
|
11949
12502
|
}
|
|
11950
12503
|
if (!read && !projectName) continue;
|
|
@@ -11960,7 +12513,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11960
12513
|
const anchorId = service.node.id;
|
|
11961
12514
|
if (!read) continue;
|
|
11962
12515
|
const { config, relFile, raw } = read;
|
|
11963
|
-
const evidenceFile = toPosix(
|
|
12516
|
+
const evidenceFile = toPosix(import_node_path54.default.relative(scanPath, import_node_path54.default.join(service.dir, relFile)));
|
|
11964
12517
|
const add = (edgeType, kind, name) => {
|
|
11965
12518
|
if (!name) return;
|
|
11966
12519
|
const result = emitPlatformResourceEdge(
|
|
@@ -11976,12 +12529,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11976
12529
|
nodesAdded += result.nodesAdded;
|
|
11977
12530
|
edgesAdded += result.edgesAdded;
|
|
11978
12531
|
};
|
|
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(
|
|
12532
|
+
add(import_types44.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
12533
|
+
for (const cron of config.crons ?? []) add(import_types44.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
12534
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
12535
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types44.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
11983
12536
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
11984
|
-
add(
|
|
12537
|
+
add(import_types44.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
11985
12538
|
}
|
|
11986
12539
|
}
|
|
11987
12540
|
return { nodesAdded, edgesAdded };
|
|
@@ -11990,13 +12543,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
11990
12543
|
// src/extract/infra/railway.ts
|
|
11991
12544
|
init_cjs_shims();
|
|
11992
12545
|
var import_node_fs23 = require("fs");
|
|
11993
|
-
var
|
|
12546
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
11994
12547
|
var import_smol_toml3 = require("smol-toml");
|
|
11995
|
-
var
|
|
12548
|
+
var import_types45 = require("@neat.is/types");
|
|
11996
12549
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
11997
12550
|
async function readRailwayConfig(dir) {
|
|
11998
12551
|
for (const filename of RAILWAY_FILENAMES) {
|
|
11999
|
-
const abs =
|
|
12552
|
+
const abs = import_node_path55.default.join(dir, filename);
|
|
12000
12553
|
if (!await exists(abs)) continue;
|
|
12001
12554
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
12002
12555
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -12012,7 +12565,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12012
12565
|
try {
|
|
12013
12566
|
read = await readRailwayConfig(service.dir);
|
|
12014
12567
|
} catch (err) {
|
|
12015
|
-
recordExtractionError("infra railway",
|
|
12568
|
+
recordExtractionError("infra railway", import_node_path55.default.relative(scanPath, service.dir), err);
|
|
12016
12569
|
continue;
|
|
12017
12570
|
}
|
|
12018
12571
|
if (!read) continue;
|
|
@@ -12022,7 +12575,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12022
12575
|
}
|
|
12023
12576
|
const anchorId = service.node.id;
|
|
12024
12577
|
const { config, relFile, raw } = read;
|
|
12025
|
-
const evidenceFile = toPosix(
|
|
12578
|
+
const evidenceFile = toPosix(import_node_path55.default.relative(scanPath, import_node_path55.default.join(service.dir, relFile)));
|
|
12026
12579
|
const add = (edgeType, kind, name) => {
|
|
12027
12580
|
if (!name) return;
|
|
12028
12581
|
const result = emitPlatformResourceEdge(
|
|
@@ -12038,9 +12591,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12038
12591
|
nodesAdded += result.nodesAdded;
|
|
12039
12592
|
edgesAdded += result.edgesAdded;
|
|
12040
12593
|
};
|
|
12041
|
-
add(
|
|
12042
|
-
add(
|
|
12043
|
-
add(
|
|
12594
|
+
add(import_types45.EdgeType.RUNS_ON, "railway", "railway");
|
|
12595
|
+
add(import_types45.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
12596
|
+
add(import_types45.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
12044
12597
|
}
|
|
12045
12598
|
return { nodesAdded, edgesAdded };
|
|
12046
12599
|
}
|
|
@@ -12048,12 +12601,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
12048
12601
|
// src/extract/infra/supabase.ts
|
|
12049
12602
|
init_cjs_shims();
|
|
12050
12603
|
var import_node_fs24 = require("fs");
|
|
12051
|
-
var
|
|
12604
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
12052
12605
|
var import_smol_toml4 = require("smol-toml");
|
|
12053
|
-
var
|
|
12606
|
+
var import_types46 = require("@neat.is/types");
|
|
12054
12607
|
async function readSupabaseConfig(dir) {
|
|
12055
|
-
const relFile =
|
|
12056
|
-
const abs =
|
|
12608
|
+
const relFile = import_node_path56.default.join("supabase", "config.toml");
|
|
12609
|
+
const abs = import_node_path56.default.join(dir, relFile);
|
|
12057
12610
|
if (!await exists(abs)) return null;
|
|
12058
12611
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
12059
12612
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -12067,7 +12620,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12067
12620
|
try {
|
|
12068
12621
|
read = await readSupabaseConfig(service.dir);
|
|
12069
12622
|
} catch (err) {
|
|
12070
|
-
recordExtractionError("infra supabase",
|
|
12623
|
+
recordExtractionError("infra supabase", import_node_path56.default.relative(scanPath, service.dir), err);
|
|
12071
12624
|
continue;
|
|
12072
12625
|
}
|
|
12073
12626
|
if (!read) continue;
|
|
@@ -12082,7 +12635,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12082
12635
|
});
|
|
12083
12636
|
}
|
|
12084
12637
|
const anchorId = service.node.id;
|
|
12085
|
-
const evidenceFile = toPosix(
|
|
12638
|
+
const evidenceFile = toPosix(import_node_path56.default.relative(scanPath, import_node_path56.default.join(service.dir, relFile)));
|
|
12086
12639
|
const add = (edgeType, kind, name) => {
|
|
12087
12640
|
if (!name) return;
|
|
12088
12641
|
const result = emitPlatformResourceEdge(
|
|
@@ -12098,10 +12651,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
12098
12651
|
nodesAdded += result.nodesAdded;
|
|
12099
12652
|
edgesAdded += result.edgesAdded;
|
|
12100
12653
|
};
|
|
12101
|
-
add(
|
|
12102
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
12103
|
-
if (config.storage) add(
|
|
12104
|
-
if (config.auth) add(
|
|
12654
|
+
add(import_types46.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
12655
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types46.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
12656
|
+
if (config.storage) add(import_types46.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
12657
|
+
if (config.auth) add(import_types46.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
12105
12658
|
}
|
|
12106
12659
|
return { nodesAdded, edgesAdded };
|
|
12107
12660
|
}
|
|
@@ -12124,14 +12677,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
12124
12677
|
|
|
12125
12678
|
// src/extract/zod-shapes.ts
|
|
12126
12679
|
init_cjs_shims();
|
|
12127
|
-
var
|
|
12128
|
-
var
|
|
12680
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
12681
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
12129
12682
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12130
|
-
var
|
|
12683
|
+
var import_types47 = require("@neat.is/types");
|
|
12131
12684
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
12132
12685
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
12133
12686
|
function parserForExt3(ext) {
|
|
12134
|
-
const p = new
|
|
12687
|
+
const p = new import_tree_sitter16.default();
|
|
12135
12688
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
12136
12689
|
return p;
|
|
12137
12690
|
}
|
|
@@ -12219,7 +12772,7 @@ function topLevelSchemas(root) {
|
|
|
12219
12772
|
}
|
|
12220
12773
|
function zodShapesFromFile(file, serviceDir) {
|
|
12221
12774
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
12222
|
-
const tree = parseSource3(parserForExt3(
|
|
12775
|
+
const tree = parseSource3(parserForExt3(import_node_path57.default.extname(file.path)), file.content);
|
|
12223
12776
|
const out = [];
|
|
12224
12777
|
const seen = /* @__PURE__ */ new Set();
|
|
12225
12778
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -12233,11 +12786,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
12233
12786
|
seen.add(name);
|
|
12234
12787
|
const line = call.startPosition.row + 1;
|
|
12235
12788
|
out.push({
|
|
12236
|
-
infraId: (0,
|
|
12789
|
+
infraId: (0, import_types47.infraId)("zod-schema", name),
|
|
12237
12790
|
name,
|
|
12238
12791
|
fields,
|
|
12239
12792
|
evidence: {
|
|
12240
|
-
file:
|
|
12793
|
+
file: import_node_path57.default.relative(serviceDir, file.path),
|
|
12241
12794
|
line,
|
|
12242
12795
|
snippet: snippet(file.content, line)
|
|
12243
12796
|
}
|
|
@@ -12268,7 +12821,7 @@ async function addZodShapes(graph, services) {
|
|
|
12268
12821
|
if (!graph.hasNode(shape.infraId)) {
|
|
12269
12822
|
const node = {
|
|
12270
12823
|
id: shape.infraId,
|
|
12271
|
-
type:
|
|
12824
|
+
type: import_types47.NodeType.InfraNode,
|
|
12272
12825
|
name: shape.name,
|
|
12273
12826
|
provider: "self",
|
|
12274
12827
|
kind: "zod-schema"
|
|
@@ -12278,14 +12831,14 @@ async function addZodShapes(graph, services) {
|
|
|
12278
12831
|
}
|
|
12279
12832
|
if (shape.fields.length > 0) {
|
|
12280
12833
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
12281
|
-
if (node.type ===
|
|
12834
|
+
if (node.type === import_types47.NodeType.InfraNode) {
|
|
12282
12835
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
12283
12836
|
...node,
|
|
12284
12837
|
columns: foldColumns(
|
|
12285
12838
|
node.columns,
|
|
12286
12839
|
shape.fields,
|
|
12287
|
-
|
|
12288
|
-
(0,
|
|
12840
|
+
import_types47.Provenance.EXTRACTED,
|
|
12841
|
+
(0, import_types47.confidenceForExtracted)("structural")
|
|
12289
12842
|
)
|
|
12290
12843
|
});
|
|
12291
12844
|
}
|
|
@@ -12299,15 +12852,15 @@ async function addZodShapes(graph, services) {
|
|
|
12299
12852
|
);
|
|
12300
12853
|
nodesAdded += n;
|
|
12301
12854
|
edgesAdded += e;
|
|
12302
|
-
const edgeId = (0,
|
|
12855
|
+
const edgeId = (0, import_types47.extractedEdgeId)(fileNodeId, shape.infraId, import_types47.EdgeType.CONTAINS);
|
|
12303
12856
|
if (!graph.hasEdge(edgeId)) {
|
|
12304
12857
|
const edge = {
|
|
12305
12858
|
id: edgeId,
|
|
12306
12859
|
source: fileNodeId,
|
|
12307
12860
|
target: shape.infraId,
|
|
12308
|
-
type:
|
|
12309
|
-
provenance:
|
|
12310
|
-
confidence: (0,
|
|
12861
|
+
type: import_types47.EdgeType.CONTAINS,
|
|
12862
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
12863
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
12311
12864
|
evidence: shape.evidence
|
|
12312
12865
|
};
|
|
12313
12866
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -12321,7 +12874,7 @@ async function addZodShapes(graph, services) {
|
|
|
12321
12874
|
|
|
12322
12875
|
// src/extract/firestore-rules.ts
|
|
12323
12876
|
init_cjs_shims();
|
|
12324
|
-
var
|
|
12877
|
+
var import_types48 = require("@neat.is/types");
|
|
12325
12878
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
12326
12879
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
12327
12880
|
function stripComments(src) {
|
|
@@ -12461,7 +13014,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
12461
13014
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
12462
13015
|
graph.forEachNode((id, attrs) => {
|
|
12463
13016
|
const node = attrs;
|
|
12464
|
-
if (node.type !==
|
|
13017
|
+
if (node.type !== import_types48.NodeType.InfraNode) return;
|
|
12465
13018
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
12466
13019
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
12467
13020
|
if (!fields || fields.size === 0) return;
|
|
@@ -12474,17 +13027,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
12474
13027
|
}
|
|
12475
13028
|
|
|
12476
13029
|
// src/extract/index.ts
|
|
12477
|
-
var
|
|
13030
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
12478
13031
|
|
|
12479
13032
|
// src/extract/retire.ts
|
|
12480
13033
|
init_cjs_shims();
|
|
12481
13034
|
var import_node_fs25 = require("fs");
|
|
12482
|
-
var
|
|
12483
|
-
var
|
|
13035
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13036
|
+
var import_types49 = require("@neat.is/types");
|
|
12484
13037
|
function dropOrphanedFileNodes(graph) {
|
|
12485
13038
|
const orphans = [];
|
|
12486
13039
|
graph.forEachNode((id, attrs) => {
|
|
12487
|
-
if (attrs.type !==
|
|
13040
|
+
if (attrs.type !== import_types49.NodeType.FileNode) return;
|
|
12488
13041
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
12489
13042
|
orphans.push(id);
|
|
12490
13043
|
}
|
|
@@ -12497,14 +13050,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
12497
13050
|
const bases = [scanPath, ...serviceDirs];
|
|
12498
13051
|
graph.forEachEdge((id, attrs) => {
|
|
12499
13052
|
const edge = attrs;
|
|
12500
|
-
if (edge.provenance !==
|
|
13053
|
+
if (edge.provenance !== import_types49.Provenance.EXTRACTED) return;
|
|
12501
13054
|
const evidenceFile = edge.evidence?.file;
|
|
12502
13055
|
if (!evidenceFile) return;
|
|
12503
|
-
if (
|
|
13056
|
+
if (import_node_path58.default.isAbsolute(evidenceFile)) {
|
|
12504
13057
|
if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
|
|
12505
13058
|
return;
|
|
12506
13059
|
}
|
|
12507
|
-
const found = bases.some((base) => (0, import_node_fs25.existsSync)(
|
|
13060
|
+
const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path58.default.join(base, evidenceFile)));
|
|
12508
13061
|
if (!found) toDrop.push(id);
|
|
12509
13062
|
});
|
|
12510
13063
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -12561,7 +13114,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12561
13114
|
}
|
|
12562
13115
|
const droppedEntries = drainDroppedExtracted();
|
|
12563
13116
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
12564
|
-
const rejectedPath =
|
|
13117
|
+
const rejectedPath = import_node_path59.default.join(import_node_path59.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
12565
13118
|
try {
|
|
12566
13119
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
12567
13120
|
} catch (err) {
|
|
@@ -12596,8 +13149,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
12596
13149
|
// src/persist.ts
|
|
12597
13150
|
init_cjs_shims();
|
|
12598
13151
|
var import_node_fs26 = require("fs");
|
|
12599
|
-
var
|
|
12600
|
-
var
|
|
13152
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
13153
|
+
var import_types50 = require("@neat.is/types");
|
|
12601
13154
|
var SCHEMA_VERSION = 7;
|
|
12602
13155
|
function migrateV1ToV2(payload) {
|
|
12603
13156
|
const nodes = payload.graph.nodes;
|
|
@@ -12621,7 +13174,7 @@ function migrateV5ToV6(payload) {
|
|
|
12621
13174
|
if (Array.isArray(nodes)) {
|
|
12622
13175
|
for (const node of nodes) {
|
|
12623
13176
|
const attrs = node.attributes;
|
|
12624
|
-
if (!attrs || attrs.type !==
|
|
13177
|
+
if (!attrs || attrs.type !== import_types50.NodeType.InfraNode) continue;
|
|
12625
13178
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
12626
13179
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
12627
13180
|
}
|
|
@@ -12637,12 +13190,12 @@ function migrateV2ToV3(payload) {
|
|
|
12637
13190
|
for (const edge of edges) {
|
|
12638
13191
|
const attrs = edge.attributes;
|
|
12639
13192
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
12640
|
-
attrs.provenance =
|
|
13193
|
+
attrs.provenance = import_types50.Provenance.OBSERVED;
|
|
12641
13194
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
12642
13195
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
12643
13196
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
12644
13197
|
if (type && source && target) {
|
|
12645
|
-
const newId = (0,
|
|
13198
|
+
const newId = (0, import_types50.observedEdgeId)(source, target, type);
|
|
12646
13199
|
attrs.id = newId;
|
|
12647
13200
|
if (edge.key) edge.key = newId;
|
|
12648
13201
|
}
|
|
@@ -12651,7 +13204,7 @@ function migrateV2ToV3(payload) {
|
|
|
12651
13204
|
return { ...payload, schemaVersion: 3 };
|
|
12652
13205
|
}
|
|
12653
13206
|
async function ensureDir(filePath) {
|
|
12654
|
-
await import_node_fs26.promises.mkdir(
|
|
13207
|
+
await import_node_fs26.promises.mkdir(import_node_path60.default.dirname(filePath), { recursive: true });
|
|
12655
13208
|
}
|
|
12656
13209
|
async function saveGraphToDisk(graph, outPath) {
|
|
12657
13210
|
await ensureDir(outPath);
|
|
@@ -12741,23 +13294,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
12741
13294
|
|
|
12742
13295
|
// src/projects.ts
|
|
12743
13296
|
init_cjs_shims();
|
|
12744
|
-
var
|
|
13297
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
12745
13298
|
function pathsForProject(project, baseDir) {
|
|
12746
13299
|
if (project === DEFAULT_PROJECT) {
|
|
12747
13300
|
return {
|
|
12748
|
-
snapshotPath:
|
|
12749
|
-
errorsPath:
|
|
12750
|
-
staleEventsPath:
|
|
12751
|
-
embeddingsCachePath:
|
|
12752
|
-
policyViolationsPath:
|
|
13301
|
+
snapshotPath: import_node_path61.default.join(baseDir, "graph.json"),
|
|
13302
|
+
errorsPath: import_node_path61.default.join(baseDir, "errors.ndjson"),
|
|
13303
|
+
staleEventsPath: import_node_path61.default.join(baseDir, "stale-events.ndjson"),
|
|
13304
|
+
embeddingsCachePath: import_node_path61.default.join(baseDir, "embeddings.json"),
|
|
13305
|
+
policyViolationsPath: import_node_path61.default.join(baseDir, "policy-violations.ndjson")
|
|
12753
13306
|
};
|
|
12754
13307
|
}
|
|
12755
13308
|
return {
|
|
12756
|
-
snapshotPath:
|
|
12757
|
-
errorsPath:
|
|
12758
|
-
staleEventsPath:
|
|
12759
|
-
embeddingsCachePath:
|
|
12760
|
-
policyViolationsPath:
|
|
13309
|
+
snapshotPath: import_node_path61.default.join(baseDir, `${project}.json`),
|
|
13310
|
+
errorsPath: import_node_path61.default.join(baseDir, `errors.${project}.ndjson`),
|
|
13311
|
+
staleEventsPath: import_node_path61.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
13312
|
+
embeddingsCachePath: import_node_path61.default.join(baseDir, `embeddings.${project}.json`),
|
|
13313
|
+
policyViolationsPath: import_node_path61.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
12761
13314
|
};
|
|
12762
13315
|
}
|
|
12763
13316
|
var Projects = class {
|
|
@@ -12795,19 +13348,19 @@ var Projects = class {
|
|
|
12795
13348
|
init_cjs_shims();
|
|
12796
13349
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
12797
13350
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
12798
|
-
var
|
|
13351
|
+
var import_types80 = require("@neat.is/types");
|
|
12799
13352
|
|
|
12800
13353
|
// src/extend/index.ts
|
|
12801
13354
|
init_cjs_shims();
|
|
12802
13355
|
var import_node_fs28 = require("fs");
|
|
12803
|
-
var
|
|
13356
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
12804
13357
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
12805
13358
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
12806
13359
|
|
|
12807
13360
|
// src/installers/package-manager.ts
|
|
12808
13361
|
init_cjs_shims();
|
|
12809
13362
|
var import_node_fs27 = require("fs");
|
|
12810
|
-
var
|
|
13363
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
12811
13364
|
var import_node_child_process = require("child_process");
|
|
12812
13365
|
var LOCKFILE_PRIORITY = [
|
|
12813
13366
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -12829,22 +13382,22 @@ async function exists2(p) {
|
|
|
12829
13382
|
}
|
|
12830
13383
|
}
|
|
12831
13384
|
async function detectPackageManager(serviceDir) {
|
|
12832
|
-
let dir =
|
|
13385
|
+
let dir = import_node_path62.default.resolve(serviceDir);
|
|
12833
13386
|
const stops = /* @__PURE__ */ new Set();
|
|
12834
13387
|
for (let i = 0; i < 64; i++) {
|
|
12835
13388
|
if (stops.has(dir)) break;
|
|
12836
13389
|
stops.add(dir);
|
|
12837
13390
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
12838
|
-
const lockPath =
|
|
13391
|
+
const lockPath = import_node_path62.default.join(dir, candidate.lockfile);
|
|
12839
13392
|
if (await exists2(lockPath)) {
|
|
12840
13393
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
12841
13394
|
}
|
|
12842
13395
|
}
|
|
12843
|
-
const parent =
|
|
13396
|
+
const parent = import_node_path62.default.dirname(dir);
|
|
12844
13397
|
if (parent === dir) break;
|
|
12845
13398
|
dir = parent;
|
|
12846
13399
|
}
|
|
12847
|
-
return { pm: "npm", cwd:
|
|
13400
|
+
return { pm: "npm", cwd: import_node_path62.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
12848
13401
|
}
|
|
12849
13402
|
async function runPackageManagerInstall(cmd) {
|
|
12850
13403
|
return new Promise((resolve) => {
|
|
@@ -12893,7 +13446,7 @@ async function fileExists2(p) {
|
|
|
12893
13446
|
}
|
|
12894
13447
|
}
|
|
12895
13448
|
async function readPackageJson(scanPath) {
|
|
12896
|
-
const pkgPath =
|
|
13449
|
+
const pkgPath = import_node_path63.default.join(scanPath, "package.json");
|
|
12897
13450
|
const raw = await import_node_fs28.promises.readFile(pkgPath, "utf8");
|
|
12898
13451
|
return JSON.parse(raw);
|
|
12899
13452
|
}
|
|
@@ -12907,27 +13460,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
12907
13460
|
]);
|
|
12908
13461
|
async function findHookFiles(scanPath) {
|
|
12909
13462
|
const found = [];
|
|
12910
|
-
const
|
|
13463
|
+
const walk9 = async (dir) => {
|
|
12911
13464
|
const entries = await import_node_fs28.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
12912
13465
|
for (const entry2 of entries) {
|
|
12913
13466
|
if (entry2.isDirectory()) {
|
|
12914
13467
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
12915
|
-
await
|
|
13468
|
+
await walk9(import_node_path63.default.join(dir, entry2.name));
|
|
12916
13469
|
} else if (entry2.isFile()) {
|
|
12917
13470
|
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(
|
|
13471
|
+
const rel = import_node_path63.default.relative(scanPath, import_node_path63.default.join(dir, entry2.name));
|
|
13472
|
+
found.push(rel.split(import_node_path63.default.sep).join("/"));
|
|
12920
13473
|
}
|
|
12921
13474
|
}
|
|
12922
13475
|
}
|
|
12923
13476
|
};
|
|
12924
|
-
await
|
|
13477
|
+
await walk9(scanPath);
|
|
12925
13478
|
return found.sort();
|
|
12926
13479
|
}
|
|
12927
13480
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
12928
13481
|
let fallback = null;
|
|
12929
13482
|
for (const file of hookFiles) {
|
|
12930
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13483
|
+
const content = await import_node_fs28.promises.readFile(import_node_path63.default.join(scanPath, file), "utf8");
|
|
12931
13484
|
const patched = splicedContent(content, snippet2);
|
|
12932
13485
|
if (patched !== null) return { file, content, patched };
|
|
12933
13486
|
if (fallback === null) fallback = { file, content };
|
|
@@ -12935,11 +13488,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
12935
13488
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
12936
13489
|
}
|
|
12937
13490
|
function extendLogPath() {
|
|
12938
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
13491
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path63.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
12939
13492
|
}
|
|
12940
13493
|
async function appendExtendLog(entry2) {
|
|
12941
13494
|
const logPath = extendLogPath();
|
|
12942
|
-
await import_node_fs28.promises.mkdir(
|
|
13495
|
+
await import_node_fs28.promises.mkdir(import_node_path63.default.dirname(logPath), { recursive: true });
|
|
12943
13496
|
await import_node_fs28.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
12944
13497
|
}
|
|
12945
13498
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -12998,7 +13551,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
12998
13551
|
}
|
|
12999
13552
|
async function describeProjectInstrumentation(ctx) {
|
|
13000
13553
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13001
|
-
const envNeat = await fileExists2(
|
|
13554
|
+
const envNeat = await fileExists2(import_node_path63.default.join(ctx.scanPath, ".env.neat"));
|
|
13002
13555
|
const registryInstrPackages = new Set(
|
|
13003
13556
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
13004
13557
|
);
|
|
@@ -13020,7 +13573,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
13020
13573
|
);
|
|
13021
13574
|
}
|
|
13022
13575
|
for (const file of hookFiles) {
|
|
13023
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13576
|
+
const content = await import_node_fs28.promises.readFile(import_node_path63.default.join(ctx.scanPath, file), "utf8");
|
|
13024
13577
|
if (content.includes(args.registration_snippet)) {
|
|
13025
13578
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
13026
13579
|
}
|
|
@@ -13032,10 +13585,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
13032
13585
|
);
|
|
13033
13586
|
}
|
|
13034
13587
|
const primaryFile = primary.file;
|
|
13035
|
-
const primaryPath =
|
|
13588
|
+
const primaryPath = import_node_path63.default.join(ctx.scanPath, primaryFile);
|
|
13036
13589
|
const filesTouched = [];
|
|
13037
13590
|
const depsAdded = [];
|
|
13038
|
-
const pkgPath =
|
|
13591
|
+
const pkgPath = import_node_path63.default.join(ctx.scanPath, "package.json");
|
|
13039
13592
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13040
13593
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
13041
13594
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -13074,7 +13627,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
13074
13627
|
};
|
|
13075
13628
|
}
|
|
13076
13629
|
for (const file of hookFiles) {
|
|
13077
|
-
const content = await import_node_fs28.promises.readFile(
|
|
13630
|
+
const content = await import_node_fs28.promises.readFile(import_node_path63.default.join(ctx.scanPath, file), "utf8");
|
|
13078
13631
|
if (content.includes(args.registration_snippet)) {
|
|
13079
13632
|
return {
|
|
13080
13633
|
library: args.library,
|
|
@@ -13115,7 +13668,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13115
13668
|
if (!match) {
|
|
13116
13669
|
return { undone: false, message: "no apply found for library" };
|
|
13117
13670
|
}
|
|
13118
|
-
const pkgPath =
|
|
13671
|
+
const pkgPath = import_node_path63.default.join(ctx.scanPath, "package.json");
|
|
13119
13672
|
if (await fileExists2(pkgPath)) {
|
|
13120
13673
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
13121
13674
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -13126,7 +13679,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
13126
13679
|
}
|
|
13127
13680
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
13128
13681
|
for (const file of hookFiles) {
|
|
13129
|
-
const filePath =
|
|
13682
|
+
const filePath = import_node_path63.default.join(ctx.scanPath, file);
|
|
13130
13683
|
const content = await import_node_fs28.promises.readFile(filePath, "utf8");
|
|
13131
13684
|
if (content.includes(match.registration_snippet)) {
|
|
13132
13685
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -13142,39 +13695,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
13142
13695
|
|
|
13143
13696
|
// src/divergences.ts
|
|
13144
13697
|
init_cjs_shims();
|
|
13145
|
-
var
|
|
13698
|
+
var import_types51 = require("@neat.is/types");
|
|
13146
13699
|
function bucketKey(source, target, type) {
|
|
13147
13700
|
return `${type}|${source}|${target}`;
|
|
13148
13701
|
}
|
|
13149
13702
|
function bucketSourceFor(graph, edge) {
|
|
13150
|
-
if (edge.type !==
|
|
13151
|
-
const parsed = (0,
|
|
13703
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) return edge.source;
|
|
13704
|
+
const parsed = (0, import_types51.parseFileId)(edge.source);
|
|
13152
13705
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
13153
13706
|
const target = graph.getNodeAttributes(edge.target);
|
|
13154
|
-
if (target.type !==
|
|
13155
|
-
return (0,
|
|
13707
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) return edge.source;
|
|
13708
|
+
return (0, import_types51.serviceId)(parsed.service);
|
|
13156
13709
|
}
|
|
13157
13710
|
function bucketEdges(graph) {
|
|
13158
13711
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
13159
13712
|
graph.forEachEdge((id, attrs) => {
|
|
13160
13713
|
const e = attrs;
|
|
13161
|
-
const parsed = (0,
|
|
13714
|
+
const parsed = (0, import_types51.parseEdgeId)(id);
|
|
13162
13715
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
13163
13716
|
const source = bucketSourceFor(graph, e);
|
|
13164
13717
|
const key = bucketKey(source, e.target, e.type);
|
|
13165
13718
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
13166
13719
|
switch (provenance) {
|
|
13167
|
-
case
|
|
13720
|
+
case import_types51.Provenance.EXTRACTED:
|
|
13168
13721
|
cur.extracted = e;
|
|
13169
13722
|
break;
|
|
13170
|
-
case
|
|
13723
|
+
case import_types51.Provenance.OBSERVED:
|
|
13171
13724
|
cur.observed = e;
|
|
13172
13725
|
break;
|
|
13173
|
-
case
|
|
13726
|
+
case import_types51.Provenance.INFERRED:
|
|
13174
13727
|
cur.inferred = e;
|
|
13175
13728
|
break;
|
|
13176
13729
|
default:
|
|
13177
|
-
if (e.provenance ===
|
|
13730
|
+
if (e.provenance === import_types51.Provenance.STALE) cur.stale = e;
|
|
13178
13731
|
}
|
|
13179
13732
|
buckets2.set(key, cur);
|
|
13180
13733
|
});
|
|
@@ -13183,22 +13736,22 @@ function bucketEdges(graph) {
|
|
|
13183
13736
|
function nodeIsFrontier(graph, nodeId) {
|
|
13184
13737
|
if (!graph.hasNode(nodeId)) return false;
|
|
13185
13738
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13186
|
-
return attrs.type ===
|
|
13739
|
+
return attrs.type === import_types51.NodeType.FrontierNode;
|
|
13187
13740
|
}
|
|
13188
13741
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
13189
13742
|
if (!graph.hasNode(nodeId)) return false;
|
|
13190
13743
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13191
|
-
return attrs.type ===
|
|
13744
|
+
return attrs.type === import_types51.NodeType.WebSocketChannelNode;
|
|
13192
13745
|
}
|
|
13193
13746
|
function nodeIsServerAction(graph, nodeId) {
|
|
13194
13747
|
if (!graph.hasNode(nodeId)) return false;
|
|
13195
13748
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13196
|
-
return attrs.type ===
|
|
13749
|
+
return attrs.type === import_types51.NodeType.ServerActionNode;
|
|
13197
13750
|
}
|
|
13198
13751
|
function nodeIsSymbol(graph, nodeId) {
|
|
13199
13752
|
if (!graph.hasNode(nodeId)) return false;
|
|
13200
13753
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
13201
|
-
return attrs.type ===
|
|
13754
|
+
return attrs.type === import_types51.NodeType.SymbolNode;
|
|
13202
13755
|
}
|
|
13203
13756
|
function clampConfidence(n) {
|
|
13204
13757
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -13218,14 +13771,14 @@ function gradedConfidence(edge) {
|
|
|
13218
13771
|
return clampConfidence(confidenceForEdge(edge));
|
|
13219
13772
|
}
|
|
13220
13773
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13774
|
+
import_types51.EdgeType.CALLS,
|
|
13775
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
13776
|
+
import_types51.EdgeType.PUBLISHES_TO,
|
|
13777
|
+
import_types51.EdgeType.CONSUMES_FROM
|
|
13225
13778
|
]);
|
|
13226
13779
|
function detectMissingDivergences(graph, bucket) {
|
|
13227
13780
|
const out = [];
|
|
13228
|
-
if (bucket.type ===
|
|
13781
|
+
if (bucket.type === import_types51.EdgeType.CONTAINS) return out;
|
|
13229
13782
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
13230
13783
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
13231
13784
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -13267,7 +13820,7 @@ function declaredHostFor(svc) {
|
|
|
13267
13820
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
13268
13821
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13269
13822
|
const e = graph.getEdgeAttributes(edgeId);
|
|
13270
|
-
if (e.type ===
|
|
13823
|
+
if (e.type === import_types51.EdgeType.CONFIGURED_BY && e.provenance === import_types51.Provenance.EXTRACTED) {
|
|
13271
13824
|
return true;
|
|
13272
13825
|
}
|
|
13273
13826
|
}
|
|
@@ -13280,10 +13833,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
13280
13833
|
const out = [];
|
|
13281
13834
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13282
13835
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13283
|
-
if (edge.type !==
|
|
13284
|
-
if (edge.provenance !==
|
|
13836
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13837
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13285
13838
|
const target = graph.getNodeAttributes(edge.target);
|
|
13286
|
-
if (target.type !==
|
|
13839
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13287
13840
|
const observedHost = target.host?.trim();
|
|
13288
13841
|
if (!observedHost) continue;
|
|
13289
13842
|
if (observedHost === declaredHost) continue;
|
|
@@ -13305,10 +13858,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
13305
13858
|
const deps = svc.dependencies ?? {};
|
|
13306
13859
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
13307
13860
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
13308
|
-
if (edge.type !==
|
|
13309
|
-
if (edge.provenance !==
|
|
13861
|
+
if (edge.type !== import_types51.EdgeType.CONNECTS_TO) continue;
|
|
13862
|
+
if (edge.provenance !== import_types51.Provenance.OBSERVED) continue;
|
|
13310
13863
|
const target = graph.getNodeAttributes(edge.target);
|
|
13311
|
-
if (target.type !==
|
|
13864
|
+
if (target.type !== import_types51.NodeType.DatabaseNode) continue;
|
|
13312
13865
|
for (const pair of compatPairs()) {
|
|
13313
13866
|
if (pair.engine !== target.engine) continue;
|
|
13314
13867
|
const declared = deps[pair.driver];
|
|
@@ -13405,7 +13958,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
13405
13958
|
for (const d of all) {
|
|
13406
13959
|
if (d.type !== "host-mismatch") continue;
|
|
13407
13960
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
13408
|
-
declaredHalf.add((0,
|
|
13961
|
+
declaredHalf.add((0, import_types51.databaseId)(d.extractedHost));
|
|
13409
13962
|
}
|
|
13410
13963
|
if (observedHalf.size === 0) return all;
|
|
13411
13964
|
return all.filter((d) => {
|
|
@@ -13424,13 +13977,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13424
13977
|
}
|
|
13425
13978
|
graph.forEachNode((nodeId, attrs) => {
|
|
13426
13979
|
const n = attrs;
|
|
13427
|
-
if (n.type ===
|
|
13980
|
+
if (n.type === import_types51.NodeType.ServiceNode) {
|
|
13428
13981
|
const svc = n;
|
|
13429
13982
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
13430
13983
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
13431
13984
|
return;
|
|
13432
13985
|
}
|
|
13433
|
-
if (n.type ===
|
|
13986
|
+
if (n.type === import_types51.NodeType.InfraNode && n.kind === "sql-table") {
|
|
13434
13987
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
13435
13988
|
}
|
|
13436
13989
|
});
|
|
@@ -13466,7 +14019,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
13466
14019
|
const bc = "column" in b && b.column ? b.column : "";
|
|
13467
14020
|
return ac.localeCompare(bc);
|
|
13468
14021
|
});
|
|
13469
|
-
return
|
|
14022
|
+
return import_types51.DivergenceResultSchema.parse({
|
|
13470
14023
|
divergences: filtered,
|
|
13471
14024
|
totalAffected: filtered.length,
|
|
13472
14025
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -13599,26 +14152,26 @@ function canonicalJson(value) {
|
|
|
13599
14152
|
init_cjs_shims();
|
|
13600
14153
|
var import_node_fs30 = require("fs");
|
|
13601
14154
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
13602
|
-
var
|
|
13603
|
-
var
|
|
14155
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
14156
|
+
var import_types52 = require("@neat.is/types");
|
|
13604
14157
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
13605
14158
|
var LOCK_RETRY_MS = 50;
|
|
13606
14159
|
function neatHome() {
|
|
13607
14160
|
const override = process.env.NEAT_HOME;
|
|
13608
|
-
if (override && override.length > 0) return
|
|
13609
|
-
return
|
|
14161
|
+
if (override && override.length > 0) return import_node_path64.default.resolve(override);
|
|
14162
|
+
return import_node_path64.default.join(import_node_os3.default.homedir(), ".neat");
|
|
13610
14163
|
}
|
|
13611
14164
|
function registryPath() {
|
|
13612
|
-
return
|
|
14165
|
+
return import_node_path64.default.join(neatHome(), "projects.json");
|
|
13613
14166
|
}
|
|
13614
14167
|
function registryLockPath() {
|
|
13615
|
-
return
|
|
14168
|
+
return import_node_path64.default.join(neatHome(), "projects.json.lock");
|
|
13616
14169
|
}
|
|
13617
14170
|
function daemonPidPath() {
|
|
13618
|
-
return
|
|
14171
|
+
return import_node_path64.default.join(neatHome(), "neatd.pid");
|
|
13619
14172
|
}
|
|
13620
14173
|
function daemonsDir() {
|
|
13621
|
-
return
|
|
14174
|
+
return import_node_path64.default.join(neatHome(), "daemons");
|
|
13622
14175
|
}
|
|
13623
14176
|
function isFiniteInt(v) {
|
|
13624
14177
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -13659,7 +14212,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
13659
14212
|
const out = [];
|
|
13660
14213
|
for (const name of names) {
|
|
13661
14214
|
if (!name.endsWith(".json")) continue;
|
|
13662
|
-
const file =
|
|
14215
|
+
const file = import_node_path64.default.join(dir, name);
|
|
13663
14216
|
let raw;
|
|
13664
14217
|
try {
|
|
13665
14218
|
raw = await import_node_fs30.promises.readFile(file, "utf8");
|
|
@@ -13736,7 +14289,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
13736
14289
|
}
|
|
13737
14290
|
}
|
|
13738
14291
|
async function writeAtomically(target, contents) {
|
|
13739
|
-
await import_node_fs30.promises.mkdir(
|
|
14292
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(target), { recursive: true });
|
|
13740
14293
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
13741
14294
|
const fd = await import_node_fs30.promises.open(tmp, "w");
|
|
13742
14295
|
try {
|
|
@@ -13749,7 +14302,7 @@ async function writeAtomically(target, contents) {
|
|
|
13749
14302
|
}
|
|
13750
14303
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
13751
14304
|
const deadline = Date.now() + timeoutMs;
|
|
13752
|
-
await import_node_fs30.promises.mkdir(
|
|
14305
|
+
await import_node_fs30.promises.mkdir(import_node_path64.default.dirname(lockPath), { recursive: true });
|
|
13753
14306
|
let probedHolder = false;
|
|
13754
14307
|
while (true) {
|
|
13755
14308
|
try {
|
|
@@ -13802,10 +14355,10 @@ async function readRegistry() {
|
|
|
13802
14355
|
throw err;
|
|
13803
14356
|
}
|
|
13804
14357
|
const parsed = JSON.parse(raw);
|
|
13805
|
-
return
|
|
14358
|
+
return import_types52.RegistryFileSchema.parse(parsed);
|
|
13806
14359
|
}
|
|
13807
14360
|
async function writeRegistry(reg) {
|
|
13808
|
-
const validated =
|
|
14361
|
+
const validated = import_types52.RegistryFileSchema.parse(reg);
|
|
13809
14362
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
13810
14363
|
}
|
|
13811
14364
|
async function getProject(name) {
|
|
@@ -13950,7 +14503,7 @@ init_auth();
|
|
|
13950
14503
|
// src/connectors-config.ts
|
|
13951
14504
|
init_cjs_shims();
|
|
13952
14505
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
13953
|
-
var
|
|
14506
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
13954
14507
|
var import_node_fs31 = require("fs");
|
|
13955
14508
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
13956
14509
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -13965,11 +14518,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
13965
14518
|
};
|
|
13966
14519
|
function neatHome2() {
|
|
13967
14520
|
const override = process.env.NEAT_HOME;
|
|
13968
|
-
if (override && override.length > 0) return
|
|
13969
|
-
return
|
|
14521
|
+
if (override && override.length > 0) return import_node_path65.default.resolve(override);
|
|
14522
|
+
return import_node_path65.default.join(import_node_os4.default.homedir(), ".neat");
|
|
13970
14523
|
}
|
|
13971
14524
|
function connectorsConfigPath(home = neatHome2()) {
|
|
13972
|
-
return
|
|
14525
|
+
return import_node_path65.default.join(home, "connectors.json");
|
|
13973
14526
|
}
|
|
13974
14527
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
13975
14528
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -14156,15 +14709,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
14156
14709
|
|
|
14157
14710
|
// src/connectors/index.ts
|
|
14158
14711
|
init_cjs_shims();
|
|
14159
|
-
var
|
|
14712
|
+
var import_types53 = require("@neat.is/types");
|
|
14160
14713
|
var NO_ENV = "unknown";
|
|
14161
14714
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
14162
14715
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14163
14716
|
const sites = [];
|
|
14164
14717
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
14165
14718
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
14166
|
-
if (edge.provenance !==
|
|
14167
|
-
const parsed = (0,
|
|
14719
|
+
if (edge.provenance !== import_types53.Provenance.EXTRACTED) continue;
|
|
14720
|
+
const parsed = (0, import_types53.parseFileId)(edge.source);
|
|
14168
14721
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
14169
14722
|
const site = { relPath: edge.evidence.file };
|
|
14170
14723
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -14175,7 +14728,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
14175
14728
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
14176
14729
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
14177
14730
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
14178
|
-
if (attrs.type !==
|
|
14731
|
+
if (attrs.type !== import_types53.NodeType.RouteNode || !attrs.path) return void 0;
|
|
14179
14732
|
const site = { relPath: attrs.path };
|
|
14180
14733
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
14181
14734
|
return site;
|
|
@@ -14656,10 +15209,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
14656
15209
|
// src/connectors/supabase/map.ts
|
|
14657
15210
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
14658
15211
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
14659
|
-
function targetFromRestPath(
|
|
14660
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
15212
|
+
function targetFromRestPath(path70) {
|
|
15213
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path70);
|
|
14661
15214
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
14662
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
15215
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path70);
|
|
14663
15216
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
14664
15217
|
return null;
|
|
14665
15218
|
}
|
|
@@ -14770,23 +15323,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
14770
15323
|
|
|
14771
15324
|
// src/connectors/supabase/resolve.ts
|
|
14772
15325
|
init_cjs_shims();
|
|
14773
|
-
var
|
|
15326
|
+
var import_types55 = require("@neat.is/types");
|
|
14774
15327
|
function createSupabaseResolveTarget(graph, config) {
|
|
14775
15328
|
return (signal, _ctx) => {
|
|
14776
15329
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
14777
15330
|
return null;
|
|
14778
15331
|
}
|
|
14779
|
-
const subResourceId = (0,
|
|
15332
|
+
const subResourceId = (0, import_types55.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
14780
15333
|
if (graph.hasNode(subResourceId)) {
|
|
14781
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
15334
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14782
15335
|
}
|
|
14783
|
-
const bareResourceId = (0,
|
|
15336
|
+
const bareResourceId = (0, import_types55.infraId)(signal.targetKind, signal.targetName);
|
|
14784
15337
|
if (graph.hasNode(bareResourceId)) {
|
|
14785
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
15338
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14786
15339
|
}
|
|
14787
|
-
const projectLevelId = (0,
|
|
15340
|
+
const projectLevelId = (0, import_types55.infraId)("supabase", config.nodeRef);
|
|
14788
15341
|
if (graph.hasNode(projectLevelId)) {
|
|
14789
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
15342
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types55.EdgeType.CALLS };
|
|
14790
15343
|
}
|
|
14791
15344
|
return null;
|
|
14792
15345
|
};
|
|
@@ -14879,7 +15432,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
14879
15432
|
|
|
14880
15433
|
// src/connectors/railway/index.ts
|
|
14881
15434
|
init_cjs_shims();
|
|
14882
|
-
var
|
|
15435
|
+
var import_types59 = require("@neat.is/types");
|
|
14883
15436
|
|
|
14884
15437
|
// src/connectors/railway/client.ts
|
|
14885
15438
|
init_cjs_shims();
|
|
@@ -15030,7 +15583,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
15030
15583
|
const out = [];
|
|
15031
15584
|
graph.forEachNode((_id, attrs) => {
|
|
15032
15585
|
const node = attrs;
|
|
15033
|
-
if (node.type !==
|
|
15586
|
+
if (node.type !== import_types59.NodeType.RouteNode) return;
|
|
15034
15587
|
const route = attrs;
|
|
15035
15588
|
if (route.service !== serviceName) return;
|
|
15036
15589
|
out.push({
|
|
@@ -15134,12 +15687,12 @@ function createRailwayResolveTarget(config) {
|
|
|
15134
15687
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
15135
15688
|
if (!serviceName) return null;
|
|
15136
15689
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
15137
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
15690
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types59.EdgeType.CALLS };
|
|
15138
15691
|
}
|
|
15139
15692
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
15140
15693
|
const peerName = config.serviceNameById[signal.targetName];
|
|
15141
15694
|
if (!peerName) return null;
|
|
15142
|
-
return { targetNodeId: (0,
|
|
15695
|
+
return { targetNodeId: (0, import_types59.serviceId)(peerName), serviceName, edgeType: import_types59.EdgeType.CONNECTS_TO };
|
|
15143
15696
|
}
|
|
15144
15697
|
return null;
|
|
15145
15698
|
};
|
|
@@ -15263,9 +15816,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
15263
15816
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
15264
15817
|
if (secondSep === -1) return null;
|
|
15265
15818
|
const method = rest.slice(0, secondSep);
|
|
15266
|
-
const
|
|
15267
|
-
if (!resourceName || !method || !
|
|
15268
|
-
return { resourceName, method, path:
|
|
15819
|
+
const path70 = rest.slice(secondSep + 1);
|
|
15820
|
+
if (!resourceName || !method || !path70) return null;
|
|
15821
|
+
return { resourceName, method, path: path70 };
|
|
15269
15822
|
}
|
|
15270
15823
|
function resourceNameFor(type, labels) {
|
|
15271
15824
|
if (!labels) return null;
|
|
@@ -15303,14 +15856,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
15303
15856
|
if (!req2) return null;
|
|
15304
15857
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
15305
15858
|
const method = req2.requestMethod.toUpperCase();
|
|
15306
|
-
const
|
|
15307
|
-
if (
|
|
15859
|
+
const path70 = pathFromRequestUrl(req2.requestUrl);
|
|
15860
|
+
if (path70 === null) return null;
|
|
15308
15861
|
const timestamp = entry2.timestamp;
|
|
15309
15862
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15310
15863
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD2;
|
|
15311
15864
|
return {
|
|
15312
15865
|
targetKind: resourceType,
|
|
15313
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
15866
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path70 }),
|
|
15314
15867
|
callCount: 1,
|
|
15315
15868
|
errorCount: isError ? 1 : 0,
|
|
15316
15869
|
lastObservedIso: timestamp
|
|
@@ -15327,7 +15880,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
15327
15880
|
|
|
15328
15881
|
// src/connectors/firebase/resolve.ts
|
|
15329
15882
|
init_cjs_shims();
|
|
15330
|
-
var
|
|
15883
|
+
var import_types60 = require("@neat.is/types");
|
|
15331
15884
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
15332
15885
|
switch (resourceType) {
|
|
15333
15886
|
case "cloud_function":
|
|
@@ -15342,7 +15895,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
15342
15895
|
const entries = [];
|
|
15343
15896
|
graph.forEachNode((_id, attrs) => {
|
|
15344
15897
|
const node = attrs;
|
|
15345
|
-
if (node.type !==
|
|
15898
|
+
if (node.type !== import_types60.NodeType.RouteNode) return;
|
|
15346
15899
|
const route = attrs;
|
|
15347
15900
|
if (route.service !== serviceName) return;
|
|
15348
15901
|
entries.push({
|
|
@@ -15374,7 +15927,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
15374
15927
|
return {
|
|
15375
15928
|
targetNodeId: match.routeNodeId,
|
|
15376
15929
|
serviceName,
|
|
15377
|
-
edgeType:
|
|
15930
|
+
edgeType: import_types60.EdgeType.CALLS
|
|
15378
15931
|
};
|
|
15379
15932
|
};
|
|
15380
15933
|
}
|
|
@@ -15401,7 +15954,7 @@ init_cjs_shims();
|
|
|
15401
15954
|
|
|
15402
15955
|
// src/connectors/cloudflare/connector.ts
|
|
15403
15956
|
init_cjs_shims();
|
|
15404
|
-
var
|
|
15957
|
+
var import_types62 = require("@neat.is/types");
|
|
15405
15958
|
|
|
15406
15959
|
// src/connectors/cloudflare/client.ts
|
|
15407
15960
|
init_cjs_shims();
|
|
@@ -15517,7 +16070,7 @@ function mapEventToSignal(event) {
|
|
|
15517
16070
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
15518
16071
|
const statusCode = metadata?.statusCode;
|
|
15519
16072
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
15520
|
-
const
|
|
16073
|
+
const path70 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
15521
16074
|
return {
|
|
15522
16075
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
15523
16076
|
targetName: scriptName,
|
|
@@ -15525,7 +16078,7 @@ function mapEventToSignal(event) {
|
|
|
15525
16078
|
errorCount: isError ? 1 : 0,
|
|
15526
16079
|
lastObservedIso: observedAt.toISOString(),
|
|
15527
16080
|
method,
|
|
15528
|
-
...
|
|
16081
|
+
...path70 ? { path: path70 } : {},
|
|
15529
16082
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
15530
16083
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
15531
16084
|
};
|
|
@@ -15565,19 +16118,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
15565
16118
|
graph.forEachNode((id, attrs) => {
|
|
15566
16119
|
if (found) return;
|
|
15567
16120
|
const a = attrs;
|
|
15568
|
-
if (a.type ===
|
|
16121
|
+
if (a.type === import_types62.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
15569
16122
|
found = id;
|
|
15570
16123
|
}
|
|
15571
16124
|
});
|
|
15572
16125
|
return found;
|
|
15573
16126
|
}
|
|
15574
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
15575
|
-
const normalizedPath = normalizePathTemplate(
|
|
16127
|
+
function findMatchingRouteNode(graph, serviceName, method, path70) {
|
|
16128
|
+
const normalizedPath = normalizePathTemplate(path70);
|
|
15576
16129
|
let found = null;
|
|
15577
16130
|
graph.forEachNode((id, attrs) => {
|
|
15578
16131
|
if (found) return;
|
|
15579
16132
|
const a = attrs;
|
|
15580
|
-
if (a.type !==
|
|
16133
|
+
if (a.type !== import_types62.NodeType.RouteNode || a.service !== serviceName) return;
|
|
15581
16134
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
15582
16135
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
15583
16136
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -15589,18 +16142,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15589
16142
|
return (signal) => {
|
|
15590
16143
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
15591
16144
|
const scriptName = signal.targetName;
|
|
15592
|
-
const { method, path:
|
|
16145
|
+
const { method, path: path70 } = signal;
|
|
15593
16146
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
15594
|
-
if (!method || !
|
|
15595
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
16147
|
+
if (!method || !path70) return wholeFileId;
|
|
16148
|
+
return findMatchingRouteNode(graph, serviceName, method, path70) ?? wholeFileId;
|
|
15596
16149
|
};
|
|
15597
16150
|
const mapping = config.workers?.[scriptName];
|
|
15598
16151
|
if (mapping) {
|
|
15599
|
-
const wholeFileId = (0,
|
|
16152
|
+
const wholeFileId = (0, import_types62.fileId)(mapping.service, mapping.entryFile);
|
|
15600
16153
|
return {
|
|
15601
16154
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
15602
16155
|
serviceName: mapping.service,
|
|
15603
|
-
edgeType:
|
|
16156
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15604
16157
|
};
|
|
15605
16158
|
}
|
|
15606
16159
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -15609,13 +16162,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
15609
16162
|
return {
|
|
15610
16163
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
15611
16164
|
serviceName: fileNode.service,
|
|
15612
|
-
edgeType:
|
|
16165
|
+
edgeType: import_types62.EdgeType.CALLS
|
|
15613
16166
|
};
|
|
15614
16167
|
}
|
|
15615
16168
|
return {
|
|
15616
|
-
targetNodeId: (0,
|
|
16169
|
+
targetNodeId: (0, import_types62.infraId)("cloudflare-worker", scriptName),
|
|
15617
16170
|
serviceName: scriptName,
|
|
15618
|
-
edgeType:
|
|
16171
|
+
edgeType: import_types62.EdgeType.CALLS,
|
|
15619
16172
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
15620
16173
|
};
|
|
15621
16174
|
};
|
|
@@ -15811,14 +16364,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
15811
16364
|
|
|
15812
16365
|
// src/connectors/neon/resolve.ts
|
|
15813
16366
|
init_cjs_shims();
|
|
15814
|
-
var
|
|
16367
|
+
var import_types66 = require("@neat.is/types");
|
|
15815
16368
|
function createNeonResolveTarget(config) {
|
|
15816
16369
|
return (signal) => {
|
|
15817
16370
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
15818
16371
|
return {
|
|
15819
|
-
targetNodeId: (0,
|
|
16372
|
+
targetNodeId: (0, import_types66.infraId)("sql-table", signal.targetName),
|
|
15820
16373
|
serviceName: config.serviceName,
|
|
15821
|
-
edgeType:
|
|
16374
|
+
edgeType: import_types66.EdgeType.CALLS,
|
|
15822
16375
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
15823
16376
|
};
|
|
15824
16377
|
};
|
|
@@ -15944,9 +16497,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
15944
16497
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
15945
16498
|
if (secondSep === -1) return null;
|
|
15946
16499
|
const method = rest.slice(0, secondSep);
|
|
15947
|
-
const
|
|
15948
|
-
if (!serviceName || !method || !
|
|
15949
|
-
return { serviceName, method, path:
|
|
16500
|
+
const path70 = rest.slice(secondSep + 1);
|
|
16501
|
+
if (!serviceName || !method || !path70) return null;
|
|
16502
|
+
return { serviceName, method, path: path70 };
|
|
15950
16503
|
}
|
|
15951
16504
|
|
|
15952
16505
|
// src/connectors/cloud-run/map.ts
|
|
@@ -15975,14 +16528,14 @@ function mapLogEntryToSignal2(entry2) {
|
|
|
15975
16528
|
if (!req2) return null;
|
|
15976
16529
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
15977
16530
|
const method = req2.requestMethod.toUpperCase();
|
|
15978
|
-
const
|
|
15979
|
-
if (
|
|
16531
|
+
const path70 = pathFromRequestUrl2(req2.requestUrl);
|
|
16532
|
+
if (path70 === null) return null;
|
|
15980
16533
|
const timestamp = entry2.timestamp;
|
|
15981
16534
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
15982
16535
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD4;
|
|
15983
16536
|
return {
|
|
15984
16537
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
15985
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
16538
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path70 }),
|
|
15986
16539
|
callCount: 1,
|
|
15987
16540
|
errorCount: isError ? 1 : 0,
|
|
15988
16541
|
lastObservedIso: timestamp
|
|
@@ -15999,14 +16552,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
15999
16552
|
|
|
16000
16553
|
// src/connectors/cloud-run/resolve.ts
|
|
16001
16554
|
init_cjs_shims();
|
|
16002
|
-
var
|
|
16555
|
+
var import_types70 = require("@neat.is/types");
|
|
16003
16556
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
16004
16557
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
16005
16558
|
let found = null;
|
|
16006
16559
|
graph.forEachNode((_id, attrs) => {
|
|
16007
16560
|
if (found) return;
|
|
16008
16561
|
const node = attrs;
|
|
16009
|
-
if (node.type !==
|
|
16562
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
16010
16563
|
const route = attrs;
|
|
16011
16564
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
16012
16565
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -16021,23 +16574,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
16021
16574
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
16022
16575
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
16023
16576
|
if (!identity) return null;
|
|
16024
|
-
const { serviceName: gcpServiceName, method, path:
|
|
16577
|
+
const { serviceName: gcpServiceName, method, path: path70 } = identity;
|
|
16025
16578
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
16026
16579
|
if (mappedService) {
|
|
16027
16580
|
const routeNodeId = findMatchingRouteNode2(
|
|
16028
16581
|
graph,
|
|
16029
16582
|
mappedService,
|
|
16030
16583
|
method,
|
|
16031
|
-
normalizePathTemplate(
|
|
16584
|
+
normalizePathTemplate(path70)
|
|
16032
16585
|
);
|
|
16033
16586
|
if (routeNodeId) {
|
|
16034
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
16587
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types70.EdgeType.CALLS };
|
|
16035
16588
|
}
|
|
16036
16589
|
}
|
|
16037
16590
|
return {
|
|
16038
|
-
targetNodeId: (0,
|
|
16591
|
+
targetNodeId: (0, import_types70.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
16039
16592
|
serviceName: mappedService ?? gcpServiceName,
|
|
16040
|
-
edgeType:
|
|
16593
|
+
edgeType: import_types70.EdgeType.CALLS,
|
|
16041
16594
|
ensureInfraNode: {
|
|
16042
16595
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
16043
16596
|
name: gcpServiceName,
|
|
@@ -16078,7 +16631,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
16078
16631
|
|
|
16079
16632
|
// src/connectors/render/index.ts
|
|
16080
16633
|
init_cjs_shims();
|
|
16081
|
-
var
|
|
16634
|
+
var import_types73 = require("@neat.is/types");
|
|
16082
16635
|
|
|
16083
16636
|
// src/connectors/render/types.ts
|
|
16084
16637
|
init_cjs_shims();
|
|
@@ -16156,7 +16709,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
16156
16709
|
const out = [];
|
|
16157
16710
|
graph.forEachNode((_id, attrs) => {
|
|
16158
16711
|
const node = attrs;
|
|
16159
|
-
if (node.type !==
|
|
16712
|
+
if (node.type !== import_types73.NodeType.RouteNode) return;
|
|
16160
16713
|
const route = attrs;
|
|
16161
16714
|
if (route.service !== serviceName) return;
|
|
16162
16715
|
out.push({
|
|
@@ -16241,7 +16794,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
16241
16794
|
function createRenderResolveTarget(config) {
|
|
16242
16795
|
return (signal) => {
|
|
16243
16796
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
16244
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
16797
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types73.EdgeType.CALLS };
|
|
16245
16798
|
}
|
|
16246
16799
|
return null;
|
|
16247
16800
|
};
|
|
@@ -16379,21 +16932,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
16379
16932
|
|
|
16380
16933
|
// src/connectors/planetscale/resolve.ts
|
|
16381
16934
|
init_cjs_shims();
|
|
16382
|
-
var
|
|
16935
|
+
var import_types77 = require("@neat.is/types");
|
|
16383
16936
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
16384
16937
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
16385
16938
|
const databaseName = `${config.organization}/${config.database}`;
|
|
16386
16939
|
return (signal, _ctx) => {
|
|
16387
16940
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
16388
|
-
const tableId = (0,
|
|
16941
|
+
const tableId = (0, import_types77.infraId)("sql-table", signal.targetName);
|
|
16389
16942
|
if (graph.hasNode(tableId)) {
|
|
16390
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
16943
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types77.EdgeType.CALLS };
|
|
16391
16944
|
}
|
|
16392
|
-
const providerId = (0,
|
|
16945
|
+
const providerId = (0, import_types77.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
16393
16946
|
return {
|
|
16394
16947
|
targetNodeId: providerId,
|
|
16395
16948
|
serviceName: config.serviceName,
|
|
16396
|
-
edgeType:
|
|
16949
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
16397
16950
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
16398
16951
|
};
|
|
16399
16952
|
};
|
|
@@ -17063,11 +17616,11 @@ function registerRoutes(scope, ctx) {
|
|
|
17063
17616
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
17064
17617
|
const parsed = [];
|
|
17065
17618
|
for (const c of candidates) {
|
|
17066
|
-
const r =
|
|
17619
|
+
const r = import_types80.DivergenceTypeSchema.safeParse(c);
|
|
17067
17620
|
if (!r.success) {
|
|
17068
17621
|
return reply.code(400).send({
|
|
17069
17622
|
error: `unknown divergence type "${c}"`,
|
|
17070
|
-
allowed:
|
|
17623
|
+
allowed: import_types80.DivergenceTypeSchema.options
|
|
17071
17624
|
});
|
|
17072
17625
|
}
|
|
17073
17626
|
parsed.push(r.data);
|
|
@@ -17376,7 +17929,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17376
17929
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
17377
17930
|
let violations = await log.readAll();
|
|
17378
17931
|
if (req2.query.severity) {
|
|
17379
|
-
const sev =
|
|
17932
|
+
const sev = import_types80.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
17380
17933
|
if (!sev.success) {
|
|
17381
17934
|
return reply.code(400).send({
|
|
17382
17935
|
error: "invalid severity",
|
|
@@ -17415,7 +17968,7 @@ function registerRoutes(scope, ctx) {
|
|
|
17415
17968
|
scope.post("/policies/check", async (req2, reply) => {
|
|
17416
17969
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
17417
17970
|
if (!proj) return;
|
|
17418
|
-
const parsed =
|
|
17971
|
+
const parsed = import_types80.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
17419
17972
|
if (!parsed.success) {
|
|
17420
17973
|
return reply.code(400).send({
|
|
17421
17974
|
error: "invalid /policies/check body",
|
|
@@ -17737,7 +18290,7 @@ init_auth();
|
|
|
17737
18290
|
// src/unrouted.ts
|
|
17738
18291
|
init_cjs_shims();
|
|
17739
18292
|
var import_node_fs32 = require("fs");
|
|
17740
|
-
var
|
|
18293
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
17741
18294
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
17742
18295
|
return {
|
|
17743
18296
|
timestamp: now.toISOString(),
|
|
@@ -17747,34 +18300,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
17747
18300
|
};
|
|
17748
18301
|
}
|
|
17749
18302
|
async function appendUnroutedSpan(neatHome4, record) {
|
|
17750
|
-
const target =
|
|
18303
|
+
const target = import_node_path66.default.join(neatHome4, "errors.ndjson");
|
|
17751
18304
|
await import_node_fs32.promises.mkdir(neatHome4, { recursive: true });
|
|
17752
18305
|
await import_node_fs32.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
17753
18306
|
}
|
|
17754
18307
|
function unroutedErrorsPath(neatHome4) {
|
|
17755
|
-
return
|
|
18308
|
+
return import_node_path66.default.join(neatHome4, "errors.ndjson");
|
|
17756
18309
|
}
|
|
17757
18310
|
|
|
17758
18311
|
// src/daemon.ts
|
|
17759
|
-
var
|
|
18312
|
+
var import_types81 = require("@neat.is/types");
|
|
17760
18313
|
function daemonJsonPath(scanPath) {
|
|
17761
|
-
return
|
|
18314
|
+
return import_node_path67.default.join(scanPath, "neat-out", "daemon.json");
|
|
17762
18315
|
}
|
|
17763
18316
|
function daemonsDiscoveryDir(home) {
|
|
17764
18317
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
17765
|
-
return
|
|
18318
|
+
return import_node_path67.default.join(base, "daemons");
|
|
17766
18319
|
}
|
|
17767
18320
|
function daemonDiscoveryPath(project, home) {
|
|
17768
|
-
return
|
|
18321
|
+
return import_node_path67.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
17769
18322
|
}
|
|
17770
18323
|
function sanitizeDiscoveryName(project) {
|
|
17771
18324
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
17772
18325
|
}
|
|
17773
18326
|
function neatHomeFromEnv() {
|
|
17774
18327
|
const env = process.env.NEAT_HOME;
|
|
17775
|
-
if (env && env.length > 0) return
|
|
18328
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17776
18329
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17777
|
-
return
|
|
18330
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17778
18331
|
}
|
|
17779
18332
|
function resolveNeatVersion() {
|
|
17780
18333
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -17843,11 +18396,11 @@ function teardownSlot(slot) {
|
|
|
17843
18396
|
}
|
|
17844
18397
|
}
|
|
17845
18398
|
function neatHomeFor(opts) {
|
|
17846
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
18399
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path67.default.resolve(opts.neatHome);
|
|
17847
18400
|
const env = process.env.NEAT_HOME;
|
|
17848
|
-
if (env && env.length > 0) return
|
|
18401
|
+
if (env && env.length > 0) return import_node_path67.default.resolve(env);
|
|
17849
18402
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
17850
|
-
return
|
|
18403
|
+
return import_node_path67.default.join(home, ".neat");
|
|
17851
18404
|
}
|
|
17852
18405
|
function routeSpanToProject(serviceName, projects) {
|
|
17853
18406
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -17895,11 +18448,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
17895
18448
|
if (!serviceName) return true;
|
|
17896
18449
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
17897
18450
|
return graph.someNode(
|
|
17898
|
-
(_id, attrs) => attrs.type ===
|
|
18451
|
+
(_id, attrs) => attrs.type === import_types81.NodeType.ServiceNode && attrs.name === serviceName
|
|
17899
18452
|
);
|
|
17900
18453
|
}
|
|
17901
18454
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
17902
|
-
const paths = pathsForProject(entry2.name,
|
|
18455
|
+
const paths = pathsForProject(entry2.name, import_node_path67.default.join(entry2.path, "neat-out"));
|
|
17903
18456
|
try {
|
|
17904
18457
|
const stat = await import_node_fs33.promises.stat(entry2.path);
|
|
17905
18458
|
if (!stat.isDirectory()) {
|
|
@@ -18015,7 +18568,7 @@ async function startDaemon(opts = {}) {
|
|
|
18015
18568
|
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
18569
|
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
18570
|
const singleProject = projectArg;
|
|
18018
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
18571
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path67.default.resolve(projectPathArg) : null;
|
|
18019
18572
|
if (singleProject && !singleProjectPath) {
|
|
18020
18573
|
throw new Error(
|
|
18021
18574
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -18030,7 +18583,7 @@ async function startDaemon(opts = {}) {
|
|
|
18030
18583
|
);
|
|
18031
18584
|
}
|
|
18032
18585
|
}
|
|
18033
|
-
const pidPath =
|
|
18586
|
+
const pidPath = import_node_path67.default.join(home, "neatd.pid");
|
|
18034
18587
|
await writeAtomically(pidPath, `${process.pid}
|
|
18035
18588
|
`);
|
|
18036
18589
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -18442,8 +18995,8 @@ async function startDaemon(opts = {}) {
|
|
|
18442
18995
|
let registryWatcher = null;
|
|
18443
18996
|
let reloadTimer = null;
|
|
18444
18997
|
if (!singleProject) try {
|
|
18445
|
-
const regDir =
|
|
18446
|
-
const regBase =
|
|
18998
|
+
const regDir = import_node_path67.default.dirname(regPath);
|
|
18999
|
+
const regBase = import_node_path67.default.basename(regPath);
|
|
18447
19000
|
registryWatcher = (0, import_node_fs33.watch)(regDir, (_eventType, filename) => {
|
|
18448
19001
|
if (filename !== null && filename !== regBase) return;
|
|
18449
19002
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
@@ -18518,7 +19071,7 @@ init_cjs_shims();
|
|
|
18518
19071
|
var import_node_child_process2 = require("child_process");
|
|
18519
19072
|
var import_node_fs34 = require("fs");
|
|
18520
19073
|
var import_node_net = __toESM(require("net"), 1);
|
|
18521
|
-
var
|
|
19074
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
18522
19075
|
var DEFAULT_WEB_PORT = 6328;
|
|
18523
19076
|
var DEFAULT_REST_PORT = 8080;
|
|
18524
19077
|
function asValidPort(value) {
|
|
@@ -18527,11 +19080,11 @@ function asValidPort(value) {
|
|
|
18527
19080
|
}
|
|
18528
19081
|
function projectRoot() {
|
|
18529
19082
|
const fromEnv = process.env.NEAT_SCAN_PATH;
|
|
18530
|
-
return
|
|
19083
|
+
return import_node_path68.default.resolve(fromEnv && fromEnv.length > 0 ? fromEnv : process.cwd());
|
|
18531
19084
|
}
|
|
18532
19085
|
async function readDaemonPorts(root) {
|
|
18533
19086
|
try {
|
|
18534
|
-
const raw = await import_node_fs34.promises.readFile(
|
|
19087
|
+
const raw = await import_node_fs34.promises.readFile(import_node_path68.default.join(root, "neat-out", "daemon.json"), "utf8");
|
|
18535
19088
|
const parsed = JSON.parse(raw);
|
|
18536
19089
|
const ports = parsed?.ports ?? {};
|
|
18537
19090
|
return { web: asValidPort(ports.web), rest: asValidPort(ports.rest) };
|
|
@@ -18576,10 +19129,10 @@ function resolveWebPackageDir() {
|
|
|
18576
19129
|
eval("require")
|
|
18577
19130
|
);
|
|
18578
19131
|
const pkgJsonPath = req.resolve("@neat.is/web/package.json");
|
|
18579
|
-
return
|
|
19132
|
+
return import_node_path68.default.dirname(pkgJsonPath);
|
|
18580
19133
|
}
|
|
18581
19134
|
function resolveStandaloneServerEntry(webDir) {
|
|
18582
|
-
return
|
|
19135
|
+
return import_node_path68.default.join(webDir, ".next/standalone/packages/web/server.js");
|
|
18583
19136
|
}
|
|
18584
19137
|
async function pickInternalPort() {
|
|
18585
19138
|
return new Promise((resolve, reject) => {
|
|
@@ -18632,7 +19185,7 @@ async function spawnWebUI(restPort, opts = {}) {
|
|
|
18632
19185
|
NEAT_API_URL: apiUrl
|
|
18633
19186
|
};
|
|
18634
19187
|
child = (0, import_node_child_process2.spawn)(process.execPath, [serverEntry], {
|
|
18635
|
-
cwd:
|
|
19188
|
+
cwd: import_node_path68.default.dirname(serverEntry),
|
|
18636
19189
|
env,
|
|
18637
19190
|
stdio: ["ignore", "inherit", "inherit"],
|
|
18638
19191
|
detached: false
|
|
@@ -18808,14 +19361,14 @@ function localVersion() {
|
|
|
18808
19361
|
}
|
|
18809
19362
|
function neatHome3() {
|
|
18810
19363
|
if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {
|
|
18811
|
-
return
|
|
19364
|
+
return import_node_path69.default.resolve(process.env.NEAT_HOME);
|
|
18812
19365
|
}
|
|
18813
19366
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
18814
|
-
return
|
|
19367
|
+
return import_node_path69.default.join(home, ".neat");
|
|
18815
19368
|
}
|
|
18816
19369
|
async function readPid() {
|
|
18817
19370
|
try {
|
|
18818
|
-
const raw = await import_node_fs35.promises.readFile(
|
|
19371
|
+
const raw = await import_node_fs35.promises.readFile(import_node_path69.default.join(neatHome3(), "neatd.pid"), "utf8");
|
|
18819
19372
|
const n = Number.parseInt(raw.trim(), 10);
|
|
18820
19373
|
return Number.isFinite(n) ? n : null;
|
|
18821
19374
|
} catch {
|