@neat.is/core 0.7.0 → 0.7.1
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-Q6DPK3RA.js → chunk-6H757ZNM.js} +2 -2
- package/dist/{chunk-UBQ4ZZT3.js → chunk-MDBE23Y3.js} +3 -3
- package/dist/{chunk-N5L3RBGP.js → chunk-P2ZEKJ35.js} +44 -2
- package/dist/chunk-P2ZEKJ35.js.map +1 -0
- package/dist/{chunk-5RIL3U5A.js → chunk-RR4LWQQB.js} +516 -229
- package/dist/chunk-RR4LWQQB.js.map +1 -0
- package/dist/cli.cjs +997 -649
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +25 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +810 -480
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +819 -489
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-ZNC2QED2.js → otel-grpc-APVZSB6W.js} +3 -3
- package/dist/server.cjs +840 -510
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-5RIL3U5A.js.map +0 -1
- package/dist/chunk-N5L3RBGP.js.map +0 -1
- /package/dist/{chunk-Q6DPK3RA.js.map → chunk-6H757ZNM.js.map} +0 -0
- /package/dist/{chunk-UBQ4ZZT3.js.map → chunk-MDBE23Y3.js.map} +0 -0
- /package/dist/{otel-grpc-ZNC2QED2.js.map → otel-grpc-APVZSB6W.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -60,8 +60,8 @@ function mountBearerAuth(app, opts) {
|
|
|
60
60
|
]);
|
|
61
61
|
const publicRead = opts.publicRead === true;
|
|
62
62
|
app.addHook("preHandler", (req, reply, done) => {
|
|
63
|
-
const
|
|
64
|
-
if (exactUnauthPaths.has(
|
|
63
|
+
const path59 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
64
|
+
if (exactUnauthPaths.has(path59) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path59)) {
|
|
65
65
|
done();
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
@@ -193,8 +193,8 @@ function reshapeGrpcRequest(req) {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
function resolveProtoRoot() {
|
|
196
|
-
const here =
|
|
197
|
-
return
|
|
196
|
+
const here = import_node_path38.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
197
|
+
return import_node_path38.default.resolve(here, "..", "proto");
|
|
198
198
|
}
|
|
199
199
|
function loadTraceService() {
|
|
200
200
|
const protoRoot = resolveProtoRoot();
|
|
@@ -262,13 +262,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
262
262
|
})
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
var import_node_url,
|
|
265
|
+
var import_node_url, import_node_path38, import_node_crypto2, grpc, protoLoader;
|
|
266
266
|
var init_otel_grpc = __esm({
|
|
267
267
|
"src/otel-grpc.ts"() {
|
|
268
268
|
"use strict";
|
|
269
269
|
init_cjs_shims();
|
|
270
270
|
import_node_url = require("url");
|
|
271
|
-
|
|
271
|
+
import_node_path38 = __toESM(require("path"), 1);
|
|
272
272
|
import_node_crypto2 = require("crypto");
|
|
273
273
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
274
274
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -354,6 +354,46 @@ function tableFromSqlStatement(sql) {
|
|
|
354
354
|
const m = /\b(?:from|into|update)\s+(?:"?[\w$]+"?\s*\.\s*)?"?([a-zA-Z_][\w$]*)"?/i.exec(sql);
|
|
355
355
|
return m ? m[1] : null;
|
|
356
356
|
}
|
|
357
|
+
function columnsFromSqlStatement(sql) {
|
|
358
|
+
if (typeof sql !== "string" || sql.length === 0) return [];
|
|
359
|
+
const s = sql.replace(/\s+/g, " ").trim();
|
|
360
|
+
if (/\bjoin\b/i.test(s)) return [];
|
|
361
|
+
if ((s.match(/\bfrom\b/gi) ?? []).length > 1) return [];
|
|
362
|
+
const bare = (raw) => {
|
|
363
|
+
let t = raw.trim().replace(/"/g, "");
|
|
364
|
+
if (/[()*]/.test(t)) return null;
|
|
365
|
+
t = t.split(/\s+as\s+/i)[0].trim();
|
|
366
|
+
t = t.split(".").pop();
|
|
367
|
+
return /^[a-z_][\w$]*$/i.test(t) ? t.toLowerCase() : null;
|
|
368
|
+
};
|
|
369
|
+
const isCol = (c) => c !== null;
|
|
370
|
+
const cols = (list) => [...new Set(list.split(",").map(bare).filter(isCol))];
|
|
371
|
+
const whereCols = (w) => w ? [
|
|
372
|
+
...new Set(
|
|
373
|
+
[
|
|
374
|
+
...w.matchAll(
|
|
375
|
+
/(?:"?[\w$]+"?\.)?"?([a-z_][\w$]*)"?\s*(?:=|<|>|<=|>=|<>|!=|\bis\b|\bin\b|\blike\b)/gi
|
|
376
|
+
)
|
|
377
|
+
].map((match) => match[1].toLowerCase()).filter((c) => !/^(and|or|not|null)$/i.test(c))
|
|
378
|
+
)
|
|
379
|
+
] : [];
|
|
380
|
+
let m;
|
|
381
|
+
if (m = /\binsert\s+into\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?\s*\(([^)]*)\)/i.exec(s)) {
|
|
382
|
+
return cols(m[1]);
|
|
383
|
+
}
|
|
384
|
+
if (m = /\bupdate\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?\s+set\s+(.+?)(?:\bwhere\b(.+))?$/i.exec(s)) {
|
|
385
|
+
const set = m[1].split(",").map((p) => bare(p.split("=")[0])).filter(isCol);
|
|
386
|
+
return [.../* @__PURE__ */ new Set([...set, ...whereCols(m[2] ?? void 0)])];
|
|
387
|
+
}
|
|
388
|
+
if (m = /\bdelete\s+from\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?(?:\s+where\b(.+))?$/i.exec(s)) {
|
|
389
|
+
return whereCols(m[1] ?? void 0);
|
|
390
|
+
}
|
|
391
|
+
if (m = /\bselect\s+(.+?)\s+from\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?(?:\s+where\b(.+))?$/i.exec(s)) {
|
|
392
|
+
if (m[1].trim() === "*") return [];
|
|
393
|
+
return [.../* @__PURE__ */ new Set([...cols(m[1]), ...whereCols(m[2] ?? void 0)])];
|
|
394
|
+
}
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
357
397
|
function messagingDestinationOf(attrs) {
|
|
358
398
|
for (const key of ["messaging.destination.name", "messaging.destination"]) {
|
|
359
399
|
const v = attrs[key];
|
|
@@ -374,8 +414,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
374
414
|
const v = attrs[key];
|
|
375
415
|
if (typeof v === "string" && v.length > 0) {
|
|
376
416
|
const q = v.indexOf("?");
|
|
377
|
-
const
|
|
378
|
-
if (
|
|
417
|
+
const path59 = q === -1 ? v : v.slice(0, q);
|
|
418
|
+
if (path59.length > 0) return path59;
|
|
379
419
|
}
|
|
380
420
|
}
|
|
381
421
|
return void 0;
|
|
@@ -412,6 +452,7 @@ function parseOtlpRequest(body) {
|
|
|
412
452
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
413
453
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
414
454
|
dbTable: typeof attrs["db.statement"] === "string" ? tableFromSqlStatement(attrs["db.statement"]) ?? void 0 : void 0,
|
|
455
|
+
dbColumns: typeof attrs["db.statement"] === "string" ? columnsFromSqlStatement(attrs["db.statement"]) : void 0,
|
|
415
456
|
httpRoute: typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0,
|
|
416
457
|
httpMethod: typeof attrs["http.request.method"] === "string" ? attrs["http.request.method"] : typeof attrs["http.method"] === "string" ? attrs["http.method"] : void 0,
|
|
417
458
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
@@ -433,10 +474,10 @@ function parseOtlpRequest(body) {
|
|
|
433
474
|
return out;
|
|
434
475
|
}
|
|
435
476
|
function loadProtoRoot() {
|
|
436
|
-
const here =
|
|
437
|
-
const protoRoot =
|
|
477
|
+
const here = import_node_path39.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
478
|
+
const protoRoot = import_node_path39.default.resolve(here, "..", "proto");
|
|
438
479
|
const root = new import_protobufjs.default.Root();
|
|
439
|
-
root.resolvePath = (_origin, target) =>
|
|
480
|
+
root.resolvePath = (_origin, target) => import_node_path39.default.resolve(protoRoot, target);
|
|
440
481
|
root.loadSync(
|
|
441
482
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
442
483
|
{ keepCase: true }
|
|
@@ -675,12 +716,12 @@ function logSpanHandler(span) {
|
|
|
675
716
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
676
717
|
);
|
|
677
718
|
}
|
|
678
|
-
var
|
|
719
|
+
var import_node_path39, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
679
720
|
var init_otel = __esm({
|
|
680
721
|
"src/otel.ts"() {
|
|
681
722
|
"use strict";
|
|
682
723
|
init_cjs_shims();
|
|
683
|
-
|
|
724
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
684
725
|
import_node_url2 = require("url");
|
|
685
726
|
import_fastify = __toESM(require("fastify"), 1);
|
|
686
727
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -1273,19 +1314,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1273
1314
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1274
1315
|
let best = { path: [start], edges: [] };
|
|
1275
1316
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1276
|
-
function step(node,
|
|
1277
|
-
if (
|
|
1278
|
-
best = { path: [...
|
|
1317
|
+
function step(node, path59, edges) {
|
|
1318
|
+
if (path59.length > best.path.length) {
|
|
1319
|
+
best = { path: [...path59], edges: [...edges] };
|
|
1279
1320
|
}
|
|
1280
|
-
if (
|
|
1321
|
+
if (path59.length - 1 >= maxDepth) return;
|
|
1281
1322
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1282
1323
|
for (const [srcId, edge] of incoming) {
|
|
1283
1324
|
if (visited.has(srcId)) continue;
|
|
1284
1325
|
visited.add(srcId);
|
|
1285
|
-
|
|
1326
|
+
path59.push(srcId);
|
|
1286
1327
|
edges.push(edge);
|
|
1287
|
-
step(srcId,
|
|
1288
|
-
|
|
1328
|
+
step(srcId, path59, edges);
|
|
1329
|
+
path59.pop();
|
|
1289
1330
|
edges.pop();
|
|
1290
1331
|
visited.delete(srcId);
|
|
1291
1332
|
}
|
|
@@ -1492,26 +1533,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
|
|
|
1492
1533
|
return best;
|
|
1493
1534
|
}
|
|
1494
1535
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1495
|
-
const
|
|
1536
|
+
const path59 = [originServiceId];
|
|
1496
1537
|
const edges = [];
|
|
1497
1538
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1498
1539
|
let current = originServiceId;
|
|
1499
1540
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1500
1541
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1501
1542
|
if (!hop) break;
|
|
1502
|
-
|
|
1543
|
+
path59.push(hop.nextService);
|
|
1503
1544
|
edges.push(hop.edge);
|
|
1504
1545
|
visited.add(hop.nextService);
|
|
1505
1546
|
current = hop.nextService;
|
|
1506
1547
|
}
|
|
1507
1548
|
if (edges.length === 0) return null;
|
|
1508
|
-
return { path:
|
|
1549
|
+
return { path: path59, edges, culprit: current };
|
|
1509
1550
|
}
|
|
1510
1551
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1511
1552
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1512
1553
|
if (!chain) return null;
|
|
1513
1554
|
const culprit = chain.culprit;
|
|
1514
|
-
const
|
|
1555
|
+
const path59 = [...chain.path];
|
|
1515
1556
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1516
1557
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1517
1558
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1519,14 +1560,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1519
1560
|
if (loc) {
|
|
1520
1561
|
let rootCauseNode = culprit;
|
|
1521
1562
|
if (loc.fileNode) {
|
|
1522
|
-
|
|
1563
|
+
path59.push(loc.fileNode);
|
|
1523
1564
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1524
1565
|
rootCauseNode = loc.fileNode;
|
|
1525
1566
|
}
|
|
1526
1567
|
return import_types.RootCauseResultSchema.parse({
|
|
1527
1568
|
rootCauseNode,
|
|
1528
1569
|
rootCauseReason: loc.rootCauseReason,
|
|
1529
|
-
traversalPath:
|
|
1570
|
+
traversalPath: path59,
|
|
1530
1571
|
edgeProvenances,
|
|
1531
1572
|
confidence,
|
|
1532
1573
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1538,7 +1579,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1538
1579
|
return import_types.RootCauseResultSchema.parse({
|
|
1539
1580
|
rootCauseNode: culprit,
|
|
1540
1581
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1541
|
-
traversalPath:
|
|
1582
|
+
traversalPath: path59,
|
|
1542
1583
|
edgeProvenances,
|
|
1543
1584
|
confidence,
|
|
1544
1585
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2126,7 +2167,7 @@ var PolicyViolationsLog = class {
|
|
|
2126
2167
|
};
|
|
2127
2168
|
|
|
2128
2169
|
// src/ingest.ts
|
|
2129
|
-
var
|
|
2170
|
+
var import_types7 = require("@neat.is/types");
|
|
2130
2171
|
|
|
2131
2172
|
// src/extract/routes.ts
|
|
2132
2173
|
init_cjs_shims();
|
|
@@ -3172,6 +3213,42 @@ async function addRoutes(graph, services) {
|
|
|
3172
3213
|
return { nodesAdded, edgesAdded };
|
|
3173
3214
|
}
|
|
3174
3215
|
|
|
3216
|
+
// src/columns.ts
|
|
3217
|
+
init_cjs_shims();
|
|
3218
|
+
var import_types6 = require("@neat.is/types");
|
|
3219
|
+
var OBSERVED_COLUMN_CONFIDENCE = 0.9;
|
|
3220
|
+
function normalizeProvenances(provenances) {
|
|
3221
|
+
return [...new Set(provenances)].sort();
|
|
3222
|
+
}
|
|
3223
|
+
function foldColumns(existing, names, provenance, confidence) {
|
|
3224
|
+
const out = (existing ?? []).map((c) => ({
|
|
3225
|
+
...c,
|
|
3226
|
+
provenances: [...c.provenances]
|
|
3227
|
+
}));
|
|
3228
|
+
const byName = new Map(out.map((c) => [c.name, c]));
|
|
3229
|
+
for (const raw of names) {
|
|
3230
|
+
const name = raw.toLowerCase();
|
|
3231
|
+
const prior = byName.get(name);
|
|
3232
|
+
if (!prior) {
|
|
3233
|
+
const col = { name, provenances: [provenance], confidence };
|
|
3234
|
+
byName.set(name, col);
|
|
3235
|
+
out.push(col);
|
|
3236
|
+
continue;
|
|
3237
|
+
}
|
|
3238
|
+
if (!prior.provenances.includes(provenance)) {
|
|
3239
|
+
prior.provenances = normalizeProvenances([...prior.provenances, provenance]);
|
|
3240
|
+
}
|
|
3241
|
+
if (confidence > prior.confidence) prior.confidence = confidence;
|
|
3242
|
+
}
|
|
3243
|
+
return out;
|
|
3244
|
+
}
|
|
3245
|
+
function columnIsDeclared(col) {
|
|
3246
|
+
return col.provenances.includes(import_types6.Provenance.EXTRACTED);
|
|
3247
|
+
}
|
|
3248
|
+
function columnIsObserved(col) {
|
|
3249
|
+
return col.provenances.includes(import_types6.Provenance.OBSERVED);
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3175
3252
|
// src/ingest.ts
|
|
3176
3253
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
3177
3254
|
var DAY_MS = 24 * HOUR_MS;
|
|
@@ -3471,11 +3548,11 @@ function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
|
3471
3548
|
};
|
|
3472
3549
|
}
|
|
3473
3550
|
function reconcileObservedRelPath(graph, serviceName, relPath) {
|
|
3474
|
-
if (graph.hasNode((0,
|
|
3551
|
+
if (graph.hasNode((0, import_types7.fileId)(serviceName, relPath))) return relPath;
|
|
3475
3552
|
let best = null;
|
|
3476
3553
|
graph.forEachNode((_id, attrs) => {
|
|
3477
3554
|
const a = attrs;
|
|
3478
|
-
if (a.type !==
|
|
3555
|
+
if (a.type !== import_types7.NodeType.FileNode || a.service !== serviceName) return;
|
|
3479
3556
|
if (a.discoveredVia === "otel") return;
|
|
3480
3557
|
const p = a.path;
|
|
3481
3558
|
if (!p) return;
|
|
@@ -3487,14 +3564,14 @@ function reconcileObservedRelPath(graph, serviceName, relPath) {
|
|
|
3487
3564
|
}
|
|
3488
3565
|
function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
|
|
3489
3566
|
const svcAttrs = graph.hasNode(serviceNodeId) ? graph.getNodeAttributes(serviceNodeId) : void 0;
|
|
3490
|
-
const canonicalService = svcAttrs && svcAttrs.type ===
|
|
3567
|
+
const canonicalService = svcAttrs && svcAttrs.type === import_types7.NodeType.ServiceNode && typeof svcAttrs.name === "string" ? svcAttrs.name : serviceName;
|
|
3491
3568
|
const relPath = reconcileObservedRelPath(graph, canonicalService, callSite.relPath);
|
|
3492
|
-
const fileNodeId = (0,
|
|
3569
|
+
const fileNodeId = (0, import_types7.fileId)(canonicalService, relPath);
|
|
3493
3570
|
if (!graph.hasNode(fileNodeId)) {
|
|
3494
3571
|
const language = languageForExt(relPath);
|
|
3495
3572
|
const node = {
|
|
3496
3573
|
id: fileNodeId,
|
|
3497
|
-
type:
|
|
3574
|
+
type: import_types7.NodeType.FileNode,
|
|
3498
3575
|
service: canonicalService,
|
|
3499
3576
|
path: relPath,
|
|
3500
3577
|
...language ? { language } : {},
|
|
@@ -3503,14 +3580,14 @@ function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
|
|
|
3503
3580
|
};
|
|
3504
3581
|
graph.addNode(fileNodeId, node);
|
|
3505
3582
|
}
|
|
3506
|
-
const containsId = makeObservedEdgeId(
|
|
3583
|
+
const containsId = makeObservedEdgeId(import_types7.EdgeType.CONTAINS, serviceNodeId, fileNodeId);
|
|
3507
3584
|
if (!graph.hasEdge(containsId)) {
|
|
3508
3585
|
const edge = {
|
|
3509
3586
|
id: containsId,
|
|
3510
3587
|
source: serviceNodeId,
|
|
3511
3588
|
target: fileNodeId,
|
|
3512
|
-
type:
|
|
3513
|
-
provenance:
|
|
3589
|
+
type: import_types7.EdgeType.CONTAINS,
|
|
3590
|
+
provenance: import_types7.Provenance.OBSERVED
|
|
3514
3591
|
};
|
|
3515
3592
|
graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge);
|
|
3516
3593
|
}
|
|
@@ -3534,11 +3611,11 @@ function pickContainingSymbol(candidates, fn) {
|
|
|
3534
3611
|
return [...candidates].sort(bySpan)[0].id;
|
|
3535
3612
|
}
|
|
3536
3613
|
function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line) {
|
|
3537
|
-
const sid = (0,
|
|
3614
|
+
const sid = (0, import_types7.symbolId)(service, relPath, fn);
|
|
3538
3615
|
if (!graph.hasNode(sid)) {
|
|
3539
3616
|
const node = {
|
|
3540
3617
|
id: sid,
|
|
3541
|
-
type:
|
|
3618
|
+
type: import_types7.NodeType.SymbolNode,
|
|
3542
3619
|
kind: "function",
|
|
3543
3620
|
qualname: fn,
|
|
3544
3621
|
span: { startLine: line, endLine: line },
|
|
@@ -3548,14 +3625,14 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
|
|
|
3548
3625
|
};
|
|
3549
3626
|
graph.addNode(sid, node);
|
|
3550
3627
|
}
|
|
3551
|
-
const containsId = makeObservedEdgeId(
|
|
3628
|
+
const containsId = makeObservedEdgeId(import_types7.EdgeType.CONTAINS, fileNodeId, sid);
|
|
3552
3629
|
if (!graph.hasEdge(containsId)) {
|
|
3553
3630
|
const edge = {
|
|
3554
3631
|
id: containsId,
|
|
3555
3632
|
source: fileNodeId,
|
|
3556
3633
|
target: sid,
|
|
3557
|
-
type:
|
|
3558
|
-
provenance:
|
|
3634
|
+
type: import_types7.EdgeType.CONTAINS,
|
|
3635
|
+
provenance: import_types7.Provenance.OBSERVED
|
|
3559
3636
|
};
|
|
3560
3637
|
graph.addEdgeWithKey(containsId, fileNodeId, sid, edge);
|
|
3561
3638
|
}
|
|
@@ -3567,9 +3644,9 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
|
3567
3644
|
let sawSymbol = false;
|
|
3568
3645
|
const candidates = [];
|
|
3569
3646
|
graph.forEachOutboundEdge(fileNodeId, (_edge, edgeAttrs, _source, target) => {
|
|
3570
|
-
if (edgeAttrs.type !==
|
|
3647
|
+
if (edgeAttrs.type !== import_types7.EdgeType.CONTAINS) return;
|
|
3571
3648
|
const t = graph.getNodeAttributes(target);
|
|
3572
|
-
if (t.type !==
|
|
3649
|
+
if (t.type !== import_types7.NodeType.SymbolNode) return;
|
|
3573
3650
|
sawSymbol = true;
|
|
3574
3651
|
if (line >= t.span.startLine && line <= t.span.endLine) {
|
|
3575
3652
|
candidates.push({ id: target, symbol: t });
|
|
@@ -3582,17 +3659,17 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
|
3582
3659
|
return fileNodeId;
|
|
3583
3660
|
}
|
|
3584
3661
|
function makeObservedEdgeId(type, source, target) {
|
|
3585
|
-
return (0,
|
|
3662
|
+
return (0, import_types7.observedEdgeId)(source, target, type);
|
|
3586
3663
|
}
|
|
3587
3664
|
function makeInferredEdgeId(type, source, target) {
|
|
3588
|
-
return (0,
|
|
3665
|
+
return (0, import_types7.inferredEdgeId)(source, target, type);
|
|
3589
3666
|
}
|
|
3590
3667
|
var INFERRED_CONFIDENCE = 0.6;
|
|
3591
3668
|
var STITCH_MAX_DEPTH = 2;
|
|
3592
3669
|
var STITCH_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3670
|
+
import_types7.EdgeType.CALLS,
|
|
3671
|
+
import_types7.EdgeType.CONNECTS_TO,
|
|
3672
|
+
import_types7.EdgeType.DEPENDS_ON
|
|
3596
3673
|
]);
|
|
3597
3674
|
var WIRE_SPAN_KIND_CLIENT = 3;
|
|
3598
3675
|
var WIRE_SPAN_KIND_PRODUCER = 4;
|
|
@@ -3608,11 +3685,11 @@ function spanServesGraphqlOperation(kind) {
|
|
|
3608
3685
|
return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
|
|
3609
3686
|
}
|
|
3610
3687
|
function ensureGraphqlOperationNode(graph, serviceName, operationType, operationName) {
|
|
3611
|
-
const id = (0,
|
|
3688
|
+
const id = (0, import_types7.graphqlOperationId)(serviceName, operationType, operationName);
|
|
3612
3689
|
if (graph.hasNode(id)) return id;
|
|
3613
3690
|
const node = {
|
|
3614
3691
|
id,
|
|
3615
|
-
type:
|
|
3692
|
+
type: import_types7.NodeType.GraphQLOperationNode,
|
|
3616
3693
|
name: operationName,
|
|
3617
3694
|
service: serviceName,
|
|
3618
3695
|
operationType: operationType.toLowerCase(),
|
|
@@ -3626,11 +3703,11 @@ function spanServesGrpcMethod(kind) {
|
|
|
3626
3703
|
return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
|
|
3627
3704
|
}
|
|
3628
3705
|
function ensureGrpcMethodNode(graph, rpcService, rpcMethod) {
|
|
3629
|
-
const id = (0,
|
|
3706
|
+
const id = (0, import_types7.grpcMethodId)(rpcService, rpcMethod);
|
|
3630
3707
|
if (graph.hasNode(id)) return id;
|
|
3631
3708
|
const node = {
|
|
3632
3709
|
id,
|
|
3633
|
-
type:
|
|
3710
|
+
type: import_types7.NodeType.GrpcMethodNode,
|
|
3634
3711
|
name: `${rpcService}/${rpcMethod}`,
|
|
3635
3712
|
rpcService,
|
|
3636
3713
|
rpcMethod,
|
|
@@ -3643,11 +3720,11 @@ function spanServesWebsocketChannel(kind) {
|
|
|
3643
3720
|
return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
|
|
3644
3721
|
}
|
|
3645
3722
|
function ensureWebsocketChannelNode(graph, serviceName, channel) {
|
|
3646
|
-
const id = (0,
|
|
3723
|
+
const id = (0, import_types7.websocketChannelId)(serviceName, channel);
|
|
3647
3724
|
if (graph.hasNode(id)) return id;
|
|
3648
3725
|
const node = {
|
|
3649
3726
|
id,
|
|
3650
|
-
type:
|
|
3727
|
+
type: import_types7.NodeType.WebSocketChannelNode,
|
|
3651
3728
|
name: channel,
|
|
3652
3729
|
service: serviceName,
|
|
3653
3730
|
channel,
|
|
@@ -3660,11 +3737,11 @@ function messagingDestinationKind(system) {
|
|
|
3660
3737
|
return `${system}-topic`;
|
|
3661
3738
|
}
|
|
3662
3739
|
function ensureMessagingDestinationNode(graph, system, destination) {
|
|
3663
|
-
const id = (0,
|
|
3740
|
+
const id = (0, import_types7.infraId)(messagingDestinationKind(system), destination);
|
|
3664
3741
|
if (graph.hasNode(id)) return id;
|
|
3665
3742
|
const node = {
|
|
3666
3743
|
id,
|
|
3667
|
-
type:
|
|
3744
|
+
type: import_types7.NodeType.InfraNode,
|
|
3668
3745
|
name: destination,
|
|
3669
3746
|
provider: "self",
|
|
3670
3747
|
kind: messagingDestinationKind(system)
|
|
@@ -3708,9 +3785,9 @@ function lookupParentSpan(traceId, parentSpanId, now) {
|
|
|
3708
3785
|
};
|
|
3709
3786
|
}
|
|
3710
3787
|
function resolveServiceId(graph, host, env) {
|
|
3711
|
-
const envTagged = (0,
|
|
3788
|
+
const envTagged = (0, import_types7.serviceId)(host, env);
|
|
3712
3789
|
if (graph.hasNode(envTagged)) return envTagged;
|
|
3713
|
-
const envLess = (0,
|
|
3790
|
+
const envLess = (0, import_types7.serviceId)(host);
|
|
3714
3791
|
if (envLess !== envTagged && graph.hasNode(envLess)) return envLess;
|
|
3715
3792
|
let sameEnv = null;
|
|
3716
3793
|
let envLessMatch = null;
|
|
@@ -3718,7 +3795,7 @@ function resolveServiceId(graph, host, env) {
|
|
|
3718
3795
|
graph.forEachNode((id, attrs) => {
|
|
3719
3796
|
if (sameEnv) return;
|
|
3720
3797
|
const a = attrs;
|
|
3721
|
-
if (a.type !==
|
|
3798
|
+
if (a.type !== import_types7.NodeType.ServiceNode) return;
|
|
3722
3799
|
const matchesByName = a.name === host;
|
|
3723
3800
|
const matchesByAlias = a.aliases ? a.aliases.includes(host) : false;
|
|
3724
3801
|
if (!matchesByName && !matchesByAlias) return;
|
|
@@ -3733,14 +3810,14 @@ function resolveServiceId(graph, host, env) {
|
|
|
3733
3810
|
return sameEnv ?? envLessMatch ?? anyMatch;
|
|
3734
3811
|
}
|
|
3735
3812
|
function frontierIdFor(host) {
|
|
3736
|
-
return (0,
|
|
3813
|
+
return (0, import_types7.frontierId)(host);
|
|
3737
3814
|
}
|
|
3738
3815
|
function ensureServiceNode(graph, serviceName, env) {
|
|
3739
|
-
const id = (0,
|
|
3816
|
+
const id = (0, import_types7.serviceId)(serviceName, env);
|
|
3740
3817
|
if (graph.hasNode(id)) return id;
|
|
3741
3818
|
const wanted = serviceName.toLowerCase();
|
|
3742
3819
|
const extractedId = graph.findNode((_nid, attrs) => {
|
|
3743
|
-
if (attrs.type !==
|
|
3820
|
+
if (attrs.type !== import_types7.NodeType.ServiceNode) return false;
|
|
3744
3821
|
const svc = attrs;
|
|
3745
3822
|
if (svc.discoveredVia === "otel") return false;
|
|
3746
3823
|
return typeof svc.name === "string" && svc.name.toLowerCase() === wanted;
|
|
@@ -3748,7 +3825,7 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
3748
3825
|
if (extractedId) return extractedId;
|
|
3749
3826
|
const node = {
|
|
3750
3827
|
id,
|
|
3751
|
-
type:
|
|
3828
|
+
type: import_types7.NodeType.ServiceNode,
|
|
3752
3829
|
name: serviceName,
|
|
3753
3830
|
language: "unknown",
|
|
3754
3831
|
discoveredVia: "otel",
|
|
@@ -3758,11 +3835,11 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
3758
3835
|
return id;
|
|
3759
3836
|
}
|
|
3760
3837
|
function ensureInfraNode(graph, kind, name, provider) {
|
|
3761
|
-
const id = (0,
|
|
3838
|
+
const id = (0, import_types7.infraId)(kind, name);
|
|
3762
3839
|
if (graph.hasNode(id)) return id;
|
|
3763
3840
|
const node = {
|
|
3764
3841
|
id,
|
|
3765
|
-
type:
|
|
3842
|
+
type: import_types7.NodeType.InfraNode,
|
|
3766
3843
|
name,
|
|
3767
3844
|
provider,
|
|
3768
3845
|
kind
|
|
@@ -3770,12 +3847,27 @@ function ensureInfraNode(graph, kind, name, provider) {
|
|
|
3770
3847
|
graph.addNode(id, node);
|
|
3771
3848
|
return id;
|
|
3772
3849
|
}
|
|
3850
|
+
var COLUMN_BEARING_INFRA_KINDS = /* @__PURE__ */ new Set(["sql-table", "supabase-table"]);
|
|
3851
|
+
function mergeColumnsAt(graph, tableNodeId, columns, provenance, confidence) {
|
|
3852
|
+
if (!columns || columns.length === 0 || !graph.hasNode(tableNodeId)) return;
|
|
3853
|
+
const node = graph.getNodeAttributes(tableNodeId);
|
|
3854
|
+
if (node.type !== import_types7.NodeType.InfraNode || !node.kind || !COLUMN_BEARING_INFRA_KINDS.has(node.kind)) {
|
|
3855
|
+
return;
|
|
3856
|
+
}
|
|
3857
|
+
graph.replaceNodeAttributes(tableNodeId, {
|
|
3858
|
+
...node,
|
|
3859
|
+
columns: foldColumns(node.columns, columns, provenance, confidence)
|
|
3860
|
+
});
|
|
3861
|
+
}
|
|
3862
|
+
function mergeObservedColumns(graph, tableNodeId, columns) {
|
|
3863
|
+
mergeColumnsAt(graph, tableNodeId, columns, import_types7.Provenance.OBSERVED, OBSERVED_COLUMN_CONFIDENCE);
|
|
3864
|
+
}
|
|
3773
3865
|
function ensureDatabaseNode(graph, host, engine) {
|
|
3774
|
-
const id = (0,
|
|
3866
|
+
const id = (0, import_types7.databaseId)(host);
|
|
3775
3867
|
if (graph.hasNode(id)) return id;
|
|
3776
3868
|
const node = {
|
|
3777
3869
|
id,
|
|
3778
|
-
type:
|
|
3870
|
+
type: import_types7.NodeType.DatabaseNode,
|
|
3779
3871
|
name: host,
|
|
3780
3872
|
engine,
|
|
3781
3873
|
engineVersion: "unknown",
|
|
@@ -3787,11 +3879,11 @@ function ensureDatabaseNode(graph, host, engine) {
|
|
|
3787
3879
|
return id;
|
|
3788
3880
|
}
|
|
3789
3881
|
function ensureLocalDatabaseNode(graph, serviceName, name, engine) {
|
|
3790
|
-
const id = (0,
|
|
3882
|
+
const id = (0, import_types7.localDatabaseId)(serviceName, name);
|
|
3791
3883
|
if (graph.hasNode(id)) return id;
|
|
3792
3884
|
const node = {
|
|
3793
3885
|
id,
|
|
3794
|
-
type:
|
|
3886
|
+
type: import_types7.NodeType.DatabaseNode,
|
|
3795
3887
|
name,
|
|
3796
3888
|
engine,
|
|
3797
3889
|
engineVersion: "unknown",
|
|
@@ -3806,17 +3898,17 @@ function findDeclaredDatabaseForService(graph, serviceNodeId, engine) {
|
|
|
3806
3898
|
const sources = [serviceNodeId];
|
|
3807
3899
|
for (const edgeId of graph.outboundEdges(serviceNodeId)) {
|
|
3808
3900
|
const e = graph.getEdgeAttributes(edgeId);
|
|
3809
|
-
if (e.type ===
|
|
3901
|
+
if (e.type === import_types7.EdgeType.CONTAINS) sources.push(e.target);
|
|
3810
3902
|
}
|
|
3811
3903
|
const matches = /* @__PURE__ */ new Set();
|
|
3812
3904
|
for (const src of sources) {
|
|
3813
3905
|
if (!graph.hasNode(src)) continue;
|
|
3814
3906
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
3815
3907
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
3816
|
-
if (edge.type !==
|
|
3908
|
+
if (edge.type !== import_types7.EdgeType.CONNECTS_TO || edge.provenance !== import_types7.Provenance.EXTRACTED) continue;
|
|
3817
3909
|
if (!graph.hasNode(edge.target)) continue;
|
|
3818
3910
|
const target = graph.getNodeAttributes(edge.target);
|
|
3819
|
-
if (target.type !==
|
|
3911
|
+
if (target.type !== import_types7.NodeType.DatabaseNode || target.engine !== engine) continue;
|
|
3820
3912
|
matches.add(edge.target);
|
|
3821
3913
|
}
|
|
3822
3914
|
}
|
|
@@ -3831,7 +3923,7 @@ function ensureFrontierNode(graph, host, ts) {
|
|
|
3831
3923
|
}
|
|
3832
3924
|
const node = {
|
|
3833
3925
|
id,
|
|
3834
|
-
type:
|
|
3926
|
+
type: import_types7.NodeType.FrontierNode,
|
|
3835
3927
|
name: host,
|
|
3836
3928
|
host,
|
|
3837
3929
|
firstObserved: ts,
|
|
@@ -3855,11 +3947,11 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
|
|
|
3855
3947
|
};
|
|
3856
3948
|
const updated = {
|
|
3857
3949
|
...existing,
|
|
3858
|
-
provenance:
|
|
3950
|
+
provenance: import_types7.Provenance.OBSERVED,
|
|
3859
3951
|
lastObserved: ts,
|
|
3860
3952
|
callCount: newSpanCount,
|
|
3861
3953
|
signal: newSignal,
|
|
3862
|
-
confidence: (0,
|
|
3954
|
+
confidence: (0, import_types7.confidenceForObservedSignal)(newSignal),
|
|
3863
3955
|
grain
|
|
3864
3956
|
// backfills legacy edges that predate ADR-142
|
|
3865
3957
|
};
|
|
@@ -3876,8 +3968,8 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
|
|
|
3876
3968
|
source,
|
|
3877
3969
|
target,
|
|
3878
3970
|
type,
|
|
3879
|
-
provenance:
|
|
3880
|
-
confidence: (0,
|
|
3971
|
+
provenance: import_types7.Provenance.OBSERVED,
|
|
3972
|
+
confidence: (0, import_types7.confidenceForObservedSignal)(signal),
|
|
3881
3973
|
lastObserved: ts,
|
|
3882
3974
|
callCount: 1,
|
|
3883
3975
|
signal,
|
|
@@ -3899,9 +3991,9 @@ function stitchTrace(graph, sourceServiceId, ts) {
|
|
|
3899
3991
|
const outbound = graph.outboundEdges(nodeId);
|
|
3900
3992
|
for (const edgeId of outbound) {
|
|
3901
3993
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
3902
|
-
if (edge.provenance !==
|
|
3994
|
+
if (edge.provenance !== import_types7.Provenance.EXTRACTED) continue;
|
|
3903
3995
|
if (!STITCH_EDGE_TYPES.has(edge.type)) continue;
|
|
3904
|
-
if (graph.hasEdge((0,
|
|
3996
|
+
if (graph.hasEdge((0, import_types7.observedEdgeId)(edge.source, edge.target, edge.type))) continue;
|
|
3905
3997
|
upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts);
|
|
3906
3998
|
if (!visited.has(edge.target)) {
|
|
3907
3999
|
visited.add(edge.target);
|
|
@@ -3923,7 +4015,7 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
3923
4015
|
source,
|
|
3924
4016
|
target,
|
|
3925
4017
|
type,
|
|
3926
|
-
provenance:
|
|
4018
|
+
provenance: import_types7.Provenance.INFERRED,
|
|
3927
4019
|
confidence: INFERRED_CONFIDENCE,
|
|
3928
4020
|
lastObserved: ts
|
|
3929
4021
|
};
|
|
@@ -3934,12 +4026,12 @@ async function appendErrorEvent(ctx, ev) {
|
|
|
3934
4026
|
await import_node_fs6.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
3935
4027
|
}
|
|
3936
4028
|
function incidentAffectedNode(span, graph, scanPath) {
|
|
3937
|
-
const sid = (0,
|
|
4029
|
+
const sid = (0, import_types7.serviceId)(span.service, span.env);
|
|
3938
4030
|
const serviceNode = graph && graph.hasNode(sid) ? graph.getNodeAttributes(sid) : void 0;
|
|
3939
4031
|
const callSite = callSiteFromSpan(span, serviceNode, scanPath);
|
|
3940
4032
|
if (callSite) {
|
|
3941
4033
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
3942
|
-
return (0,
|
|
4034
|
+
return (0, import_types7.fileId)(span.service, relPath);
|
|
3943
4035
|
}
|
|
3944
4036
|
return sid;
|
|
3945
4037
|
}
|
|
@@ -4064,7 +4156,7 @@ function findRouteNodeByHttpRoute(graph, serviceName, method, httpRoute) {
|
|
|
4064
4156
|
graph.forEachNode((id, attrs) => {
|
|
4065
4157
|
if (found) return;
|
|
4066
4158
|
const a = attrs;
|
|
4067
|
-
if (a.type !==
|
|
4159
|
+
if (a.type !== import_types7.NodeType.RouteNode || a.service !== serviceName) return;
|
|
4068
4160
|
if (m && a.method !== "ALL" && a.method !== m) return;
|
|
4069
4161
|
if (normalizePathTemplate(a.pathTemplate) === target) found = id;
|
|
4070
4162
|
});
|
|
@@ -4095,7 +4187,7 @@ async function handleSpan(ctx, span) {
|
|
|
4095
4187
|
let targetId;
|
|
4096
4188
|
if (host) {
|
|
4097
4189
|
ensureDatabaseNode(ctx.graph, host, span.dbSystem);
|
|
4098
|
-
targetId = (0,
|
|
4190
|
+
targetId = (0, import_types7.databaseId)(host);
|
|
4099
4191
|
} else {
|
|
4100
4192
|
const declared = findDeclaredDatabaseForService(ctx.graph, sourceId, span.dbSystem);
|
|
4101
4193
|
if (declared) {
|
|
@@ -4112,7 +4204,7 @@ async function handleSpan(ctx, span) {
|
|
|
4112
4204
|
}
|
|
4113
4205
|
const result = upsertObservedEdge(
|
|
4114
4206
|
ctx.graph,
|
|
4115
|
-
|
|
4207
|
+
import_types7.EdgeType.CONNECTS_TO,
|
|
4116
4208
|
observedSource(),
|
|
4117
4209
|
targetId,
|
|
4118
4210
|
ts,
|
|
@@ -4124,7 +4216,7 @@ async function handleSpan(ctx, span) {
|
|
|
4124
4216
|
const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
|
|
4125
4217
|
upsertObservedEdge(
|
|
4126
4218
|
ctx.graph,
|
|
4127
|
-
|
|
4219
|
+
import_types7.EdgeType.CALLS,
|
|
4128
4220
|
observedSource(),
|
|
4129
4221
|
collectionId,
|
|
4130
4222
|
ts,
|
|
@@ -4136,13 +4228,14 @@ async function handleSpan(ctx, span) {
|
|
|
4136
4228
|
const tableId = ensureInfraNode(ctx.graph, "sql-table", span.dbTable, "self");
|
|
4137
4229
|
upsertObservedEdge(
|
|
4138
4230
|
ctx.graph,
|
|
4139
|
-
|
|
4231
|
+
import_types7.EdgeType.CALLS,
|
|
4140
4232
|
observedSource(),
|
|
4141
4233
|
tableId,
|
|
4142
4234
|
ts,
|
|
4143
4235
|
isError,
|
|
4144
4236
|
callSiteEvidence
|
|
4145
4237
|
);
|
|
4238
|
+
mergeObservedColumns(ctx.graph, tableId, span.dbColumns);
|
|
4146
4239
|
}
|
|
4147
4240
|
}
|
|
4148
4241
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
@@ -4151,7 +4244,7 @@ async function handleSpan(ctx, span) {
|
|
|
4151
4244
|
span.messagingSystem,
|
|
4152
4245
|
span.messagingDestination
|
|
4153
4246
|
);
|
|
4154
|
-
const edgeType = span.kind === WIRE_SPAN_KIND_CONSUMER ?
|
|
4247
|
+
const edgeType = span.kind === WIRE_SPAN_KIND_CONSUMER ? import_types7.EdgeType.CONSUMES_FROM : import_types7.EdgeType.PUBLISHES_TO;
|
|
4155
4248
|
const result = upsertObservedEdge(
|
|
4156
4249
|
ctx.graph,
|
|
4157
4250
|
edgeType,
|
|
@@ -4171,7 +4264,7 @@ async function handleSpan(ctx, span) {
|
|
|
4171
4264
|
);
|
|
4172
4265
|
const result = upsertObservedEdge(
|
|
4173
4266
|
ctx.graph,
|
|
4174
|
-
|
|
4267
|
+
import_types7.EdgeType.CONTAINS,
|
|
4175
4268
|
observedSource(),
|
|
4176
4269
|
targetId,
|
|
4177
4270
|
ts,
|
|
@@ -4183,7 +4276,7 @@ async function handleSpan(ctx, span) {
|
|
|
4183
4276
|
const targetId = ensureGrpcMethodNode(ctx.graph, span.rpcService, span.rpcMethod);
|
|
4184
4277
|
const result = upsertObservedEdge(
|
|
4185
4278
|
ctx.graph,
|
|
4186
|
-
|
|
4279
|
+
import_types7.EdgeType.CONTAINS,
|
|
4187
4280
|
observedSource(),
|
|
4188
4281
|
targetId,
|
|
4189
4282
|
ts,
|
|
@@ -4199,7 +4292,7 @@ async function handleSpan(ctx, span) {
|
|
|
4199
4292
|
);
|
|
4200
4293
|
const result = upsertObservedEdge(
|
|
4201
4294
|
ctx.graph,
|
|
4202
|
-
|
|
4295
|
+
import_types7.EdgeType.CONNECTS_TO,
|
|
4203
4296
|
observedSource(),
|
|
4204
4297
|
targetId,
|
|
4205
4298
|
ts,
|
|
@@ -4215,7 +4308,7 @@ async function handleSpan(ctx, span) {
|
|
|
4215
4308
|
if (targetId && targetId !== sourceId) {
|
|
4216
4309
|
upsertObservedEdge(
|
|
4217
4310
|
ctx.graph,
|
|
4218
|
-
|
|
4311
|
+
import_types7.EdgeType.CALLS,
|
|
4219
4312
|
observedSource(),
|
|
4220
4313
|
targetId,
|
|
4221
4314
|
ts,
|
|
@@ -4228,7 +4321,7 @@ async function handleSpan(ctx, span) {
|
|
|
4228
4321
|
const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts);
|
|
4229
4322
|
upsertObservedEdge(
|
|
4230
4323
|
ctx.graph,
|
|
4231
|
-
|
|
4324
|
+
import_types7.EdgeType.CALLS,
|
|
4232
4325
|
observedSource(),
|
|
4233
4326
|
frontierNodeId,
|
|
4234
4327
|
ts,
|
|
@@ -4254,7 +4347,7 @@ async function handleSpan(ctx, span) {
|
|
|
4254
4347
|
} : void 0;
|
|
4255
4348
|
upsertObservedEdge(
|
|
4256
4349
|
ctx.graph,
|
|
4257
|
-
|
|
4350
|
+
import_types7.EdgeType.CALLS,
|
|
4258
4351
|
fallbackSource,
|
|
4259
4352
|
sourceId,
|
|
4260
4353
|
ts,
|
|
@@ -4264,7 +4357,7 @@ async function handleSpan(ctx, span) {
|
|
|
4264
4357
|
}
|
|
4265
4358
|
}
|
|
4266
4359
|
}
|
|
4267
|
-
if (span.httpRoute && (span.kind === 2 || span.kind === 0 || span.kind === void 0)) {
|
|
4360
|
+
if (span.httpRoute && (span.kind === 2 || span.kind === 1 || span.kind === 0 || span.kind === void 0)) {
|
|
4268
4361
|
const routeNodeId = findRouteNodeByHttpRoute(
|
|
4269
4362
|
ctx.graph,
|
|
4270
4363
|
span.service,
|
|
@@ -4273,7 +4366,7 @@ async function handleSpan(ctx, span) {
|
|
|
4273
4366
|
);
|
|
4274
4367
|
if (routeNodeId) {
|
|
4275
4368
|
const routeSvc = ctx.graph.getNodeAttributes(routeNodeId).service;
|
|
4276
|
-
upsertObservedEdge(ctx.graph,
|
|
4369
|
+
upsertObservedEdge(ctx.graph, import_types7.EdgeType.CONTAINS, (0, import_types7.serviceId)(routeSvc), routeNodeId, ts, isError);
|
|
4277
4370
|
}
|
|
4278
4371
|
}
|
|
4279
4372
|
if (span.statusCode === 2) {
|
|
@@ -4312,7 +4405,7 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
4312
4405
|
const aliasIndex = /* @__PURE__ */ new Map();
|
|
4313
4406
|
graph.forEachNode((id, attrs) => {
|
|
4314
4407
|
const a = attrs;
|
|
4315
|
-
if (a.type !==
|
|
4408
|
+
if (a.type !== import_types7.NodeType.ServiceNode) return;
|
|
4316
4409
|
aliasIndex.set(a.name, id);
|
|
4317
4410
|
if (a.aliases) {
|
|
4318
4411
|
for (const alias of a.aliases) aliasIndex.set(alias, id);
|
|
@@ -4321,7 +4414,7 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
4321
4414
|
const toPromote = [];
|
|
4322
4415
|
graph.forEachNode((id, attrs) => {
|
|
4323
4416
|
const a = attrs;
|
|
4324
|
-
if (a.type !==
|
|
4417
|
+
if (a.type !== import_types7.NodeType.FrontierNode) return;
|
|
4325
4418
|
const target = aliasIndex.get(a.host);
|
|
4326
4419
|
if (!target) return;
|
|
4327
4420
|
if (target === id) return;
|
|
@@ -4355,7 +4448,7 @@ function rewireFrontierEdges(graph, frontierId2, serviceId7) {
|
|
|
4355
4448
|
}
|
|
4356
4449
|
function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
4357
4450
|
graph.dropEdge(oldEdgeId);
|
|
4358
|
-
const newId = edge.provenance ===
|
|
4451
|
+
const newId = edge.provenance === import_types7.Provenance.OBSERVED ? (0, import_types7.observedEdgeId)(newSource, newTarget, edge.type) : edge.provenance === import_types7.Provenance.INFERRED ? (0, import_types7.inferredEdgeId)(newSource, newTarget, edge.type) : (0, import_types7.extractedEdgeId)(newSource, newTarget, edge.type);
|
|
4359
4452
|
if (graph.hasEdge(newId)) {
|
|
4360
4453
|
const existing = graph.getEdgeAttributes(newId);
|
|
4361
4454
|
const merged = {
|
|
@@ -4389,12 +4482,12 @@ async function markStaleEdges(graph, options = {}) {
|
|
|
4389
4482
|
const project = options.project ?? DEFAULT_PROJECT;
|
|
4390
4483
|
graph.forEachEdge((id, attrs) => {
|
|
4391
4484
|
const e = attrs;
|
|
4392
|
-
if (e.provenance !==
|
|
4485
|
+
if (e.provenance !== import_types7.Provenance.OBSERVED) return;
|
|
4393
4486
|
if (!e.lastObserved) return;
|
|
4394
4487
|
const threshold = thresholdForEdgeType(e.type, thresholds);
|
|
4395
4488
|
const age = now - new Date(e.lastObserved).getTime();
|
|
4396
4489
|
if (age > threshold) {
|
|
4397
|
-
const updated = { ...e, provenance:
|
|
4490
|
+
const updated = { ...e, provenance: import_types7.Provenance.STALE, confidence: 0.3 };
|
|
4398
4491
|
graph.replaceEdgeAttributes(id, updated);
|
|
4399
4492
|
events.push({
|
|
4400
4493
|
edgeId: id,
|
|
@@ -4411,8 +4504,8 @@ async function markStaleEdges(graph, options = {}) {
|
|
|
4411
4504
|
project,
|
|
4412
4505
|
payload: {
|
|
4413
4506
|
edgeId: id,
|
|
4414
|
-
from:
|
|
4415
|
-
to:
|
|
4507
|
+
from: import_types7.Provenance.OBSERVED,
|
|
4508
|
+
to: import_types7.Provenance.STALE
|
|
4416
4509
|
}
|
|
4417
4510
|
});
|
|
4418
4511
|
}
|
|
@@ -4521,7 +4614,7 @@ function mergeSnapshot(graph, snapshot) {
|
|
|
4521
4614
|
const validEdges = [];
|
|
4522
4615
|
for (const node of incomingNodes) {
|
|
4523
4616
|
if (node.attributes === void 0) continue;
|
|
4524
|
-
const parsed =
|
|
4617
|
+
const parsed = import_types7.GraphNodeSchema.safeParse(node.attributes);
|
|
4525
4618
|
if (!parsed.success) {
|
|
4526
4619
|
issues.push(`node "${node.key}": ${describeZodIssues(parsed.error)}`);
|
|
4527
4620
|
continue;
|
|
@@ -4530,7 +4623,7 @@ function mergeSnapshot(graph, snapshot) {
|
|
|
4530
4623
|
}
|
|
4531
4624
|
for (const edge of incomingEdges) {
|
|
4532
4625
|
if (edge.attributes === void 0) continue;
|
|
4533
|
-
const parsed =
|
|
4626
|
+
const parsed = import_types7.GraphEdgeSchema.safeParse(edge.attributes);
|
|
4534
4627
|
if (!parsed.success) {
|
|
4535
4628
|
const label = edge.key ?? `${edge.source}->${edge.target}`;
|
|
4536
4629
|
issues.push(`edge "${label}": ${describeZodIssues(parsed.error)}`);
|
|
@@ -4564,7 +4657,7 @@ var import_node_fs10 = require("fs");
|
|
|
4564
4657
|
var import_node_path11 = __toESM(require("path"), 1);
|
|
4565
4658
|
var import_ignore = __toESM(require("ignore"), 1);
|
|
4566
4659
|
var import_minimatch2 = require("minimatch");
|
|
4567
|
-
var
|
|
4660
|
+
var import_types9 = require("@neat.is/types");
|
|
4568
4661
|
|
|
4569
4662
|
// src/extract/python.ts
|
|
4570
4663
|
init_cjs_shims();
|
|
@@ -4637,7 +4730,7 @@ function pythonToPackage(service) {
|
|
|
4637
4730
|
init_cjs_shims();
|
|
4638
4731
|
var import_node_fs8 = require("fs");
|
|
4639
4732
|
var import_node_path9 = __toESM(require("path"), 1);
|
|
4640
|
-
var
|
|
4733
|
+
var import_types8 = require("@neat.is/types");
|
|
4641
4734
|
function parseGoMod(source) {
|
|
4642
4735
|
const module2 = source.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
|
|
4643
4736
|
if (!module2) return null;
|
|
@@ -4665,8 +4758,8 @@ async function discoverGoService(scanPath, dir) {
|
|
|
4665
4758
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
4666
4759
|
const pkg = { name, dependencies: mod.dependencies };
|
|
4667
4760
|
const node = {
|
|
4668
|
-
id: (0,
|
|
4669
|
-
type:
|
|
4761
|
+
id: (0, import_types8.serviceId)(name),
|
|
4762
|
+
type: import_types8.NodeType.ServiceNode,
|
|
4670
4763
|
name,
|
|
4671
4764
|
language: "go",
|
|
4672
4765
|
dependencies: mod.dependencies,
|
|
@@ -4852,8 +4945,8 @@ async function discoverNodeService(scanPath, dir) {
|
|
|
4852
4945
|
const framework = detectJsFramework(pkg);
|
|
4853
4946
|
const language = await detectJsServiceLanguage(dir, pkg);
|
|
4854
4947
|
const node = {
|
|
4855
|
-
id: (0,
|
|
4856
|
-
type:
|
|
4948
|
+
id: (0, import_types9.serviceId)(pkg.name),
|
|
4949
|
+
type: import_types9.NodeType.ServiceNode,
|
|
4857
4950
|
name: pkg.name,
|
|
4858
4951
|
language,
|
|
4859
4952
|
version: pkg.version,
|
|
@@ -4869,8 +4962,8 @@ async function discoverPyService(scanPath, dir) {
|
|
|
4869
4962
|
if (!py) return null;
|
|
4870
4963
|
const pkg = pythonToPackage(py);
|
|
4871
4964
|
const node = {
|
|
4872
|
-
id: (0,
|
|
4873
|
-
type:
|
|
4965
|
+
id: (0, import_types9.serviceId)(py.name),
|
|
4966
|
+
type: import_types9.NodeType.ServiceNode,
|
|
4874
4967
|
name: py.name,
|
|
4875
4968
|
language: "python",
|
|
4876
4969
|
version: py.version,
|
|
@@ -4966,7 +5059,7 @@ init_cjs_shims();
|
|
|
4966
5059
|
var import_node_path12 = __toESM(require("path"), 1);
|
|
4967
5060
|
var import_node_fs11 = require("fs");
|
|
4968
5061
|
var import_yaml2 = require("yaml");
|
|
4969
|
-
var
|
|
5062
|
+
var import_types10 = require("@neat.is/types");
|
|
4970
5063
|
var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
4971
5064
|
"Service",
|
|
4972
5065
|
"Deployment",
|
|
@@ -4976,7 +5069,7 @@ var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
|
4976
5069
|
function addAliases(graph, serviceId7, candidates) {
|
|
4977
5070
|
if (!graph.hasNode(serviceId7)) return;
|
|
4978
5071
|
const node = graph.getNodeAttributes(serviceId7);
|
|
4979
|
-
if (node.type !==
|
|
5072
|
+
if (node.type !== import_types10.NodeType.ServiceNode) return;
|
|
4980
5073
|
const set = new Set(node.aliases ?? []);
|
|
4981
5074
|
for (const c of candidates) {
|
|
4982
5075
|
if (!c) continue;
|
|
@@ -5157,7 +5250,7 @@ var import_node_path14 = __toESM(require("path"), 1);
|
|
|
5157
5250
|
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
5158
5251
|
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5159
5252
|
var import_tree_sitter_typescript = __toESM(require("tree-sitter-typescript"), 1);
|
|
5160
|
-
var
|
|
5253
|
+
var import_types11 = require("@neat.is/types");
|
|
5161
5254
|
var PARSE_CHUNK2 = 16384;
|
|
5162
5255
|
var GRAMMAR_BY_EXT = {
|
|
5163
5256
|
".ts": import_tree_sitter_typescript.default.typescript,
|
|
@@ -5248,7 +5341,7 @@ function disambiguate(defs) {
|
|
|
5248
5341
|
}
|
|
5249
5342
|
async function addSymbols(graph, services) {
|
|
5250
5343
|
const parsers = /* @__PURE__ */ new Map();
|
|
5251
|
-
const
|
|
5344
|
+
const parserForExt2 = (ext) => {
|
|
5252
5345
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
5253
5346
|
if (!grammar) return null;
|
|
5254
5347
|
let parser = parsers.get(ext);
|
|
@@ -5264,7 +5357,7 @@ async function addSymbols(graph, services) {
|
|
|
5264
5357
|
for (const service of services) {
|
|
5265
5358
|
const files = await loadSourceFiles(service.dir);
|
|
5266
5359
|
for (const file of files) {
|
|
5267
|
-
const parser =
|
|
5360
|
+
const parser = parserForExt2(import_node_path14.default.extname(file.path));
|
|
5268
5361
|
if (!parser) continue;
|
|
5269
5362
|
const relPath = toPosix(import_node_path14.default.relative(service.dir, file.path));
|
|
5270
5363
|
let defs;
|
|
@@ -5285,11 +5378,11 @@ async function addSymbols(graph, services) {
|
|
|
5285
5378
|
nodesAdded += fn;
|
|
5286
5379
|
edgesAdded += fe;
|
|
5287
5380
|
for (const { def, disambiguator } of disambiguate(defs)) {
|
|
5288
|
-
const sid = (0,
|
|
5381
|
+
const sid = (0, import_types11.symbolId)(service.pkg.name, relPath, def.qualname, disambiguator);
|
|
5289
5382
|
if (!graph.hasNode(sid)) {
|
|
5290
5383
|
const node = {
|
|
5291
5384
|
id: sid,
|
|
5292
|
-
type:
|
|
5385
|
+
type: import_types11.NodeType.SymbolNode,
|
|
5293
5386
|
kind: def.kind,
|
|
5294
5387
|
qualname: def.qualname,
|
|
5295
5388
|
span: { startLine: def.startLine, endLine: def.endLine },
|
|
@@ -5300,15 +5393,15 @@ async function addSymbols(graph, services) {
|
|
|
5300
5393
|
graph.addNode(sid, node);
|
|
5301
5394
|
nodesAdded++;
|
|
5302
5395
|
}
|
|
5303
|
-
const containsId = (0,
|
|
5396
|
+
const containsId = (0, import_types11.extractedEdgeId)(fileNodeId, sid, import_types11.EdgeType.CONTAINS);
|
|
5304
5397
|
if (!graph.hasEdge(containsId)) {
|
|
5305
5398
|
const edge = {
|
|
5306
5399
|
id: containsId,
|
|
5307
5400
|
source: fileNodeId,
|
|
5308
5401
|
target: sid,
|
|
5309
|
-
type:
|
|
5310
|
-
provenance:
|
|
5311
|
-
confidence: (0,
|
|
5402
|
+
type: import_types11.EdgeType.CONTAINS,
|
|
5403
|
+
provenance: import_types11.Provenance.EXTRACTED,
|
|
5404
|
+
confidence: (0, import_types11.confidenceForExtracted)("structural"),
|
|
5312
5405
|
evidence: {
|
|
5313
5406
|
file: relPath,
|
|
5314
5407
|
line: def.startLine,
|
|
@@ -5328,7 +5421,7 @@ async function addSymbols(graph, services) {
|
|
|
5328
5421
|
init_cjs_shims();
|
|
5329
5422
|
var import_node_path16 = __toESM(require("path"), 1);
|
|
5330
5423
|
var import_tree_sitter4 = __toESM(require("tree-sitter"), 1);
|
|
5331
|
-
var
|
|
5424
|
+
var import_types13 = require("@neat.is/types");
|
|
5332
5425
|
|
|
5333
5426
|
// src/extract/imports.ts
|
|
5334
5427
|
init_cjs_shims();
|
|
@@ -5338,7 +5431,7 @@ var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
|
|
|
5338
5431
|
var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5339
5432
|
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
5340
5433
|
var import_tree_sitter_go2 = __toESM(require("tree-sitter-go"), 1);
|
|
5341
|
-
var
|
|
5434
|
+
var import_types12 = require("@neat.is/types");
|
|
5342
5435
|
var PARSE_CHUNK3 = 16384;
|
|
5343
5436
|
function parseSource3(parser, source) {
|
|
5344
5437
|
return parser.parse(
|
|
@@ -5612,17 +5705,17 @@ async function resolveGoImport(specifier, modulePath, serviceDir) {
|
|
|
5612
5705
|
return toPosix(import_node_path15.default.relative(serviceDir, candidates[0]));
|
|
5613
5706
|
}
|
|
5614
5707
|
function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
|
|
5615
|
-
const importeeFileId = (0,
|
|
5708
|
+
const importeeFileId = (0, import_types12.fileId)(serviceName, importeeRelPath);
|
|
5616
5709
|
if (!graph.hasNode(importeeFileId)) return 0;
|
|
5617
|
-
const edgeId = (0,
|
|
5710
|
+
const edgeId = (0, import_types12.extractedEdgeId)(importerFileId, importeeFileId, import_types12.EdgeType.IMPORTS);
|
|
5618
5711
|
if (graph.hasEdge(edgeId)) return 0;
|
|
5619
5712
|
const edge = {
|
|
5620
5713
|
id: edgeId,
|
|
5621
5714
|
source: importerFileId,
|
|
5622
5715
|
target: importeeFileId,
|
|
5623
|
-
type:
|
|
5624
|
-
provenance:
|
|
5625
|
-
confidence: (0,
|
|
5716
|
+
type: import_types12.EdgeType.IMPORTS,
|
|
5717
|
+
provenance: import_types12.Provenance.EXTRACTED,
|
|
5718
|
+
confidence: (0, import_types12.confidenceForExtracted)("structural"),
|
|
5626
5719
|
evidence: { file: importerRelPath, line, snippet: snippet2 }
|
|
5627
5720
|
};
|
|
5628
5721
|
graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge);
|
|
@@ -5639,7 +5732,7 @@ async function addImports(graph, services) {
|
|
|
5639
5732
|
for (const file of files) {
|
|
5640
5733
|
if (isTestPath(file.path)) continue;
|
|
5641
5734
|
const relFile = toPosix(import_node_path15.default.relative(service.dir, file.path));
|
|
5642
|
-
const importerFileId = (0,
|
|
5735
|
+
const importerFileId = (0, import_types12.fileId)(service.pkg.name, relFile);
|
|
5643
5736
|
const isPython = import_node_path15.default.extname(file.path) === ".py";
|
|
5644
5737
|
const isGo = import_node_path15.default.extname(file.path) === ".go";
|
|
5645
5738
|
if (isGo) {
|
|
@@ -5800,7 +5893,7 @@ function stringInner(node) {
|
|
|
5800
5893
|
}
|
|
5801
5894
|
async function addSymbolEdges(graph, services) {
|
|
5802
5895
|
const parsers = /* @__PURE__ */ new Map();
|
|
5803
|
-
const
|
|
5896
|
+
const parserForExt2 = (ext) => {
|
|
5804
5897
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
5805
5898
|
if (!grammar) return null;
|
|
5806
5899
|
let parser = parsers.get(ext);
|
|
@@ -5817,7 +5910,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5817
5910
|
const tsPaths = await loadTsPathConfig(service.dir);
|
|
5818
5911
|
const files = await loadSourceFiles(service.dir);
|
|
5819
5912
|
for (const file of files) {
|
|
5820
|
-
const parser =
|
|
5913
|
+
const parser = parserForExt2(import_node_path16.default.extname(file.path));
|
|
5821
5914
|
if (!parser) continue;
|
|
5822
5915
|
const relPath = toPosix(import_node_path16.default.relative(service.dir, file.path));
|
|
5823
5916
|
const fileDir = import_node_path16.default.dirname(file.path);
|
|
@@ -5830,7 +5923,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5830
5923
|
}
|
|
5831
5924
|
const disambiguated = disambiguate(collectSymbolDefs(root));
|
|
5832
5925
|
const locals = disambiguated.map(({ def, disambiguator }) => ({
|
|
5833
|
-
sid: (0,
|
|
5926
|
+
sid: (0, import_types13.symbolId)(serviceName, relPath, def.qualname, disambiguator),
|
|
5834
5927
|
qualname: def.qualname,
|
|
5835
5928
|
kind: def.kind,
|
|
5836
5929
|
startLine: def.startLine,
|
|
@@ -5859,10 +5952,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
5859
5952
|
if (local) return local.kind === wantKind ? local.sid : null;
|
|
5860
5953
|
const imp = resolvedImports.get(name);
|
|
5861
5954
|
if (imp) {
|
|
5862
|
-
const candidate = (0,
|
|
5955
|
+
const candidate = (0, import_types13.symbolId)(serviceName, imp.targetRelPath, imp.importedName);
|
|
5863
5956
|
if (graph.hasNode(candidate)) {
|
|
5864
5957
|
const node = graph.getNodeAttributes(candidate);
|
|
5865
|
-
if (node.type ===
|
|
5958
|
+
if (node.type === import_types13.NodeType.SymbolNode && node.kind === wantKind) return candidate;
|
|
5866
5959
|
}
|
|
5867
5960
|
}
|
|
5868
5961
|
return null;
|
|
@@ -5889,7 +5982,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5889
5982
|
sourceSid: self.sid,
|
|
5890
5983
|
targetName: ext.name,
|
|
5891
5984
|
wantKind: "class",
|
|
5892
|
-
edgeType:
|
|
5985
|
+
edgeType: import_types13.EdgeType.INHERITS,
|
|
5893
5986
|
line: ext.line
|
|
5894
5987
|
});
|
|
5895
5988
|
}
|
|
@@ -5898,7 +5991,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5898
5991
|
sourceSid: self.sid,
|
|
5899
5992
|
targetName: impl.name,
|
|
5900
5993
|
wantKind: "class",
|
|
5901
|
-
edgeType:
|
|
5994
|
+
edgeType: import_types13.EdgeType.IMPLEMENTS,
|
|
5902
5995
|
line: impl.line
|
|
5903
5996
|
});
|
|
5904
5997
|
}
|
|
@@ -5914,7 +6007,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5914
6007
|
sourceSid: caller.sid,
|
|
5915
6008
|
targetName: fn.text,
|
|
5916
6009
|
wantKind: "function",
|
|
5917
|
-
edgeType:
|
|
6010
|
+
edgeType: import_types13.EdgeType.CALLS,
|
|
5918
6011
|
line
|
|
5919
6012
|
});
|
|
5920
6013
|
}
|
|
@@ -5930,15 +6023,15 @@ async function addSymbolEdges(graph, services) {
|
|
|
5930
6023
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
5931
6024
|
if (!targetSid) continue;
|
|
5932
6025
|
if (targetSid === req.sourceSid) continue;
|
|
5933
|
-
const edgeId = (0,
|
|
6026
|
+
const edgeId = (0, import_types13.extractedEdgeId)(req.sourceSid, targetSid, req.edgeType);
|
|
5934
6027
|
if (graph.hasEdge(edgeId)) continue;
|
|
5935
6028
|
const edge = {
|
|
5936
6029
|
id: edgeId,
|
|
5937
6030
|
source: req.sourceSid,
|
|
5938
6031
|
target: targetSid,
|
|
5939
6032
|
type: req.edgeType,
|
|
5940
|
-
provenance:
|
|
5941
|
-
confidence: (0,
|
|
6033
|
+
provenance: import_types13.Provenance.EXTRACTED,
|
|
6034
|
+
confidence: (0, import_types13.confidenceForExtracted)("structural"),
|
|
5942
6035
|
evidence: {
|
|
5943
6036
|
file: relPath,
|
|
5944
6037
|
line: req.line,
|
|
@@ -5956,7 +6049,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5956
6049
|
// src/extract/databases/index.ts
|
|
5957
6050
|
init_cjs_shims();
|
|
5958
6051
|
var import_node_path24 = __toESM(require("path"), 1);
|
|
5959
|
-
var
|
|
6052
|
+
var import_types14 = require("@neat.is/types");
|
|
5960
6053
|
|
|
5961
6054
|
// src/extract/databases/db-config-yaml.ts
|
|
5962
6055
|
init_cjs_shims();
|
|
@@ -6460,8 +6553,8 @@ function compatibleDriversFor(engine) {
|
|
|
6460
6553
|
}
|
|
6461
6554
|
function toDatabaseNode(config) {
|
|
6462
6555
|
return {
|
|
6463
|
-
id: (0,
|
|
6464
|
-
type:
|
|
6556
|
+
id: (0, import_types14.databaseId)(config.host),
|
|
6557
|
+
type: import_types14.NodeType.DatabaseNode,
|
|
6465
6558
|
name: config.database || config.host,
|
|
6466
6559
|
engine: config.engine,
|
|
6467
6560
|
engineVersion: config.engineVersion,
|
|
@@ -6602,12 +6695,12 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6602
6695
|
edgesAdded += fe;
|
|
6603
6696
|
const evidenceFile = toPosix(import_node_path24.default.relative(scanPath, config.sourceFile));
|
|
6604
6697
|
const edge = {
|
|
6605
|
-
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id,
|
|
6698
|
+
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types14.EdgeType.CONNECTS_TO),
|
|
6606
6699
|
source: fileNodeId,
|
|
6607
6700
|
target: dbNode.id,
|
|
6608
|
-
type:
|
|
6609
|
-
provenance:
|
|
6610
|
-
confidence: (0,
|
|
6701
|
+
type: import_types14.EdgeType.CONNECTS_TO,
|
|
6702
|
+
provenance: import_types14.Provenance.EXTRACTED,
|
|
6703
|
+
confidence: (0, import_types14.confidenceForExtracted)("structural"),
|
|
6611
6704
|
evidence: { file: evidenceFile }
|
|
6612
6705
|
};
|
|
6613
6706
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -6619,11 +6712,11 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6619
6712
|
const primary = allConfigs[0];
|
|
6620
6713
|
service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
|
|
6621
6714
|
const relPath = import_node_path24.default.relative(scanPath, primary.sourceFile);
|
|
6622
|
-
const cfgId = (0,
|
|
6715
|
+
const cfgId = (0, import_types14.configId)(relPath);
|
|
6623
6716
|
if (!graph.hasNode(cfgId)) {
|
|
6624
6717
|
const cfgNode = {
|
|
6625
6718
|
id: cfgId,
|
|
6626
|
-
type:
|
|
6719
|
+
type: import_types14.NodeType.ConfigNode,
|
|
6627
6720
|
name: import_node_path24.default.basename(primary.sourceFile),
|
|
6628
6721
|
path: relPath,
|
|
6629
6722
|
fileType: isConfigFile(import_node_path24.default.basename(primary.sourceFile)).fileType || "config"
|
|
@@ -6632,12 +6725,12 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6632
6725
|
nodesAdded++;
|
|
6633
6726
|
}
|
|
6634
6727
|
const cfgEdge = {
|
|
6635
|
-
id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId,
|
|
6728
|
+
id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId, import_types14.EdgeType.CONFIGURED_BY),
|
|
6636
6729
|
source: service.node.id,
|
|
6637
6730
|
target: cfgId,
|
|
6638
|
-
type:
|
|
6639
|
-
provenance:
|
|
6640
|
-
confidence: (0,
|
|
6731
|
+
type: import_types14.EdgeType.CONFIGURED_BY,
|
|
6732
|
+
provenance: import_types14.Provenance.EXTRACTED,
|
|
6733
|
+
confidence: (0, import_types14.confidenceForExtracted)("structural"),
|
|
6641
6734
|
evidence: { file: toPosix(relPath) }
|
|
6642
6735
|
};
|
|
6643
6736
|
if (!graph.hasEdge(cfgEdge.id)) {
|
|
@@ -6669,7 +6762,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6669
6762
|
init_cjs_shims();
|
|
6670
6763
|
var import_node_fs15 = require("fs");
|
|
6671
6764
|
var import_node_path25 = __toESM(require("path"), 1);
|
|
6672
|
-
var
|
|
6765
|
+
var import_types15 = require("@neat.is/types");
|
|
6673
6766
|
async function walkConfigFiles(dir) {
|
|
6674
6767
|
const out = [];
|
|
6675
6768
|
async function walk6(current) {
|
|
@@ -6696,8 +6789,8 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
6696
6789
|
for (const file of configFiles) {
|
|
6697
6790
|
const relPath = import_node_path25.default.relative(scanPath, file);
|
|
6698
6791
|
const node = {
|
|
6699
|
-
id: (0,
|
|
6700
|
-
type:
|
|
6792
|
+
id: (0, import_types15.configId)(relPath),
|
|
6793
|
+
type: import_types15.NodeType.ConfigNode,
|
|
6701
6794
|
name: import_node_path25.default.basename(file),
|
|
6702
6795
|
path: relPath,
|
|
6703
6796
|
fileType: isConfigFile(import_node_path25.default.basename(file)).fileType
|
|
@@ -6716,12 +6809,12 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
6716
6809
|
nodesAdded += fn;
|
|
6717
6810
|
edgesAdded += fe;
|
|
6718
6811
|
const edge = {
|
|
6719
|
-
id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
6812
|
+
id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types15.EdgeType.CONFIGURED_BY),
|
|
6720
6813
|
source: fileNodeId,
|
|
6721
6814
|
target: node.id,
|
|
6722
|
-
type:
|
|
6723
|
-
provenance:
|
|
6724
|
-
confidence: (0,
|
|
6815
|
+
type: import_types15.EdgeType.CONFIGURED_BY,
|
|
6816
|
+
provenance: import_types15.Provenance.EXTRACTED,
|
|
6817
|
+
confidence: (0, import_types15.confidenceForExtracted)("structural"),
|
|
6725
6818
|
evidence: { file: relPath.split(import_node_path25.default.sep).join("/") }
|
|
6726
6819
|
};
|
|
6727
6820
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -6737,7 +6830,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
6737
6830
|
init_cjs_shims();
|
|
6738
6831
|
var import_node_fs16 = require("fs");
|
|
6739
6832
|
var import_node_path26 = __toESM(require("path"), 1);
|
|
6740
|
-
var
|
|
6833
|
+
var import_types16 = require("@neat.is/types");
|
|
6741
6834
|
var PROTO_EXTENSION = ".proto";
|
|
6742
6835
|
function packageOf(content) {
|
|
6743
6836
|
const m = content.match(/^\s*package\s+([A-Za-z_][A-Za-z0-9_.]*)\s*;/m);
|
|
@@ -6815,11 +6908,11 @@ async function addGrpcMethods(graph, services) {
|
|
|
6815
6908
|
}
|
|
6816
6909
|
if (methods.length === 0) continue;
|
|
6817
6910
|
for (const method of methods) {
|
|
6818
|
-
const mid = (0,
|
|
6911
|
+
const mid = (0, import_types16.grpcMethodId)(method.rpcService, method.rpcMethod);
|
|
6819
6912
|
if (!graph.hasNode(mid)) {
|
|
6820
6913
|
const node = {
|
|
6821
6914
|
id: mid,
|
|
6822
|
-
type:
|
|
6915
|
+
type: import_types16.NodeType.GrpcMethodNode,
|
|
6823
6916
|
name: `${method.rpcService}/${method.rpcMethod}`,
|
|
6824
6917
|
rpcService: method.rpcService,
|
|
6825
6918
|
rpcMethod: method.rpcMethod,
|
|
@@ -6830,15 +6923,15 @@ async function addGrpcMethods(graph, services) {
|
|
|
6830
6923
|
graph.addNode(mid, node);
|
|
6831
6924
|
nodesAdded++;
|
|
6832
6925
|
}
|
|
6833
|
-
const containsId = (0,
|
|
6926
|
+
const containsId = (0, import_types16.extractedEdgeId)(service.node.id, mid, import_types16.EdgeType.CONTAINS);
|
|
6834
6927
|
if (!graph.hasEdge(containsId)) {
|
|
6835
6928
|
const edge = {
|
|
6836
6929
|
id: containsId,
|
|
6837
6930
|
source: service.node.id,
|
|
6838
6931
|
target: mid,
|
|
6839
|
-
type:
|
|
6840
|
-
provenance:
|
|
6841
|
-
confidence: (0,
|
|
6932
|
+
type: import_types16.EdgeType.CONTAINS,
|
|
6933
|
+
provenance: import_types16.Provenance.EXTRACTED,
|
|
6934
|
+
confidence: (0, import_types16.confidenceForExtracted)("structural"),
|
|
6842
6935
|
evidence: {
|
|
6843
6936
|
file: relFile,
|
|
6844
6937
|
line: method.line,
|
|
@@ -6856,7 +6949,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
6856
6949
|
|
|
6857
6950
|
// src/extract/calls/index.ts
|
|
6858
6951
|
init_cjs_shims();
|
|
6859
|
-
var
|
|
6952
|
+
var import_types29 = require("@neat.is/types");
|
|
6860
6953
|
|
|
6861
6954
|
// src/extract/calls/http.ts
|
|
6862
6955
|
init_cjs_shims();
|
|
@@ -6864,7 +6957,7 @@ var import_node_path27 = __toESM(require("path"), 1);
|
|
|
6864
6957
|
var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
|
|
6865
6958
|
var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
|
|
6866
6959
|
var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
|
|
6867
|
-
var
|
|
6960
|
+
var import_types17 = require("@neat.is/types");
|
|
6868
6961
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
6869
6962
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
6870
6963
|
function isInsideJsxExternalLink(node) {
|
|
@@ -6950,7 +7043,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
6950
7043
|
const dedupKey = `${relFile}|${targetId}`;
|
|
6951
7044
|
if (seen.has(dedupKey)) continue;
|
|
6952
7045
|
seen.add(dedupKey);
|
|
6953
|
-
const confidence = (0,
|
|
7046
|
+
const confidence = (0, import_types17.confidenceForExtracted)("url-literal-service-target");
|
|
6954
7047
|
const ev = {
|
|
6955
7048
|
file: relFile,
|
|
6956
7049
|
line: site.line,
|
|
@@ -6964,25 +7057,25 @@ async function addHttpCallEdges(graph, services) {
|
|
|
6964
7057
|
);
|
|
6965
7058
|
nodesAdded += n;
|
|
6966
7059
|
edgesAdded += e;
|
|
6967
|
-
if (!(0,
|
|
7060
|
+
if (!(0, import_types17.passesExtractedFloor)(confidence)) {
|
|
6968
7061
|
noteExtractedDropped({
|
|
6969
7062
|
source: fileNodeId,
|
|
6970
7063
|
target: targetId,
|
|
6971
|
-
type:
|
|
7064
|
+
type: import_types17.EdgeType.CALLS,
|
|
6972
7065
|
confidence,
|
|
6973
7066
|
confidenceKind: "url-literal-service-target",
|
|
6974
7067
|
evidence: ev
|
|
6975
7068
|
});
|
|
6976
7069
|
continue;
|
|
6977
7070
|
}
|
|
6978
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId,
|
|
7071
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId, import_types17.EdgeType.CALLS);
|
|
6979
7072
|
if (!graph.hasEdge(edgeId)) {
|
|
6980
7073
|
const edge = {
|
|
6981
7074
|
id: edgeId,
|
|
6982
7075
|
source: fileNodeId,
|
|
6983
7076
|
target: targetId,
|
|
6984
|
-
type:
|
|
6985
|
-
provenance:
|
|
7077
|
+
type: import_types17.EdgeType.CALLS,
|
|
7078
|
+
provenance: import_types17.Provenance.EXTRACTED,
|
|
6986
7079
|
confidence,
|
|
6987
7080
|
evidence: ev
|
|
6988
7081
|
};
|
|
@@ -7000,7 +7093,7 @@ init_cjs_shims();
|
|
|
7000
7093
|
var import_node_path28 = __toESM(require("path"), 1);
|
|
7001
7094
|
var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
|
|
7002
7095
|
var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
|
|
7003
|
-
var
|
|
7096
|
+
var import_types18 = require("@neat.is/types");
|
|
7004
7097
|
var PARSE_CHUNK5 = 16384;
|
|
7005
7098
|
function parseSource5(parser, source) {
|
|
7006
7099
|
return parser.parse(
|
|
@@ -7165,9 +7258,9 @@ function buildRouteIndex(graph) {
|
|
|
7165
7258
|
const index = /* @__PURE__ */ new Map();
|
|
7166
7259
|
graph.forEachNode((_id, attrs) => {
|
|
7167
7260
|
const node = attrs;
|
|
7168
|
-
if (node.type !==
|
|
7261
|
+
if (node.type !== import_types18.NodeType.RouteNode) return;
|
|
7169
7262
|
const route = attrs;
|
|
7170
|
-
const owner = (0,
|
|
7263
|
+
const owner = (0, import_types18.serviceId)(route.service);
|
|
7171
7264
|
const entry = {
|
|
7172
7265
|
method: route.method.toUpperCase(),
|
|
7173
7266
|
normalizedPath: normalizePathTemplate(route.pathTemplate),
|
|
@@ -7225,7 +7318,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
7225
7318
|
);
|
|
7226
7319
|
nodesAdded += n;
|
|
7227
7320
|
edgesAdded += e;
|
|
7228
|
-
const confidence = (0,
|
|
7321
|
+
const confidence = (0, import_types18.confidenceForExtracted)("verified-call-site");
|
|
7229
7322
|
const ev = {
|
|
7230
7323
|
file: relFile,
|
|
7231
7324
|
line: site.line,
|
|
@@ -7233,25 +7326,25 @@ async function addRouteCallEdges(graph, services) {
|
|
|
7233
7326
|
method: site.method ?? match.method,
|
|
7234
7327
|
pathTemplate: site.pathTemplate
|
|
7235
7328
|
};
|
|
7236
|
-
if (!(0,
|
|
7329
|
+
if (!(0, import_types18.passesExtractedFloor)(confidence)) {
|
|
7237
7330
|
noteExtractedDropped({
|
|
7238
7331
|
source: fileNodeId,
|
|
7239
7332
|
target: match.routeNodeId,
|
|
7240
|
-
type:
|
|
7333
|
+
type: import_types18.EdgeType.CALLS,
|
|
7241
7334
|
confidence,
|
|
7242
7335
|
confidenceKind: "verified-call-site",
|
|
7243
7336
|
evidence: ev
|
|
7244
7337
|
});
|
|
7245
7338
|
continue;
|
|
7246
7339
|
}
|
|
7247
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId,
|
|
7340
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId, import_types18.EdgeType.CALLS);
|
|
7248
7341
|
if (!graph.hasEdge(edgeId)) {
|
|
7249
7342
|
const edge = {
|
|
7250
7343
|
id: edgeId,
|
|
7251
7344
|
source: fileNodeId,
|
|
7252
7345
|
target: match.routeNodeId,
|
|
7253
|
-
type:
|
|
7254
|
-
provenance:
|
|
7346
|
+
type: import_types18.EdgeType.CALLS,
|
|
7347
|
+
provenance: import_types18.Provenance.EXTRACTED,
|
|
7255
7348
|
confidence,
|
|
7256
7349
|
evidence: ev
|
|
7257
7350
|
};
|
|
@@ -7267,7 +7360,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
7267
7360
|
// src/extract/calls/kafka.ts
|
|
7268
7361
|
init_cjs_shims();
|
|
7269
7362
|
var import_node_path29 = __toESM(require("path"), 1);
|
|
7270
|
-
var
|
|
7363
|
+
var import_types19 = require("@neat.is/types");
|
|
7271
7364
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
7272
7365
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
7273
7366
|
function findAll(re, text) {
|
|
@@ -7288,7 +7381,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
7288
7381
|
seen.add(key);
|
|
7289
7382
|
const line = lineOf(file.content, topic);
|
|
7290
7383
|
out.push({
|
|
7291
|
-
infraId: (0,
|
|
7384
|
+
infraId: (0, import_types19.infraId)("kafka-topic", topic),
|
|
7292
7385
|
name: topic,
|
|
7293
7386
|
kind: "kafka-topic",
|
|
7294
7387
|
edgeType,
|
|
@@ -7311,7 +7404,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
7311
7404
|
// src/extract/calls/redis.ts
|
|
7312
7405
|
init_cjs_shims();
|
|
7313
7406
|
var import_node_path30 = __toESM(require("path"), 1);
|
|
7314
|
-
var
|
|
7407
|
+
var import_types20 = require("@neat.is/types");
|
|
7315
7408
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
7316
7409
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
7317
7410
|
const out = [];
|
|
@@ -7324,7 +7417,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
7324
7417
|
seen.add(host);
|
|
7325
7418
|
const line = lineOf(file.content, host);
|
|
7326
7419
|
out.push({
|
|
7327
|
-
infraId: (0,
|
|
7420
|
+
infraId: (0, import_types20.infraId)("redis", host),
|
|
7328
7421
|
name: host,
|
|
7329
7422
|
kind: "redis",
|
|
7330
7423
|
edgeType: "CALLS",
|
|
@@ -7345,7 +7438,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
7345
7438
|
// src/extract/calls/aws.ts
|
|
7346
7439
|
init_cjs_shims();
|
|
7347
7440
|
var import_node_path31 = __toESM(require("path"), 1);
|
|
7348
|
-
var
|
|
7441
|
+
var import_types21 = require("@neat.is/types");
|
|
7349
7442
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
7350
7443
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
7351
7444
|
function hasMarker(text, markers) {
|
|
@@ -7369,7 +7462,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
7369
7462
|
seen.add(key);
|
|
7370
7463
|
const line = lineOf(file.content, name);
|
|
7371
7464
|
out.push({
|
|
7372
|
-
infraId: (0,
|
|
7465
|
+
infraId: (0, import_types21.infraId)(kind, name),
|
|
7373
7466
|
name,
|
|
7374
7467
|
kind,
|
|
7375
7468
|
edgeType: "CALLS",
|
|
@@ -7404,7 +7497,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
7404
7497
|
// src/extract/calls/grpc.ts
|
|
7405
7498
|
init_cjs_shims();
|
|
7406
7499
|
var import_node_path32 = __toESM(require("path"), 1);
|
|
7407
|
-
var
|
|
7500
|
+
var import_types22 = require("@neat.is/types");
|
|
7408
7501
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
7409
7502
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
7410
7503
|
var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
|
|
@@ -7453,7 +7546,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
7453
7546
|
const { kind } = classified;
|
|
7454
7547
|
const line = lineOf(file.content, m[0]);
|
|
7455
7548
|
out.push({
|
|
7456
|
-
infraId: (0,
|
|
7549
|
+
infraId: (0, import_types22.infraId)(kind, name),
|
|
7457
7550
|
name,
|
|
7458
7551
|
kind,
|
|
7459
7552
|
edgeType: "CALLS",
|
|
@@ -7474,7 +7567,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
7474
7567
|
// src/extract/calls/supabase.ts
|
|
7475
7568
|
init_cjs_shims();
|
|
7476
7569
|
var import_node_path33 = __toESM(require("path"), 1);
|
|
7477
|
-
var
|
|
7570
|
+
var import_types23 = require("@neat.is/types");
|
|
7478
7571
|
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
7479
7572
|
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
7480
7573
|
var SUPABASE_CLIENT_RE = /\b(createClient|createServerClient|createBrowserClient)\s*\(\s*(?:['"`]([^'"`]*)['"`])?/g;
|
|
@@ -7522,7 +7615,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
7522
7615
|
seen.add(name);
|
|
7523
7616
|
const line = lineOf(file.content, m[0]);
|
|
7524
7617
|
out.push({
|
|
7525
|
-
infraId: (0,
|
|
7618
|
+
infraId: (0, import_types23.infraId)("supabase", name),
|
|
7526
7619
|
name,
|
|
7527
7620
|
kind: "supabase",
|
|
7528
7621
|
edgeType: "CALLS",
|
|
@@ -7553,7 +7646,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
7553
7646
|
seen.add(key);
|
|
7554
7647
|
const line = lineOf(file.content, am[0]);
|
|
7555
7648
|
out.push({
|
|
7556
|
-
infraId: (0,
|
|
7649
|
+
infraId: (0, import_types23.infraId)(kind, resource),
|
|
7557
7650
|
name: resource,
|
|
7558
7651
|
kind,
|
|
7559
7652
|
edgeType: "CALLS",
|
|
@@ -7572,7 +7665,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
7572
7665
|
// src/extract/calls/mongoose.ts
|
|
7573
7666
|
init_cjs_shims();
|
|
7574
7667
|
var import_node_path34 = __toESM(require("path"), 1);
|
|
7575
|
-
var
|
|
7668
|
+
var import_types24 = require("@neat.is/types");
|
|
7576
7669
|
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
7577
7670
|
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
7578
7671
|
var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
|
|
@@ -7717,7 +7810,7 @@ function collectModelDefs(content, pluralizeOn) {
|
|
|
7717
7810
|
function endpoint(r, file, serviceDir, matchText) {
|
|
7718
7811
|
const line = lineOf(file.content, matchText);
|
|
7719
7812
|
return {
|
|
7720
|
-
infraId: (0,
|
|
7813
|
+
infraId: (0, import_types24.infraId)(r.kind, r.name),
|
|
7721
7814
|
name: r.name,
|
|
7722
7815
|
kind: r.kind,
|
|
7723
7816
|
edgeType: "CALLS",
|
|
@@ -7870,7 +7963,7 @@ init_cjs_shims();
|
|
|
7870
7963
|
var import_node_path35 = __toESM(require("path"), 1);
|
|
7871
7964
|
var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
|
|
7872
7965
|
var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
|
|
7873
|
-
var
|
|
7966
|
+
var import_types25 = require("@neat.is/types");
|
|
7874
7967
|
var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
|
|
7875
7968
|
var PARSE_CHUNK6 = 16384;
|
|
7876
7969
|
function makePyParser4() {
|
|
@@ -7930,20 +8023,57 @@ function walk3(node, visit) {
|
|
|
7930
8023
|
visit(node);
|
|
7931
8024
|
for (const c of namedChildren(node)) walk3(c, visit);
|
|
7932
8025
|
}
|
|
8026
|
+
var COLUMN_BUILDERS = /* @__PURE__ */ new Set(["Column", "mapped_column"]);
|
|
8027
|
+
function isColumnBuilder(call) {
|
|
8028
|
+
const fn = call.childForFieldName("function");
|
|
8029
|
+
const t = fn?.text;
|
|
8030
|
+
if (!t) return false;
|
|
8031
|
+
const base = t.includes(".") ? t.slice(t.lastIndexOf(".") + 1) : t;
|
|
8032
|
+
return COLUMN_BUILDERS.has(base);
|
|
8033
|
+
}
|
|
8034
|
+
function firstPositionalString(call) {
|
|
8035
|
+
const args = call.childForFieldName("arguments");
|
|
8036
|
+
if (!args) return null;
|
|
8037
|
+
for (const arg of namedChildren(args)) {
|
|
8038
|
+
if (arg.type === "keyword_argument") continue;
|
|
8039
|
+
return arg.type === "string" ? pyStaticStringText2(arg) : null;
|
|
8040
|
+
}
|
|
8041
|
+
return null;
|
|
8042
|
+
}
|
|
8043
|
+
function columnsFromClassBody(body) {
|
|
8044
|
+
const out = [];
|
|
8045
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8046
|
+
for (const stmt of namedChildren(body)) {
|
|
8047
|
+
if (stmt.type !== "expression_statement") continue;
|
|
8048
|
+
const assign = stmt.namedChild(0);
|
|
8049
|
+
if (assign?.type !== "assignment") continue;
|
|
8050
|
+
const left = assign.childForFieldName("left");
|
|
8051
|
+
if (left?.type !== "identifier") continue;
|
|
8052
|
+
const right = assign.childForFieldName("right");
|
|
8053
|
+
if (right?.type !== "call" || !isColumnBuilder(right)) continue;
|
|
8054
|
+
const name = firstPositionalString(right) ?? left.text;
|
|
8055
|
+
if (name && !seen.has(name)) {
|
|
8056
|
+
seen.add(name);
|
|
8057
|
+
out.push(name);
|
|
8058
|
+
}
|
|
8059
|
+
}
|
|
8060
|
+
return out;
|
|
8061
|
+
}
|
|
7933
8062
|
function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
7934
8063
|
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return [];
|
|
7935
8064
|
const tree = parseSource6(makePyParser4(), file.content);
|
|
7936
8065
|
const out = [];
|
|
7937
8066
|
const seen = /* @__PURE__ */ new Set();
|
|
7938
|
-
const push = (name, line) => {
|
|
8067
|
+
const push = (name, line, columns) => {
|
|
7939
8068
|
if (seen.has(name)) return;
|
|
7940
8069
|
seen.add(name);
|
|
7941
8070
|
out.push({
|
|
7942
|
-
infraId: (0,
|
|
8071
|
+
infraId: (0, import_types25.infraId)("sql-table", name),
|
|
7943
8072
|
name,
|
|
7944
8073
|
kind: "sql-table",
|
|
7945
8074
|
edgeType: "CALLS",
|
|
7946
8075
|
confidenceKind: "verified-call-site",
|
|
8076
|
+
...columns && columns.length > 0 ? { columns } : {},
|
|
7947
8077
|
evidence: {
|
|
7948
8078
|
file: import_node_path35.default.relative(serviceDir, file.path),
|
|
7949
8079
|
line,
|
|
@@ -7959,11 +8089,12 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
7959
8089
|
const line = node.startPosition.row + 1;
|
|
7960
8090
|
const explicit = explicitTablename(body);
|
|
7961
8091
|
if (explicit === "computed") return;
|
|
8092
|
+
const columns = columnsFromClassBody(body);
|
|
7962
8093
|
if (explicit) {
|
|
7963
|
-
push(explicit.name, line);
|
|
8094
|
+
push(explicit.name, line, columns);
|
|
7964
8095
|
return;
|
|
7965
8096
|
}
|
|
7966
|
-
if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line);
|
|
8097
|
+
if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line, columns);
|
|
7967
8098
|
return;
|
|
7968
8099
|
}
|
|
7969
8100
|
if (node.type === "call") {
|
|
@@ -8045,7 +8176,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
8045
8176
|
if (seen.has(key)) continue;
|
|
8046
8177
|
seen.add(key);
|
|
8047
8178
|
out.push({
|
|
8048
|
-
infraId: (0,
|
|
8179
|
+
infraId: (0, import_types25.infraId)("sql-table", t),
|
|
8049
8180
|
name: t,
|
|
8050
8181
|
kind: "sql-table",
|
|
8051
8182
|
edgeType: "CALLS",
|
|
@@ -8066,7 +8197,7 @@ init_cjs_shims();
|
|
|
8066
8197
|
var import_node_path36 = __toESM(require("path"), 1);
|
|
8067
8198
|
var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
|
|
8068
8199
|
var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
8069
|
-
var
|
|
8200
|
+
var import_types26 = require("@neat.is/types");
|
|
8070
8201
|
var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
|
|
8071
8202
|
var PARSE_CHUNK7 = 16384;
|
|
8072
8203
|
function makePyParser5() {
|
|
@@ -8146,7 +8277,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
8146
8277
|
seen.add(table);
|
|
8147
8278
|
const line = node.startPosition.row + 1;
|
|
8148
8279
|
out.push({
|
|
8149
|
-
infraId: (0,
|
|
8280
|
+
infraId: (0, import_types26.infraId)("sql-table", table),
|
|
8150
8281
|
name: table,
|
|
8151
8282
|
kind: "sql-table",
|
|
8152
8283
|
edgeType: "CALLS",
|
|
@@ -8157,12 +8288,129 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
8157
8288
|
return out;
|
|
8158
8289
|
}
|
|
8159
8290
|
|
|
8160
|
-
// src/extract/calls/
|
|
8291
|
+
// src/extract/calls/drizzle.ts
|
|
8161
8292
|
init_cjs_shims();
|
|
8162
|
-
var
|
|
8293
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
8163
8294
|
var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
|
|
8295
|
+
var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
|
|
8296
|
+
var import_types27 = require("@neat.is/types");
|
|
8297
|
+
var DRIZZLE_IMPORT_RE = /drizzle-orm/;
|
|
8298
|
+
var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
|
|
8299
|
+
function parserForExt(ext) {
|
|
8300
|
+
const p = new import_tree_sitter9.default();
|
|
8301
|
+
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript6.default);
|
|
8302
|
+
return p;
|
|
8303
|
+
}
|
|
8304
|
+
function namedChildren3(node) {
|
|
8305
|
+
const out = [];
|
|
8306
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8307
|
+
const c = node.namedChild(i);
|
|
8308
|
+
if (c) out.push(c);
|
|
8309
|
+
}
|
|
8310
|
+
return out;
|
|
8311
|
+
}
|
|
8312
|
+
function stringLiteralText2(node) {
|
|
8313
|
+
if (!node || node.type !== "string") return null;
|
|
8314
|
+
for (const child of namedChildren3(node)) {
|
|
8315
|
+
if (child.type === "string_fragment") return child.text;
|
|
8316
|
+
}
|
|
8317
|
+
return "";
|
|
8318
|
+
}
|
|
8319
|
+
function firstStringArg(call) {
|
|
8320
|
+
const args = call.childForFieldName("arguments");
|
|
8321
|
+
if (!args) return null;
|
|
8322
|
+
for (const arg of namedChildren3(args)) {
|
|
8323
|
+
if (arg.type === "string") return stringLiteralText2(arg);
|
|
8324
|
+
return null;
|
|
8325
|
+
}
|
|
8326
|
+
return null;
|
|
8327
|
+
}
|
|
8328
|
+
function builderColumnName(value) {
|
|
8329
|
+
let node = value;
|
|
8330
|
+
while (node) {
|
|
8331
|
+
if (node.type === "call_expression") {
|
|
8332
|
+
const fn = node.childForFieldName("function");
|
|
8333
|
+
if (fn?.type === "identifier") return firstStringArg(node);
|
|
8334
|
+
if (fn?.type === "member_expression") {
|
|
8335
|
+
node = fn.childForFieldName("object");
|
|
8336
|
+
continue;
|
|
8337
|
+
}
|
|
8338
|
+
return null;
|
|
8339
|
+
}
|
|
8340
|
+
if (node.type === "member_expression") {
|
|
8341
|
+
node = node.childForFieldName("object");
|
|
8342
|
+
continue;
|
|
8343
|
+
}
|
|
8344
|
+
return null;
|
|
8345
|
+
}
|
|
8346
|
+
return null;
|
|
8347
|
+
}
|
|
8348
|
+
function keyName(key) {
|
|
8349
|
+
if (!key) return null;
|
|
8350
|
+
if (key.type === "property_identifier") return key.text;
|
|
8351
|
+
if (key.type === "string") return stringLiteralText2(key);
|
|
8352
|
+
return null;
|
|
8353
|
+
}
|
|
8354
|
+
function columnsFromObject(obj) {
|
|
8355
|
+
const out = [];
|
|
8356
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8357
|
+
for (const child of namedChildren3(obj)) {
|
|
8358
|
+
if (child.type !== "pair") continue;
|
|
8359
|
+
const value = child.childForFieldName("value");
|
|
8360
|
+
const key = keyName(child.childForFieldName("key"));
|
|
8361
|
+
const name = (value ? builderColumnName(value) : null) ?? key;
|
|
8362
|
+
if (name && !seen.has(name)) {
|
|
8363
|
+
seen.add(name);
|
|
8364
|
+
out.push(name);
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
return out;
|
|
8368
|
+
}
|
|
8369
|
+
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
8370
|
+
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
8371
|
+
const tree = parseSource2(parserForExt(import_node_path37.default.extname(file.path)), file.content);
|
|
8372
|
+
const out = [];
|
|
8373
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8374
|
+
const walk6 = (node) => {
|
|
8375
|
+
if (node.type === "call_expression") {
|
|
8376
|
+
const fn = node.childForFieldName("function");
|
|
8377
|
+
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
8378
|
+
const args = node.childForFieldName("arguments");
|
|
8379
|
+
const argNodes = args ? namedChildren3(args) : [];
|
|
8380
|
+
const tableName = stringLiteralText2(argNodes[0] ?? null);
|
|
8381
|
+
const obj = argNodes[1];
|
|
8382
|
+
if (tableName && obj?.type === "object" && !seen.has(tableName)) {
|
|
8383
|
+
seen.add(tableName);
|
|
8384
|
+
const columns = columnsFromObject(obj);
|
|
8385
|
+
const line = node.startPosition.row + 1;
|
|
8386
|
+
out.push({
|
|
8387
|
+
infraId: (0, import_types27.infraId)("sql-table", tableName),
|
|
8388
|
+
name: tableName,
|
|
8389
|
+
kind: "sql-table",
|
|
8390
|
+
edgeType: "CALLS",
|
|
8391
|
+
confidenceKind: "structural",
|
|
8392
|
+
columns,
|
|
8393
|
+
evidence: {
|
|
8394
|
+
file: import_node_path37.default.relative(serviceDir, file.path),
|
|
8395
|
+
line,
|
|
8396
|
+
snippet: snippet(file.content, line)
|
|
8397
|
+
}
|
|
8398
|
+
});
|
|
8399
|
+
}
|
|
8400
|
+
}
|
|
8401
|
+
}
|
|
8402
|
+
for (const c of namedChildren3(node)) walk6(c);
|
|
8403
|
+
};
|
|
8404
|
+
walk6(tree.rootNode);
|
|
8405
|
+
return out;
|
|
8406
|
+
}
|
|
8407
|
+
|
|
8408
|
+
// src/extract/calls/go.ts
|
|
8409
|
+
init_cjs_shims();
|
|
8410
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
8411
|
+
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
8164
8412
|
var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
|
|
8165
|
-
var
|
|
8413
|
+
var import_types28 = require("@neat.is/types");
|
|
8166
8414
|
init_otel();
|
|
8167
8415
|
var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
|
|
8168
8416
|
var PARSE_CHUNK8 = 16384;
|
|
@@ -8174,8 +8422,8 @@ function walk5(node, visit) {
|
|
|
8174
8422
|
}
|
|
8175
8423
|
}
|
|
8176
8424
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
8177
|
-
if (
|
|
8178
|
-
const parser = new
|
|
8425
|
+
if (import_node_path40.default.extname(file.path) !== ".go") return [];
|
|
8426
|
+
const parser = new import_tree_sitter10.default();
|
|
8179
8427
|
parser.setLanguage(import_tree_sitter_go3.default);
|
|
8180
8428
|
const tree = parser.parse(
|
|
8181
8429
|
(index) => index >= file.content.length ? "" : file.content.slice(index, index + PARSE_CHUNK8)
|
|
@@ -8194,12 +8442,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8194
8442
|
if (!table) return;
|
|
8195
8443
|
const line = node.startPosition.row + 1;
|
|
8196
8444
|
out.push({
|
|
8197
|
-
infraId: (0,
|
|
8445
|
+
infraId: (0, import_types28.infraId)("sql-table", table),
|
|
8198
8446
|
name: table,
|
|
8199
8447
|
kind: "sql-table",
|
|
8200
8448
|
edgeType: "CALLS",
|
|
8201
8449
|
confidenceKind: "verified-call-site",
|
|
8202
|
-
evidence: { file: toPosix(
|
|
8450
|
+
evidence: { file: toPosix(import_node_path40.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
|
|
8203
8451
|
});
|
|
8204
8452
|
});
|
|
8205
8453
|
return out;
|
|
@@ -8209,11 +8457,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8209
8457
|
function edgeTypeFromEndpoint(ep) {
|
|
8210
8458
|
switch (ep.edgeType) {
|
|
8211
8459
|
case "PUBLISHES_TO":
|
|
8212
|
-
return
|
|
8460
|
+
return import_types29.EdgeType.PUBLISHES_TO;
|
|
8213
8461
|
case "CONSUMES_FROM":
|
|
8214
|
-
return
|
|
8462
|
+
return import_types29.EdgeType.CONSUMES_FROM;
|
|
8215
8463
|
default:
|
|
8216
|
-
return
|
|
8464
|
+
return import_types29.EdgeType.CALLS;
|
|
8217
8465
|
}
|
|
8218
8466
|
}
|
|
8219
8467
|
function isAwsKind(kind) {
|
|
@@ -8239,6 +8487,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8239
8487
|
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
8240
8488
|
endpoints.push(...sqlalchemyEndpointsFromFile(maskedFile, service.dir));
|
|
8241
8489
|
endpoints.push(...djangoOrmEndpointsFromFile(maskedFile, service.dir));
|
|
8490
|
+
endpoints.push(...drizzleEndpointsFromFile(maskedFile, service.dir));
|
|
8242
8491
|
try {
|
|
8243
8492
|
endpoints.push(...goSqlEndpointsFromFile(maskedFile, service.dir));
|
|
8244
8493
|
} catch (err) {
|
|
@@ -8253,7 +8502,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8253
8502
|
if (!graph.hasNode(ep.infraId)) {
|
|
8254
8503
|
const node = {
|
|
8255
8504
|
id: ep.infraId,
|
|
8256
|
-
type:
|
|
8505
|
+
type: import_types29.NodeType.InfraNode,
|
|
8257
8506
|
name: ep.name,
|
|
8258
8507
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
8259
8508
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -8264,8 +8513,22 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8264
8513
|
graph.addNode(node.id, node);
|
|
8265
8514
|
nodesAdded++;
|
|
8266
8515
|
}
|
|
8516
|
+
if (ep.columns && ep.columns.length > 0) {
|
|
8517
|
+
const node = graph.getNodeAttributes(ep.infraId);
|
|
8518
|
+
if (node.type === import_types29.NodeType.InfraNode) {
|
|
8519
|
+
graph.replaceNodeAttributes(ep.infraId, {
|
|
8520
|
+
...node,
|
|
8521
|
+
columns: foldColumns(
|
|
8522
|
+
node.columns,
|
|
8523
|
+
ep.columns,
|
|
8524
|
+
import_types29.Provenance.EXTRACTED,
|
|
8525
|
+
(0, import_types29.confidenceForExtracted)(ep.confidenceKind)
|
|
8526
|
+
)
|
|
8527
|
+
});
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8267
8530
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
8268
|
-
const confidence = (0,
|
|
8531
|
+
const confidence = (0, import_types29.confidenceForExtracted)(ep.confidenceKind);
|
|
8269
8532
|
const relFile = toPosix(ep.evidence.file);
|
|
8270
8533
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
8271
8534
|
graph,
|
|
@@ -8275,7 +8538,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8275
8538
|
);
|
|
8276
8539
|
nodesAdded += n;
|
|
8277
8540
|
edgesAdded += e;
|
|
8278
|
-
if (!(0,
|
|
8541
|
+
if (!(0, import_types29.passesExtractedFloor)(confidence)) {
|
|
8279
8542
|
noteExtractedDropped({
|
|
8280
8543
|
source: fileNodeId,
|
|
8281
8544
|
target: ep.infraId,
|
|
@@ -8295,7 +8558,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8295
8558
|
source: fileNodeId,
|
|
8296
8559
|
target: ep.infraId,
|
|
8297
8560
|
type: edgeType,
|
|
8298
|
-
provenance:
|
|
8561
|
+
provenance: import_types29.Provenance.EXTRACTED,
|
|
8299
8562
|
confidence,
|
|
8300
8563
|
evidence: ep.evidence
|
|
8301
8564
|
};
|
|
@@ -8321,16 +8584,16 @@ init_cjs_shims();
|
|
|
8321
8584
|
|
|
8322
8585
|
// src/extract/infra/docker-compose.ts
|
|
8323
8586
|
init_cjs_shims();
|
|
8324
|
-
var
|
|
8325
|
-
var
|
|
8587
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
8588
|
+
var import_types31 = require("@neat.is/types");
|
|
8326
8589
|
|
|
8327
8590
|
// src/extract/infra/shared.ts
|
|
8328
8591
|
init_cjs_shims();
|
|
8329
|
-
var
|
|
8592
|
+
var import_types30 = require("@neat.is/types");
|
|
8330
8593
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
8331
8594
|
return {
|
|
8332
|
-
id: (0,
|
|
8333
|
-
type:
|
|
8595
|
+
id: (0, import_types30.infraId)(kind, name),
|
|
8596
|
+
type: import_types30.NodeType.InfraNode,
|
|
8334
8597
|
name,
|
|
8335
8598
|
provider,
|
|
8336
8599
|
kind,
|
|
@@ -8374,8 +8637,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
8374
8637
|
source: anchorId,
|
|
8375
8638
|
target: node.id,
|
|
8376
8639
|
type: edgeType,
|
|
8377
|
-
provenance:
|
|
8378
|
-
confidence: (0,
|
|
8640
|
+
provenance: import_types30.Provenance.EXTRACTED,
|
|
8641
|
+
confidence: (0, import_types30.confidenceForExtracted)("structural"),
|
|
8379
8642
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
8380
8643
|
};
|
|
8381
8644
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8392,7 +8655,7 @@ function dependsOnList(value) {
|
|
|
8392
8655
|
}
|
|
8393
8656
|
function serviceNameToServiceNode(name, services) {
|
|
8394
8657
|
for (const s of services) {
|
|
8395
|
-
if (s.node.name === name ||
|
|
8658
|
+
if (s.node.name === name || import_node_path41.default.basename(s.dir) === name) return s.node.id;
|
|
8396
8659
|
}
|
|
8397
8660
|
return null;
|
|
8398
8661
|
}
|
|
@@ -8401,7 +8664,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8401
8664
|
let edgesAdded = 0;
|
|
8402
8665
|
let composePath = null;
|
|
8403
8666
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
8404
|
-
const abs =
|
|
8667
|
+
const abs = import_node_path41.default.join(scanPath, name);
|
|
8405
8668
|
if (await exists(abs)) {
|
|
8406
8669
|
composePath = abs;
|
|
8407
8670
|
break;
|
|
@@ -8414,13 +8677,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8414
8677
|
} catch (err) {
|
|
8415
8678
|
recordExtractionError(
|
|
8416
8679
|
"infra docker-compose",
|
|
8417
|
-
|
|
8680
|
+
import_node_path41.default.relative(scanPath, composePath),
|
|
8418
8681
|
err
|
|
8419
8682
|
);
|
|
8420
8683
|
return { nodesAdded, edgesAdded };
|
|
8421
8684
|
}
|
|
8422
8685
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
8423
|
-
const evidenceFile =
|
|
8686
|
+
const evidenceFile = import_node_path41.default.relative(scanPath, composePath).split(import_node_path41.default.sep).join("/");
|
|
8424
8687
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
8425
8688
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
8426
8689
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -8442,15 +8705,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8442
8705
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
8443
8706
|
const targetId = composeNameToNodeId.get(dep);
|
|
8444
8707
|
if (!targetId) continue;
|
|
8445
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
8708
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types31.EdgeType.DEPENDS_ON);
|
|
8446
8709
|
if (graph.hasEdge(edgeId)) continue;
|
|
8447
8710
|
const edge = {
|
|
8448
8711
|
id: edgeId,
|
|
8449
8712
|
source: sourceId,
|
|
8450
8713
|
target: targetId,
|
|
8451
|
-
type:
|
|
8452
|
-
provenance:
|
|
8453
|
-
confidence: (0,
|
|
8714
|
+
type: import_types31.EdgeType.DEPENDS_ON,
|
|
8715
|
+
provenance: import_types31.Provenance.EXTRACTED,
|
|
8716
|
+
confidence: (0, import_types31.confidenceForExtracted)("structural"),
|
|
8454
8717
|
evidence: { file: evidenceFile }
|
|
8455
8718
|
};
|
|
8456
8719
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8462,9 +8725,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8462
8725
|
|
|
8463
8726
|
// src/extract/infra/dockerfile.ts
|
|
8464
8727
|
init_cjs_shims();
|
|
8465
|
-
var
|
|
8728
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8466
8729
|
var import_node_fs17 = require("fs");
|
|
8467
|
-
var
|
|
8730
|
+
var import_types32 = require("@neat.is/types");
|
|
8468
8731
|
function readDockerfile(content) {
|
|
8469
8732
|
let image = null;
|
|
8470
8733
|
const ports = [];
|
|
@@ -8493,7 +8756,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8493
8756
|
let nodesAdded = 0;
|
|
8494
8757
|
let edgesAdded = 0;
|
|
8495
8758
|
for (const service of services) {
|
|
8496
|
-
const dockerfilePath =
|
|
8759
|
+
const dockerfilePath = import_node_path42.default.join(service.dir, "Dockerfile");
|
|
8497
8760
|
if (!await exists(dockerfilePath)) continue;
|
|
8498
8761
|
let content;
|
|
8499
8762
|
try {
|
|
@@ -8501,7 +8764,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8501
8764
|
} catch (err) {
|
|
8502
8765
|
recordExtractionError(
|
|
8503
8766
|
"infra dockerfile",
|
|
8504
|
-
|
|
8767
|
+
import_node_path42.default.relative(scanPath, dockerfilePath),
|
|
8505
8768
|
err
|
|
8506
8769
|
);
|
|
8507
8770
|
continue;
|
|
@@ -8513,8 +8776,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8513
8776
|
graph.addNode(node.id, node);
|
|
8514
8777
|
nodesAdded++;
|
|
8515
8778
|
}
|
|
8516
|
-
const relDockerfile = toPosix(
|
|
8517
|
-
const evidenceFile = toPosix(
|
|
8779
|
+
const relDockerfile = toPosix(import_node_path42.default.relative(service.dir, dockerfilePath));
|
|
8780
|
+
const evidenceFile = toPosix(import_node_path42.default.relative(scanPath, dockerfilePath));
|
|
8518
8781
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
8519
8782
|
graph,
|
|
8520
8783
|
service.pkg.name,
|
|
@@ -8523,15 +8786,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8523
8786
|
);
|
|
8524
8787
|
nodesAdded += fn;
|
|
8525
8788
|
edgesAdded += fe;
|
|
8526
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
8789
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types32.EdgeType.RUNS_ON);
|
|
8527
8790
|
if (!graph.hasEdge(edgeId)) {
|
|
8528
8791
|
const edge = {
|
|
8529
8792
|
id: edgeId,
|
|
8530
8793
|
source: fileNodeId,
|
|
8531
8794
|
target: node.id,
|
|
8532
|
-
type:
|
|
8533
|
-
provenance:
|
|
8534
|
-
confidence: (0,
|
|
8795
|
+
type: import_types32.EdgeType.RUNS_ON,
|
|
8796
|
+
provenance: import_types32.Provenance.EXTRACTED,
|
|
8797
|
+
confidence: (0, import_types32.confidenceForExtracted)("structural"),
|
|
8535
8798
|
evidence: {
|
|
8536
8799
|
file: evidenceFile,
|
|
8537
8800
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -8546,15 +8809,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8546
8809
|
graph.addNode(portNode.id, portNode);
|
|
8547
8810
|
nodesAdded++;
|
|
8548
8811
|
}
|
|
8549
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
8812
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types32.EdgeType.CONNECTS_TO);
|
|
8550
8813
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
8551
8814
|
const portEdge = {
|
|
8552
8815
|
id: portEdgeId,
|
|
8553
8816
|
source: fileNodeId,
|
|
8554
8817
|
target: portNode.id,
|
|
8555
|
-
type:
|
|
8556
|
-
provenance:
|
|
8557
|
-
confidence: (0,
|
|
8818
|
+
type: import_types32.EdgeType.CONNECTS_TO,
|
|
8819
|
+
provenance: import_types32.Provenance.EXTRACTED,
|
|
8820
|
+
confidence: (0, import_types32.confidenceForExtracted)("structural"),
|
|
8558
8821
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
8559
8822
|
};
|
|
8560
8823
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -8567,8 +8830,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8567
8830
|
// src/extract/infra/terraform.ts
|
|
8568
8831
|
init_cjs_shims();
|
|
8569
8832
|
var import_node_fs18 = require("fs");
|
|
8570
|
-
var
|
|
8571
|
-
var
|
|
8833
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
8834
|
+
var import_types33 = require("@neat.is/types");
|
|
8572
8835
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
8573
8836
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
8574
8837
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -8578,11 +8841,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
8578
8841
|
for (const entry of entries) {
|
|
8579
8842
|
if (entry.isDirectory()) {
|
|
8580
8843
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
8581
|
-
const child =
|
|
8844
|
+
const child = import_node_path43.default.join(start, entry.name);
|
|
8582
8845
|
if (await isPythonVenvDir(child)) continue;
|
|
8583
8846
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
8584
8847
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
8585
|
-
out.push(
|
|
8848
|
+
out.push(import_node_path43.default.join(start, entry.name));
|
|
8586
8849
|
}
|
|
8587
8850
|
}
|
|
8588
8851
|
return out;
|
|
@@ -8614,7 +8877,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8614
8877
|
const files = await walkTfFiles(scanPath);
|
|
8615
8878
|
for (const file of files) {
|
|
8616
8879
|
const content = await import_node_fs18.promises.readFile(file, "utf8");
|
|
8617
|
-
const evidenceFile = toPosix(
|
|
8880
|
+
const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, file));
|
|
8618
8881
|
const resources = [];
|
|
8619
8882
|
const byKey = /* @__PURE__ */ new Map();
|
|
8620
8883
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -8649,16 +8912,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8649
8912
|
if (!target) continue;
|
|
8650
8913
|
if (seen.has(target.nodeId)) continue;
|
|
8651
8914
|
seen.add(target.nodeId);
|
|
8652
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
8915
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types33.EdgeType.DEPENDS_ON);
|
|
8653
8916
|
if (graph.hasEdge(edgeId)) continue;
|
|
8654
8917
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
8655
8918
|
const edge = {
|
|
8656
8919
|
id: edgeId,
|
|
8657
8920
|
source: resource.nodeId,
|
|
8658
8921
|
target: target.nodeId,
|
|
8659
|
-
type:
|
|
8660
|
-
provenance:
|
|
8661
|
-
confidence: (0,
|
|
8922
|
+
type: import_types33.EdgeType.DEPENDS_ON,
|
|
8923
|
+
provenance: import_types33.Provenance.EXTRACTED,
|
|
8924
|
+
confidence: (0, import_types33.confidenceForExtracted)("structural"),
|
|
8662
8925
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
8663
8926
|
};
|
|
8664
8927
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8672,7 +8935,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8672
8935
|
// src/extract/infra/k8s.ts
|
|
8673
8936
|
init_cjs_shims();
|
|
8674
8937
|
var import_node_fs19 = require("fs");
|
|
8675
|
-
var
|
|
8938
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8676
8939
|
var import_yaml3 = require("yaml");
|
|
8677
8940
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
8678
8941
|
Service: "k8s-service",
|
|
@@ -8690,11 +8953,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
8690
8953
|
for (const entry of entries) {
|
|
8691
8954
|
if (entry.isDirectory()) {
|
|
8692
8955
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
8693
|
-
const child =
|
|
8956
|
+
const child = import_node_path44.default.join(start, entry.name);
|
|
8694
8957
|
if (await isPythonVenvDir(child)) continue;
|
|
8695
8958
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
8696
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
8697
|
-
out.push(
|
|
8959
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path44.default.extname(entry.name))) {
|
|
8960
|
+
out.push(import_node_path44.default.join(start, entry.name));
|
|
8698
8961
|
}
|
|
8699
8962
|
}
|
|
8700
8963
|
return out;
|
|
@@ -8728,13 +8991,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
8728
8991
|
// src/extract/infra/cloudflare.ts
|
|
8729
8992
|
init_cjs_shims();
|
|
8730
8993
|
var import_node_fs20 = require("fs");
|
|
8731
|
-
var
|
|
8994
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8732
8995
|
var import_smol_toml2 = require("smol-toml");
|
|
8733
|
-
var
|
|
8996
|
+
var import_types34 = require("@neat.is/types");
|
|
8734
8997
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
8735
8998
|
async function readWranglerConfig(dir) {
|
|
8736
8999
|
for (const filename of WRANGLER_FILENAMES) {
|
|
8737
|
-
const abs =
|
|
9000
|
+
const abs = import_node_path45.default.join(dir, filename);
|
|
8738
9001
|
if (!await exists(abs)) continue;
|
|
8739
9002
|
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
8740
9003
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -8778,8 +9041,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
8778
9041
|
source: anchorId,
|
|
8779
9042
|
target: node.id,
|
|
8780
9043
|
type: edgeType,
|
|
8781
|
-
provenance:
|
|
8782
|
-
confidence: (0,
|
|
9044
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9045
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8783
9046
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
8784
9047
|
};
|
|
8785
9048
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8797,11 +9060,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8797
9060
|
try {
|
|
8798
9061
|
read = await readWranglerConfig(service.dir);
|
|
8799
9062
|
} catch (err) {
|
|
8800
|
-
recordExtractionError("infra cloudflare",
|
|
9063
|
+
recordExtractionError("infra cloudflare", import_node_path45.default.relative(scanPath, service.dir), err);
|
|
8801
9064
|
continue;
|
|
8802
9065
|
}
|
|
8803
9066
|
if (!read || !read.config.name) continue;
|
|
8804
|
-
const evidenceFile = toPosix(
|
|
9067
|
+
const evidenceFile = toPosix(import_node_path45.default.relative(scanPath, import_node_path45.default.join(service.dir, read.relFile)));
|
|
8805
9068
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
8806
9069
|
}
|
|
8807
9070
|
for (const worker of discovered) {
|
|
@@ -8813,7 +9076,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8813
9076
|
}
|
|
8814
9077
|
let anchorId = service.node.id;
|
|
8815
9078
|
if (config.main) {
|
|
8816
|
-
const entryRelPath = toPosix(
|
|
9079
|
+
const entryRelPath = toPosix(import_node_path45.default.normalize(config.main));
|
|
8817
9080
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
8818
9081
|
graph,
|
|
8819
9082
|
service.pkg.name,
|
|
@@ -8840,15 +9103,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8840
9103
|
nodesAdded++;
|
|
8841
9104
|
}
|
|
8842
9105
|
if (runtimeNode.id !== anchorId) {
|
|
8843
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
9106
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types34.EdgeType.RUNS_ON);
|
|
8844
9107
|
if (!graph.hasEdge(runsOnId)) {
|
|
8845
9108
|
const edge = {
|
|
8846
9109
|
id: runsOnId,
|
|
8847
9110
|
source: anchorId,
|
|
8848
9111
|
target: runtimeNode.id,
|
|
8849
|
-
type:
|
|
8850
|
-
provenance:
|
|
8851
|
-
confidence: (0,
|
|
9112
|
+
type: import_types34.EdgeType.RUNS_ON,
|
|
9113
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9114
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8852
9115
|
evidence: {
|
|
8853
9116
|
file: evidenceFile,
|
|
8854
9117
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -8862,7 +9125,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8862
9125
|
const result = addResourceEdge(
|
|
8863
9126
|
graph,
|
|
8864
9127
|
anchorId,
|
|
8865
|
-
|
|
9128
|
+
import_types34.EdgeType.CONNECTS_TO,
|
|
8866
9129
|
"cloudflare-route",
|
|
8867
9130
|
route,
|
|
8868
9131
|
evidenceFile,
|
|
@@ -8886,7 +9149,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8886
9149
|
const result = addResourceEdge(
|
|
8887
9150
|
graph,
|
|
8888
9151
|
anchorId,
|
|
8889
|
-
|
|
9152
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8890
9153
|
group.kind,
|
|
8891
9154
|
name,
|
|
8892
9155
|
evidenceFile,
|
|
@@ -8900,7 +9163,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8900
9163
|
const result = addResourceEdge(
|
|
8901
9164
|
graph,
|
|
8902
9165
|
anchorId,
|
|
8903
|
-
|
|
9166
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8904
9167
|
"cloudflare-cron",
|
|
8905
9168
|
cron,
|
|
8906
9169
|
evidenceFile,
|
|
@@ -8913,7 +9176,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8913
9176
|
const result = addResourceEdge(
|
|
8914
9177
|
graph,
|
|
8915
9178
|
anchorId,
|
|
8916
|
-
|
|
9179
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8917
9180
|
"cloudflare-env-var",
|
|
8918
9181
|
varName,
|
|
8919
9182
|
evidenceFile,
|
|
@@ -8926,15 +9189,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8926
9189
|
if (!svc.service) continue;
|
|
8927
9190
|
const target = workerIndex.get(svc.service);
|
|
8928
9191
|
if (target && target.anchorId !== anchorId) {
|
|
8929
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
9192
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types34.EdgeType.CALLS);
|
|
8930
9193
|
if (!graph.hasEdge(edgeId)) {
|
|
8931
9194
|
const edge = {
|
|
8932
9195
|
id: edgeId,
|
|
8933
9196
|
source: anchorId,
|
|
8934
9197
|
target: target.anchorId,
|
|
8935
|
-
type:
|
|
8936
|
-
provenance:
|
|
8937
|
-
confidence: (0,
|
|
9198
|
+
type: import_types34.EdgeType.CALLS,
|
|
9199
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9200
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8938
9201
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
8939
9202
|
};
|
|
8940
9203
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8945,7 +9208,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8945
9208
|
const result = addResourceEdge(
|
|
8946
9209
|
graph,
|
|
8947
9210
|
anchorId,
|
|
8948
|
-
|
|
9211
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8949
9212
|
"cloudflare-service-binding",
|
|
8950
9213
|
svc.service,
|
|
8951
9214
|
evidenceFile,
|
|
@@ -8961,12 +9224,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8961
9224
|
// src/extract/infra/vercel.ts
|
|
8962
9225
|
init_cjs_shims();
|
|
8963
9226
|
var import_node_fs21 = require("fs");
|
|
8964
|
-
var
|
|
8965
|
-
var
|
|
9227
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
9228
|
+
var import_types35 = require("@neat.is/types");
|
|
8966
9229
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
8967
9230
|
async function readVercelConfig(dir) {
|
|
8968
9231
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
8969
|
-
const abs =
|
|
9232
|
+
const abs = import_node_path46.default.join(dir, filename);
|
|
8970
9233
|
if (!await exists(abs)) continue;
|
|
8971
9234
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
8972
9235
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -8975,7 +9238,7 @@ async function readVercelConfig(dir) {
|
|
|
8975
9238
|
return null;
|
|
8976
9239
|
}
|
|
8977
9240
|
async function readLinkedProjectName(dir) {
|
|
8978
|
-
const abs =
|
|
9241
|
+
const abs = import_node_path46.default.join(dir, ".vercel", "project.json");
|
|
8979
9242
|
if (!await exists(abs)) return void 0;
|
|
8980
9243
|
const parsed = JSON.parse(await import_node_fs21.promises.readFile(abs, "utf8"));
|
|
8981
9244
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -8993,7 +9256,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
8993
9256
|
read = await readVercelConfig(service.dir);
|
|
8994
9257
|
projectName = await readLinkedProjectName(service.dir);
|
|
8995
9258
|
} catch (err) {
|
|
8996
|
-
recordExtractionError("infra vercel",
|
|
9259
|
+
recordExtractionError("infra vercel", import_node_path46.default.relative(scanPath, service.dir), err);
|
|
8997
9260
|
continue;
|
|
8998
9261
|
}
|
|
8999
9262
|
if (!read && !projectName) continue;
|
|
@@ -9009,7 +9272,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9009
9272
|
const anchorId = service.node.id;
|
|
9010
9273
|
if (!read) continue;
|
|
9011
9274
|
const { config, relFile, raw } = read;
|
|
9012
|
-
const evidenceFile = toPosix(
|
|
9275
|
+
const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, relFile)));
|
|
9013
9276
|
const add = (edgeType, kind, name) => {
|
|
9014
9277
|
if (!name) return;
|
|
9015
9278
|
const result = emitPlatformResourceEdge(
|
|
@@ -9025,12 +9288,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9025
9288
|
nodesAdded += result.nodesAdded;
|
|
9026
9289
|
edgesAdded += result.edgesAdded;
|
|
9027
9290
|
};
|
|
9028
|
-
add(
|
|
9029
|
-
for (const cron of config.crons ?? []) add(
|
|
9030
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
9031
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
9291
|
+
add(import_types35.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
9292
|
+
for (const cron of config.crons ?? []) add(import_types35.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
9293
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9294
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9032
9295
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
9033
|
-
add(
|
|
9296
|
+
add(import_types35.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
9034
9297
|
}
|
|
9035
9298
|
}
|
|
9036
9299
|
return { nodesAdded, edgesAdded };
|
|
@@ -9039,13 +9302,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9039
9302
|
// src/extract/infra/railway.ts
|
|
9040
9303
|
init_cjs_shims();
|
|
9041
9304
|
var import_node_fs22 = require("fs");
|
|
9042
|
-
var
|
|
9305
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9043
9306
|
var import_smol_toml3 = require("smol-toml");
|
|
9044
|
-
var
|
|
9307
|
+
var import_types36 = require("@neat.is/types");
|
|
9045
9308
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
9046
9309
|
async function readRailwayConfig(dir) {
|
|
9047
9310
|
for (const filename of RAILWAY_FILENAMES) {
|
|
9048
|
-
const abs =
|
|
9311
|
+
const abs = import_node_path47.default.join(dir, filename);
|
|
9049
9312
|
if (!await exists(abs)) continue;
|
|
9050
9313
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
9051
9314
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9061,7 +9324,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9061
9324
|
try {
|
|
9062
9325
|
read = await readRailwayConfig(service.dir);
|
|
9063
9326
|
} catch (err) {
|
|
9064
|
-
recordExtractionError("infra railway",
|
|
9327
|
+
recordExtractionError("infra railway", import_node_path47.default.relative(scanPath, service.dir), err);
|
|
9065
9328
|
continue;
|
|
9066
9329
|
}
|
|
9067
9330
|
if (!read) continue;
|
|
@@ -9071,7 +9334,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9071
9334
|
}
|
|
9072
9335
|
const anchorId = service.node.id;
|
|
9073
9336
|
const { config, relFile, raw } = read;
|
|
9074
|
-
const evidenceFile = toPosix(
|
|
9337
|
+
const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
|
|
9075
9338
|
const add = (edgeType, kind, name) => {
|
|
9076
9339
|
if (!name) return;
|
|
9077
9340
|
const result = emitPlatformResourceEdge(
|
|
@@ -9087,9 +9350,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9087
9350
|
nodesAdded += result.nodesAdded;
|
|
9088
9351
|
edgesAdded += result.edgesAdded;
|
|
9089
9352
|
};
|
|
9090
|
-
add(
|
|
9091
|
-
add(
|
|
9092
|
-
add(
|
|
9353
|
+
add(import_types36.EdgeType.RUNS_ON, "railway", "railway");
|
|
9354
|
+
add(import_types36.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
9355
|
+
add(import_types36.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
9093
9356
|
}
|
|
9094
9357
|
return { nodesAdded, edgesAdded };
|
|
9095
9358
|
}
|
|
@@ -9097,12 +9360,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9097
9360
|
// src/extract/infra/supabase.ts
|
|
9098
9361
|
init_cjs_shims();
|
|
9099
9362
|
var import_node_fs23 = require("fs");
|
|
9100
|
-
var
|
|
9363
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
9101
9364
|
var import_smol_toml4 = require("smol-toml");
|
|
9102
|
-
var
|
|
9365
|
+
var import_types37 = require("@neat.is/types");
|
|
9103
9366
|
async function readSupabaseConfig(dir) {
|
|
9104
|
-
const relFile =
|
|
9105
|
-
const abs =
|
|
9367
|
+
const relFile = import_node_path48.default.join("supabase", "config.toml");
|
|
9368
|
+
const abs = import_node_path48.default.join(dir, relFile);
|
|
9106
9369
|
if (!await exists(abs)) return null;
|
|
9107
9370
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
9108
9371
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -9116,7 +9379,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9116
9379
|
try {
|
|
9117
9380
|
read = await readSupabaseConfig(service.dir);
|
|
9118
9381
|
} catch (err) {
|
|
9119
|
-
recordExtractionError("infra supabase",
|
|
9382
|
+
recordExtractionError("infra supabase", import_node_path48.default.relative(scanPath, service.dir), err);
|
|
9120
9383
|
continue;
|
|
9121
9384
|
}
|
|
9122
9385
|
if (!read) continue;
|
|
@@ -9131,7 +9394,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9131
9394
|
});
|
|
9132
9395
|
}
|
|
9133
9396
|
const anchorId = service.node.id;
|
|
9134
|
-
const evidenceFile = toPosix(
|
|
9397
|
+
const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
|
|
9135
9398
|
const add = (edgeType, kind, name) => {
|
|
9136
9399
|
if (!name) return;
|
|
9137
9400
|
const result = emitPlatformResourceEdge(
|
|
@@ -9147,10 +9410,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9147
9410
|
nodesAdded += result.nodesAdded;
|
|
9148
9411
|
edgesAdded += result.edgesAdded;
|
|
9149
9412
|
};
|
|
9150
|
-
add(
|
|
9151
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
9152
|
-
if (config.storage) add(
|
|
9153
|
-
if (config.auth) add(
|
|
9413
|
+
add(import_types37.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
9414
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types37.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
9415
|
+
if (config.storage) add(import_types37.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
9416
|
+
if (config.auth) add(import_types37.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
9154
9417
|
}
|
|
9155
9418
|
return { nodesAdded, edgesAdded };
|
|
9156
9419
|
}
|
|
@@ -9172,17 +9435,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
9172
9435
|
}
|
|
9173
9436
|
|
|
9174
9437
|
// src/extract/index.ts
|
|
9175
|
-
var
|
|
9438
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9176
9439
|
|
|
9177
9440
|
// src/extract/retire.ts
|
|
9178
9441
|
init_cjs_shims();
|
|
9179
9442
|
var import_node_fs24 = require("fs");
|
|
9180
|
-
var
|
|
9181
|
-
var
|
|
9443
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9444
|
+
var import_types38 = require("@neat.is/types");
|
|
9182
9445
|
function dropOrphanedFileNodes(graph) {
|
|
9183
9446
|
const orphans = [];
|
|
9184
9447
|
graph.forEachNode((id, attrs) => {
|
|
9185
|
-
if (attrs.type !==
|
|
9448
|
+
if (attrs.type !== import_types38.NodeType.FileNode) return;
|
|
9186
9449
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
9187
9450
|
orphans.push(id);
|
|
9188
9451
|
}
|
|
@@ -9195,14 +9458,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
9195
9458
|
const bases = [scanPath, ...serviceDirs];
|
|
9196
9459
|
graph.forEachEdge((id, attrs) => {
|
|
9197
9460
|
const edge = attrs;
|
|
9198
|
-
if (edge.provenance !==
|
|
9461
|
+
if (edge.provenance !== import_types38.Provenance.EXTRACTED) return;
|
|
9199
9462
|
const evidenceFile = edge.evidence?.file;
|
|
9200
9463
|
if (!evidenceFile) return;
|
|
9201
|
-
if (
|
|
9464
|
+
if (import_node_path49.default.isAbsolute(evidenceFile)) {
|
|
9202
9465
|
if (!(0, import_node_fs24.existsSync)(evidenceFile)) toDrop.push(id);
|
|
9203
9466
|
return;
|
|
9204
9467
|
}
|
|
9205
|
-
const found = bases.some((base) => (0, import_node_fs24.existsSync)(
|
|
9468
|
+
const found = bases.some((base) => (0, import_node_fs24.existsSync)(import_node_path49.default.join(base, evidenceFile)));
|
|
9206
9469
|
if (!found) toDrop.push(id);
|
|
9207
9470
|
});
|
|
9208
9471
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -9255,7 +9518,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9255
9518
|
}
|
|
9256
9519
|
const droppedEntries = drainDroppedExtracted();
|
|
9257
9520
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
9258
|
-
const rejectedPath =
|
|
9521
|
+
const rejectedPath = import_node_path50.default.join(import_node_path50.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
9259
9522
|
try {
|
|
9260
9523
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
9261
9524
|
} catch (err) {
|
|
@@ -9290,9 +9553,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9290
9553
|
// src/persist.ts
|
|
9291
9554
|
init_cjs_shims();
|
|
9292
9555
|
var import_node_fs25 = require("fs");
|
|
9293
|
-
var
|
|
9294
|
-
var
|
|
9295
|
-
var SCHEMA_VERSION =
|
|
9556
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
9557
|
+
var import_types39 = require("@neat.is/types");
|
|
9558
|
+
var SCHEMA_VERSION = 6;
|
|
9296
9559
|
function migrateV1ToV2(payload) {
|
|
9297
9560
|
const nodes = payload.graph.nodes;
|
|
9298
9561
|
if (Array.isArray(nodes)) {
|
|
@@ -9310,18 +9573,30 @@ function migrateV3ToV4(payload) {
|
|
|
9310
9573
|
function migrateV4ToV5(payload) {
|
|
9311
9574
|
return { ...payload, schemaVersion: 5 };
|
|
9312
9575
|
}
|
|
9576
|
+
function migrateV5ToV6(payload) {
|
|
9577
|
+
const nodes = payload.graph.nodes;
|
|
9578
|
+
if (Array.isArray(nodes)) {
|
|
9579
|
+
for (const node of nodes) {
|
|
9580
|
+
const attrs = node.attributes;
|
|
9581
|
+
if (!attrs || attrs.type !== import_types39.NodeType.InfraNode) continue;
|
|
9582
|
+
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
9583
|
+
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
9584
|
+
}
|
|
9585
|
+
}
|
|
9586
|
+
return { ...payload, schemaVersion: 6 };
|
|
9587
|
+
}
|
|
9313
9588
|
function migrateV2ToV3(payload) {
|
|
9314
9589
|
const edges = payload.graph.edges;
|
|
9315
9590
|
if (Array.isArray(edges)) {
|
|
9316
9591
|
for (const edge of edges) {
|
|
9317
9592
|
const attrs = edge.attributes;
|
|
9318
9593
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
9319
|
-
attrs.provenance =
|
|
9594
|
+
attrs.provenance = import_types39.Provenance.OBSERVED;
|
|
9320
9595
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
9321
9596
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
9322
9597
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
9323
9598
|
if (type && source && target) {
|
|
9324
|
-
const newId = (0,
|
|
9599
|
+
const newId = (0, import_types39.observedEdgeId)(source, target, type);
|
|
9325
9600
|
attrs.id = newId;
|
|
9326
9601
|
if (edge.key) edge.key = newId;
|
|
9327
9602
|
}
|
|
@@ -9330,7 +9605,7 @@ function migrateV2ToV3(payload) {
|
|
|
9330
9605
|
return { ...payload, schemaVersion: 3 };
|
|
9331
9606
|
}
|
|
9332
9607
|
async function ensureDir(filePath) {
|
|
9333
|
-
await import_node_fs25.promises.mkdir(
|
|
9608
|
+
await import_node_fs25.promises.mkdir(import_node_path51.default.dirname(filePath), { recursive: true });
|
|
9334
9609
|
}
|
|
9335
9610
|
async function saveGraphToDisk(graph, outPath) {
|
|
9336
9611
|
await ensureDir(outPath);
|
|
@@ -9364,6 +9639,9 @@ async function loadGraphFromDisk(graph, outPath) {
|
|
|
9364
9639
|
if (payload.schemaVersion === 4) {
|
|
9365
9640
|
payload = migrateV4ToV5(payload);
|
|
9366
9641
|
}
|
|
9642
|
+
if (payload.schemaVersion === 5) {
|
|
9643
|
+
payload = migrateV5ToV6(payload);
|
|
9644
|
+
}
|
|
9367
9645
|
if (payload.schemaVersion !== SCHEMA_VERSION) {
|
|
9368
9646
|
throw new Error(
|
|
9369
9647
|
`persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`
|
|
@@ -9416,19 +9694,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
9416
9694
|
init_cjs_shims();
|
|
9417
9695
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
9418
9696
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
9419
|
-
var
|
|
9697
|
+
var import_types58 = require("@neat.is/types");
|
|
9420
9698
|
|
|
9421
9699
|
// src/extend/index.ts
|
|
9422
9700
|
init_cjs_shims();
|
|
9423
9701
|
var import_node_fs27 = require("fs");
|
|
9424
|
-
var
|
|
9702
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
9425
9703
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
9426
9704
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
9427
9705
|
|
|
9428
9706
|
// src/installers/package-manager.ts
|
|
9429
9707
|
init_cjs_shims();
|
|
9430
9708
|
var import_node_fs26 = require("fs");
|
|
9431
|
-
var
|
|
9709
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
9432
9710
|
var import_node_child_process = require("child_process");
|
|
9433
9711
|
var LOCKFILE_PRIORITY = [
|
|
9434
9712
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -9450,22 +9728,22 @@ async function exists2(p) {
|
|
|
9450
9728
|
}
|
|
9451
9729
|
}
|
|
9452
9730
|
async function detectPackageManager(serviceDir) {
|
|
9453
|
-
let dir =
|
|
9731
|
+
let dir = import_node_path52.default.resolve(serviceDir);
|
|
9454
9732
|
const stops = /* @__PURE__ */ new Set();
|
|
9455
9733
|
for (let i = 0; i < 64; i++) {
|
|
9456
9734
|
if (stops.has(dir)) break;
|
|
9457
9735
|
stops.add(dir);
|
|
9458
9736
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
9459
|
-
const lockPath =
|
|
9737
|
+
const lockPath = import_node_path52.default.join(dir, candidate.lockfile);
|
|
9460
9738
|
if (await exists2(lockPath)) {
|
|
9461
9739
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
9462
9740
|
}
|
|
9463
9741
|
}
|
|
9464
|
-
const parent =
|
|
9742
|
+
const parent = import_node_path52.default.dirname(dir);
|
|
9465
9743
|
if (parent === dir) break;
|
|
9466
9744
|
dir = parent;
|
|
9467
9745
|
}
|
|
9468
|
-
return { pm: "npm", cwd:
|
|
9746
|
+
return { pm: "npm", cwd: import_node_path52.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
9469
9747
|
}
|
|
9470
9748
|
async function runPackageManagerInstall(cmd) {
|
|
9471
9749
|
return new Promise((resolve) => {
|
|
@@ -9514,7 +9792,7 @@ async function fileExists2(p) {
|
|
|
9514
9792
|
}
|
|
9515
9793
|
}
|
|
9516
9794
|
async function readPackageJson(scanPath) {
|
|
9517
|
-
const pkgPath =
|
|
9795
|
+
const pkgPath = import_node_path53.default.join(scanPath, "package.json");
|
|
9518
9796
|
const raw = await import_node_fs27.promises.readFile(pkgPath, "utf8");
|
|
9519
9797
|
return JSON.parse(raw);
|
|
9520
9798
|
}
|
|
@@ -9533,11 +9811,11 @@ async function findHookFiles(scanPath) {
|
|
|
9533
9811
|
for (const entry of entries) {
|
|
9534
9812
|
if (entry.isDirectory()) {
|
|
9535
9813
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
9536
|
-
await walk6(
|
|
9814
|
+
await walk6(import_node_path53.default.join(dir, entry.name));
|
|
9537
9815
|
} else if (entry.isFile()) {
|
|
9538
9816
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
9539
|
-
const rel =
|
|
9540
|
-
found.push(rel.split(
|
|
9817
|
+
const rel = import_node_path53.default.relative(scanPath, import_node_path53.default.join(dir, entry.name));
|
|
9818
|
+
found.push(rel.split(import_node_path53.default.sep).join("/"));
|
|
9541
9819
|
}
|
|
9542
9820
|
}
|
|
9543
9821
|
}
|
|
@@ -9548,7 +9826,7 @@ async function findHookFiles(scanPath) {
|
|
|
9548
9826
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
9549
9827
|
let fallback = null;
|
|
9550
9828
|
for (const file of hookFiles) {
|
|
9551
|
-
const content = await import_node_fs27.promises.readFile(
|
|
9829
|
+
const content = await import_node_fs27.promises.readFile(import_node_path53.default.join(scanPath, file), "utf8");
|
|
9552
9830
|
const patched = splicedContent(content, snippet2);
|
|
9553
9831
|
if (patched !== null) return { file, content, patched };
|
|
9554
9832
|
if (fallback === null) fallback = { file, content };
|
|
@@ -9556,11 +9834,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
9556
9834
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
9557
9835
|
}
|
|
9558
9836
|
function extendLogPath() {
|
|
9559
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
9837
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path53.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
9560
9838
|
}
|
|
9561
9839
|
async function appendExtendLog(entry) {
|
|
9562
9840
|
const logPath = extendLogPath();
|
|
9563
|
-
await import_node_fs27.promises.mkdir(
|
|
9841
|
+
await import_node_fs27.promises.mkdir(import_node_path53.default.dirname(logPath), { recursive: true });
|
|
9564
9842
|
await import_node_fs27.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
9565
9843
|
}
|
|
9566
9844
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -9619,7 +9897,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
9619
9897
|
}
|
|
9620
9898
|
async function describeProjectInstrumentation(ctx) {
|
|
9621
9899
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
9622
|
-
const envNeat = await fileExists2(
|
|
9900
|
+
const envNeat = await fileExists2(import_node_path53.default.join(ctx.scanPath, ".env.neat"));
|
|
9623
9901
|
const registryInstrPackages = new Set(
|
|
9624
9902
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
9625
9903
|
);
|
|
@@ -9641,7 +9919,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
9641
9919
|
);
|
|
9642
9920
|
}
|
|
9643
9921
|
for (const file of hookFiles) {
|
|
9644
|
-
const content = await import_node_fs27.promises.readFile(
|
|
9922
|
+
const content = await import_node_fs27.promises.readFile(import_node_path53.default.join(ctx.scanPath, file), "utf8");
|
|
9645
9923
|
if (content.includes(args.registration_snippet)) {
|
|
9646
9924
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
9647
9925
|
}
|
|
@@ -9653,10 +9931,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
9653
9931
|
);
|
|
9654
9932
|
}
|
|
9655
9933
|
const primaryFile = primary.file;
|
|
9656
|
-
const primaryPath =
|
|
9934
|
+
const primaryPath = import_node_path53.default.join(ctx.scanPath, primaryFile);
|
|
9657
9935
|
const filesTouched = [];
|
|
9658
9936
|
const depsAdded = [];
|
|
9659
|
-
const pkgPath =
|
|
9937
|
+
const pkgPath = import_node_path53.default.join(ctx.scanPath, "package.json");
|
|
9660
9938
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
9661
9939
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
9662
9940
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -9695,7 +9973,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
9695
9973
|
};
|
|
9696
9974
|
}
|
|
9697
9975
|
for (const file of hookFiles) {
|
|
9698
|
-
const content = await import_node_fs27.promises.readFile(
|
|
9976
|
+
const content = await import_node_fs27.promises.readFile(import_node_path53.default.join(ctx.scanPath, file), "utf8");
|
|
9699
9977
|
if (content.includes(args.registration_snippet)) {
|
|
9700
9978
|
return {
|
|
9701
9979
|
library: args.library,
|
|
@@ -9736,7 +10014,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
9736
10014
|
if (!match) {
|
|
9737
10015
|
return { undone: false, message: "no apply found for library" };
|
|
9738
10016
|
}
|
|
9739
|
-
const pkgPath =
|
|
10017
|
+
const pkgPath = import_node_path53.default.join(ctx.scanPath, "package.json");
|
|
9740
10018
|
if (await fileExists2(pkgPath)) {
|
|
9741
10019
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
9742
10020
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -9747,7 +10025,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
9747
10025
|
}
|
|
9748
10026
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
9749
10027
|
for (const file of hookFiles) {
|
|
9750
|
-
const filePath =
|
|
10028
|
+
const filePath = import_node_path53.default.join(ctx.scanPath, file);
|
|
9751
10029
|
const content = await import_node_fs27.promises.readFile(filePath, "utf8");
|
|
9752
10030
|
if (content.includes(match.registration_snippet)) {
|
|
9753
10031
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -9763,39 +10041,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
9763
10041
|
|
|
9764
10042
|
// src/divergences.ts
|
|
9765
10043
|
init_cjs_shims();
|
|
9766
|
-
var
|
|
10044
|
+
var import_types40 = require("@neat.is/types");
|
|
9767
10045
|
function bucketKey(source, target, type) {
|
|
9768
10046
|
return `${type}|${source}|${target}`;
|
|
9769
10047
|
}
|
|
9770
10048
|
function bucketSourceFor(graph, edge) {
|
|
9771
|
-
if (edge.type !==
|
|
9772
|
-
const parsed = (0,
|
|
10049
|
+
if (edge.type !== import_types40.EdgeType.CONNECTS_TO) return edge.source;
|
|
10050
|
+
const parsed = (0, import_types40.parseFileId)(edge.source);
|
|
9773
10051
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
9774
10052
|
const target = graph.getNodeAttributes(edge.target);
|
|
9775
|
-
if (target.type !==
|
|
9776
|
-
return (0,
|
|
10053
|
+
if (target.type !== import_types40.NodeType.DatabaseNode) return edge.source;
|
|
10054
|
+
return (0, import_types40.serviceId)(parsed.service);
|
|
9777
10055
|
}
|
|
9778
10056
|
function bucketEdges(graph) {
|
|
9779
10057
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
9780
10058
|
graph.forEachEdge((id, attrs) => {
|
|
9781
10059
|
const e = attrs;
|
|
9782
|
-
const parsed = (0,
|
|
10060
|
+
const parsed = (0, import_types40.parseEdgeId)(id);
|
|
9783
10061
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
9784
10062
|
const source = bucketSourceFor(graph, e);
|
|
9785
10063
|
const key = bucketKey(source, e.target, e.type);
|
|
9786
10064
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
9787
10065
|
switch (provenance) {
|
|
9788
|
-
case
|
|
10066
|
+
case import_types40.Provenance.EXTRACTED:
|
|
9789
10067
|
cur.extracted = e;
|
|
9790
10068
|
break;
|
|
9791
|
-
case
|
|
10069
|
+
case import_types40.Provenance.OBSERVED:
|
|
9792
10070
|
cur.observed = e;
|
|
9793
10071
|
break;
|
|
9794
|
-
case
|
|
10072
|
+
case import_types40.Provenance.INFERRED:
|
|
9795
10073
|
cur.inferred = e;
|
|
9796
10074
|
break;
|
|
9797
10075
|
default:
|
|
9798
|
-
if (e.provenance ===
|
|
10076
|
+
if (e.provenance === import_types40.Provenance.STALE) cur.stale = e;
|
|
9799
10077
|
}
|
|
9800
10078
|
buckets2.set(key, cur);
|
|
9801
10079
|
});
|
|
@@ -9804,17 +10082,17 @@ function bucketEdges(graph) {
|
|
|
9804
10082
|
function nodeIsFrontier(graph, nodeId) {
|
|
9805
10083
|
if (!graph.hasNode(nodeId)) return false;
|
|
9806
10084
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
9807
|
-
return attrs.type ===
|
|
10085
|
+
return attrs.type === import_types40.NodeType.FrontierNode;
|
|
9808
10086
|
}
|
|
9809
10087
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
9810
10088
|
if (!graph.hasNode(nodeId)) return false;
|
|
9811
10089
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
9812
|
-
return attrs.type ===
|
|
10090
|
+
return attrs.type === import_types40.NodeType.WebSocketChannelNode;
|
|
9813
10091
|
}
|
|
9814
10092
|
function nodeIsSymbol(graph, nodeId) {
|
|
9815
10093
|
if (!graph.hasNode(nodeId)) return false;
|
|
9816
10094
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
9817
|
-
return attrs.type ===
|
|
10095
|
+
return attrs.type === import_types40.NodeType.SymbolNode;
|
|
9818
10096
|
}
|
|
9819
10097
|
function clampConfidence(n) {
|
|
9820
10098
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -9834,14 +10112,14 @@ function gradedConfidence(edge) {
|
|
|
9834
10112
|
return clampConfidence(confidenceForEdge(edge));
|
|
9835
10113
|
}
|
|
9836
10114
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
10115
|
+
import_types40.EdgeType.CALLS,
|
|
10116
|
+
import_types40.EdgeType.CONNECTS_TO,
|
|
10117
|
+
import_types40.EdgeType.PUBLISHES_TO,
|
|
10118
|
+
import_types40.EdgeType.CONSUMES_FROM
|
|
9841
10119
|
]);
|
|
9842
10120
|
function detectMissingDivergences(graph, bucket) {
|
|
9843
10121
|
const out = [];
|
|
9844
|
-
if (bucket.type ===
|
|
10122
|
+
if (bucket.type === import_types40.EdgeType.CONTAINS) return out;
|
|
9845
10123
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
9846
10124
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
9847
10125
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
@@ -9883,7 +10161,7 @@ function declaredHostFor(svc) {
|
|
|
9883
10161
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
9884
10162
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
9885
10163
|
const e = graph.getEdgeAttributes(edgeId);
|
|
9886
|
-
if (e.type ===
|
|
10164
|
+
if (e.type === import_types40.EdgeType.CONFIGURED_BY && e.provenance === import_types40.Provenance.EXTRACTED) {
|
|
9887
10165
|
return true;
|
|
9888
10166
|
}
|
|
9889
10167
|
}
|
|
@@ -9896,10 +10174,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
9896
10174
|
const out = [];
|
|
9897
10175
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
9898
10176
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
9899
|
-
if (edge.type !==
|
|
9900
|
-
if (edge.provenance !==
|
|
10177
|
+
if (edge.type !== import_types40.EdgeType.CONNECTS_TO) continue;
|
|
10178
|
+
if (edge.provenance !== import_types40.Provenance.OBSERVED) continue;
|
|
9901
10179
|
const target = graph.getNodeAttributes(edge.target);
|
|
9902
|
-
if (target.type !==
|
|
10180
|
+
if (target.type !== import_types40.NodeType.DatabaseNode) continue;
|
|
9903
10181
|
const observedHost = target.host?.trim();
|
|
9904
10182
|
if (!observedHost) continue;
|
|
9905
10183
|
if (observedHost === declaredHost) continue;
|
|
@@ -9921,10 +10199,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
9921
10199
|
const deps = svc.dependencies ?? {};
|
|
9922
10200
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
9923
10201
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
9924
|
-
if (edge.type !==
|
|
9925
|
-
if (edge.provenance !==
|
|
10202
|
+
if (edge.type !== import_types40.EdgeType.CONNECTS_TO) continue;
|
|
10203
|
+
if (edge.provenance !== import_types40.Provenance.OBSERVED) continue;
|
|
9926
10204
|
const target = graph.getNodeAttributes(edge.target);
|
|
9927
|
-
if (target.type !==
|
|
10205
|
+
if (target.type !== import_types40.NodeType.DatabaseNode) continue;
|
|
9928
10206
|
for (const pair of compatPairs()) {
|
|
9929
10207
|
if (pair.engine !== target.engine) continue;
|
|
9930
10208
|
const declared = deps[pair.driver];
|
|
@@ -9974,6 +10252,44 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
9974
10252
|
}
|
|
9975
10253
|
return out;
|
|
9976
10254
|
}
|
|
10255
|
+
var RECOMMENDATION_COLUMN_MISSING_OBSERVED = "Verify the column is exercised in production; a migration that renamed or dropped it may have left a writer declaring the old name.";
|
|
10256
|
+
var RECOMMENDATION_COLUMN_MISSING_EXTRACTED = "The schema or migration is likely behind the code \u2014 production writes a column the declared schema does not carry. Check for a field rename that updated the query but not the model.";
|
|
10257
|
+
function detectColumnDrift(node) {
|
|
10258
|
+
const columns = node.columns;
|
|
10259
|
+
if (!columns || columns.length === 0) return [];
|
|
10260
|
+
const anyDeclared = columns.some(columnIsDeclared);
|
|
10261
|
+
const anyObserved = columns.some(columnIsObserved);
|
|
10262
|
+
if (!anyDeclared || !anyObserved) return [];
|
|
10263
|
+
const out = [];
|
|
10264
|
+
for (const col of columns) {
|
|
10265
|
+
const declared = columnIsDeclared(col);
|
|
10266
|
+
const observed = columnIsObserved(col);
|
|
10267
|
+
if (declared && !observed) {
|
|
10268
|
+
out.push({
|
|
10269
|
+
type: "missing-observed",
|
|
10270
|
+
source: node.id,
|
|
10271
|
+
target: node.id,
|
|
10272
|
+
table: node.id,
|
|
10273
|
+
column: col.name,
|
|
10274
|
+
confidence: clampConfidence(col.confidence),
|
|
10275
|
+
reason: `Schema declares column ${node.name}.${col.name} but no production statement has touched it.`,
|
|
10276
|
+
recommendation: RECOMMENDATION_COLUMN_MISSING_OBSERVED
|
|
10277
|
+
});
|
|
10278
|
+
} else if (observed && !declared) {
|
|
10279
|
+
out.push({
|
|
10280
|
+
type: "missing-extracted",
|
|
10281
|
+
source: node.id,
|
|
10282
|
+
target: node.id,
|
|
10283
|
+
table: node.id,
|
|
10284
|
+
column: col.name,
|
|
10285
|
+
confidence: clampConfidence(col.confidence),
|
|
10286
|
+
reason: `Production touched column ${node.name}.${col.name} but the schema does not declare it.`,
|
|
10287
|
+
recommendation: RECOMMENDATION_COLUMN_MISSING_EXTRACTED
|
|
10288
|
+
});
|
|
10289
|
+
}
|
|
10290
|
+
}
|
|
10291
|
+
return out;
|
|
10292
|
+
}
|
|
9977
10293
|
function involvesNode(d, nodeId) {
|
|
9978
10294
|
return d.source === nodeId || d.target === nodeId;
|
|
9979
10295
|
}
|
|
@@ -9983,7 +10299,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
9983
10299
|
for (const d of all) {
|
|
9984
10300
|
if (d.type !== "host-mismatch") continue;
|
|
9985
10301
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
9986
|
-
declaredHalf.add((0,
|
|
10302
|
+
declaredHalf.add((0, import_types40.databaseId)(d.extractedHost));
|
|
9987
10303
|
}
|
|
9988
10304
|
if (observedHalf.size === 0) return all;
|
|
9989
10305
|
return all.filter((d) => {
|
|
@@ -10002,10 +10318,15 @@ function computeDivergences(graph, opts = {}) {
|
|
|
10002
10318
|
}
|
|
10003
10319
|
graph.forEachNode((nodeId, attrs) => {
|
|
10004
10320
|
const n = attrs;
|
|
10005
|
-
if (n.type
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10321
|
+
if (n.type === import_types40.NodeType.ServiceNode) {
|
|
10322
|
+
const svc = n;
|
|
10323
|
+
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
10324
|
+
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
10325
|
+
return;
|
|
10326
|
+
}
|
|
10327
|
+
if (n.type === import_types40.NodeType.InfraNode && n.kind === "sql-table") {
|
|
10328
|
+
for (const d of detectColumnDrift(n)) all.push(d);
|
|
10329
|
+
}
|
|
10009
10330
|
});
|
|
10010
10331
|
const reconciled = suppressHostMismatchHalves(all);
|
|
10011
10332
|
let filtered = reconciled;
|
|
@@ -10034,9 +10355,12 @@ function computeDivergences(graph, opts = {}) {
|
|
|
10034
10355
|
if (lead !== 0) return lead;
|
|
10035
10356
|
if (a.type !== b.type) return a.type.localeCompare(b.type);
|
|
10036
10357
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
10037
|
-
return a.target.localeCompare(b.target);
|
|
10358
|
+
if (a.target !== b.target) return a.target.localeCompare(b.target);
|
|
10359
|
+
const ac = "column" in a && a.column ? a.column : "";
|
|
10360
|
+
const bc = "column" in b && b.column ? b.column : "";
|
|
10361
|
+
return ac.localeCompare(bc);
|
|
10038
10362
|
});
|
|
10039
|
-
return
|
|
10363
|
+
return import_types40.DivergenceResultSchema.parse({
|
|
10040
10364
|
divergences: filtered,
|
|
10041
10365
|
totalAffected: filtered.length,
|
|
10042
10366
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -10167,23 +10491,23 @@ function canonicalJson(value) {
|
|
|
10167
10491
|
|
|
10168
10492
|
// src/projects.ts
|
|
10169
10493
|
init_cjs_shims();
|
|
10170
|
-
var
|
|
10494
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
10171
10495
|
function pathsForProject(project, baseDir) {
|
|
10172
10496
|
if (project === DEFAULT_PROJECT) {
|
|
10173
10497
|
return {
|
|
10174
|
-
snapshotPath:
|
|
10175
|
-
errorsPath:
|
|
10176
|
-
staleEventsPath:
|
|
10177
|
-
embeddingsCachePath:
|
|
10178
|
-
policyViolationsPath:
|
|
10498
|
+
snapshotPath: import_node_path54.default.join(baseDir, "graph.json"),
|
|
10499
|
+
errorsPath: import_node_path54.default.join(baseDir, "errors.ndjson"),
|
|
10500
|
+
staleEventsPath: import_node_path54.default.join(baseDir, "stale-events.ndjson"),
|
|
10501
|
+
embeddingsCachePath: import_node_path54.default.join(baseDir, "embeddings.json"),
|
|
10502
|
+
policyViolationsPath: import_node_path54.default.join(baseDir, "policy-violations.ndjson")
|
|
10179
10503
|
};
|
|
10180
10504
|
}
|
|
10181
10505
|
return {
|
|
10182
|
-
snapshotPath:
|
|
10183
|
-
errorsPath:
|
|
10184
|
-
staleEventsPath:
|
|
10185
|
-
embeddingsCachePath:
|
|
10186
|
-
policyViolationsPath:
|
|
10506
|
+
snapshotPath: import_node_path54.default.join(baseDir, `${project}.json`),
|
|
10507
|
+
errorsPath: import_node_path54.default.join(baseDir, `errors.${project}.ndjson`),
|
|
10508
|
+
staleEventsPath: import_node_path54.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
10509
|
+
embeddingsCachePath: import_node_path54.default.join(baseDir, `embeddings.${project}.json`),
|
|
10510
|
+
policyViolationsPath: import_node_path54.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
10187
10511
|
};
|
|
10188
10512
|
}
|
|
10189
10513
|
var Projects = class {
|
|
@@ -10221,26 +10545,26 @@ var Projects = class {
|
|
|
10221
10545
|
init_cjs_shims();
|
|
10222
10546
|
var import_node_fs29 = require("fs");
|
|
10223
10547
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
10224
|
-
var
|
|
10225
|
-
var
|
|
10548
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
10549
|
+
var import_types41 = require("@neat.is/types");
|
|
10226
10550
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
10227
10551
|
var LOCK_RETRY_MS = 50;
|
|
10228
10552
|
function neatHome() {
|
|
10229
10553
|
const override = process.env.NEAT_HOME;
|
|
10230
|
-
if (override && override.length > 0) return
|
|
10231
|
-
return
|
|
10554
|
+
if (override && override.length > 0) return import_node_path55.default.resolve(override);
|
|
10555
|
+
return import_node_path55.default.join(import_node_os3.default.homedir(), ".neat");
|
|
10232
10556
|
}
|
|
10233
10557
|
function registryPath() {
|
|
10234
|
-
return
|
|
10558
|
+
return import_node_path55.default.join(neatHome(), "projects.json");
|
|
10235
10559
|
}
|
|
10236
10560
|
function registryLockPath() {
|
|
10237
|
-
return
|
|
10561
|
+
return import_node_path55.default.join(neatHome(), "projects.json.lock");
|
|
10238
10562
|
}
|
|
10239
10563
|
function daemonPidPath() {
|
|
10240
|
-
return
|
|
10564
|
+
return import_node_path55.default.join(neatHome(), "neatd.pid");
|
|
10241
10565
|
}
|
|
10242
10566
|
function daemonsDir() {
|
|
10243
|
-
return
|
|
10567
|
+
return import_node_path55.default.join(neatHome(), "daemons");
|
|
10244
10568
|
}
|
|
10245
10569
|
function isFiniteInt(v) {
|
|
10246
10570
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -10281,7 +10605,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
10281
10605
|
const out = [];
|
|
10282
10606
|
for (const name of names) {
|
|
10283
10607
|
if (!name.endsWith(".json")) continue;
|
|
10284
|
-
const file =
|
|
10608
|
+
const file = import_node_path55.default.join(dir, name);
|
|
10285
10609
|
let raw;
|
|
10286
10610
|
try {
|
|
10287
10611
|
raw = await import_node_fs29.promises.readFile(file, "utf8");
|
|
@@ -10358,7 +10682,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
10358
10682
|
}
|
|
10359
10683
|
}
|
|
10360
10684
|
async function normalizeProjectPath(input) {
|
|
10361
|
-
const resolved =
|
|
10685
|
+
const resolved = import_node_path55.default.resolve(input);
|
|
10362
10686
|
try {
|
|
10363
10687
|
return await import_node_fs29.promises.realpath(resolved);
|
|
10364
10688
|
} catch {
|
|
@@ -10366,7 +10690,7 @@ async function normalizeProjectPath(input) {
|
|
|
10366
10690
|
}
|
|
10367
10691
|
}
|
|
10368
10692
|
async function writeAtomically(target, contents) {
|
|
10369
|
-
await import_node_fs29.promises.mkdir(
|
|
10693
|
+
await import_node_fs29.promises.mkdir(import_node_path55.default.dirname(target), { recursive: true });
|
|
10370
10694
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
10371
10695
|
const fd = await import_node_fs29.promises.open(tmp, "w");
|
|
10372
10696
|
try {
|
|
@@ -10379,7 +10703,7 @@ async function writeAtomically(target, contents) {
|
|
|
10379
10703
|
}
|
|
10380
10704
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
10381
10705
|
const deadline = Date.now() + timeoutMs;
|
|
10382
|
-
await import_node_fs29.promises.mkdir(
|
|
10706
|
+
await import_node_fs29.promises.mkdir(import_node_path55.default.dirname(lockPath), { recursive: true });
|
|
10383
10707
|
let probedHolder = false;
|
|
10384
10708
|
while (true) {
|
|
10385
10709
|
try {
|
|
@@ -10432,10 +10756,10 @@ async function readRegistry() {
|
|
|
10432
10756
|
throw err;
|
|
10433
10757
|
}
|
|
10434
10758
|
const parsed = JSON.parse(raw);
|
|
10435
|
-
return
|
|
10759
|
+
return import_types41.RegistryFileSchema.parse(parsed);
|
|
10436
10760
|
}
|
|
10437
10761
|
async function writeRegistry(reg) {
|
|
10438
|
-
const validated =
|
|
10762
|
+
const validated = import_types41.RegistryFileSchema.parse(reg);
|
|
10439
10763
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
10440
10764
|
}
|
|
10441
10765
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -10630,7 +10954,7 @@ init_auth();
|
|
|
10630
10954
|
// src/connectors-config.ts
|
|
10631
10955
|
init_cjs_shims();
|
|
10632
10956
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10633
|
-
var
|
|
10957
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
10634
10958
|
var import_node_fs30 = require("fs");
|
|
10635
10959
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10636
10960
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -10645,11 +10969,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10645
10969
|
};
|
|
10646
10970
|
function neatHome2() {
|
|
10647
10971
|
const override = process.env.NEAT_HOME;
|
|
10648
|
-
if (override && override.length > 0) return
|
|
10649
|
-
return
|
|
10972
|
+
if (override && override.length > 0) return import_node_path56.default.resolve(override);
|
|
10973
|
+
return import_node_path56.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10650
10974
|
}
|
|
10651
10975
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10652
|
-
return
|
|
10976
|
+
return import_node_path56.default.join(home, "connectors.json");
|
|
10653
10977
|
}
|
|
10654
10978
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10655
10979
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -10836,15 +11160,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
10836
11160
|
|
|
10837
11161
|
// src/connectors/index.ts
|
|
10838
11162
|
init_cjs_shims();
|
|
10839
|
-
var
|
|
11163
|
+
var import_types42 = require("@neat.is/types");
|
|
10840
11164
|
var NO_ENV = "unknown";
|
|
10841
11165
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
10842
11166
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
10843
11167
|
const sites = [];
|
|
10844
11168
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
10845
11169
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
10846
|
-
if (edge.provenance !==
|
|
10847
|
-
const parsed = (0,
|
|
11170
|
+
if (edge.provenance !== import_types42.Provenance.EXTRACTED) continue;
|
|
11171
|
+
const parsed = (0, import_types42.parseFileId)(edge.source);
|
|
10848
11172
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
10849
11173
|
const site = { relPath: edge.evidence.file };
|
|
10850
11174
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -10855,7 +11179,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
10855
11179
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
10856
11180
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
10857
11181
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
10858
|
-
if (attrs.type !==
|
|
11182
|
+
if (attrs.type !== import_types42.NodeType.RouteNode || !attrs.path) return void 0;
|
|
10859
11183
|
const site = { relPath: attrs.path };
|
|
10860
11184
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
10861
11185
|
return site;
|
|
@@ -10875,6 +11199,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
10875
11199
|
const { kind, name, provider } = resolved.ensureInfraNode;
|
|
10876
11200
|
ensureInfraNode(graph, kind, name, provider);
|
|
10877
11201
|
}
|
|
11202
|
+
mergeObservedColumns(graph, resolved.targetNodeId, signal.columns);
|
|
10878
11203
|
const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV);
|
|
10879
11204
|
const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : routeCallSiteFor(graph, resolved.targetNodeId) ?? staticCallSiteFor(graph, resolved.serviceName, resolved.targetNodeId);
|
|
10880
11205
|
const sourceId = callSite ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite) : serviceNodeId;
|
|
@@ -11305,6 +11630,7 @@ async function fetchSupabaseEdgeLogs(config, token, startIso, endIso, fetchImpl
|
|
|
11305
11630
|
|
|
11306
11631
|
// src/connectors/supabase/map.ts
|
|
11307
11632
|
init_cjs_shims();
|
|
11633
|
+
init_otel();
|
|
11308
11634
|
|
|
11309
11635
|
// src/connectors/supabase/types.ts
|
|
11310
11636
|
init_cjs_shims();
|
|
@@ -11330,10 +11656,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
11330
11656
|
// src/connectors/supabase/map.ts
|
|
11331
11657
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
11332
11658
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
11333
|
-
function targetFromRestPath(
|
|
11334
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
11659
|
+
function targetFromRestPath(path59) {
|
|
11660
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path59);
|
|
11335
11661
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
11336
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
11662
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path59);
|
|
11337
11663
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
11338
11664
|
return null;
|
|
11339
11665
|
}
|
|
@@ -11397,12 +11723,14 @@ function diffPgStatStatementsToSignals(rows, previous, nowIso2) {
|
|
|
11397
11723
|
if (delta <= 0) continue;
|
|
11398
11724
|
const table = tableNameFromQueryText(row.query);
|
|
11399
11725
|
if (!table) continue;
|
|
11726
|
+
const columns = columnsFromSqlStatement(row.query);
|
|
11400
11727
|
signals.push({
|
|
11401
11728
|
targetKind: SUPABASE_TABLE_TARGET_KIND,
|
|
11402
11729
|
targetName: table,
|
|
11403
11730
|
callCount: delta,
|
|
11404
11731
|
errorCount: 0,
|
|
11405
|
-
lastObservedIso: nowIso2
|
|
11732
|
+
lastObservedIso: nowIso2,
|
|
11733
|
+
...columns.length > 0 ? { columns } : {}
|
|
11406
11734
|
});
|
|
11407
11735
|
}
|
|
11408
11736
|
for (const queryid of [...previous.keys()]) {
|
|
@@ -11442,23 +11770,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
11442
11770
|
|
|
11443
11771
|
// src/connectors/supabase/resolve.ts
|
|
11444
11772
|
init_cjs_shims();
|
|
11445
|
-
var
|
|
11773
|
+
var import_types44 = require("@neat.is/types");
|
|
11446
11774
|
function createSupabaseResolveTarget(graph, config) {
|
|
11447
11775
|
return (signal, _ctx) => {
|
|
11448
11776
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
11449
11777
|
return null;
|
|
11450
11778
|
}
|
|
11451
|
-
const subResourceId = (0,
|
|
11779
|
+
const subResourceId = (0, import_types44.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
11452
11780
|
if (graph.hasNode(subResourceId)) {
|
|
11453
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
11781
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
|
|
11454
11782
|
}
|
|
11455
|
-
const bareResourceId = (0,
|
|
11783
|
+
const bareResourceId = (0, import_types44.infraId)(signal.targetKind, signal.targetName);
|
|
11456
11784
|
if (graph.hasNode(bareResourceId)) {
|
|
11457
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
11785
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
|
|
11458
11786
|
}
|
|
11459
|
-
const projectLevelId = (0,
|
|
11787
|
+
const projectLevelId = (0, import_types44.infraId)("supabase", config.nodeRef);
|
|
11460
11788
|
if (graph.hasNode(projectLevelId)) {
|
|
11461
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
11789
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types44.EdgeType.CALLS };
|
|
11462
11790
|
}
|
|
11463
11791
|
return null;
|
|
11464
11792
|
};
|
|
@@ -11551,7 +11879,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
11551
11879
|
|
|
11552
11880
|
// src/connectors/railway/index.ts
|
|
11553
11881
|
init_cjs_shims();
|
|
11554
|
-
var
|
|
11882
|
+
var import_types48 = require("@neat.is/types");
|
|
11555
11883
|
|
|
11556
11884
|
// src/connectors/railway/client.ts
|
|
11557
11885
|
init_cjs_shims();
|
|
@@ -11702,7 +12030,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
11702
12030
|
const out = [];
|
|
11703
12031
|
graph.forEachNode((_id, attrs) => {
|
|
11704
12032
|
const node = attrs;
|
|
11705
|
-
if (node.type !==
|
|
12033
|
+
if (node.type !== import_types48.NodeType.RouteNode) return;
|
|
11706
12034
|
const route = attrs;
|
|
11707
12035
|
if (route.service !== serviceName) return;
|
|
11708
12036
|
out.push({
|
|
@@ -11806,12 +12134,12 @@ function createRailwayResolveTarget(config) {
|
|
|
11806
12134
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
11807
12135
|
if (!serviceName) return null;
|
|
11808
12136
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
11809
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
12137
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types48.EdgeType.CALLS };
|
|
11810
12138
|
}
|
|
11811
12139
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
11812
12140
|
const peerName = config.serviceNameById[signal.targetName];
|
|
11813
12141
|
if (!peerName) return null;
|
|
11814
|
-
return { targetNodeId: (0,
|
|
12142
|
+
return { targetNodeId: (0, import_types48.serviceId)(peerName), serviceName, edgeType: import_types48.EdgeType.CONNECTS_TO };
|
|
11815
12143
|
}
|
|
11816
12144
|
return null;
|
|
11817
12145
|
};
|
|
@@ -11935,9 +12263,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
11935
12263
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
11936
12264
|
if (secondSep === -1) return null;
|
|
11937
12265
|
const method = rest.slice(0, secondSep);
|
|
11938
|
-
const
|
|
11939
|
-
if (!resourceName || !method || !
|
|
11940
|
-
return { resourceName, method, path:
|
|
12266
|
+
const path59 = rest.slice(secondSep + 1);
|
|
12267
|
+
if (!resourceName || !method || !path59) return null;
|
|
12268
|
+
return { resourceName, method, path: path59 };
|
|
11941
12269
|
}
|
|
11942
12270
|
function resourceNameFor(type, labels) {
|
|
11943
12271
|
if (!labels) return null;
|
|
@@ -11975,14 +12303,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
11975
12303
|
if (!req) return null;
|
|
11976
12304
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
11977
12305
|
const method = req.requestMethod.toUpperCase();
|
|
11978
|
-
const
|
|
11979
|
-
if (
|
|
12306
|
+
const path59 = pathFromRequestUrl(req.requestUrl);
|
|
12307
|
+
if (path59 === null) return null;
|
|
11980
12308
|
const timestamp = entry.timestamp;
|
|
11981
12309
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
11982
12310
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
11983
12311
|
return {
|
|
11984
12312
|
targetKind: resourceType,
|
|
11985
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
12313
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path59 }),
|
|
11986
12314
|
callCount: 1,
|
|
11987
12315
|
errorCount: isError ? 1 : 0,
|
|
11988
12316
|
lastObservedIso: timestamp
|
|
@@ -11999,7 +12327,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
11999
12327
|
|
|
12000
12328
|
// src/connectors/firebase/resolve.ts
|
|
12001
12329
|
init_cjs_shims();
|
|
12002
|
-
var
|
|
12330
|
+
var import_types49 = require("@neat.is/types");
|
|
12003
12331
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
12004
12332
|
switch (resourceType) {
|
|
12005
12333
|
case "cloud_function":
|
|
@@ -12014,7 +12342,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
12014
12342
|
const entries = [];
|
|
12015
12343
|
graph.forEachNode((_id, attrs) => {
|
|
12016
12344
|
const node = attrs;
|
|
12017
|
-
if (node.type !==
|
|
12345
|
+
if (node.type !== import_types49.NodeType.RouteNode) return;
|
|
12018
12346
|
const route = attrs;
|
|
12019
12347
|
if (route.service !== serviceName) return;
|
|
12020
12348
|
entries.push({
|
|
@@ -12046,7 +12374,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
12046
12374
|
return {
|
|
12047
12375
|
targetNodeId: match.routeNodeId,
|
|
12048
12376
|
serviceName,
|
|
12049
|
-
edgeType:
|
|
12377
|
+
edgeType: import_types49.EdgeType.CALLS
|
|
12050
12378
|
};
|
|
12051
12379
|
};
|
|
12052
12380
|
}
|
|
@@ -12073,7 +12401,7 @@ init_cjs_shims();
|
|
|
12073
12401
|
|
|
12074
12402
|
// src/connectors/cloudflare/connector.ts
|
|
12075
12403
|
init_cjs_shims();
|
|
12076
|
-
var
|
|
12404
|
+
var import_types51 = require("@neat.is/types");
|
|
12077
12405
|
|
|
12078
12406
|
// src/connectors/cloudflare/client.ts
|
|
12079
12407
|
init_cjs_shims();
|
|
@@ -12189,7 +12517,7 @@ function mapEventToSignal(event) {
|
|
|
12189
12517
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
12190
12518
|
const statusCode = metadata?.statusCode;
|
|
12191
12519
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
12192
|
-
const
|
|
12520
|
+
const path59 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
12193
12521
|
return {
|
|
12194
12522
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
12195
12523
|
targetName: scriptName,
|
|
@@ -12197,7 +12525,7 @@ function mapEventToSignal(event) {
|
|
|
12197
12525
|
errorCount: isError ? 1 : 0,
|
|
12198
12526
|
lastObservedIso: observedAt.toISOString(),
|
|
12199
12527
|
method,
|
|
12200
|
-
...
|
|
12528
|
+
...path59 ? { path: path59 } : {},
|
|
12201
12529
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
12202
12530
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
12203
12531
|
};
|
|
@@ -12237,19 +12565,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
12237
12565
|
graph.forEachNode((id, attrs) => {
|
|
12238
12566
|
if (found) return;
|
|
12239
12567
|
const a = attrs;
|
|
12240
|
-
if (a.type ===
|
|
12568
|
+
if (a.type === import_types51.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
12241
12569
|
found = id;
|
|
12242
12570
|
}
|
|
12243
12571
|
});
|
|
12244
12572
|
return found;
|
|
12245
12573
|
}
|
|
12246
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
12247
|
-
const normalizedPath = normalizePathTemplate(
|
|
12574
|
+
function findMatchingRouteNode(graph, serviceName, method, path59) {
|
|
12575
|
+
const normalizedPath = normalizePathTemplate(path59);
|
|
12248
12576
|
let found = null;
|
|
12249
12577
|
graph.forEachNode((id, attrs) => {
|
|
12250
12578
|
if (found) return;
|
|
12251
12579
|
const a = attrs;
|
|
12252
|
-
if (a.type !==
|
|
12580
|
+
if (a.type !== import_types51.NodeType.RouteNode || a.service !== serviceName) return;
|
|
12253
12581
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
12254
12582
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
12255
12583
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -12261,18 +12589,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12261
12589
|
return (signal) => {
|
|
12262
12590
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
12263
12591
|
const scriptName = signal.targetName;
|
|
12264
|
-
const { method, path:
|
|
12592
|
+
const { method, path: path59 } = signal;
|
|
12265
12593
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
12266
|
-
if (!method || !
|
|
12267
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
12594
|
+
if (!method || !path59) return wholeFileId;
|
|
12595
|
+
return findMatchingRouteNode(graph, serviceName, method, path59) ?? wholeFileId;
|
|
12268
12596
|
};
|
|
12269
12597
|
const mapping = config.workers?.[scriptName];
|
|
12270
12598
|
if (mapping) {
|
|
12271
|
-
const wholeFileId = (0,
|
|
12599
|
+
const wholeFileId = (0, import_types51.fileId)(mapping.service, mapping.entryFile);
|
|
12272
12600
|
return {
|
|
12273
12601
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
12274
12602
|
serviceName: mapping.service,
|
|
12275
|
-
edgeType:
|
|
12603
|
+
edgeType: import_types51.EdgeType.CALLS
|
|
12276
12604
|
};
|
|
12277
12605
|
}
|
|
12278
12606
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -12281,13 +12609,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12281
12609
|
return {
|
|
12282
12610
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
12283
12611
|
serviceName: fileNode.service,
|
|
12284
|
-
edgeType:
|
|
12612
|
+
edgeType: import_types51.EdgeType.CALLS
|
|
12285
12613
|
};
|
|
12286
12614
|
}
|
|
12287
12615
|
return {
|
|
12288
|
-
targetNodeId: (0,
|
|
12616
|
+
targetNodeId: (0, import_types51.infraId)("cloudflare-worker", scriptName),
|
|
12289
12617
|
serviceName: scriptName,
|
|
12290
|
-
edgeType:
|
|
12618
|
+
edgeType: import_types51.EdgeType.CALLS,
|
|
12291
12619
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
12292
12620
|
};
|
|
12293
12621
|
};
|
|
@@ -12465,12 +12793,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
12465
12793
|
if (!prior || calls <= prior.calls) continue;
|
|
12466
12794
|
const table = tableFromSqlStatement(row.query);
|
|
12467
12795
|
if (!table) continue;
|
|
12796
|
+
const columns = columnsFromSqlStatement(row.query);
|
|
12468
12797
|
signals.push({
|
|
12469
12798
|
targetKind: NEON_SQL_TABLE_TARGET_KIND,
|
|
12470
12799
|
targetName: table,
|
|
12471
12800
|
callCount: calls - prior.calls,
|
|
12472
12801
|
errorCount: 0,
|
|
12473
|
-
lastObservedIso: observedAtIso
|
|
12802
|
+
lastObservedIso: observedAtIso,
|
|
12803
|
+
...columns.length > 0 ? { columns } : {}
|
|
12474
12804
|
});
|
|
12475
12805
|
}
|
|
12476
12806
|
for (const queryid of previous.keys()) {
|
|
@@ -12481,14 +12811,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
12481
12811
|
|
|
12482
12812
|
// src/connectors/neon/resolve.ts
|
|
12483
12813
|
init_cjs_shims();
|
|
12484
|
-
var
|
|
12814
|
+
var import_types55 = require("@neat.is/types");
|
|
12485
12815
|
function createNeonResolveTarget(config) {
|
|
12486
12816
|
return (signal) => {
|
|
12487
12817
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
12488
12818
|
return {
|
|
12489
|
-
targetNodeId: (0,
|
|
12819
|
+
targetNodeId: (0, import_types55.infraId)("sql-table", signal.targetName),
|
|
12490
12820
|
serviceName: config.serviceName,
|
|
12491
|
-
edgeType:
|
|
12821
|
+
edgeType: import_types55.EdgeType.CALLS,
|
|
12492
12822
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
12493
12823
|
};
|
|
12494
12824
|
};
|
|
@@ -13052,11 +13382,11 @@ function registerRoutes(scope, ctx) {
|
|
|
13052
13382
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
13053
13383
|
const parsed = [];
|
|
13054
13384
|
for (const c of candidates) {
|
|
13055
|
-
const r =
|
|
13385
|
+
const r = import_types58.DivergenceTypeSchema.safeParse(c);
|
|
13056
13386
|
if (!r.success) {
|
|
13057
13387
|
return reply.code(400).send({
|
|
13058
13388
|
error: `unknown divergence type "${c}"`,
|
|
13059
|
-
allowed:
|
|
13389
|
+
allowed: import_types58.DivergenceTypeSchema.options
|
|
13060
13390
|
});
|
|
13061
13391
|
}
|
|
13062
13392
|
parsed.push(r.data);
|
|
@@ -13365,7 +13695,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13365
13695
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
13366
13696
|
let violations = await log.readAll();
|
|
13367
13697
|
if (req.query.severity) {
|
|
13368
|
-
const sev =
|
|
13698
|
+
const sev = import_types58.PolicySeveritySchema.safeParse(req.query.severity);
|
|
13369
13699
|
if (!sev.success) {
|
|
13370
13700
|
return reply.code(400).send({
|
|
13371
13701
|
error: "invalid severity",
|
|
@@ -13404,7 +13734,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13404
13734
|
scope.post("/policies/check", async (req, reply) => {
|
|
13405
13735
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
13406
13736
|
if (!proj) return;
|
|
13407
|
-
const parsed =
|
|
13737
|
+
const parsed = import_types58.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
13408
13738
|
if (!parsed.success) {
|
|
13409
13739
|
return reply.code(400).send({
|
|
13410
13740
|
error: "invalid /policies/check body",
|
|
@@ -13726,7 +14056,7 @@ init_otel_grpc();
|
|
|
13726
14056
|
// src/daemon.ts
|
|
13727
14057
|
init_cjs_shims();
|
|
13728
14058
|
var import_node_fs32 = require("fs");
|
|
13729
|
-
var
|
|
14059
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13730
14060
|
var import_node_module = require("module");
|
|
13731
14061
|
init_otel();
|
|
13732
14062
|
init_auth();
|
|
@@ -13734,7 +14064,7 @@ init_auth();
|
|
|
13734
14064
|
// src/unrouted.ts
|
|
13735
14065
|
init_cjs_shims();
|
|
13736
14066
|
var import_node_fs31 = require("fs");
|
|
13737
|
-
var
|
|
14067
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
13738
14068
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
13739
14069
|
return {
|
|
13740
14070
|
timestamp: now.toISOString(),
|
|
@@ -13744,34 +14074,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
13744
14074
|
};
|
|
13745
14075
|
}
|
|
13746
14076
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
13747
|
-
const target =
|
|
14077
|
+
const target = import_node_path57.default.join(neatHome3, "errors.ndjson");
|
|
13748
14078
|
await import_node_fs31.promises.mkdir(neatHome3, { recursive: true });
|
|
13749
14079
|
await import_node_fs31.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
13750
14080
|
}
|
|
13751
14081
|
function unroutedErrorsPath(neatHome3) {
|
|
13752
|
-
return
|
|
14082
|
+
return import_node_path57.default.join(neatHome3, "errors.ndjson");
|
|
13753
14083
|
}
|
|
13754
14084
|
|
|
13755
14085
|
// src/daemon.ts
|
|
13756
|
-
var
|
|
14086
|
+
var import_types59 = require("@neat.is/types");
|
|
13757
14087
|
function daemonJsonPath(scanPath) {
|
|
13758
|
-
return
|
|
14088
|
+
return import_node_path58.default.join(scanPath, "neat-out", "daemon.json");
|
|
13759
14089
|
}
|
|
13760
14090
|
function daemonsDiscoveryDir(home) {
|
|
13761
14091
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
13762
|
-
return
|
|
14092
|
+
return import_node_path58.default.join(base, "daemons");
|
|
13763
14093
|
}
|
|
13764
14094
|
function daemonDiscoveryPath(project, home) {
|
|
13765
|
-
return
|
|
14095
|
+
return import_node_path58.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
13766
14096
|
}
|
|
13767
14097
|
function sanitizeDiscoveryName(project) {
|
|
13768
14098
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
13769
14099
|
}
|
|
13770
14100
|
function neatHomeFromEnv() {
|
|
13771
14101
|
const env = process.env.NEAT_HOME;
|
|
13772
|
-
if (env && env.length > 0) return
|
|
14102
|
+
if (env && env.length > 0) return import_node_path58.default.resolve(env);
|
|
13773
14103
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
13774
|
-
return
|
|
14104
|
+
return import_node_path58.default.join(home, ".neat");
|
|
13775
14105
|
}
|
|
13776
14106
|
function resolveNeatVersion() {
|
|
13777
14107
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -13826,11 +14156,11 @@ function teardownSlot(slot) {
|
|
|
13826
14156
|
}
|
|
13827
14157
|
}
|
|
13828
14158
|
function neatHomeFor(opts) {
|
|
13829
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
14159
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path58.default.resolve(opts.neatHome);
|
|
13830
14160
|
const env = process.env.NEAT_HOME;
|
|
13831
|
-
if (env && env.length > 0) return
|
|
14161
|
+
if (env && env.length > 0) return import_node_path58.default.resolve(env);
|
|
13832
14162
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
13833
|
-
return
|
|
14163
|
+
return import_node_path58.default.join(home, ".neat");
|
|
13834
14164
|
}
|
|
13835
14165
|
function routeSpanToProject(serviceName, projects) {
|
|
13836
14166
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -13878,11 +14208,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
13878
14208
|
if (!serviceName) return true;
|
|
13879
14209
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
13880
14210
|
return graph.someNode(
|
|
13881
|
-
(_id, attrs) => attrs.type ===
|
|
14211
|
+
(_id, attrs) => attrs.type === import_types59.NodeType.ServiceNode && attrs.name === serviceName
|
|
13882
14212
|
);
|
|
13883
14213
|
}
|
|
13884
14214
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
13885
|
-
const paths = pathsForProject(entry.name,
|
|
14215
|
+
const paths = pathsForProject(entry.name, import_node_path58.default.join(entry.path, "neat-out"));
|
|
13886
14216
|
try {
|
|
13887
14217
|
const stat = await import_node_fs32.promises.stat(entry.path);
|
|
13888
14218
|
if (!stat.isDirectory()) {
|
|
@@ -13998,7 +14328,7 @@ async function startDaemon(opts = {}) {
|
|
|
13998
14328
|
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;
|
|
13999
14329
|
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;
|
|
14000
14330
|
const singleProject = projectArg;
|
|
14001
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
14331
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path58.default.resolve(projectPathArg) : null;
|
|
14002
14332
|
if (singleProject && !singleProjectPath) {
|
|
14003
14333
|
throw new Error(
|
|
14004
14334
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -14013,7 +14343,7 @@ async function startDaemon(opts = {}) {
|
|
|
14013
14343
|
);
|
|
14014
14344
|
}
|
|
14015
14345
|
}
|
|
14016
|
-
const pidPath =
|
|
14346
|
+
const pidPath = import_node_path58.default.join(home, "neatd.pid");
|
|
14017
14347
|
await writeAtomically(pidPath, `${process.pid}
|
|
14018
14348
|
`);
|
|
14019
14349
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -14425,8 +14755,8 @@ async function startDaemon(opts = {}) {
|
|
|
14425
14755
|
let registryWatcher = null;
|
|
14426
14756
|
let reloadTimer = null;
|
|
14427
14757
|
if (!singleProject) try {
|
|
14428
|
-
const regDir =
|
|
14429
|
-
const regBase =
|
|
14758
|
+
const regDir = import_node_path58.default.dirname(regPath);
|
|
14759
|
+
const regBase = import_node_path58.default.basename(regPath);
|
|
14430
14760
|
registryWatcher = (0, import_node_fs32.watch)(regDir, (_eventType, filename) => {
|
|
14431
14761
|
if (filename !== null && filename !== regBase) return;
|
|
14432
14762
|
if (reloadTimer) clearTimeout(reloadTimer);
|