@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/cli.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path71 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path71) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path71)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -194,8 +194,8 @@ function reshapeGrpcRequest(req) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
function resolveProtoRoot() {
|
|
197
|
-
const here =
|
|
198
|
-
return
|
|
197
|
+
const here = import_node_path39.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path39.default.resolve(here, "..", "proto");
|
|
199
199
|
}
|
|
200
200
|
function loadTraceService() {
|
|
201
201
|
const protoRoot = resolveProtoRoot();
|
|
@@ -263,13 +263,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
263
263
|
})
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
|
-
var import_node_url2,
|
|
266
|
+
var import_node_url2, import_node_path39, import_node_crypto2, grpc, protoLoader;
|
|
267
267
|
var init_otel_grpc = __esm({
|
|
268
268
|
"src/otel-grpc.ts"() {
|
|
269
269
|
"use strict";
|
|
270
270
|
init_cjs_shims();
|
|
271
271
|
import_node_url2 = require("url");
|
|
272
|
-
|
|
272
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
273
273
|
import_node_crypto2 = require("crypto");
|
|
274
274
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
275
275
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -355,6 +355,46 @@ function tableFromSqlStatement(sql) {
|
|
|
355
355
|
const m = /\b(?:from|into|update)\s+(?:"?[\w$]+"?\s*\.\s*)?"?([a-zA-Z_][\w$]*)"?/i.exec(sql);
|
|
356
356
|
return m ? m[1] : null;
|
|
357
357
|
}
|
|
358
|
+
function columnsFromSqlStatement(sql) {
|
|
359
|
+
if (typeof sql !== "string" || sql.length === 0) return [];
|
|
360
|
+
const s = sql.replace(/\s+/g, " ").trim();
|
|
361
|
+
if (/\bjoin\b/i.test(s)) return [];
|
|
362
|
+
if ((s.match(/\bfrom\b/gi) ?? []).length > 1) return [];
|
|
363
|
+
const bare = (raw) => {
|
|
364
|
+
let t = raw.trim().replace(/"/g, "");
|
|
365
|
+
if (/[()*]/.test(t)) return null;
|
|
366
|
+
t = t.split(/\s+as\s+/i)[0].trim();
|
|
367
|
+
t = t.split(".").pop();
|
|
368
|
+
return /^[a-z_][\w$]*$/i.test(t) ? t.toLowerCase() : null;
|
|
369
|
+
};
|
|
370
|
+
const isCol = (c) => c !== null;
|
|
371
|
+
const cols = (list) => [...new Set(list.split(",").map(bare).filter(isCol))];
|
|
372
|
+
const whereCols = (w) => w ? [
|
|
373
|
+
...new Set(
|
|
374
|
+
[
|
|
375
|
+
...w.matchAll(
|
|
376
|
+
/(?:"?[\w$]+"?\.)?"?([a-z_][\w$]*)"?\s*(?:=|<|>|<=|>=|<>|!=|\bis\b|\bin\b|\blike\b)/gi
|
|
377
|
+
)
|
|
378
|
+
].map((match) => match[1].toLowerCase()).filter((c) => !/^(and|or|not|null)$/i.test(c))
|
|
379
|
+
)
|
|
380
|
+
] : [];
|
|
381
|
+
let m;
|
|
382
|
+
if (m = /\binsert\s+into\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?\s*\(([^)]*)\)/i.exec(s)) {
|
|
383
|
+
return cols(m[1]);
|
|
384
|
+
}
|
|
385
|
+
if (m = /\bupdate\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?\s+set\s+(.+?)(?:\bwhere\b(.+))?$/i.exec(s)) {
|
|
386
|
+
const set = m[1].split(",").map((p) => bare(p.split("=")[0])).filter(isCol);
|
|
387
|
+
return [.../* @__PURE__ */ new Set([...set, ...whereCols(m[2] ?? void 0)])];
|
|
388
|
+
}
|
|
389
|
+
if (m = /\bdelete\s+from\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?(?:\s+where\b(.+))?$/i.exec(s)) {
|
|
390
|
+
return whereCols(m[1] ?? void 0);
|
|
391
|
+
}
|
|
392
|
+
if (m = /\bselect\s+(.+?)\s+from\s+(?:"?[\w$]+"?\.)?"?[\w$]+"?(?:\s+where\b(.+))?$/i.exec(s)) {
|
|
393
|
+
if (m[1].trim() === "*") return [];
|
|
394
|
+
return [.../* @__PURE__ */ new Set([...cols(m[1]), ...whereCols(m[2] ?? void 0)])];
|
|
395
|
+
}
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
358
398
|
function messagingDestinationOf(attrs) {
|
|
359
399
|
for (const key of ["messaging.destination.name", "messaging.destination"]) {
|
|
360
400
|
const v = attrs[key];
|
|
@@ -375,8 +415,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
375
415
|
const v = attrs[key];
|
|
376
416
|
if (typeof v === "string" && v.length > 0) {
|
|
377
417
|
const q = v.indexOf("?");
|
|
378
|
-
const
|
|
379
|
-
if (
|
|
418
|
+
const path71 = q === -1 ? v : v.slice(0, q);
|
|
419
|
+
if (path71.length > 0) return path71;
|
|
380
420
|
}
|
|
381
421
|
}
|
|
382
422
|
return void 0;
|
|
@@ -413,6 +453,7 @@ function parseOtlpRequest(body) {
|
|
|
413
453
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
414
454
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
415
455
|
dbTable: typeof attrs["db.statement"] === "string" ? tableFromSqlStatement(attrs["db.statement"]) ?? void 0 : void 0,
|
|
456
|
+
dbColumns: typeof attrs["db.statement"] === "string" ? columnsFromSqlStatement(attrs["db.statement"]) : void 0,
|
|
416
457
|
httpRoute: typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0,
|
|
417
458
|
httpMethod: typeof attrs["http.request.method"] === "string" ? attrs["http.request.method"] : typeof attrs["http.method"] === "string" ? attrs["http.method"] : void 0,
|
|
418
459
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
@@ -434,10 +475,10 @@ function parseOtlpRequest(body) {
|
|
|
434
475
|
return out;
|
|
435
476
|
}
|
|
436
477
|
function loadProtoRoot() {
|
|
437
|
-
const here =
|
|
438
|
-
const protoRoot =
|
|
478
|
+
const here = import_node_path40.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
479
|
+
const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
|
|
439
480
|
const root = new import_protobufjs.default.Root();
|
|
440
|
-
root.resolvePath = (_origin, target) =>
|
|
481
|
+
root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
|
|
441
482
|
root.loadSync(
|
|
442
483
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
443
484
|
{ keepCase: true }
|
|
@@ -668,12 +709,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
668
709
|
}
|
|
669
710
|
}
|
|
670
711
|
}
|
|
671
|
-
var
|
|
712
|
+
var import_node_path40, import_node_url3, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
672
713
|
var init_otel = __esm({
|
|
673
714
|
"src/otel.ts"() {
|
|
674
715
|
"use strict";
|
|
675
716
|
init_cjs_shims();
|
|
676
|
-
|
|
717
|
+
import_node_path40 = __toESM(require("path"), 1);
|
|
677
718
|
import_node_url3 = require("url");
|
|
678
719
|
import_fastify = __toESM(require("fastify"), 1);
|
|
679
720
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -710,7 +751,7 @@ __export(cli_exports, {
|
|
|
710
751
|
});
|
|
711
752
|
module.exports = __toCommonJS(cli_exports);
|
|
712
753
|
init_cjs_shims();
|
|
713
|
-
var
|
|
754
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
714
755
|
var import_node_os6 = __toESM(require("os"), 1);
|
|
715
756
|
var import_node_fs43 = require("fs");
|
|
716
757
|
|
|
@@ -1280,19 +1321,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1280
1321
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1281
1322
|
let best = { path: [start], edges: [] };
|
|
1282
1323
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1283
|
-
function step(node,
|
|
1284
|
-
if (
|
|
1285
|
-
best = { path: [...
|
|
1324
|
+
function step(node, path71, edges) {
|
|
1325
|
+
if (path71.length > best.path.length) {
|
|
1326
|
+
best = { path: [...path71], edges: [...edges] };
|
|
1286
1327
|
}
|
|
1287
|
-
if (
|
|
1328
|
+
if (path71.length - 1 >= maxDepth) return;
|
|
1288
1329
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1289
1330
|
for (const [srcId, edge] of incoming) {
|
|
1290
1331
|
if (visited.has(srcId)) continue;
|
|
1291
1332
|
visited.add(srcId);
|
|
1292
|
-
|
|
1333
|
+
path71.push(srcId);
|
|
1293
1334
|
edges.push(edge);
|
|
1294
|
-
step(srcId,
|
|
1295
|
-
|
|
1335
|
+
step(srcId, path71, edges);
|
|
1336
|
+
path71.pop();
|
|
1296
1337
|
edges.pop();
|
|
1297
1338
|
visited.delete(srcId);
|
|
1298
1339
|
}
|
|
@@ -1499,26 +1540,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
|
|
|
1499
1540
|
return best;
|
|
1500
1541
|
}
|
|
1501
1542
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1502
|
-
const
|
|
1543
|
+
const path71 = [originServiceId];
|
|
1503
1544
|
const edges = [];
|
|
1504
1545
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1505
1546
|
let current = originServiceId;
|
|
1506
1547
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1507
1548
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1508
1549
|
if (!hop) break;
|
|
1509
|
-
|
|
1550
|
+
path71.push(hop.nextService);
|
|
1510
1551
|
edges.push(hop.edge);
|
|
1511
1552
|
visited.add(hop.nextService);
|
|
1512
1553
|
current = hop.nextService;
|
|
1513
1554
|
}
|
|
1514
1555
|
if (edges.length === 0) return null;
|
|
1515
|
-
return { path:
|
|
1556
|
+
return { path: path71, edges, culprit: current };
|
|
1516
1557
|
}
|
|
1517
1558
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1518
1559
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1519
1560
|
if (!chain) return null;
|
|
1520
1561
|
const culprit = chain.culprit;
|
|
1521
|
-
const
|
|
1562
|
+
const path71 = [...chain.path];
|
|
1522
1563
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1523
1564
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1524
1565
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1526,14 +1567,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1526
1567
|
if (loc) {
|
|
1527
1568
|
let rootCauseNode = culprit;
|
|
1528
1569
|
if (loc.fileNode) {
|
|
1529
|
-
|
|
1570
|
+
path71.push(loc.fileNode);
|
|
1530
1571
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1531
1572
|
rootCauseNode = loc.fileNode;
|
|
1532
1573
|
}
|
|
1533
1574
|
return import_types.RootCauseResultSchema.parse({
|
|
1534
1575
|
rootCauseNode,
|
|
1535
1576
|
rootCauseReason: loc.rootCauseReason,
|
|
1536
|
-
traversalPath:
|
|
1577
|
+
traversalPath: path71,
|
|
1537
1578
|
edgeProvenances,
|
|
1538
1579
|
confidence,
|
|
1539
1580
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1545,7 +1586,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1545
1586
|
return import_types.RootCauseResultSchema.parse({
|
|
1546
1587
|
rootCauseNode: culprit,
|
|
1547
1588
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1548
|
-
traversalPath:
|
|
1589
|
+
traversalPath: path71,
|
|
1549
1590
|
edgeProvenances,
|
|
1550
1591
|
confidence,
|
|
1551
1592
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2133,7 +2174,7 @@ var PolicyViolationsLog = class {
|
|
|
2133
2174
|
};
|
|
2134
2175
|
|
|
2135
2176
|
// src/ingest.ts
|
|
2136
|
-
var
|
|
2177
|
+
var import_types7 = require("@neat.is/types");
|
|
2137
2178
|
|
|
2138
2179
|
// src/extract/routes.ts
|
|
2139
2180
|
init_cjs_shims();
|
|
@@ -3191,6 +3232,42 @@ async function addRoutes(graph, services) {
|
|
|
3191
3232
|
return { nodesAdded, edgesAdded };
|
|
3192
3233
|
}
|
|
3193
3234
|
|
|
3235
|
+
// src/columns.ts
|
|
3236
|
+
init_cjs_shims();
|
|
3237
|
+
var import_types6 = require("@neat.is/types");
|
|
3238
|
+
var OBSERVED_COLUMN_CONFIDENCE = 0.9;
|
|
3239
|
+
function normalizeProvenances(provenances) {
|
|
3240
|
+
return [...new Set(provenances)].sort();
|
|
3241
|
+
}
|
|
3242
|
+
function foldColumns(existing, names, provenance, confidence) {
|
|
3243
|
+
const out = (existing ?? []).map((c) => ({
|
|
3244
|
+
...c,
|
|
3245
|
+
provenances: [...c.provenances]
|
|
3246
|
+
}));
|
|
3247
|
+
const byName = new Map(out.map((c) => [c.name, c]));
|
|
3248
|
+
for (const raw of names) {
|
|
3249
|
+
const name = raw.toLowerCase();
|
|
3250
|
+
const prior = byName.get(name);
|
|
3251
|
+
if (!prior) {
|
|
3252
|
+
const col = { name, provenances: [provenance], confidence };
|
|
3253
|
+
byName.set(name, col);
|
|
3254
|
+
out.push(col);
|
|
3255
|
+
continue;
|
|
3256
|
+
}
|
|
3257
|
+
if (!prior.provenances.includes(provenance)) {
|
|
3258
|
+
prior.provenances = normalizeProvenances([...prior.provenances, provenance]);
|
|
3259
|
+
}
|
|
3260
|
+
if (confidence > prior.confidence) prior.confidence = confidence;
|
|
3261
|
+
}
|
|
3262
|
+
return out;
|
|
3263
|
+
}
|
|
3264
|
+
function columnIsDeclared(col) {
|
|
3265
|
+
return col.provenances.includes(import_types6.Provenance.EXTRACTED);
|
|
3266
|
+
}
|
|
3267
|
+
function columnIsObserved(col) {
|
|
3268
|
+
return col.provenances.includes(import_types6.Provenance.OBSERVED);
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3194
3271
|
// src/ingest.ts
|
|
3195
3272
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
3196
3273
|
var DAY_MS = 24 * HOUR_MS;
|
|
@@ -3490,11 +3567,11 @@ function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
|
3490
3567
|
};
|
|
3491
3568
|
}
|
|
3492
3569
|
function reconcileObservedRelPath(graph, serviceName, relPath) {
|
|
3493
|
-
if (graph.hasNode((0,
|
|
3570
|
+
if (graph.hasNode((0, import_types7.fileId)(serviceName, relPath))) return relPath;
|
|
3494
3571
|
let best = null;
|
|
3495
3572
|
graph.forEachNode((_id, attrs) => {
|
|
3496
3573
|
const a = attrs;
|
|
3497
|
-
if (a.type !==
|
|
3574
|
+
if (a.type !== import_types7.NodeType.FileNode || a.service !== serviceName) return;
|
|
3498
3575
|
if (a.discoveredVia === "otel") return;
|
|
3499
3576
|
const p = a.path;
|
|
3500
3577
|
if (!p) return;
|
|
@@ -3506,14 +3583,14 @@ function reconcileObservedRelPath(graph, serviceName, relPath) {
|
|
|
3506
3583
|
}
|
|
3507
3584
|
function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
|
|
3508
3585
|
const svcAttrs = graph.hasNode(serviceNodeId) ? graph.getNodeAttributes(serviceNodeId) : void 0;
|
|
3509
|
-
const canonicalService = svcAttrs && svcAttrs.type ===
|
|
3586
|
+
const canonicalService = svcAttrs && svcAttrs.type === import_types7.NodeType.ServiceNode && typeof svcAttrs.name === "string" ? svcAttrs.name : serviceName;
|
|
3510
3587
|
const relPath = reconcileObservedRelPath(graph, canonicalService, callSite.relPath);
|
|
3511
|
-
const fileNodeId = (0,
|
|
3588
|
+
const fileNodeId = (0, import_types7.fileId)(canonicalService, relPath);
|
|
3512
3589
|
if (!graph.hasNode(fileNodeId)) {
|
|
3513
3590
|
const language = languageForExt(relPath);
|
|
3514
3591
|
const node = {
|
|
3515
3592
|
id: fileNodeId,
|
|
3516
|
-
type:
|
|
3593
|
+
type: import_types7.NodeType.FileNode,
|
|
3517
3594
|
service: canonicalService,
|
|
3518
3595
|
path: relPath,
|
|
3519
3596
|
...language ? { language } : {},
|
|
@@ -3522,14 +3599,14 @@ function ensureObservedFileNode(graph, serviceName, serviceNodeId, callSite) {
|
|
|
3522
3599
|
};
|
|
3523
3600
|
graph.addNode(fileNodeId, node);
|
|
3524
3601
|
}
|
|
3525
|
-
const containsId = makeObservedEdgeId(
|
|
3602
|
+
const containsId = makeObservedEdgeId(import_types7.EdgeType.CONTAINS, serviceNodeId, fileNodeId);
|
|
3526
3603
|
if (!graph.hasEdge(containsId)) {
|
|
3527
3604
|
const edge = {
|
|
3528
3605
|
id: containsId,
|
|
3529
3606
|
source: serviceNodeId,
|
|
3530
3607
|
target: fileNodeId,
|
|
3531
|
-
type:
|
|
3532
|
-
provenance:
|
|
3608
|
+
type: import_types7.EdgeType.CONTAINS,
|
|
3609
|
+
provenance: import_types7.Provenance.OBSERVED
|
|
3533
3610
|
};
|
|
3534
3611
|
graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge);
|
|
3535
3612
|
}
|
|
@@ -3553,11 +3630,11 @@ function pickContainingSymbol(candidates, fn) {
|
|
|
3553
3630
|
return [...candidates].sort(bySpan)[0].id;
|
|
3554
3631
|
}
|
|
3555
3632
|
function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line) {
|
|
3556
|
-
const sid = (0,
|
|
3633
|
+
const sid = (0, import_types7.symbolId)(service, relPath, fn);
|
|
3557
3634
|
if (!graph.hasNode(sid)) {
|
|
3558
3635
|
const node = {
|
|
3559
3636
|
id: sid,
|
|
3560
|
-
type:
|
|
3637
|
+
type: import_types7.NodeType.SymbolNode,
|
|
3561
3638
|
kind: "function",
|
|
3562
3639
|
qualname: fn,
|
|
3563
3640
|
span: { startLine: line, endLine: line },
|
|
@@ -3567,14 +3644,14 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
|
|
|
3567
3644
|
};
|
|
3568
3645
|
graph.addNode(sid, node);
|
|
3569
3646
|
}
|
|
3570
|
-
const containsId = makeObservedEdgeId(
|
|
3647
|
+
const containsId = makeObservedEdgeId(import_types7.EdgeType.CONTAINS, fileNodeId, sid);
|
|
3571
3648
|
if (!graph.hasEdge(containsId)) {
|
|
3572
3649
|
const edge = {
|
|
3573
3650
|
id: containsId,
|
|
3574
3651
|
source: fileNodeId,
|
|
3575
3652
|
target: sid,
|
|
3576
|
-
type:
|
|
3577
|
-
provenance:
|
|
3653
|
+
type: import_types7.EdgeType.CONTAINS,
|
|
3654
|
+
provenance: import_types7.Provenance.OBSERVED
|
|
3578
3655
|
};
|
|
3579
3656
|
graph.addEdgeWithKey(containsId, fileNodeId, sid, edge);
|
|
3580
3657
|
}
|
|
@@ -3586,9 +3663,9 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
|
3586
3663
|
let sawSymbol = false;
|
|
3587
3664
|
const candidates = [];
|
|
3588
3665
|
graph.forEachOutboundEdge(fileNodeId, (_edge, edgeAttrs, _source, target) => {
|
|
3589
|
-
if (edgeAttrs.type !==
|
|
3666
|
+
if (edgeAttrs.type !== import_types7.EdgeType.CONTAINS) return;
|
|
3590
3667
|
const t = graph.getNodeAttributes(target);
|
|
3591
|
-
if (t.type !==
|
|
3668
|
+
if (t.type !== import_types7.NodeType.SymbolNode) return;
|
|
3592
3669
|
sawSymbol = true;
|
|
3593
3670
|
if (line >= t.span.startLine && line <= t.span.endLine) {
|
|
3594
3671
|
candidates.push({ id: target, symbol: t });
|
|
@@ -3601,17 +3678,17 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
|
3601
3678
|
return fileNodeId;
|
|
3602
3679
|
}
|
|
3603
3680
|
function makeObservedEdgeId(type, source, target) {
|
|
3604
|
-
return (0,
|
|
3681
|
+
return (0, import_types7.observedEdgeId)(source, target, type);
|
|
3605
3682
|
}
|
|
3606
3683
|
function makeInferredEdgeId(type, source, target) {
|
|
3607
|
-
return (0,
|
|
3684
|
+
return (0, import_types7.inferredEdgeId)(source, target, type);
|
|
3608
3685
|
}
|
|
3609
3686
|
var INFERRED_CONFIDENCE = 0.6;
|
|
3610
3687
|
var STITCH_MAX_DEPTH = 2;
|
|
3611
3688
|
var STITCH_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3689
|
+
import_types7.EdgeType.CALLS,
|
|
3690
|
+
import_types7.EdgeType.CONNECTS_TO,
|
|
3691
|
+
import_types7.EdgeType.DEPENDS_ON
|
|
3615
3692
|
]);
|
|
3616
3693
|
var WIRE_SPAN_KIND_CLIENT = 3;
|
|
3617
3694
|
var WIRE_SPAN_KIND_PRODUCER = 4;
|
|
@@ -3627,11 +3704,11 @@ function spanServesGraphqlOperation(kind) {
|
|
|
3627
3704
|
return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
|
|
3628
3705
|
}
|
|
3629
3706
|
function ensureGraphqlOperationNode(graph, serviceName, operationType, operationName) {
|
|
3630
|
-
const id = (0,
|
|
3707
|
+
const id = (0, import_types7.graphqlOperationId)(serviceName, operationType, operationName);
|
|
3631
3708
|
if (graph.hasNode(id)) return id;
|
|
3632
3709
|
const node = {
|
|
3633
3710
|
id,
|
|
3634
|
-
type:
|
|
3711
|
+
type: import_types7.NodeType.GraphQLOperationNode,
|
|
3635
3712
|
name: operationName,
|
|
3636
3713
|
service: serviceName,
|
|
3637
3714
|
operationType: operationType.toLowerCase(),
|
|
@@ -3645,11 +3722,11 @@ function spanServesGrpcMethod(kind) {
|
|
|
3645
3722
|
return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
|
|
3646
3723
|
}
|
|
3647
3724
|
function ensureGrpcMethodNode(graph, rpcService, rpcMethod) {
|
|
3648
|
-
const id = (0,
|
|
3725
|
+
const id = (0, import_types7.grpcMethodId)(rpcService, rpcMethod);
|
|
3649
3726
|
if (graph.hasNode(id)) return id;
|
|
3650
3727
|
const node = {
|
|
3651
3728
|
id,
|
|
3652
|
-
type:
|
|
3729
|
+
type: import_types7.NodeType.GrpcMethodNode,
|
|
3653
3730
|
name: `${rpcService}/${rpcMethod}`,
|
|
3654
3731
|
rpcService,
|
|
3655
3732
|
rpcMethod,
|
|
@@ -3662,11 +3739,11 @@ function spanServesWebsocketChannel(kind) {
|
|
|
3662
3739
|
return kind !== WIRE_SPAN_KIND_CLIENT && kind !== WIRE_SPAN_KIND_PRODUCER && kind !== WIRE_SPAN_KIND_CONSUMER;
|
|
3663
3740
|
}
|
|
3664
3741
|
function ensureWebsocketChannelNode(graph, serviceName, channel) {
|
|
3665
|
-
const id = (0,
|
|
3742
|
+
const id = (0, import_types7.websocketChannelId)(serviceName, channel);
|
|
3666
3743
|
if (graph.hasNode(id)) return id;
|
|
3667
3744
|
const node = {
|
|
3668
3745
|
id,
|
|
3669
|
-
type:
|
|
3746
|
+
type: import_types7.NodeType.WebSocketChannelNode,
|
|
3670
3747
|
name: channel,
|
|
3671
3748
|
service: serviceName,
|
|
3672
3749
|
channel,
|
|
@@ -3679,11 +3756,11 @@ function messagingDestinationKind(system) {
|
|
|
3679
3756
|
return `${system}-topic`;
|
|
3680
3757
|
}
|
|
3681
3758
|
function ensureMessagingDestinationNode(graph, system, destination) {
|
|
3682
|
-
const id = (0,
|
|
3759
|
+
const id = (0, import_types7.infraId)(messagingDestinationKind(system), destination);
|
|
3683
3760
|
if (graph.hasNode(id)) return id;
|
|
3684
3761
|
const node = {
|
|
3685
3762
|
id,
|
|
3686
|
-
type:
|
|
3763
|
+
type: import_types7.NodeType.InfraNode,
|
|
3687
3764
|
name: destination,
|
|
3688
3765
|
provider: "self",
|
|
3689
3766
|
kind: messagingDestinationKind(system)
|
|
@@ -3727,9 +3804,9 @@ function lookupParentSpan(traceId, parentSpanId, now) {
|
|
|
3727
3804
|
};
|
|
3728
3805
|
}
|
|
3729
3806
|
function resolveServiceId(graph, host, env) {
|
|
3730
|
-
const envTagged = (0,
|
|
3807
|
+
const envTagged = (0, import_types7.serviceId)(host, env);
|
|
3731
3808
|
if (graph.hasNode(envTagged)) return envTagged;
|
|
3732
|
-
const envLess = (0,
|
|
3809
|
+
const envLess = (0, import_types7.serviceId)(host);
|
|
3733
3810
|
if (envLess !== envTagged && graph.hasNode(envLess)) return envLess;
|
|
3734
3811
|
let sameEnv = null;
|
|
3735
3812
|
let envLessMatch = null;
|
|
@@ -3737,7 +3814,7 @@ function resolveServiceId(graph, host, env) {
|
|
|
3737
3814
|
graph.forEachNode((id, attrs) => {
|
|
3738
3815
|
if (sameEnv) return;
|
|
3739
3816
|
const a = attrs;
|
|
3740
|
-
if (a.type !==
|
|
3817
|
+
if (a.type !== import_types7.NodeType.ServiceNode) return;
|
|
3741
3818
|
const matchesByName = a.name === host;
|
|
3742
3819
|
const matchesByAlias = a.aliases ? a.aliases.includes(host) : false;
|
|
3743
3820
|
if (!matchesByName && !matchesByAlias) return;
|
|
@@ -3752,14 +3829,14 @@ function resolveServiceId(graph, host, env) {
|
|
|
3752
3829
|
return sameEnv ?? envLessMatch ?? anyMatch;
|
|
3753
3830
|
}
|
|
3754
3831
|
function frontierIdFor(host) {
|
|
3755
|
-
return (0,
|
|
3832
|
+
return (0, import_types7.frontierId)(host);
|
|
3756
3833
|
}
|
|
3757
3834
|
function ensureServiceNode(graph, serviceName, env) {
|
|
3758
|
-
const id = (0,
|
|
3835
|
+
const id = (0, import_types7.serviceId)(serviceName, env);
|
|
3759
3836
|
if (graph.hasNode(id)) return id;
|
|
3760
3837
|
const wanted = serviceName.toLowerCase();
|
|
3761
3838
|
const extractedId = graph.findNode((_nid, attrs) => {
|
|
3762
|
-
if (attrs.type !==
|
|
3839
|
+
if (attrs.type !== import_types7.NodeType.ServiceNode) return false;
|
|
3763
3840
|
const svc = attrs;
|
|
3764
3841
|
if (svc.discoveredVia === "otel") return false;
|
|
3765
3842
|
return typeof svc.name === "string" && svc.name.toLowerCase() === wanted;
|
|
@@ -3767,7 +3844,7 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
3767
3844
|
if (extractedId) return extractedId;
|
|
3768
3845
|
const node = {
|
|
3769
3846
|
id,
|
|
3770
|
-
type:
|
|
3847
|
+
type: import_types7.NodeType.ServiceNode,
|
|
3771
3848
|
name: serviceName,
|
|
3772
3849
|
language: "unknown",
|
|
3773
3850
|
discoveredVia: "otel",
|
|
@@ -3777,11 +3854,11 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
3777
3854
|
return id;
|
|
3778
3855
|
}
|
|
3779
3856
|
function ensureInfraNode(graph, kind, name, provider) {
|
|
3780
|
-
const id = (0,
|
|
3857
|
+
const id = (0, import_types7.infraId)(kind, name);
|
|
3781
3858
|
if (graph.hasNode(id)) return id;
|
|
3782
3859
|
const node = {
|
|
3783
3860
|
id,
|
|
3784
|
-
type:
|
|
3861
|
+
type: import_types7.NodeType.InfraNode,
|
|
3785
3862
|
name,
|
|
3786
3863
|
provider,
|
|
3787
3864
|
kind
|
|
@@ -3789,12 +3866,27 @@ function ensureInfraNode(graph, kind, name, provider) {
|
|
|
3789
3866
|
graph.addNode(id, node);
|
|
3790
3867
|
return id;
|
|
3791
3868
|
}
|
|
3869
|
+
var COLUMN_BEARING_INFRA_KINDS = /* @__PURE__ */ new Set(["sql-table", "supabase-table"]);
|
|
3870
|
+
function mergeColumnsAt(graph, tableNodeId, columns, provenance, confidence) {
|
|
3871
|
+
if (!columns || columns.length === 0 || !graph.hasNode(tableNodeId)) return;
|
|
3872
|
+
const node = graph.getNodeAttributes(tableNodeId);
|
|
3873
|
+
if (node.type !== import_types7.NodeType.InfraNode || !node.kind || !COLUMN_BEARING_INFRA_KINDS.has(node.kind)) {
|
|
3874
|
+
return;
|
|
3875
|
+
}
|
|
3876
|
+
graph.replaceNodeAttributes(tableNodeId, {
|
|
3877
|
+
...node,
|
|
3878
|
+
columns: foldColumns(node.columns, columns, provenance, confidence)
|
|
3879
|
+
});
|
|
3880
|
+
}
|
|
3881
|
+
function mergeObservedColumns(graph, tableNodeId, columns) {
|
|
3882
|
+
mergeColumnsAt(graph, tableNodeId, columns, import_types7.Provenance.OBSERVED, OBSERVED_COLUMN_CONFIDENCE);
|
|
3883
|
+
}
|
|
3792
3884
|
function ensureDatabaseNode(graph, host, engine) {
|
|
3793
|
-
const id = (0,
|
|
3885
|
+
const id = (0, import_types7.databaseId)(host);
|
|
3794
3886
|
if (graph.hasNode(id)) return id;
|
|
3795
3887
|
const node = {
|
|
3796
3888
|
id,
|
|
3797
|
-
type:
|
|
3889
|
+
type: import_types7.NodeType.DatabaseNode,
|
|
3798
3890
|
name: host,
|
|
3799
3891
|
engine,
|
|
3800
3892
|
engineVersion: "unknown",
|
|
@@ -3806,11 +3898,11 @@ function ensureDatabaseNode(graph, host, engine) {
|
|
|
3806
3898
|
return id;
|
|
3807
3899
|
}
|
|
3808
3900
|
function ensureLocalDatabaseNode(graph, serviceName, name, engine) {
|
|
3809
|
-
const id = (0,
|
|
3901
|
+
const id = (0, import_types7.localDatabaseId)(serviceName, name);
|
|
3810
3902
|
if (graph.hasNode(id)) return id;
|
|
3811
3903
|
const node = {
|
|
3812
3904
|
id,
|
|
3813
|
-
type:
|
|
3905
|
+
type: import_types7.NodeType.DatabaseNode,
|
|
3814
3906
|
name,
|
|
3815
3907
|
engine,
|
|
3816
3908
|
engineVersion: "unknown",
|
|
@@ -3825,17 +3917,17 @@ function findDeclaredDatabaseForService(graph, serviceNodeId, engine) {
|
|
|
3825
3917
|
const sources = [serviceNodeId];
|
|
3826
3918
|
for (const edgeId of graph.outboundEdges(serviceNodeId)) {
|
|
3827
3919
|
const e = graph.getEdgeAttributes(edgeId);
|
|
3828
|
-
if (e.type ===
|
|
3920
|
+
if (e.type === import_types7.EdgeType.CONTAINS) sources.push(e.target);
|
|
3829
3921
|
}
|
|
3830
3922
|
const matches = /* @__PURE__ */ new Set();
|
|
3831
3923
|
for (const src of sources) {
|
|
3832
3924
|
if (!graph.hasNode(src)) continue;
|
|
3833
3925
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
3834
3926
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
3835
|
-
if (edge.type !==
|
|
3927
|
+
if (edge.type !== import_types7.EdgeType.CONNECTS_TO || edge.provenance !== import_types7.Provenance.EXTRACTED) continue;
|
|
3836
3928
|
if (!graph.hasNode(edge.target)) continue;
|
|
3837
3929
|
const target = graph.getNodeAttributes(edge.target);
|
|
3838
|
-
if (target.type !==
|
|
3930
|
+
if (target.type !== import_types7.NodeType.DatabaseNode || target.engine !== engine) continue;
|
|
3839
3931
|
matches.add(edge.target);
|
|
3840
3932
|
}
|
|
3841
3933
|
}
|
|
@@ -3850,7 +3942,7 @@ function ensureFrontierNode(graph, host, ts) {
|
|
|
3850
3942
|
}
|
|
3851
3943
|
const node = {
|
|
3852
3944
|
id,
|
|
3853
|
-
type:
|
|
3945
|
+
type: import_types7.NodeType.FrontierNode,
|
|
3854
3946
|
name: host,
|
|
3855
3947
|
host,
|
|
3856
3948
|
firstObserved: ts,
|
|
@@ -3874,11 +3966,11 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
|
|
|
3874
3966
|
};
|
|
3875
3967
|
const updated = {
|
|
3876
3968
|
...existing,
|
|
3877
|
-
provenance:
|
|
3969
|
+
provenance: import_types7.Provenance.OBSERVED,
|
|
3878
3970
|
lastObserved: ts,
|
|
3879
3971
|
callCount: newSpanCount,
|
|
3880
3972
|
signal: newSignal,
|
|
3881
|
-
confidence: (0,
|
|
3973
|
+
confidence: (0, import_types7.confidenceForObservedSignal)(newSignal),
|
|
3882
3974
|
grain
|
|
3883
3975
|
// backfills legacy edges that predate ADR-142
|
|
3884
3976
|
};
|
|
@@ -3895,8 +3987,8 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
|
|
|
3895
3987
|
source,
|
|
3896
3988
|
target,
|
|
3897
3989
|
type,
|
|
3898
|
-
provenance:
|
|
3899
|
-
confidence: (0,
|
|
3990
|
+
provenance: import_types7.Provenance.OBSERVED,
|
|
3991
|
+
confidence: (0, import_types7.confidenceForObservedSignal)(signal),
|
|
3900
3992
|
lastObserved: ts,
|
|
3901
3993
|
callCount: 1,
|
|
3902
3994
|
signal,
|
|
@@ -3918,9 +4010,9 @@ function stitchTrace(graph, sourceServiceId, ts) {
|
|
|
3918
4010
|
const outbound = graph.outboundEdges(nodeId);
|
|
3919
4011
|
for (const edgeId of outbound) {
|
|
3920
4012
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
3921
|
-
if (edge.provenance !==
|
|
4013
|
+
if (edge.provenance !== import_types7.Provenance.EXTRACTED) continue;
|
|
3922
4014
|
if (!STITCH_EDGE_TYPES.has(edge.type)) continue;
|
|
3923
|
-
if (graph.hasEdge((0,
|
|
4015
|
+
if (graph.hasEdge((0, import_types7.observedEdgeId)(edge.source, edge.target, edge.type))) continue;
|
|
3924
4016
|
upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts);
|
|
3925
4017
|
if (!visited.has(edge.target)) {
|
|
3926
4018
|
visited.add(edge.target);
|
|
@@ -3942,7 +4034,7 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
3942
4034
|
source,
|
|
3943
4035
|
target,
|
|
3944
4036
|
type,
|
|
3945
|
-
provenance:
|
|
4037
|
+
provenance: import_types7.Provenance.INFERRED,
|
|
3946
4038
|
confidence: INFERRED_CONFIDENCE,
|
|
3947
4039
|
lastObserved: ts
|
|
3948
4040
|
};
|
|
@@ -3953,12 +4045,12 @@ async function appendErrorEvent(ctx, ev) {
|
|
|
3953
4045
|
await import_node_fs7.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
3954
4046
|
}
|
|
3955
4047
|
function incidentAffectedNode(span, graph, scanPath) {
|
|
3956
|
-
const sid = (0,
|
|
4048
|
+
const sid = (0, import_types7.serviceId)(span.service, span.env);
|
|
3957
4049
|
const serviceNode = graph && graph.hasNode(sid) ? graph.getNodeAttributes(sid) : void 0;
|
|
3958
4050
|
const callSite = callSiteFromSpan(span, serviceNode, scanPath);
|
|
3959
4051
|
if (callSite) {
|
|
3960
4052
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
3961
|
-
return (0,
|
|
4053
|
+
return (0, import_types7.fileId)(span.service, relPath);
|
|
3962
4054
|
}
|
|
3963
4055
|
return sid;
|
|
3964
4056
|
}
|
|
@@ -4083,7 +4175,7 @@ function findRouteNodeByHttpRoute(graph, serviceName, method, httpRoute) {
|
|
|
4083
4175
|
graph.forEachNode((id, attrs) => {
|
|
4084
4176
|
if (found) return;
|
|
4085
4177
|
const a = attrs;
|
|
4086
|
-
if (a.type !==
|
|
4178
|
+
if (a.type !== import_types7.NodeType.RouteNode || a.service !== serviceName) return;
|
|
4087
4179
|
if (m && a.method !== "ALL" && a.method !== m) return;
|
|
4088
4180
|
if (normalizePathTemplate(a.pathTemplate) === target) found = id;
|
|
4089
4181
|
});
|
|
@@ -4114,7 +4206,7 @@ async function handleSpan(ctx, span) {
|
|
|
4114
4206
|
let targetId;
|
|
4115
4207
|
if (host) {
|
|
4116
4208
|
ensureDatabaseNode(ctx.graph, host, span.dbSystem);
|
|
4117
|
-
targetId = (0,
|
|
4209
|
+
targetId = (0, import_types7.databaseId)(host);
|
|
4118
4210
|
} else {
|
|
4119
4211
|
const declared = findDeclaredDatabaseForService(ctx.graph, sourceId, span.dbSystem);
|
|
4120
4212
|
if (declared) {
|
|
@@ -4131,7 +4223,7 @@ async function handleSpan(ctx, span) {
|
|
|
4131
4223
|
}
|
|
4132
4224
|
const result = upsertObservedEdge(
|
|
4133
4225
|
ctx.graph,
|
|
4134
|
-
|
|
4226
|
+
import_types7.EdgeType.CONNECTS_TO,
|
|
4135
4227
|
observedSource(),
|
|
4136
4228
|
targetId,
|
|
4137
4229
|
ts,
|
|
@@ -4143,7 +4235,7 @@ async function handleSpan(ctx, span) {
|
|
|
4143
4235
|
const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
|
|
4144
4236
|
upsertObservedEdge(
|
|
4145
4237
|
ctx.graph,
|
|
4146
|
-
|
|
4238
|
+
import_types7.EdgeType.CALLS,
|
|
4147
4239
|
observedSource(),
|
|
4148
4240
|
collectionId,
|
|
4149
4241
|
ts,
|
|
@@ -4155,13 +4247,14 @@ async function handleSpan(ctx, span) {
|
|
|
4155
4247
|
const tableId = ensureInfraNode(ctx.graph, "sql-table", span.dbTable, "self");
|
|
4156
4248
|
upsertObservedEdge(
|
|
4157
4249
|
ctx.graph,
|
|
4158
|
-
|
|
4250
|
+
import_types7.EdgeType.CALLS,
|
|
4159
4251
|
observedSource(),
|
|
4160
4252
|
tableId,
|
|
4161
4253
|
ts,
|
|
4162
4254
|
isError,
|
|
4163
4255
|
callSiteEvidence
|
|
4164
4256
|
);
|
|
4257
|
+
mergeObservedColumns(ctx.graph, tableId, span.dbColumns);
|
|
4165
4258
|
}
|
|
4166
4259
|
}
|
|
4167
4260
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
@@ -4170,7 +4263,7 @@ async function handleSpan(ctx, span) {
|
|
|
4170
4263
|
span.messagingSystem,
|
|
4171
4264
|
span.messagingDestination
|
|
4172
4265
|
);
|
|
4173
|
-
const edgeType = span.kind === WIRE_SPAN_KIND_CONSUMER ?
|
|
4266
|
+
const edgeType = span.kind === WIRE_SPAN_KIND_CONSUMER ? import_types7.EdgeType.CONSUMES_FROM : import_types7.EdgeType.PUBLISHES_TO;
|
|
4174
4267
|
const result = upsertObservedEdge(
|
|
4175
4268
|
ctx.graph,
|
|
4176
4269
|
edgeType,
|
|
@@ -4190,7 +4283,7 @@ async function handleSpan(ctx, span) {
|
|
|
4190
4283
|
);
|
|
4191
4284
|
const result = upsertObservedEdge(
|
|
4192
4285
|
ctx.graph,
|
|
4193
|
-
|
|
4286
|
+
import_types7.EdgeType.CONTAINS,
|
|
4194
4287
|
observedSource(),
|
|
4195
4288
|
targetId,
|
|
4196
4289
|
ts,
|
|
@@ -4202,7 +4295,7 @@ async function handleSpan(ctx, span) {
|
|
|
4202
4295
|
const targetId = ensureGrpcMethodNode(ctx.graph, span.rpcService, span.rpcMethod);
|
|
4203
4296
|
const result = upsertObservedEdge(
|
|
4204
4297
|
ctx.graph,
|
|
4205
|
-
|
|
4298
|
+
import_types7.EdgeType.CONTAINS,
|
|
4206
4299
|
observedSource(),
|
|
4207
4300
|
targetId,
|
|
4208
4301
|
ts,
|
|
@@ -4218,7 +4311,7 @@ async function handleSpan(ctx, span) {
|
|
|
4218
4311
|
);
|
|
4219
4312
|
const result = upsertObservedEdge(
|
|
4220
4313
|
ctx.graph,
|
|
4221
|
-
|
|
4314
|
+
import_types7.EdgeType.CONNECTS_TO,
|
|
4222
4315
|
observedSource(),
|
|
4223
4316
|
targetId,
|
|
4224
4317
|
ts,
|
|
@@ -4234,7 +4327,7 @@ async function handleSpan(ctx, span) {
|
|
|
4234
4327
|
if (targetId && targetId !== sourceId) {
|
|
4235
4328
|
upsertObservedEdge(
|
|
4236
4329
|
ctx.graph,
|
|
4237
|
-
|
|
4330
|
+
import_types7.EdgeType.CALLS,
|
|
4238
4331
|
observedSource(),
|
|
4239
4332
|
targetId,
|
|
4240
4333
|
ts,
|
|
@@ -4247,7 +4340,7 @@ async function handleSpan(ctx, span) {
|
|
|
4247
4340
|
const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts);
|
|
4248
4341
|
upsertObservedEdge(
|
|
4249
4342
|
ctx.graph,
|
|
4250
|
-
|
|
4343
|
+
import_types7.EdgeType.CALLS,
|
|
4251
4344
|
observedSource(),
|
|
4252
4345
|
frontierNodeId,
|
|
4253
4346
|
ts,
|
|
@@ -4273,7 +4366,7 @@ async function handleSpan(ctx, span) {
|
|
|
4273
4366
|
} : void 0;
|
|
4274
4367
|
upsertObservedEdge(
|
|
4275
4368
|
ctx.graph,
|
|
4276
|
-
|
|
4369
|
+
import_types7.EdgeType.CALLS,
|
|
4277
4370
|
fallbackSource,
|
|
4278
4371
|
sourceId,
|
|
4279
4372
|
ts,
|
|
@@ -4283,7 +4376,7 @@ async function handleSpan(ctx, span) {
|
|
|
4283
4376
|
}
|
|
4284
4377
|
}
|
|
4285
4378
|
}
|
|
4286
|
-
if (span.httpRoute && (span.kind === 2 || span.kind === 0 || span.kind === void 0)) {
|
|
4379
|
+
if (span.httpRoute && (span.kind === 2 || span.kind === 1 || span.kind === 0 || span.kind === void 0)) {
|
|
4287
4380
|
const routeNodeId = findRouteNodeByHttpRoute(
|
|
4288
4381
|
ctx.graph,
|
|
4289
4382
|
span.service,
|
|
@@ -4292,7 +4385,7 @@ async function handleSpan(ctx, span) {
|
|
|
4292
4385
|
);
|
|
4293
4386
|
if (routeNodeId) {
|
|
4294
4387
|
const routeSvc = ctx.graph.getNodeAttributes(routeNodeId).service;
|
|
4295
|
-
upsertObservedEdge(ctx.graph,
|
|
4388
|
+
upsertObservedEdge(ctx.graph, import_types7.EdgeType.CONTAINS, (0, import_types7.serviceId)(routeSvc), routeNodeId, ts, isError);
|
|
4296
4389
|
}
|
|
4297
4390
|
}
|
|
4298
4391
|
if (span.statusCode === 2) {
|
|
@@ -4331,7 +4424,7 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
4331
4424
|
const aliasIndex = /* @__PURE__ */ new Map();
|
|
4332
4425
|
graph.forEachNode((id, attrs) => {
|
|
4333
4426
|
const a = attrs;
|
|
4334
|
-
if (a.type !==
|
|
4427
|
+
if (a.type !== import_types7.NodeType.ServiceNode) return;
|
|
4335
4428
|
aliasIndex.set(a.name, id);
|
|
4336
4429
|
if (a.aliases) {
|
|
4337
4430
|
for (const alias of a.aliases) aliasIndex.set(alias, id);
|
|
@@ -4340,7 +4433,7 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
4340
4433
|
const toPromote = [];
|
|
4341
4434
|
graph.forEachNode((id, attrs) => {
|
|
4342
4435
|
const a = attrs;
|
|
4343
|
-
if (a.type !==
|
|
4436
|
+
if (a.type !== import_types7.NodeType.FrontierNode) return;
|
|
4344
4437
|
const target = aliasIndex.get(a.host);
|
|
4345
4438
|
if (!target) return;
|
|
4346
4439
|
if (target === id) return;
|
|
@@ -4374,7 +4467,7 @@ function rewireFrontierEdges(graph, frontierId2, serviceId7) {
|
|
|
4374
4467
|
}
|
|
4375
4468
|
function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
4376
4469
|
graph.dropEdge(oldEdgeId);
|
|
4377
|
-
const newId = edge.provenance ===
|
|
4470
|
+
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);
|
|
4378
4471
|
if (graph.hasEdge(newId)) {
|
|
4379
4472
|
const existing = graph.getEdgeAttributes(newId);
|
|
4380
4473
|
const merged = {
|
|
@@ -4408,12 +4501,12 @@ async function markStaleEdges(graph, options = {}) {
|
|
|
4408
4501
|
const project = options.project ?? DEFAULT_PROJECT;
|
|
4409
4502
|
graph.forEachEdge((id, attrs) => {
|
|
4410
4503
|
const e = attrs;
|
|
4411
|
-
if (e.provenance !==
|
|
4504
|
+
if (e.provenance !== import_types7.Provenance.OBSERVED) return;
|
|
4412
4505
|
if (!e.lastObserved) return;
|
|
4413
4506
|
const threshold = thresholdForEdgeType(e.type, thresholds);
|
|
4414
4507
|
const age = now - new Date(e.lastObserved).getTime();
|
|
4415
4508
|
if (age > threshold) {
|
|
4416
|
-
const updated = { ...e, provenance:
|
|
4509
|
+
const updated = { ...e, provenance: import_types7.Provenance.STALE, confidence: 0.3 };
|
|
4417
4510
|
graph.replaceEdgeAttributes(id, updated);
|
|
4418
4511
|
events.push({
|
|
4419
4512
|
edgeId: id,
|
|
@@ -4430,8 +4523,8 @@ async function markStaleEdges(graph, options = {}) {
|
|
|
4430
4523
|
project,
|
|
4431
4524
|
payload: {
|
|
4432
4525
|
edgeId: id,
|
|
4433
|
-
from:
|
|
4434
|
-
to:
|
|
4526
|
+
from: import_types7.Provenance.OBSERVED,
|
|
4527
|
+
to: import_types7.Provenance.STALE
|
|
4435
4528
|
}
|
|
4436
4529
|
});
|
|
4437
4530
|
}
|
|
@@ -4540,7 +4633,7 @@ function mergeSnapshot(graph, snapshot) {
|
|
|
4540
4633
|
const validEdges = [];
|
|
4541
4634
|
for (const node of incomingNodes) {
|
|
4542
4635
|
if (node.attributes === void 0) continue;
|
|
4543
|
-
const parsed =
|
|
4636
|
+
const parsed = import_types7.GraphNodeSchema.safeParse(node.attributes);
|
|
4544
4637
|
if (!parsed.success) {
|
|
4545
4638
|
issues.push(`node "${node.key}": ${describeZodIssues(parsed.error)}`);
|
|
4546
4639
|
continue;
|
|
@@ -4549,7 +4642,7 @@ function mergeSnapshot(graph, snapshot) {
|
|
|
4549
4642
|
}
|
|
4550
4643
|
for (const edge of incomingEdges) {
|
|
4551
4644
|
if (edge.attributes === void 0) continue;
|
|
4552
|
-
const parsed =
|
|
4645
|
+
const parsed = import_types7.GraphEdgeSchema.safeParse(edge.attributes);
|
|
4553
4646
|
if (!parsed.success) {
|
|
4554
4647
|
const label = edge.key ?? `${edge.source}->${edge.target}`;
|
|
4555
4648
|
issues.push(`edge "${label}": ${describeZodIssues(parsed.error)}`);
|
|
@@ -4583,7 +4676,7 @@ var import_node_fs11 = require("fs");
|
|
|
4583
4676
|
var import_node_path12 = __toESM(require("path"), 1);
|
|
4584
4677
|
var import_ignore = __toESM(require("ignore"), 1);
|
|
4585
4678
|
var import_minimatch2 = require("minimatch");
|
|
4586
|
-
var
|
|
4679
|
+
var import_types9 = require("@neat.is/types");
|
|
4587
4680
|
|
|
4588
4681
|
// src/extract/python.ts
|
|
4589
4682
|
init_cjs_shims();
|
|
@@ -4656,7 +4749,7 @@ function pythonToPackage(service) {
|
|
|
4656
4749
|
init_cjs_shims();
|
|
4657
4750
|
var import_node_fs9 = require("fs");
|
|
4658
4751
|
var import_node_path10 = __toESM(require("path"), 1);
|
|
4659
|
-
var
|
|
4752
|
+
var import_types8 = require("@neat.is/types");
|
|
4660
4753
|
function parseGoMod(source) {
|
|
4661
4754
|
const module2 = source.match(/^\s*module\s+(\S+)\s*$/m)?.[1];
|
|
4662
4755
|
if (!module2) return null;
|
|
@@ -4684,8 +4777,8 @@ async function discoverGoService(scanPath, dir) {
|
|
|
4684
4777
|
const name = mod.module.split("/").filter(Boolean).pop() ?? mod.module;
|
|
4685
4778
|
const pkg = { name, dependencies: mod.dependencies };
|
|
4686
4779
|
const node = {
|
|
4687
|
-
id: (0,
|
|
4688
|
-
type:
|
|
4780
|
+
id: (0, import_types8.serviceId)(name),
|
|
4781
|
+
type: import_types8.NodeType.ServiceNode,
|
|
4689
4782
|
name,
|
|
4690
4783
|
language: "go",
|
|
4691
4784
|
dependencies: mod.dependencies,
|
|
@@ -4871,8 +4964,8 @@ async function discoverNodeService(scanPath, dir) {
|
|
|
4871
4964
|
const framework = detectJsFramework(pkg);
|
|
4872
4965
|
const language = await detectJsServiceLanguage(dir, pkg);
|
|
4873
4966
|
const node = {
|
|
4874
|
-
id: (0,
|
|
4875
|
-
type:
|
|
4967
|
+
id: (0, import_types9.serviceId)(pkg.name),
|
|
4968
|
+
type: import_types9.NodeType.ServiceNode,
|
|
4876
4969
|
name: pkg.name,
|
|
4877
4970
|
language,
|
|
4878
4971
|
version: pkg.version,
|
|
@@ -4888,8 +4981,8 @@ async function discoverPyService(scanPath, dir) {
|
|
|
4888
4981
|
if (!py) return null;
|
|
4889
4982
|
const pkg = pythonToPackage(py);
|
|
4890
4983
|
const node = {
|
|
4891
|
-
id: (0,
|
|
4892
|
-
type:
|
|
4984
|
+
id: (0, import_types9.serviceId)(py.name),
|
|
4985
|
+
type: import_types9.NodeType.ServiceNode,
|
|
4893
4986
|
name: py.name,
|
|
4894
4987
|
language: "python",
|
|
4895
4988
|
version: py.version,
|
|
@@ -4985,7 +5078,7 @@ init_cjs_shims();
|
|
|
4985
5078
|
var import_node_path13 = __toESM(require("path"), 1);
|
|
4986
5079
|
var import_node_fs12 = require("fs");
|
|
4987
5080
|
var import_yaml2 = require("yaml");
|
|
4988
|
-
var
|
|
5081
|
+
var import_types10 = require("@neat.is/types");
|
|
4989
5082
|
var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
4990
5083
|
"Service",
|
|
4991
5084
|
"Deployment",
|
|
@@ -4995,7 +5088,7 @@ var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
|
4995
5088
|
function addAliases(graph, serviceId7, candidates) {
|
|
4996
5089
|
if (!graph.hasNode(serviceId7)) return;
|
|
4997
5090
|
const node = graph.getNodeAttributes(serviceId7);
|
|
4998
|
-
if (node.type !==
|
|
5091
|
+
if (node.type !== import_types10.NodeType.ServiceNode) return;
|
|
4999
5092
|
const set = new Set(node.aliases ?? []);
|
|
5000
5093
|
for (const c of candidates) {
|
|
5001
5094
|
if (!c) continue;
|
|
@@ -5176,7 +5269,7 @@ var import_node_path15 = __toESM(require("path"), 1);
|
|
|
5176
5269
|
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
5177
5270
|
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5178
5271
|
var import_tree_sitter_typescript = __toESM(require("tree-sitter-typescript"), 1);
|
|
5179
|
-
var
|
|
5272
|
+
var import_types11 = require("@neat.is/types");
|
|
5180
5273
|
var PARSE_CHUNK2 = 16384;
|
|
5181
5274
|
var GRAMMAR_BY_EXT = {
|
|
5182
5275
|
".ts": import_tree_sitter_typescript.default.typescript,
|
|
@@ -5267,7 +5360,7 @@ function disambiguate(defs) {
|
|
|
5267
5360
|
}
|
|
5268
5361
|
async function addSymbols(graph, services) {
|
|
5269
5362
|
const parsers = /* @__PURE__ */ new Map();
|
|
5270
|
-
const
|
|
5363
|
+
const parserForExt2 = (ext) => {
|
|
5271
5364
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
5272
5365
|
if (!grammar) return null;
|
|
5273
5366
|
let parser = parsers.get(ext);
|
|
@@ -5283,7 +5376,7 @@ async function addSymbols(graph, services) {
|
|
|
5283
5376
|
for (const service of services) {
|
|
5284
5377
|
const files = await loadSourceFiles(service.dir);
|
|
5285
5378
|
for (const file of files) {
|
|
5286
|
-
const parser =
|
|
5379
|
+
const parser = parserForExt2(import_node_path15.default.extname(file.path));
|
|
5287
5380
|
if (!parser) continue;
|
|
5288
5381
|
const relPath = toPosix(import_node_path15.default.relative(service.dir, file.path));
|
|
5289
5382
|
let defs;
|
|
@@ -5304,11 +5397,11 @@ async function addSymbols(graph, services) {
|
|
|
5304
5397
|
nodesAdded += fn;
|
|
5305
5398
|
edgesAdded += fe;
|
|
5306
5399
|
for (const { def, disambiguator } of disambiguate(defs)) {
|
|
5307
|
-
const sid = (0,
|
|
5400
|
+
const sid = (0, import_types11.symbolId)(service.pkg.name, relPath, def.qualname, disambiguator);
|
|
5308
5401
|
if (!graph.hasNode(sid)) {
|
|
5309
5402
|
const node = {
|
|
5310
5403
|
id: sid,
|
|
5311
|
-
type:
|
|
5404
|
+
type: import_types11.NodeType.SymbolNode,
|
|
5312
5405
|
kind: def.kind,
|
|
5313
5406
|
qualname: def.qualname,
|
|
5314
5407
|
span: { startLine: def.startLine, endLine: def.endLine },
|
|
@@ -5319,15 +5412,15 @@ async function addSymbols(graph, services) {
|
|
|
5319
5412
|
graph.addNode(sid, node);
|
|
5320
5413
|
nodesAdded++;
|
|
5321
5414
|
}
|
|
5322
|
-
const containsId = (0,
|
|
5415
|
+
const containsId = (0, import_types11.extractedEdgeId)(fileNodeId, sid, import_types11.EdgeType.CONTAINS);
|
|
5323
5416
|
if (!graph.hasEdge(containsId)) {
|
|
5324
5417
|
const edge = {
|
|
5325
5418
|
id: containsId,
|
|
5326
5419
|
source: fileNodeId,
|
|
5327
5420
|
target: sid,
|
|
5328
|
-
type:
|
|
5329
|
-
provenance:
|
|
5330
|
-
confidence: (0,
|
|
5421
|
+
type: import_types11.EdgeType.CONTAINS,
|
|
5422
|
+
provenance: import_types11.Provenance.EXTRACTED,
|
|
5423
|
+
confidence: (0, import_types11.confidenceForExtracted)("structural"),
|
|
5331
5424
|
evidence: {
|
|
5332
5425
|
file: relPath,
|
|
5333
5426
|
line: def.startLine,
|
|
@@ -5347,7 +5440,7 @@ async function addSymbols(graph, services) {
|
|
|
5347
5440
|
init_cjs_shims();
|
|
5348
5441
|
var import_node_path17 = __toESM(require("path"), 1);
|
|
5349
5442
|
var import_tree_sitter4 = __toESM(require("tree-sitter"), 1);
|
|
5350
|
-
var
|
|
5443
|
+
var import_types13 = require("@neat.is/types");
|
|
5351
5444
|
|
|
5352
5445
|
// src/extract/imports.ts
|
|
5353
5446
|
init_cjs_shims();
|
|
@@ -5357,7 +5450,7 @@ var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
|
|
|
5357
5450
|
var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5358
5451
|
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
5359
5452
|
var import_tree_sitter_go2 = __toESM(require("tree-sitter-go"), 1);
|
|
5360
|
-
var
|
|
5453
|
+
var import_types12 = require("@neat.is/types");
|
|
5361
5454
|
var PARSE_CHUNK3 = 16384;
|
|
5362
5455
|
function parseSource3(parser, source) {
|
|
5363
5456
|
return parser.parse(
|
|
@@ -5631,17 +5724,17 @@ async function resolveGoImport(specifier, modulePath, serviceDir) {
|
|
|
5631
5724
|
return toPosix(import_node_path16.default.relative(serviceDir, candidates[0]));
|
|
5632
5725
|
}
|
|
5633
5726
|
function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
|
|
5634
|
-
const importeeFileId = (0,
|
|
5727
|
+
const importeeFileId = (0, import_types12.fileId)(serviceName, importeeRelPath);
|
|
5635
5728
|
if (!graph.hasNode(importeeFileId)) return 0;
|
|
5636
|
-
const edgeId = (0,
|
|
5729
|
+
const edgeId = (0, import_types12.extractedEdgeId)(importerFileId, importeeFileId, import_types12.EdgeType.IMPORTS);
|
|
5637
5730
|
if (graph.hasEdge(edgeId)) return 0;
|
|
5638
5731
|
const edge = {
|
|
5639
5732
|
id: edgeId,
|
|
5640
5733
|
source: importerFileId,
|
|
5641
5734
|
target: importeeFileId,
|
|
5642
|
-
type:
|
|
5643
|
-
provenance:
|
|
5644
|
-
confidence: (0,
|
|
5735
|
+
type: import_types12.EdgeType.IMPORTS,
|
|
5736
|
+
provenance: import_types12.Provenance.EXTRACTED,
|
|
5737
|
+
confidence: (0, import_types12.confidenceForExtracted)("structural"),
|
|
5645
5738
|
evidence: { file: importerRelPath, line, snippet: snippet2 }
|
|
5646
5739
|
};
|
|
5647
5740
|
graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge);
|
|
@@ -5658,7 +5751,7 @@ async function addImports(graph, services) {
|
|
|
5658
5751
|
for (const file of files) {
|
|
5659
5752
|
if (isTestPath(file.path)) continue;
|
|
5660
5753
|
const relFile = toPosix(import_node_path16.default.relative(service.dir, file.path));
|
|
5661
|
-
const importerFileId = (0,
|
|
5754
|
+
const importerFileId = (0, import_types12.fileId)(service.pkg.name, relFile);
|
|
5662
5755
|
const isPython = import_node_path16.default.extname(file.path) === ".py";
|
|
5663
5756
|
const isGo = import_node_path16.default.extname(file.path) === ".go";
|
|
5664
5757
|
if (isGo) {
|
|
@@ -5819,7 +5912,7 @@ function stringInner(node) {
|
|
|
5819
5912
|
}
|
|
5820
5913
|
async function addSymbolEdges(graph, services) {
|
|
5821
5914
|
const parsers = /* @__PURE__ */ new Map();
|
|
5822
|
-
const
|
|
5915
|
+
const parserForExt2 = (ext) => {
|
|
5823
5916
|
const grammar = GRAMMAR_BY_EXT[ext];
|
|
5824
5917
|
if (!grammar) return null;
|
|
5825
5918
|
let parser = parsers.get(ext);
|
|
@@ -5836,7 +5929,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5836
5929
|
const tsPaths = await loadTsPathConfig(service.dir);
|
|
5837
5930
|
const files = await loadSourceFiles(service.dir);
|
|
5838
5931
|
for (const file of files) {
|
|
5839
|
-
const parser =
|
|
5932
|
+
const parser = parserForExt2(import_node_path17.default.extname(file.path));
|
|
5840
5933
|
if (!parser) continue;
|
|
5841
5934
|
const relPath = toPosix(import_node_path17.default.relative(service.dir, file.path));
|
|
5842
5935
|
const fileDir = import_node_path17.default.dirname(file.path);
|
|
@@ -5849,7 +5942,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5849
5942
|
}
|
|
5850
5943
|
const disambiguated = disambiguate(collectSymbolDefs(root));
|
|
5851
5944
|
const locals = disambiguated.map(({ def, disambiguator }) => ({
|
|
5852
|
-
sid: (0,
|
|
5945
|
+
sid: (0, import_types13.symbolId)(serviceName, relPath, def.qualname, disambiguator),
|
|
5853
5946
|
qualname: def.qualname,
|
|
5854
5947
|
kind: def.kind,
|
|
5855
5948
|
startLine: def.startLine,
|
|
@@ -5878,10 +5971,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
5878
5971
|
if (local) return local.kind === wantKind ? local.sid : null;
|
|
5879
5972
|
const imp = resolvedImports.get(name);
|
|
5880
5973
|
if (imp) {
|
|
5881
|
-
const candidate = (0,
|
|
5974
|
+
const candidate = (0, import_types13.symbolId)(serviceName, imp.targetRelPath, imp.importedName);
|
|
5882
5975
|
if (graph.hasNode(candidate)) {
|
|
5883
5976
|
const node = graph.getNodeAttributes(candidate);
|
|
5884
|
-
if (node.type ===
|
|
5977
|
+
if (node.type === import_types13.NodeType.SymbolNode && node.kind === wantKind) return candidate;
|
|
5885
5978
|
}
|
|
5886
5979
|
}
|
|
5887
5980
|
return null;
|
|
@@ -5908,7 +6001,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5908
6001
|
sourceSid: self.sid,
|
|
5909
6002
|
targetName: ext.name,
|
|
5910
6003
|
wantKind: "class",
|
|
5911
|
-
edgeType:
|
|
6004
|
+
edgeType: import_types13.EdgeType.INHERITS,
|
|
5912
6005
|
line: ext.line
|
|
5913
6006
|
});
|
|
5914
6007
|
}
|
|
@@ -5917,7 +6010,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5917
6010
|
sourceSid: self.sid,
|
|
5918
6011
|
targetName: impl.name,
|
|
5919
6012
|
wantKind: "class",
|
|
5920
|
-
edgeType:
|
|
6013
|
+
edgeType: import_types13.EdgeType.IMPLEMENTS,
|
|
5921
6014
|
line: impl.line
|
|
5922
6015
|
});
|
|
5923
6016
|
}
|
|
@@ -5933,7 +6026,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5933
6026
|
sourceSid: caller.sid,
|
|
5934
6027
|
targetName: fn.text,
|
|
5935
6028
|
wantKind: "function",
|
|
5936
|
-
edgeType:
|
|
6029
|
+
edgeType: import_types13.EdgeType.CALLS,
|
|
5937
6030
|
line
|
|
5938
6031
|
});
|
|
5939
6032
|
}
|
|
@@ -5949,15 +6042,15 @@ async function addSymbolEdges(graph, services) {
|
|
|
5949
6042
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
5950
6043
|
if (!targetSid) continue;
|
|
5951
6044
|
if (targetSid === req.sourceSid) continue;
|
|
5952
|
-
const edgeId = (0,
|
|
6045
|
+
const edgeId = (0, import_types13.extractedEdgeId)(req.sourceSid, targetSid, req.edgeType);
|
|
5953
6046
|
if (graph.hasEdge(edgeId)) continue;
|
|
5954
6047
|
const edge = {
|
|
5955
6048
|
id: edgeId,
|
|
5956
6049
|
source: req.sourceSid,
|
|
5957
6050
|
target: targetSid,
|
|
5958
6051
|
type: req.edgeType,
|
|
5959
|
-
provenance:
|
|
5960
|
-
confidence: (0,
|
|
6052
|
+
provenance: import_types13.Provenance.EXTRACTED,
|
|
6053
|
+
confidence: (0, import_types13.confidenceForExtracted)("structural"),
|
|
5961
6054
|
evidence: {
|
|
5962
6055
|
file: relPath,
|
|
5963
6056
|
line: req.line,
|
|
@@ -5975,7 +6068,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
5975
6068
|
// src/extract/databases/index.ts
|
|
5976
6069
|
init_cjs_shims();
|
|
5977
6070
|
var import_node_path25 = __toESM(require("path"), 1);
|
|
5978
|
-
var
|
|
6071
|
+
var import_types14 = require("@neat.is/types");
|
|
5979
6072
|
|
|
5980
6073
|
// src/extract/databases/db-config-yaml.ts
|
|
5981
6074
|
init_cjs_shims();
|
|
@@ -6479,8 +6572,8 @@ function compatibleDriversFor(engine) {
|
|
|
6479
6572
|
}
|
|
6480
6573
|
function toDatabaseNode(config) {
|
|
6481
6574
|
return {
|
|
6482
|
-
id: (0,
|
|
6483
|
-
type:
|
|
6575
|
+
id: (0, import_types14.databaseId)(config.host),
|
|
6576
|
+
type: import_types14.NodeType.DatabaseNode,
|
|
6484
6577
|
name: config.database || config.host,
|
|
6485
6578
|
engine: config.engine,
|
|
6486
6579
|
engineVersion: config.engineVersion,
|
|
@@ -6621,12 +6714,12 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6621
6714
|
edgesAdded += fe;
|
|
6622
6715
|
const evidenceFile = toPosix(import_node_path25.default.relative(scanPath, config.sourceFile));
|
|
6623
6716
|
const edge = {
|
|
6624
|
-
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id,
|
|
6717
|
+
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types14.EdgeType.CONNECTS_TO),
|
|
6625
6718
|
source: fileNodeId,
|
|
6626
6719
|
target: dbNode.id,
|
|
6627
|
-
type:
|
|
6628
|
-
provenance:
|
|
6629
|
-
confidence: (0,
|
|
6720
|
+
type: import_types14.EdgeType.CONNECTS_TO,
|
|
6721
|
+
provenance: import_types14.Provenance.EXTRACTED,
|
|
6722
|
+
confidence: (0, import_types14.confidenceForExtracted)("structural"),
|
|
6630
6723
|
evidence: { file: evidenceFile }
|
|
6631
6724
|
};
|
|
6632
6725
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -6638,11 +6731,11 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6638
6731
|
const primary = allConfigs[0];
|
|
6639
6732
|
service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
|
|
6640
6733
|
const relPath = import_node_path25.default.relative(scanPath, primary.sourceFile);
|
|
6641
|
-
const cfgId = (0,
|
|
6734
|
+
const cfgId = (0, import_types14.configId)(relPath);
|
|
6642
6735
|
if (!graph.hasNode(cfgId)) {
|
|
6643
6736
|
const cfgNode = {
|
|
6644
6737
|
id: cfgId,
|
|
6645
|
-
type:
|
|
6738
|
+
type: import_types14.NodeType.ConfigNode,
|
|
6646
6739
|
name: import_node_path25.default.basename(primary.sourceFile),
|
|
6647
6740
|
path: relPath,
|
|
6648
6741
|
fileType: isConfigFile(import_node_path25.default.basename(primary.sourceFile)).fileType || "config"
|
|
@@ -6651,12 +6744,12 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6651
6744
|
nodesAdded++;
|
|
6652
6745
|
}
|
|
6653
6746
|
const cfgEdge = {
|
|
6654
|
-
id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId,
|
|
6747
|
+
id: (0, import_types3.extractedEdgeId)(service.node.id, cfgId, import_types14.EdgeType.CONFIGURED_BY),
|
|
6655
6748
|
source: service.node.id,
|
|
6656
6749
|
target: cfgId,
|
|
6657
|
-
type:
|
|
6658
|
-
provenance:
|
|
6659
|
-
confidence: (0,
|
|
6750
|
+
type: import_types14.EdgeType.CONFIGURED_BY,
|
|
6751
|
+
provenance: import_types14.Provenance.EXTRACTED,
|
|
6752
|
+
confidence: (0, import_types14.confidenceForExtracted)("structural"),
|
|
6660
6753
|
evidence: { file: toPosix(relPath) }
|
|
6661
6754
|
};
|
|
6662
6755
|
if (!graph.hasEdge(cfgEdge.id)) {
|
|
@@ -6688,7 +6781,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
6688
6781
|
init_cjs_shims();
|
|
6689
6782
|
var import_node_fs16 = require("fs");
|
|
6690
6783
|
var import_node_path26 = __toESM(require("path"), 1);
|
|
6691
|
-
var
|
|
6784
|
+
var import_types15 = require("@neat.is/types");
|
|
6692
6785
|
async function walkConfigFiles(dir) {
|
|
6693
6786
|
const out = [];
|
|
6694
6787
|
async function walk6(current) {
|
|
@@ -6715,8 +6808,8 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
6715
6808
|
for (const file of configFiles) {
|
|
6716
6809
|
const relPath = import_node_path26.default.relative(scanPath, file);
|
|
6717
6810
|
const node = {
|
|
6718
|
-
id: (0,
|
|
6719
|
-
type:
|
|
6811
|
+
id: (0, import_types15.configId)(relPath),
|
|
6812
|
+
type: import_types15.NodeType.ConfigNode,
|
|
6720
6813
|
name: import_node_path26.default.basename(file),
|
|
6721
6814
|
path: relPath,
|
|
6722
6815
|
fileType: isConfigFile(import_node_path26.default.basename(file)).fileType
|
|
@@ -6735,12 +6828,12 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
6735
6828
|
nodesAdded += fn;
|
|
6736
6829
|
edgesAdded += fe;
|
|
6737
6830
|
const edge = {
|
|
6738
|
-
id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
6831
|
+
id: (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types15.EdgeType.CONFIGURED_BY),
|
|
6739
6832
|
source: fileNodeId,
|
|
6740
6833
|
target: node.id,
|
|
6741
|
-
type:
|
|
6742
|
-
provenance:
|
|
6743
|
-
confidence: (0,
|
|
6834
|
+
type: import_types15.EdgeType.CONFIGURED_BY,
|
|
6835
|
+
provenance: import_types15.Provenance.EXTRACTED,
|
|
6836
|
+
confidence: (0, import_types15.confidenceForExtracted)("structural"),
|
|
6744
6837
|
evidence: { file: relPath.split(import_node_path26.default.sep).join("/") }
|
|
6745
6838
|
};
|
|
6746
6839
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -6756,7 +6849,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
6756
6849
|
init_cjs_shims();
|
|
6757
6850
|
var import_node_fs17 = require("fs");
|
|
6758
6851
|
var import_node_path27 = __toESM(require("path"), 1);
|
|
6759
|
-
var
|
|
6852
|
+
var import_types16 = require("@neat.is/types");
|
|
6760
6853
|
var PROTO_EXTENSION = ".proto";
|
|
6761
6854
|
function packageOf(content) {
|
|
6762
6855
|
const m = content.match(/^\s*package\s+([A-Za-z_][A-Za-z0-9_.]*)\s*;/m);
|
|
@@ -6834,11 +6927,11 @@ async function addGrpcMethods(graph, services) {
|
|
|
6834
6927
|
}
|
|
6835
6928
|
if (methods.length === 0) continue;
|
|
6836
6929
|
for (const method of methods) {
|
|
6837
|
-
const mid = (0,
|
|
6930
|
+
const mid = (0, import_types16.grpcMethodId)(method.rpcService, method.rpcMethod);
|
|
6838
6931
|
if (!graph.hasNode(mid)) {
|
|
6839
6932
|
const node = {
|
|
6840
6933
|
id: mid,
|
|
6841
|
-
type:
|
|
6934
|
+
type: import_types16.NodeType.GrpcMethodNode,
|
|
6842
6935
|
name: `${method.rpcService}/${method.rpcMethod}`,
|
|
6843
6936
|
rpcService: method.rpcService,
|
|
6844
6937
|
rpcMethod: method.rpcMethod,
|
|
@@ -6849,15 +6942,15 @@ async function addGrpcMethods(graph, services) {
|
|
|
6849
6942
|
graph.addNode(mid, node);
|
|
6850
6943
|
nodesAdded++;
|
|
6851
6944
|
}
|
|
6852
|
-
const containsId = (0,
|
|
6945
|
+
const containsId = (0, import_types16.extractedEdgeId)(service.node.id, mid, import_types16.EdgeType.CONTAINS);
|
|
6853
6946
|
if (!graph.hasEdge(containsId)) {
|
|
6854
6947
|
const edge = {
|
|
6855
6948
|
id: containsId,
|
|
6856
6949
|
source: service.node.id,
|
|
6857
6950
|
target: mid,
|
|
6858
|
-
type:
|
|
6859
|
-
provenance:
|
|
6860
|
-
confidence: (0,
|
|
6951
|
+
type: import_types16.EdgeType.CONTAINS,
|
|
6952
|
+
provenance: import_types16.Provenance.EXTRACTED,
|
|
6953
|
+
confidence: (0, import_types16.confidenceForExtracted)("structural"),
|
|
6861
6954
|
evidence: {
|
|
6862
6955
|
file: relFile,
|
|
6863
6956
|
line: method.line,
|
|
@@ -6875,7 +6968,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
6875
6968
|
|
|
6876
6969
|
// src/extract/calls/index.ts
|
|
6877
6970
|
init_cjs_shims();
|
|
6878
|
-
var
|
|
6971
|
+
var import_types29 = require("@neat.is/types");
|
|
6879
6972
|
|
|
6880
6973
|
// src/extract/calls/http.ts
|
|
6881
6974
|
init_cjs_shims();
|
|
@@ -6883,7 +6976,7 @@ var import_node_path28 = __toESM(require("path"), 1);
|
|
|
6883
6976
|
var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
|
|
6884
6977
|
var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
|
|
6885
6978
|
var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
|
|
6886
|
-
var
|
|
6979
|
+
var import_types17 = require("@neat.is/types");
|
|
6887
6980
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
6888
6981
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
6889
6982
|
function isInsideJsxExternalLink(node) {
|
|
@@ -6969,7 +7062,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
6969
7062
|
const dedupKey = `${relFile}|${targetId}`;
|
|
6970
7063
|
if (seen.has(dedupKey)) continue;
|
|
6971
7064
|
seen.add(dedupKey);
|
|
6972
|
-
const confidence = (0,
|
|
7065
|
+
const confidence = (0, import_types17.confidenceForExtracted)("url-literal-service-target");
|
|
6973
7066
|
const ev = {
|
|
6974
7067
|
file: relFile,
|
|
6975
7068
|
line: site.line,
|
|
@@ -6983,25 +7076,25 @@ async function addHttpCallEdges(graph, services) {
|
|
|
6983
7076
|
);
|
|
6984
7077
|
nodesAdded += n;
|
|
6985
7078
|
edgesAdded += e;
|
|
6986
|
-
if (!(0,
|
|
7079
|
+
if (!(0, import_types17.passesExtractedFloor)(confidence)) {
|
|
6987
7080
|
noteExtractedDropped({
|
|
6988
7081
|
source: fileNodeId,
|
|
6989
7082
|
target: targetId,
|
|
6990
|
-
type:
|
|
7083
|
+
type: import_types17.EdgeType.CALLS,
|
|
6991
7084
|
confidence,
|
|
6992
7085
|
confidenceKind: "url-literal-service-target",
|
|
6993
7086
|
evidence: ev
|
|
6994
7087
|
});
|
|
6995
7088
|
continue;
|
|
6996
7089
|
}
|
|
6997
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId,
|
|
7090
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, targetId, import_types17.EdgeType.CALLS);
|
|
6998
7091
|
if (!graph.hasEdge(edgeId)) {
|
|
6999
7092
|
const edge = {
|
|
7000
7093
|
id: edgeId,
|
|
7001
7094
|
source: fileNodeId,
|
|
7002
7095
|
target: targetId,
|
|
7003
|
-
type:
|
|
7004
|
-
provenance:
|
|
7096
|
+
type: import_types17.EdgeType.CALLS,
|
|
7097
|
+
provenance: import_types17.Provenance.EXTRACTED,
|
|
7005
7098
|
confidence,
|
|
7006
7099
|
evidence: ev
|
|
7007
7100
|
};
|
|
@@ -7019,7 +7112,7 @@ init_cjs_shims();
|
|
|
7019
7112
|
var import_node_path29 = __toESM(require("path"), 1);
|
|
7020
7113
|
var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
|
|
7021
7114
|
var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
|
|
7022
|
-
var
|
|
7115
|
+
var import_types18 = require("@neat.is/types");
|
|
7023
7116
|
var PARSE_CHUNK5 = 16384;
|
|
7024
7117
|
function parseSource5(parser, source) {
|
|
7025
7118
|
return parser.parse(
|
|
@@ -7184,9 +7277,9 @@ function buildRouteIndex(graph) {
|
|
|
7184
7277
|
const index = /* @__PURE__ */ new Map();
|
|
7185
7278
|
graph.forEachNode((_id, attrs) => {
|
|
7186
7279
|
const node = attrs;
|
|
7187
|
-
if (node.type !==
|
|
7280
|
+
if (node.type !== import_types18.NodeType.RouteNode) return;
|
|
7188
7281
|
const route = attrs;
|
|
7189
|
-
const owner = (0,
|
|
7282
|
+
const owner = (0, import_types18.serviceId)(route.service);
|
|
7190
7283
|
const entry2 = {
|
|
7191
7284
|
method: route.method.toUpperCase(),
|
|
7192
7285
|
normalizedPath: normalizePathTemplate(route.pathTemplate),
|
|
@@ -7244,7 +7337,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
7244
7337
|
);
|
|
7245
7338
|
nodesAdded += n;
|
|
7246
7339
|
edgesAdded += e;
|
|
7247
|
-
const confidence = (0,
|
|
7340
|
+
const confidence = (0, import_types18.confidenceForExtracted)("verified-call-site");
|
|
7248
7341
|
const ev = {
|
|
7249
7342
|
file: relFile,
|
|
7250
7343
|
line: site.line,
|
|
@@ -7252,25 +7345,25 @@ async function addRouteCallEdges(graph, services) {
|
|
|
7252
7345
|
method: site.method ?? match.method,
|
|
7253
7346
|
pathTemplate: site.pathTemplate
|
|
7254
7347
|
};
|
|
7255
|
-
if (!(0,
|
|
7348
|
+
if (!(0, import_types18.passesExtractedFloor)(confidence)) {
|
|
7256
7349
|
noteExtractedDropped({
|
|
7257
7350
|
source: fileNodeId,
|
|
7258
7351
|
target: match.routeNodeId,
|
|
7259
|
-
type:
|
|
7352
|
+
type: import_types18.EdgeType.CALLS,
|
|
7260
7353
|
confidence,
|
|
7261
7354
|
confidenceKind: "verified-call-site",
|
|
7262
7355
|
evidence: ev
|
|
7263
7356
|
});
|
|
7264
7357
|
continue;
|
|
7265
7358
|
}
|
|
7266
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId,
|
|
7359
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, match.routeNodeId, import_types18.EdgeType.CALLS);
|
|
7267
7360
|
if (!graph.hasEdge(edgeId)) {
|
|
7268
7361
|
const edge = {
|
|
7269
7362
|
id: edgeId,
|
|
7270
7363
|
source: fileNodeId,
|
|
7271
7364
|
target: match.routeNodeId,
|
|
7272
|
-
type:
|
|
7273
|
-
provenance:
|
|
7365
|
+
type: import_types18.EdgeType.CALLS,
|
|
7366
|
+
provenance: import_types18.Provenance.EXTRACTED,
|
|
7274
7367
|
confidence,
|
|
7275
7368
|
evidence: ev
|
|
7276
7369
|
};
|
|
@@ -7286,7 +7379,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
7286
7379
|
// src/extract/calls/kafka.ts
|
|
7287
7380
|
init_cjs_shims();
|
|
7288
7381
|
var import_node_path30 = __toESM(require("path"), 1);
|
|
7289
|
-
var
|
|
7382
|
+
var import_types19 = require("@neat.is/types");
|
|
7290
7383
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
7291
7384
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
7292
7385
|
function findAll(re, text) {
|
|
@@ -7307,7 +7400,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
7307
7400
|
seen.add(key);
|
|
7308
7401
|
const line = lineOf(file.content, topic);
|
|
7309
7402
|
out.push({
|
|
7310
|
-
infraId: (0,
|
|
7403
|
+
infraId: (0, import_types19.infraId)("kafka-topic", topic),
|
|
7311
7404
|
name: topic,
|
|
7312
7405
|
kind: "kafka-topic",
|
|
7313
7406
|
edgeType,
|
|
@@ -7330,7 +7423,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
7330
7423
|
// src/extract/calls/redis.ts
|
|
7331
7424
|
init_cjs_shims();
|
|
7332
7425
|
var import_node_path31 = __toESM(require("path"), 1);
|
|
7333
|
-
var
|
|
7426
|
+
var import_types20 = require("@neat.is/types");
|
|
7334
7427
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
7335
7428
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
7336
7429
|
const out = [];
|
|
@@ -7343,7 +7436,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
7343
7436
|
seen.add(host);
|
|
7344
7437
|
const line = lineOf(file.content, host);
|
|
7345
7438
|
out.push({
|
|
7346
|
-
infraId: (0,
|
|
7439
|
+
infraId: (0, import_types20.infraId)("redis", host),
|
|
7347
7440
|
name: host,
|
|
7348
7441
|
kind: "redis",
|
|
7349
7442
|
edgeType: "CALLS",
|
|
@@ -7364,7 +7457,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
7364
7457
|
// src/extract/calls/aws.ts
|
|
7365
7458
|
init_cjs_shims();
|
|
7366
7459
|
var import_node_path32 = __toESM(require("path"), 1);
|
|
7367
|
-
var
|
|
7460
|
+
var import_types21 = require("@neat.is/types");
|
|
7368
7461
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
7369
7462
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
7370
7463
|
function hasMarker(text, markers) {
|
|
@@ -7388,7 +7481,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
7388
7481
|
seen.add(key);
|
|
7389
7482
|
const line = lineOf(file.content, name);
|
|
7390
7483
|
out.push({
|
|
7391
|
-
infraId: (0,
|
|
7484
|
+
infraId: (0, import_types21.infraId)(kind, name),
|
|
7392
7485
|
name,
|
|
7393
7486
|
kind,
|
|
7394
7487
|
edgeType: "CALLS",
|
|
@@ -7423,7 +7516,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
7423
7516
|
// src/extract/calls/grpc.ts
|
|
7424
7517
|
init_cjs_shims();
|
|
7425
7518
|
var import_node_path33 = __toESM(require("path"), 1);
|
|
7426
|
-
var
|
|
7519
|
+
var import_types22 = require("@neat.is/types");
|
|
7427
7520
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
7428
7521
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
7429
7522
|
var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
|
|
@@ -7472,7 +7565,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
7472
7565
|
const { kind } = classified;
|
|
7473
7566
|
const line = lineOf(file.content, m[0]);
|
|
7474
7567
|
out.push({
|
|
7475
|
-
infraId: (0,
|
|
7568
|
+
infraId: (0, import_types22.infraId)(kind, name),
|
|
7476
7569
|
name,
|
|
7477
7570
|
kind,
|
|
7478
7571
|
edgeType: "CALLS",
|
|
@@ -7493,7 +7586,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
7493
7586
|
// src/extract/calls/supabase.ts
|
|
7494
7587
|
init_cjs_shims();
|
|
7495
7588
|
var import_node_path34 = __toESM(require("path"), 1);
|
|
7496
|
-
var
|
|
7589
|
+
var import_types23 = require("@neat.is/types");
|
|
7497
7590
|
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
7498
7591
|
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
7499
7592
|
var SUPABASE_CLIENT_RE = /\b(createClient|createServerClient|createBrowserClient)\s*\(\s*(?:['"`]([^'"`]*)['"`])?/g;
|
|
@@ -7541,7 +7634,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
7541
7634
|
seen.add(name);
|
|
7542
7635
|
const line = lineOf(file.content, m[0]);
|
|
7543
7636
|
out.push({
|
|
7544
|
-
infraId: (0,
|
|
7637
|
+
infraId: (0, import_types23.infraId)("supabase", name),
|
|
7545
7638
|
name,
|
|
7546
7639
|
kind: "supabase",
|
|
7547
7640
|
edgeType: "CALLS",
|
|
@@ -7572,7 +7665,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
7572
7665
|
seen.add(key);
|
|
7573
7666
|
const line = lineOf(file.content, am[0]);
|
|
7574
7667
|
out.push({
|
|
7575
|
-
infraId: (0,
|
|
7668
|
+
infraId: (0, import_types23.infraId)(kind, resource),
|
|
7576
7669
|
name: resource,
|
|
7577
7670
|
kind,
|
|
7578
7671
|
edgeType: "CALLS",
|
|
@@ -7591,7 +7684,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
7591
7684
|
// src/extract/calls/mongoose.ts
|
|
7592
7685
|
init_cjs_shims();
|
|
7593
7686
|
var import_node_path35 = __toESM(require("path"), 1);
|
|
7594
|
-
var
|
|
7687
|
+
var import_types24 = require("@neat.is/types");
|
|
7595
7688
|
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
7596
7689
|
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
7597
7690
|
var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
|
|
@@ -7736,7 +7829,7 @@ function collectModelDefs(content, pluralizeOn) {
|
|
|
7736
7829
|
function endpoint(r, file, serviceDir, matchText) {
|
|
7737
7830
|
const line = lineOf(file.content, matchText);
|
|
7738
7831
|
return {
|
|
7739
|
-
infraId: (0,
|
|
7832
|
+
infraId: (0, import_types24.infraId)(r.kind, r.name),
|
|
7740
7833
|
name: r.name,
|
|
7741
7834
|
kind: r.kind,
|
|
7742
7835
|
edgeType: "CALLS",
|
|
@@ -7889,7 +7982,7 @@ init_cjs_shims();
|
|
|
7889
7982
|
var import_node_path36 = __toESM(require("path"), 1);
|
|
7890
7983
|
var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
|
|
7891
7984
|
var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
|
|
7892
|
-
var
|
|
7985
|
+
var import_types25 = require("@neat.is/types");
|
|
7893
7986
|
var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
|
|
7894
7987
|
var PARSE_CHUNK6 = 16384;
|
|
7895
7988
|
function makePyParser4() {
|
|
@@ -7949,20 +8042,57 @@ function walk3(node, visit) {
|
|
|
7949
8042
|
visit(node);
|
|
7950
8043
|
for (const c of namedChildren(node)) walk3(c, visit);
|
|
7951
8044
|
}
|
|
8045
|
+
var COLUMN_BUILDERS = /* @__PURE__ */ new Set(["Column", "mapped_column"]);
|
|
8046
|
+
function isColumnBuilder(call) {
|
|
8047
|
+
const fn = call.childForFieldName("function");
|
|
8048
|
+
const t = fn?.text;
|
|
8049
|
+
if (!t) return false;
|
|
8050
|
+
const base = t.includes(".") ? t.slice(t.lastIndexOf(".") + 1) : t;
|
|
8051
|
+
return COLUMN_BUILDERS.has(base);
|
|
8052
|
+
}
|
|
8053
|
+
function firstPositionalString(call) {
|
|
8054
|
+
const args = call.childForFieldName("arguments");
|
|
8055
|
+
if (!args) return null;
|
|
8056
|
+
for (const arg of namedChildren(args)) {
|
|
8057
|
+
if (arg.type === "keyword_argument") continue;
|
|
8058
|
+
return arg.type === "string" ? pyStaticStringText2(arg) : null;
|
|
8059
|
+
}
|
|
8060
|
+
return null;
|
|
8061
|
+
}
|
|
8062
|
+
function columnsFromClassBody(body) {
|
|
8063
|
+
const out = [];
|
|
8064
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8065
|
+
for (const stmt of namedChildren(body)) {
|
|
8066
|
+
if (stmt.type !== "expression_statement") continue;
|
|
8067
|
+
const assign = stmt.namedChild(0);
|
|
8068
|
+
if (assign?.type !== "assignment") continue;
|
|
8069
|
+
const left = assign.childForFieldName("left");
|
|
8070
|
+
if (left?.type !== "identifier") continue;
|
|
8071
|
+
const right = assign.childForFieldName("right");
|
|
8072
|
+
if (right?.type !== "call" || !isColumnBuilder(right)) continue;
|
|
8073
|
+
const name = firstPositionalString(right) ?? left.text;
|
|
8074
|
+
if (name && !seen.has(name)) {
|
|
8075
|
+
seen.add(name);
|
|
8076
|
+
out.push(name);
|
|
8077
|
+
}
|
|
8078
|
+
}
|
|
8079
|
+
return out;
|
|
8080
|
+
}
|
|
7952
8081
|
function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
7953
8082
|
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return [];
|
|
7954
8083
|
const tree = parseSource6(makePyParser4(), file.content);
|
|
7955
8084
|
const out = [];
|
|
7956
8085
|
const seen = /* @__PURE__ */ new Set();
|
|
7957
|
-
const push = (name, line) => {
|
|
8086
|
+
const push = (name, line, columns) => {
|
|
7958
8087
|
if (seen.has(name)) return;
|
|
7959
8088
|
seen.add(name);
|
|
7960
8089
|
out.push({
|
|
7961
|
-
infraId: (0,
|
|
8090
|
+
infraId: (0, import_types25.infraId)("sql-table", name),
|
|
7962
8091
|
name,
|
|
7963
8092
|
kind: "sql-table",
|
|
7964
8093
|
edgeType: "CALLS",
|
|
7965
8094
|
confidenceKind: "verified-call-site",
|
|
8095
|
+
...columns && columns.length > 0 ? { columns } : {},
|
|
7966
8096
|
evidence: {
|
|
7967
8097
|
file: import_node_path36.default.relative(serviceDir, file.path),
|
|
7968
8098
|
line,
|
|
@@ -7978,11 +8108,12 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
7978
8108
|
const line = node.startPosition.row + 1;
|
|
7979
8109
|
const explicit = explicitTablename(body);
|
|
7980
8110
|
if (explicit === "computed") return;
|
|
8111
|
+
const columns = columnsFromClassBody(body);
|
|
7981
8112
|
if (explicit) {
|
|
7982
|
-
push(explicit.name, line);
|
|
8113
|
+
push(explicit.name, line, columns);
|
|
7983
8114
|
return;
|
|
7984
8115
|
}
|
|
7985
|
-
if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line);
|
|
8116
|
+
if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line, columns);
|
|
7986
8117
|
return;
|
|
7987
8118
|
}
|
|
7988
8119
|
if (node.type === "call") {
|
|
@@ -8064,7 +8195,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
8064
8195
|
if (seen.has(key)) continue;
|
|
8065
8196
|
seen.add(key);
|
|
8066
8197
|
out.push({
|
|
8067
|
-
infraId: (0,
|
|
8198
|
+
infraId: (0, import_types25.infraId)("sql-table", t),
|
|
8068
8199
|
name: t,
|
|
8069
8200
|
kind: "sql-table",
|
|
8070
8201
|
edgeType: "CALLS",
|
|
@@ -8085,7 +8216,7 @@ init_cjs_shims();
|
|
|
8085
8216
|
var import_node_path37 = __toESM(require("path"), 1);
|
|
8086
8217
|
var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
|
|
8087
8218
|
var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
8088
|
-
var
|
|
8219
|
+
var import_types26 = require("@neat.is/types");
|
|
8089
8220
|
var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
|
|
8090
8221
|
var PARSE_CHUNK7 = 16384;
|
|
8091
8222
|
function makePyParser5() {
|
|
@@ -8165,7 +8296,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
8165
8296
|
seen.add(table);
|
|
8166
8297
|
const line = node.startPosition.row + 1;
|
|
8167
8298
|
out.push({
|
|
8168
|
-
infraId: (0,
|
|
8299
|
+
infraId: (0, import_types26.infraId)("sql-table", table),
|
|
8169
8300
|
name: table,
|
|
8170
8301
|
kind: "sql-table",
|
|
8171
8302
|
edgeType: "CALLS",
|
|
@@ -8176,12 +8307,129 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
8176
8307
|
return out;
|
|
8177
8308
|
}
|
|
8178
8309
|
|
|
8179
|
-
// src/extract/calls/
|
|
8310
|
+
// src/extract/calls/drizzle.ts
|
|
8180
8311
|
init_cjs_shims();
|
|
8181
|
-
var
|
|
8312
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
8182
8313
|
var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
|
|
8314
|
+
var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
|
|
8315
|
+
var import_types27 = require("@neat.is/types");
|
|
8316
|
+
var DRIZZLE_IMPORT_RE = /drizzle-orm/;
|
|
8317
|
+
var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
|
|
8318
|
+
function parserForExt(ext) {
|
|
8319
|
+
const p = new import_tree_sitter9.default();
|
|
8320
|
+
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript6.default);
|
|
8321
|
+
return p;
|
|
8322
|
+
}
|
|
8323
|
+
function namedChildren3(node) {
|
|
8324
|
+
const out = [];
|
|
8325
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8326
|
+
const c = node.namedChild(i);
|
|
8327
|
+
if (c) out.push(c);
|
|
8328
|
+
}
|
|
8329
|
+
return out;
|
|
8330
|
+
}
|
|
8331
|
+
function stringLiteralText2(node) {
|
|
8332
|
+
if (!node || node.type !== "string") return null;
|
|
8333
|
+
for (const child of namedChildren3(node)) {
|
|
8334
|
+
if (child.type === "string_fragment") return child.text;
|
|
8335
|
+
}
|
|
8336
|
+
return "";
|
|
8337
|
+
}
|
|
8338
|
+
function firstStringArg(call) {
|
|
8339
|
+
const args = call.childForFieldName("arguments");
|
|
8340
|
+
if (!args) return null;
|
|
8341
|
+
for (const arg of namedChildren3(args)) {
|
|
8342
|
+
if (arg.type === "string") return stringLiteralText2(arg);
|
|
8343
|
+
return null;
|
|
8344
|
+
}
|
|
8345
|
+
return null;
|
|
8346
|
+
}
|
|
8347
|
+
function builderColumnName(value) {
|
|
8348
|
+
let node = value;
|
|
8349
|
+
while (node) {
|
|
8350
|
+
if (node.type === "call_expression") {
|
|
8351
|
+
const fn = node.childForFieldName("function");
|
|
8352
|
+
if (fn?.type === "identifier") return firstStringArg(node);
|
|
8353
|
+
if (fn?.type === "member_expression") {
|
|
8354
|
+
node = fn.childForFieldName("object");
|
|
8355
|
+
continue;
|
|
8356
|
+
}
|
|
8357
|
+
return null;
|
|
8358
|
+
}
|
|
8359
|
+
if (node.type === "member_expression") {
|
|
8360
|
+
node = node.childForFieldName("object");
|
|
8361
|
+
continue;
|
|
8362
|
+
}
|
|
8363
|
+
return null;
|
|
8364
|
+
}
|
|
8365
|
+
return null;
|
|
8366
|
+
}
|
|
8367
|
+
function keyName(key) {
|
|
8368
|
+
if (!key) return null;
|
|
8369
|
+
if (key.type === "property_identifier") return key.text;
|
|
8370
|
+
if (key.type === "string") return stringLiteralText2(key);
|
|
8371
|
+
return null;
|
|
8372
|
+
}
|
|
8373
|
+
function columnsFromObject(obj) {
|
|
8374
|
+
const out = [];
|
|
8375
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8376
|
+
for (const child of namedChildren3(obj)) {
|
|
8377
|
+
if (child.type !== "pair") continue;
|
|
8378
|
+
const value = child.childForFieldName("value");
|
|
8379
|
+
const key = keyName(child.childForFieldName("key"));
|
|
8380
|
+
const name = (value ? builderColumnName(value) : null) ?? key;
|
|
8381
|
+
if (name && !seen.has(name)) {
|
|
8382
|
+
seen.add(name);
|
|
8383
|
+
out.push(name);
|
|
8384
|
+
}
|
|
8385
|
+
}
|
|
8386
|
+
return out;
|
|
8387
|
+
}
|
|
8388
|
+
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
8389
|
+
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
8390
|
+
const tree = parseSource2(parserForExt(import_node_path38.default.extname(file.path)), file.content);
|
|
8391
|
+
const out = [];
|
|
8392
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8393
|
+
const walk6 = (node) => {
|
|
8394
|
+
if (node.type === "call_expression") {
|
|
8395
|
+
const fn = node.childForFieldName("function");
|
|
8396
|
+
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
8397
|
+
const args = node.childForFieldName("arguments");
|
|
8398
|
+
const argNodes = args ? namedChildren3(args) : [];
|
|
8399
|
+
const tableName = stringLiteralText2(argNodes[0] ?? null);
|
|
8400
|
+
const obj = argNodes[1];
|
|
8401
|
+
if (tableName && obj?.type === "object" && !seen.has(tableName)) {
|
|
8402
|
+
seen.add(tableName);
|
|
8403
|
+
const columns = columnsFromObject(obj);
|
|
8404
|
+
const line = node.startPosition.row + 1;
|
|
8405
|
+
out.push({
|
|
8406
|
+
infraId: (0, import_types27.infraId)("sql-table", tableName),
|
|
8407
|
+
name: tableName,
|
|
8408
|
+
kind: "sql-table",
|
|
8409
|
+
edgeType: "CALLS",
|
|
8410
|
+
confidenceKind: "structural",
|
|
8411
|
+
columns,
|
|
8412
|
+
evidence: {
|
|
8413
|
+
file: import_node_path38.default.relative(serviceDir, file.path),
|
|
8414
|
+
line,
|
|
8415
|
+
snippet: snippet(file.content, line)
|
|
8416
|
+
}
|
|
8417
|
+
});
|
|
8418
|
+
}
|
|
8419
|
+
}
|
|
8420
|
+
}
|
|
8421
|
+
for (const c of namedChildren3(node)) walk6(c);
|
|
8422
|
+
};
|
|
8423
|
+
walk6(tree.rootNode);
|
|
8424
|
+
return out;
|
|
8425
|
+
}
|
|
8426
|
+
|
|
8427
|
+
// src/extract/calls/go.ts
|
|
8428
|
+
init_cjs_shims();
|
|
8429
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
8430
|
+
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
8183
8431
|
var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
|
|
8184
|
-
var
|
|
8432
|
+
var import_types28 = require("@neat.is/types");
|
|
8185
8433
|
init_otel();
|
|
8186
8434
|
var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
|
|
8187
8435
|
var PARSE_CHUNK8 = 16384;
|
|
@@ -8193,8 +8441,8 @@ function walk5(node, visit) {
|
|
|
8193
8441
|
}
|
|
8194
8442
|
}
|
|
8195
8443
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
8196
|
-
if (
|
|
8197
|
-
const parser = new
|
|
8444
|
+
if (import_node_path41.default.extname(file.path) !== ".go") return [];
|
|
8445
|
+
const parser = new import_tree_sitter10.default();
|
|
8198
8446
|
parser.setLanguage(import_tree_sitter_go3.default);
|
|
8199
8447
|
const tree = parser.parse(
|
|
8200
8448
|
(index) => index >= file.content.length ? "" : file.content.slice(index, index + PARSE_CHUNK8)
|
|
@@ -8213,12 +8461,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8213
8461
|
if (!table) return;
|
|
8214
8462
|
const line = node.startPosition.row + 1;
|
|
8215
8463
|
out.push({
|
|
8216
|
-
infraId: (0,
|
|
8464
|
+
infraId: (0, import_types28.infraId)("sql-table", table),
|
|
8217
8465
|
name: table,
|
|
8218
8466
|
kind: "sql-table",
|
|
8219
8467
|
edgeType: "CALLS",
|
|
8220
8468
|
confidenceKind: "verified-call-site",
|
|
8221
|
-
evidence: { file: toPosix(
|
|
8469
|
+
evidence: { file: toPosix(import_node_path41.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
|
|
8222
8470
|
});
|
|
8223
8471
|
});
|
|
8224
8472
|
return out;
|
|
@@ -8228,11 +8476,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8228
8476
|
function edgeTypeFromEndpoint(ep) {
|
|
8229
8477
|
switch (ep.edgeType) {
|
|
8230
8478
|
case "PUBLISHES_TO":
|
|
8231
|
-
return
|
|
8479
|
+
return import_types29.EdgeType.PUBLISHES_TO;
|
|
8232
8480
|
case "CONSUMES_FROM":
|
|
8233
|
-
return
|
|
8481
|
+
return import_types29.EdgeType.CONSUMES_FROM;
|
|
8234
8482
|
default:
|
|
8235
|
-
return
|
|
8483
|
+
return import_types29.EdgeType.CALLS;
|
|
8236
8484
|
}
|
|
8237
8485
|
}
|
|
8238
8486
|
function isAwsKind(kind) {
|
|
@@ -8258,6 +8506,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8258
8506
|
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
8259
8507
|
endpoints.push(...sqlalchemyEndpointsFromFile(maskedFile, service.dir));
|
|
8260
8508
|
endpoints.push(...djangoOrmEndpointsFromFile(maskedFile, service.dir));
|
|
8509
|
+
endpoints.push(...drizzleEndpointsFromFile(maskedFile, service.dir));
|
|
8261
8510
|
try {
|
|
8262
8511
|
endpoints.push(...goSqlEndpointsFromFile(maskedFile, service.dir));
|
|
8263
8512
|
} catch (err) {
|
|
@@ -8272,7 +8521,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8272
8521
|
if (!graph.hasNode(ep.infraId)) {
|
|
8273
8522
|
const node = {
|
|
8274
8523
|
id: ep.infraId,
|
|
8275
|
-
type:
|
|
8524
|
+
type: import_types29.NodeType.InfraNode,
|
|
8276
8525
|
name: ep.name,
|
|
8277
8526
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
8278
8527
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -8283,8 +8532,22 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8283
8532
|
graph.addNode(node.id, node);
|
|
8284
8533
|
nodesAdded++;
|
|
8285
8534
|
}
|
|
8535
|
+
if (ep.columns && ep.columns.length > 0) {
|
|
8536
|
+
const node = graph.getNodeAttributes(ep.infraId);
|
|
8537
|
+
if (node.type === import_types29.NodeType.InfraNode) {
|
|
8538
|
+
graph.replaceNodeAttributes(ep.infraId, {
|
|
8539
|
+
...node,
|
|
8540
|
+
columns: foldColumns(
|
|
8541
|
+
node.columns,
|
|
8542
|
+
ep.columns,
|
|
8543
|
+
import_types29.Provenance.EXTRACTED,
|
|
8544
|
+
(0, import_types29.confidenceForExtracted)(ep.confidenceKind)
|
|
8545
|
+
)
|
|
8546
|
+
});
|
|
8547
|
+
}
|
|
8548
|
+
}
|
|
8286
8549
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
8287
|
-
const confidence = (0,
|
|
8550
|
+
const confidence = (0, import_types29.confidenceForExtracted)(ep.confidenceKind);
|
|
8288
8551
|
const relFile = toPosix(ep.evidence.file);
|
|
8289
8552
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
8290
8553
|
graph,
|
|
@@ -8294,7 +8557,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8294
8557
|
);
|
|
8295
8558
|
nodesAdded += n;
|
|
8296
8559
|
edgesAdded += e;
|
|
8297
|
-
if (!(0,
|
|
8560
|
+
if (!(0, import_types29.passesExtractedFloor)(confidence)) {
|
|
8298
8561
|
noteExtractedDropped({
|
|
8299
8562
|
source: fileNodeId,
|
|
8300
8563
|
target: ep.infraId,
|
|
@@ -8314,7 +8577,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8314
8577
|
source: fileNodeId,
|
|
8315
8578
|
target: ep.infraId,
|
|
8316
8579
|
type: edgeType,
|
|
8317
|
-
provenance:
|
|
8580
|
+
provenance: import_types29.Provenance.EXTRACTED,
|
|
8318
8581
|
confidence,
|
|
8319
8582
|
evidence: ep.evidence
|
|
8320
8583
|
};
|
|
@@ -8340,16 +8603,16 @@ init_cjs_shims();
|
|
|
8340
8603
|
|
|
8341
8604
|
// src/extract/infra/docker-compose.ts
|
|
8342
8605
|
init_cjs_shims();
|
|
8343
|
-
var
|
|
8344
|
-
var
|
|
8606
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8607
|
+
var import_types31 = require("@neat.is/types");
|
|
8345
8608
|
|
|
8346
8609
|
// src/extract/infra/shared.ts
|
|
8347
8610
|
init_cjs_shims();
|
|
8348
|
-
var
|
|
8611
|
+
var import_types30 = require("@neat.is/types");
|
|
8349
8612
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
8350
8613
|
return {
|
|
8351
|
-
id: (0,
|
|
8352
|
-
type:
|
|
8614
|
+
id: (0, import_types30.infraId)(kind, name),
|
|
8615
|
+
type: import_types30.NodeType.InfraNode,
|
|
8353
8616
|
name,
|
|
8354
8617
|
provider,
|
|
8355
8618
|
kind,
|
|
@@ -8393,8 +8656,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
8393
8656
|
source: anchorId,
|
|
8394
8657
|
target: node.id,
|
|
8395
8658
|
type: edgeType,
|
|
8396
|
-
provenance:
|
|
8397
|
-
confidence: (0,
|
|
8659
|
+
provenance: import_types30.Provenance.EXTRACTED,
|
|
8660
|
+
confidence: (0, import_types30.confidenceForExtracted)("structural"),
|
|
8398
8661
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
8399
8662
|
};
|
|
8400
8663
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8411,7 +8674,7 @@ function dependsOnList(value) {
|
|
|
8411
8674
|
}
|
|
8412
8675
|
function serviceNameToServiceNode(name, services) {
|
|
8413
8676
|
for (const s of services) {
|
|
8414
|
-
if (s.node.name === name ||
|
|
8677
|
+
if (s.node.name === name || import_node_path42.default.basename(s.dir) === name) return s.node.id;
|
|
8415
8678
|
}
|
|
8416
8679
|
return null;
|
|
8417
8680
|
}
|
|
@@ -8420,7 +8683,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8420
8683
|
let edgesAdded = 0;
|
|
8421
8684
|
let composePath = null;
|
|
8422
8685
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
8423
|
-
const abs =
|
|
8686
|
+
const abs = import_node_path42.default.join(scanPath, name);
|
|
8424
8687
|
if (await exists(abs)) {
|
|
8425
8688
|
composePath = abs;
|
|
8426
8689
|
break;
|
|
@@ -8433,13 +8696,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8433
8696
|
} catch (err) {
|
|
8434
8697
|
recordExtractionError(
|
|
8435
8698
|
"infra docker-compose",
|
|
8436
|
-
|
|
8699
|
+
import_node_path42.default.relative(scanPath, composePath),
|
|
8437
8700
|
err
|
|
8438
8701
|
);
|
|
8439
8702
|
return { nodesAdded, edgesAdded };
|
|
8440
8703
|
}
|
|
8441
8704
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
8442
|
-
const evidenceFile =
|
|
8705
|
+
const evidenceFile = import_node_path42.default.relative(scanPath, composePath).split(import_node_path42.default.sep).join("/");
|
|
8443
8706
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
8444
8707
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
8445
8708
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -8461,15 +8724,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8461
8724
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
8462
8725
|
const targetId = composeNameToNodeId.get(dep);
|
|
8463
8726
|
if (!targetId) continue;
|
|
8464
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
8727
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types31.EdgeType.DEPENDS_ON);
|
|
8465
8728
|
if (graph.hasEdge(edgeId)) continue;
|
|
8466
8729
|
const edge = {
|
|
8467
8730
|
id: edgeId,
|
|
8468
8731
|
source: sourceId,
|
|
8469
8732
|
target: targetId,
|
|
8470
|
-
type:
|
|
8471
|
-
provenance:
|
|
8472
|
-
confidence: (0,
|
|
8733
|
+
type: import_types31.EdgeType.DEPENDS_ON,
|
|
8734
|
+
provenance: import_types31.Provenance.EXTRACTED,
|
|
8735
|
+
confidence: (0, import_types31.confidenceForExtracted)("structural"),
|
|
8473
8736
|
evidence: { file: evidenceFile }
|
|
8474
8737
|
};
|
|
8475
8738
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8481,9 +8744,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8481
8744
|
|
|
8482
8745
|
// src/extract/infra/dockerfile.ts
|
|
8483
8746
|
init_cjs_shims();
|
|
8484
|
-
var
|
|
8747
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
8485
8748
|
var import_node_fs18 = require("fs");
|
|
8486
|
-
var
|
|
8749
|
+
var import_types32 = require("@neat.is/types");
|
|
8487
8750
|
function readDockerfile(content) {
|
|
8488
8751
|
let image = null;
|
|
8489
8752
|
const ports = [];
|
|
@@ -8512,7 +8775,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8512
8775
|
let nodesAdded = 0;
|
|
8513
8776
|
let edgesAdded = 0;
|
|
8514
8777
|
for (const service of services) {
|
|
8515
|
-
const dockerfilePath =
|
|
8778
|
+
const dockerfilePath = import_node_path43.default.join(service.dir, "Dockerfile");
|
|
8516
8779
|
if (!await exists(dockerfilePath)) continue;
|
|
8517
8780
|
let content;
|
|
8518
8781
|
try {
|
|
@@ -8520,7 +8783,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8520
8783
|
} catch (err) {
|
|
8521
8784
|
recordExtractionError(
|
|
8522
8785
|
"infra dockerfile",
|
|
8523
|
-
|
|
8786
|
+
import_node_path43.default.relative(scanPath, dockerfilePath),
|
|
8524
8787
|
err
|
|
8525
8788
|
);
|
|
8526
8789
|
continue;
|
|
@@ -8532,8 +8795,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8532
8795
|
graph.addNode(node.id, node);
|
|
8533
8796
|
nodesAdded++;
|
|
8534
8797
|
}
|
|
8535
|
-
const relDockerfile = toPosix(
|
|
8536
|
-
const evidenceFile = toPosix(
|
|
8798
|
+
const relDockerfile = toPosix(import_node_path43.default.relative(service.dir, dockerfilePath));
|
|
8799
|
+
const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, dockerfilePath));
|
|
8537
8800
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
8538
8801
|
graph,
|
|
8539
8802
|
service.pkg.name,
|
|
@@ -8542,15 +8805,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8542
8805
|
);
|
|
8543
8806
|
nodesAdded += fn;
|
|
8544
8807
|
edgesAdded += fe;
|
|
8545
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
8808
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types32.EdgeType.RUNS_ON);
|
|
8546
8809
|
if (!graph.hasEdge(edgeId)) {
|
|
8547
8810
|
const edge = {
|
|
8548
8811
|
id: edgeId,
|
|
8549
8812
|
source: fileNodeId,
|
|
8550
8813
|
target: node.id,
|
|
8551
|
-
type:
|
|
8552
|
-
provenance:
|
|
8553
|
-
confidence: (0,
|
|
8814
|
+
type: import_types32.EdgeType.RUNS_ON,
|
|
8815
|
+
provenance: import_types32.Provenance.EXTRACTED,
|
|
8816
|
+
confidence: (0, import_types32.confidenceForExtracted)("structural"),
|
|
8554
8817
|
evidence: {
|
|
8555
8818
|
file: evidenceFile,
|
|
8556
8819
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -8565,15 +8828,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8565
8828
|
graph.addNode(portNode.id, portNode);
|
|
8566
8829
|
nodesAdded++;
|
|
8567
8830
|
}
|
|
8568
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
8831
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types32.EdgeType.CONNECTS_TO);
|
|
8569
8832
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
8570
8833
|
const portEdge = {
|
|
8571
8834
|
id: portEdgeId,
|
|
8572
8835
|
source: fileNodeId,
|
|
8573
8836
|
target: portNode.id,
|
|
8574
|
-
type:
|
|
8575
|
-
provenance:
|
|
8576
|
-
confidence: (0,
|
|
8837
|
+
type: import_types32.EdgeType.CONNECTS_TO,
|
|
8838
|
+
provenance: import_types32.Provenance.EXTRACTED,
|
|
8839
|
+
confidence: (0, import_types32.confidenceForExtracted)("structural"),
|
|
8577
8840
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
8578
8841
|
};
|
|
8579
8842
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -8586,8 +8849,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8586
8849
|
// src/extract/infra/terraform.ts
|
|
8587
8850
|
init_cjs_shims();
|
|
8588
8851
|
var import_node_fs19 = require("fs");
|
|
8589
|
-
var
|
|
8590
|
-
var
|
|
8852
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8853
|
+
var import_types33 = require("@neat.is/types");
|
|
8591
8854
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
8592
8855
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
8593
8856
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -8597,11 +8860,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
8597
8860
|
for (const entry2 of entries) {
|
|
8598
8861
|
if (entry2.isDirectory()) {
|
|
8599
8862
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
8600
|
-
const child =
|
|
8863
|
+
const child = import_node_path44.default.join(start, entry2.name);
|
|
8601
8864
|
if (await isPythonVenvDir(child)) continue;
|
|
8602
8865
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
8603
8866
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
8604
|
-
out.push(
|
|
8867
|
+
out.push(import_node_path44.default.join(start, entry2.name));
|
|
8605
8868
|
}
|
|
8606
8869
|
}
|
|
8607
8870
|
return out;
|
|
@@ -8633,7 +8896,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8633
8896
|
const files = await walkTfFiles(scanPath);
|
|
8634
8897
|
for (const file of files) {
|
|
8635
8898
|
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
8636
|
-
const evidenceFile = toPosix(
|
|
8899
|
+
const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, file));
|
|
8637
8900
|
const resources = [];
|
|
8638
8901
|
const byKey = /* @__PURE__ */ new Map();
|
|
8639
8902
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -8668,16 +8931,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8668
8931
|
if (!target) continue;
|
|
8669
8932
|
if (seen.has(target.nodeId)) continue;
|
|
8670
8933
|
seen.add(target.nodeId);
|
|
8671
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
8934
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types33.EdgeType.DEPENDS_ON);
|
|
8672
8935
|
if (graph.hasEdge(edgeId)) continue;
|
|
8673
8936
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
8674
8937
|
const edge = {
|
|
8675
8938
|
id: edgeId,
|
|
8676
8939
|
source: resource.nodeId,
|
|
8677
8940
|
target: target.nodeId,
|
|
8678
|
-
type:
|
|
8679
|
-
provenance:
|
|
8680
|
-
confidence: (0,
|
|
8941
|
+
type: import_types33.EdgeType.DEPENDS_ON,
|
|
8942
|
+
provenance: import_types33.Provenance.EXTRACTED,
|
|
8943
|
+
confidence: (0, import_types33.confidenceForExtracted)("structural"),
|
|
8681
8944
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
8682
8945
|
};
|
|
8683
8946
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8691,7 +8954,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8691
8954
|
// src/extract/infra/k8s.ts
|
|
8692
8955
|
init_cjs_shims();
|
|
8693
8956
|
var import_node_fs20 = require("fs");
|
|
8694
|
-
var
|
|
8957
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8695
8958
|
var import_yaml3 = require("yaml");
|
|
8696
8959
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
8697
8960
|
Service: "k8s-service",
|
|
@@ -8709,11 +8972,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
8709
8972
|
for (const entry2 of entries) {
|
|
8710
8973
|
if (entry2.isDirectory()) {
|
|
8711
8974
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
8712
|
-
const child =
|
|
8975
|
+
const child = import_node_path45.default.join(start, entry2.name);
|
|
8713
8976
|
if (await isPythonVenvDir(child)) continue;
|
|
8714
8977
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
8715
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
8716
|
-
out.push(
|
|
8978
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path45.default.extname(entry2.name))) {
|
|
8979
|
+
out.push(import_node_path45.default.join(start, entry2.name));
|
|
8717
8980
|
}
|
|
8718
8981
|
}
|
|
8719
8982
|
return out;
|
|
@@ -8747,13 +9010,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
8747
9010
|
// src/extract/infra/cloudflare.ts
|
|
8748
9011
|
init_cjs_shims();
|
|
8749
9012
|
var import_node_fs21 = require("fs");
|
|
8750
|
-
var
|
|
9013
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8751
9014
|
var import_smol_toml2 = require("smol-toml");
|
|
8752
|
-
var
|
|
9015
|
+
var import_types34 = require("@neat.is/types");
|
|
8753
9016
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
8754
9017
|
async function readWranglerConfig(dir) {
|
|
8755
9018
|
for (const filename of WRANGLER_FILENAMES) {
|
|
8756
|
-
const abs =
|
|
9019
|
+
const abs = import_node_path46.default.join(dir, filename);
|
|
8757
9020
|
if (!await exists(abs)) continue;
|
|
8758
9021
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
8759
9022
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -8797,8 +9060,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
8797
9060
|
source: anchorId,
|
|
8798
9061
|
target: node.id,
|
|
8799
9062
|
type: edgeType,
|
|
8800
|
-
provenance:
|
|
8801
|
-
confidence: (0,
|
|
9063
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9064
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8802
9065
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
8803
9066
|
};
|
|
8804
9067
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8816,11 +9079,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8816
9079
|
try {
|
|
8817
9080
|
read = await readWranglerConfig(service.dir);
|
|
8818
9081
|
} catch (err) {
|
|
8819
|
-
recordExtractionError("infra cloudflare",
|
|
9082
|
+
recordExtractionError("infra cloudflare", import_node_path46.default.relative(scanPath, service.dir), err);
|
|
8820
9083
|
continue;
|
|
8821
9084
|
}
|
|
8822
9085
|
if (!read || !read.config.name) continue;
|
|
8823
|
-
const evidenceFile = toPosix(
|
|
9086
|
+
const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, read.relFile)));
|
|
8824
9087
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
8825
9088
|
}
|
|
8826
9089
|
for (const worker of discovered) {
|
|
@@ -8832,7 +9095,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8832
9095
|
}
|
|
8833
9096
|
let anchorId = service.node.id;
|
|
8834
9097
|
if (config.main) {
|
|
8835
|
-
const entryRelPath = toPosix(
|
|
9098
|
+
const entryRelPath = toPosix(import_node_path46.default.normalize(config.main));
|
|
8836
9099
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
8837
9100
|
graph,
|
|
8838
9101
|
service.pkg.name,
|
|
@@ -8859,15 +9122,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8859
9122
|
nodesAdded++;
|
|
8860
9123
|
}
|
|
8861
9124
|
if (runtimeNode.id !== anchorId) {
|
|
8862
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
9125
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types34.EdgeType.RUNS_ON);
|
|
8863
9126
|
if (!graph.hasEdge(runsOnId)) {
|
|
8864
9127
|
const edge = {
|
|
8865
9128
|
id: runsOnId,
|
|
8866
9129
|
source: anchorId,
|
|
8867
9130
|
target: runtimeNode.id,
|
|
8868
|
-
type:
|
|
8869
|
-
provenance:
|
|
8870
|
-
confidence: (0,
|
|
9131
|
+
type: import_types34.EdgeType.RUNS_ON,
|
|
9132
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9133
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8871
9134
|
evidence: {
|
|
8872
9135
|
file: evidenceFile,
|
|
8873
9136
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -8881,7 +9144,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8881
9144
|
const result = addResourceEdge(
|
|
8882
9145
|
graph,
|
|
8883
9146
|
anchorId,
|
|
8884
|
-
|
|
9147
|
+
import_types34.EdgeType.CONNECTS_TO,
|
|
8885
9148
|
"cloudflare-route",
|
|
8886
9149
|
route,
|
|
8887
9150
|
evidenceFile,
|
|
@@ -8905,7 +9168,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8905
9168
|
const result = addResourceEdge(
|
|
8906
9169
|
graph,
|
|
8907
9170
|
anchorId,
|
|
8908
|
-
|
|
9171
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8909
9172
|
group.kind,
|
|
8910
9173
|
name,
|
|
8911
9174
|
evidenceFile,
|
|
@@ -8919,7 +9182,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8919
9182
|
const result = addResourceEdge(
|
|
8920
9183
|
graph,
|
|
8921
9184
|
anchorId,
|
|
8922
|
-
|
|
9185
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8923
9186
|
"cloudflare-cron",
|
|
8924
9187
|
cron,
|
|
8925
9188
|
evidenceFile,
|
|
@@ -8932,7 +9195,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8932
9195
|
const result = addResourceEdge(
|
|
8933
9196
|
graph,
|
|
8934
9197
|
anchorId,
|
|
8935
|
-
|
|
9198
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8936
9199
|
"cloudflare-env-var",
|
|
8937
9200
|
varName,
|
|
8938
9201
|
evidenceFile,
|
|
@@ -8945,15 +9208,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8945
9208
|
if (!svc.service) continue;
|
|
8946
9209
|
const target = workerIndex.get(svc.service);
|
|
8947
9210
|
if (target && target.anchorId !== anchorId) {
|
|
8948
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
9211
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types34.EdgeType.CALLS);
|
|
8949
9212
|
if (!graph.hasEdge(edgeId)) {
|
|
8950
9213
|
const edge = {
|
|
8951
9214
|
id: edgeId,
|
|
8952
9215
|
source: anchorId,
|
|
8953
9216
|
target: target.anchorId,
|
|
8954
|
-
type:
|
|
8955
|
-
provenance:
|
|
8956
|
-
confidence: (0,
|
|
9217
|
+
type: import_types34.EdgeType.CALLS,
|
|
9218
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9219
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8957
9220
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
8958
9221
|
};
|
|
8959
9222
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8964,7 +9227,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8964
9227
|
const result = addResourceEdge(
|
|
8965
9228
|
graph,
|
|
8966
9229
|
anchorId,
|
|
8967
|
-
|
|
9230
|
+
import_types34.EdgeType.DEPENDS_ON,
|
|
8968
9231
|
"cloudflare-service-binding",
|
|
8969
9232
|
svc.service,
|
|
8970
9233
|
evidenceFile,
|
|
@@ -8980,12 +9243,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
8980
9243
|
// src/extract/infra/vercel.ts
|
|
8981
9244
|
init_cjs_shims();
|
|
8982
9245
|
var import_node_fs22 = require("fs");
|
|
8983
|
-
var
|
|
8984
|
-
var
|
|
9246
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9247
|
+
var import_types35 = require("@neat.is/types");
|
|
8985
9248
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
8986
9249
|
async function readVercelConfig(dir) {
|
|
8987
9250
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
8988
|
-
const abs =
|
|
9251
|
+
const abs = import_node_path47.default.join(dir, filename);
|
|
8989
9252
|
if (!await exists(abs)) continue;
|
|
8990
9253
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
8991
9254
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -8994,7 +9257,7 @@ async function readVercelConfig(dir) {
|
|
|
8994
9257
|
return null;
|
|
8995
9258
|
}
|
|
8996
9259
|
async function readLinkedProjectName(dir) {
|
|
8997
|
-
const abs =
|
|
9260
|
+
const abs = import_node_path47.default.join(dir, ".vercel", "project.json");
|
|
8998
9261
|
if (!await exists(abs)) return void 0;
|
|
8999
9262
|
const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
|
|
9000
9263
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -9012,7 +9275,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9012
9275
|
read = await readVercelConfig(service.dir);
|
|
9013
9276
|
projectName = await readLinkedProjectName(service.dir);
|
|
9014
9277
|
} catch (err) {
|
|
9015
|
-
recordExtractionError("infra vercel",
|
|
9278
|
+
recordExtractionError("infra vercel", import_node_path47.default.relative(scanPath, service.dir), err);
|
|
9016
9279
|
continue;
|
|
9017
9280
|
}
|
|
9018
9281
|
if (!read && !projectName) continue;
|
|
@@ -9028,7 +9291,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9028
9291
|
const anchorId = service.node.id;
|
|
9029
9292
|
if (!read) continue;
|
|
9030
9293
|
const { config, relFile, raw } = read;
|
|
9031
|
-
const evidenceFile = toPosix(
|
|
9294
|
+
const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
|
|
9032
9295
|
const add = (edgeType, kind, name) => {
|
|
9033
9296
|
if (!name) return;
|
|
9034
9297
|
const result = emitPlatformResourceEdge(
|
|
@@ -9044,12 +9307,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9044
9307
|
nodesAdded += result.nodesAdded;
|
|
9045
9308
|
edgesAdded += result.edgesAdded;
|
|
9046
9309
|
};
|
|
9047
|
-
add(
|
|
9048
|
-
for (const cron of config.crons ?? []) add(
|
|
9049
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
9050
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
9310
|
+
add(import_types35.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
9311
|
+
for (const cron of config.crons ?? []) add(import_types35.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
9312
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9313
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types35.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9051
9314
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
9052
|
-
add(
|
|
9315
|
+
add(import_types35.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
9053
9316
|
}
|
|
9054
9317
|
}
|
|
9055
9318
|
return { nodesAdded, edgesAdded };
|
|
@@ -9058,13 +9321,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9058
9321
|
// src/extract/infra/railway.ts
|
|
9059
9322
|
init_cjs_shims();
|
|
9060
9323
|
var import_node_fs23 = require("fs");
|
|
9061
|
-
var
|
|
9324
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
9062
9325
|
var import_smol_toml3 = require("smol-toml");
|
|
9063
|
-
var
|
|
9326
|
+
var import_types36 = require("@neat.is/types");
|
|
9064
9327
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
9065
9328
|
async function readRailwayConfig(dir) {
|
|
9066
9329
|
for (const filename of RAILWAY_FILENAMES) {
|
|
9067
|
-
const abs =
|
|
9330
|
+
const abs = import_node_path48.default.join(dir, filename);
|
|
9068
9331
|
if (!await exists(abs)) continue;
|
|
9069
9332
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
9070
9333
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9080,7 +9343,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9080
9343
|
try {
|
|
9081
9344
|
read = await readRailwayConfig(service.dir);
|
|
9082
9345
|
} catch (err) {
|
|
9083
|
-
recordExtractionError("infra railway",
|
|
9346
|
+
recordExtractionError("infra railway", import_node_path48.default.relative(scanPath, service.dir), err);
|
|
9084
9347
|
continue;
|
|
9085
9348
|
}
|
|
9086
9349
|
if (!read) continue;
|
|
@@ -9090,7 +9353,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9090
9353
|
}
|
|
9091
9354
|
const anchorId = service.node.id;
|
|
9092
9355
|
const { config, relFile, raw } = read;
|
|
9093
|
-
const evidenceFile = toPosix(
|
|
9356
|
+
const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
|
|
9094
9357
|
const add = (edgeType, kind, name) => {
|
|
9095
9358
|
if (!name) return;
|
|
9096
9359
|
const result = emitPlatformResourceEdge(
|
|
@@ -9106,9 +9369,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9106
9369
|
nodesAdded += result.nodesAdded;
|
|
9107
9370
|
edgesAdded += result.edgesAdded;
|
|
9108
9371
|
};
|
|
9109
|
-
add(
|
|
9110
|
-
add(
|
|
9111
|
-
add(
|
|
9372
|
+
add(import_types36.EdgeType.RUNS_ON, "railway", "railway");
|
|
9373
|
+
add(import_types36.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
9374
|
+
add(import_types36.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
9112
9375
|
}
|
|
9113
9376
|
return { nodesAdded, edgesAdded };
|
|
9114
9377
|
}
|
|
@@ -9116,12 +9379,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9116
9379
|
// src/extract/infra/supabase.ts
|
|
9117
9380
|
init_cjs_shims();
|
|
9118
9381
|
var import_node_fs24 = require("fs");
|
|
9119
|
-
var
|
|
9382
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9120
9383
|
var import_smol_toml4 = require("smol-toml");
|
|
9121
|
-
var
|
|
9384
|
+
var import_types37 = require("@neat.is/types");
|
|
9122
9385
|
async function readSupabaseConfig(dir) {
|
|
9123
|
-
const relFile =
|
|
9124
|
-
const abs =
|
|
9386
|
+
const relFile = import_node_path49.default.join("supabase", "config.toml");
|
|
9387
|
+
const abs = import_node_path49.default.join(dir, relFile);
|
|
9125
9388
|
if (!await exists(abs)) return null;
|
|
9126
9389
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
9127
9390
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -9135,7 +9398,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9135
9398
|
try {
|
|
9136
9399
|
read = await readSupabaseConfig(service.dir);
|
|
9137
9400
|
} catch (err) {
|
|
9138
|
-
recordExtractionError("infra supabase",
|
|
9401
|
+
recordExtractionError("infra supabase", import_node_path49.default.relative(scanPath, service.dir), err);
|
|
9139
9402
|
continue;
|
|
9140
9403
|
}
|
|
9141
9404
|
if (!read) continue;
|
|
@@ -9150,7 +9413,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9150
9413
|
});
|
|
9151
9414
|
}
|
|
9152
9415
|
const anchorId = service.node.id;
|
|
9153
|
-
const evidenceFile = toPosix(
|
|
9416
|
+
const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
|
|
9154
9417
|
const add = (edgeType, kind, name) => {
|
|
9155
9418
|
if (!name) return;
|
|
9156
9419
|
const result = emitPlatformResourceEdge(
|
|
@@ -9166,10 +9429,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9166
9429
|
nodesAdded += result.nodesAdded;
|
|
9167
9430
|
edgesAdded += result.edgesAdded;
|
|
9168
9431
|
};
|
|
9169
|
-
add(
|
|
9170
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
9171
|
-
if (config.storage) add(
|
|
9172
|
-
if (config.auth) add(
|
|
9432
|
+
add(import_types37.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
9433
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types37.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
9434
|
+
if (config.storage) add(import_types37.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
9435
|
+
if (config.auth) add(import_types37.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
9173
9436
|
}
|
|
9174
9437
|
return { nodesAdded, edgesAdded };
|
|
9175
9438
|
}
|
|
@@ -9191,17 +9454,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
9191
9454
|
}
|
|
9192
9455
|
|
|
9193
9456
|
// src/extract/index.ts
|
|
9194
|
-
var
|
|
9457
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
9195
9458
|
|
|
9196
9459
|
// src/extract/retire.ts
|
|
9197
9460
|
init_cjs_shims();
|
|
9198
9461
|
var import_node_fs25 = require("fs");
|
|
9199
|
-
var
|
|
9200
|
-
var
|
|
9462
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9463
|
+
var import_types38 = require("@neat.is/types");
|
|
9201
9464
|
function dropOrphanedFileNodes(graph) {
|
|
9202
9465
|
const orphans = [];
|
|
9203
9466
|
graph.forEachNode((id, attrs) => {
|
|
9204
|
-
if (attrs.type !==
|
|
9467
|
+
if (attrs.type !== import_types38.NodeType.FileNode) return;
|
|
9205
9468
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
9206
9469
|
orphans.push(id);
|
|
9207
9470
|
}
|
|
@@ -9214,7 +9477,7 @@ function retireEdgesByFile(graph, file) {
|
|
|
9214
9477
|
const toDrop = [];
|
|
9215
9478
|
graph.forEachEdge((id, attrs) => {
|
|
9216
9479
|
const edge = attrs;
|
|
9217
|
-
if (edge.provenance !==
|
|
9480
|
+
if (edge.provenance !== import_types38.Provenance.EXTRACTED) return;
|
|
9218
9481
|
if (!edge.evidence?.file) return;
|
|
9219
9482
|
if (edge.evidence.file === normalized) toDrop.push(id);
|
|
9220
9483
|
});
|
|
@@ -9227,14 +9490,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
9227
9490
|
const bases = [scanPath, ...serviceDirs];
|
|
9228
9491
|
graph.forEachEdge((id, attrs) => {
|
|
9229
9492
|
const edge = attrs;
|
|
9230
|
-
if (edge.provenance !==
|
|
9493
|
+
if (edge.provenance !== import_types38.Provenance.EXTRACTED) return;
|
|
9231
9494
|
const evidenceFile = edge.evidence?.file;
|
|
9232
9495
|
if (!evidenceFile) return;
|
|
9233
|
-
if (
|
|
9496
|
+
if (import_node_path50.default.isAbsolute(evidenceFile)) {
|
|
9234
9497
|
if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
|
|
9235
9498
|
return;
|
|
9236
9499
|
}
|
|
9237
|
-
const found = bases.some((base) => (0, import_node_fs25.existsSync)(
|
|
9500
|
+
const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path50.default.join(base, evidenceFile)));
|
|
9238
9501
|
if (!found) toDrop.push(id);
|
|
9239
9502
|
});
|
|
9240
9503
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -9287,7 +9550,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9287
9550
|
}
|
|
9288
9551
|
const droppedEntries = drainDroppedExtracted();
|
|
9289
9552
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
9290
|
-
const rejectedPath =
|
|
9553
|
+
const rejectedPath = import_node_path51.default.join(import_node_path51.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
9291
9554
|
try {
|
|
9292
9555
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
9293
9556
|
} catch (err) {
|
|
@@ -9321,39 +9584,39 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9321
9584
|
|
|
9322
9585
|
// src/divergences.ts
|
|
9323
9586
|
init_cjs_shims();
|
|
9324
|
-
var
|
|
9587
|
+
var import_types39 = require("@neat.is/types");
|
|
9325
9588
|
function bucketKey(source, target, type) {
|
|
9326
9589
|
return `${type}|${source}|${target}`;
|
|
9327
9590
|
}
|
|
9328
9591
|
function bucketSourceFor(graph, edge) {
|
|
9329
|
-
if (edge.type !==
|
|
9330
|
-
const parsed = (0,
|
|
9592
|
+
if (edge.type !== import_types39.EdgeType.CONNECTS_TO) return edge.source;
|
|
9593
|
+
const parsed = (0, import_types39.parseFileId)(edge.source);
|
|
9331
9594
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
9332
9595
|
const target = graph.getNodeAttributes(edge.target);
|
|
9333
|
-
if (target.type !==
|
|
9334
|
-
return (0,
|
|
9596
|
+
if (target.type !== import_types39.NodeType.DatabaseNode) return edge.source;
|
|
9597
|
+
return (0, import_types39.serviceId)(parsed.service);
|
|
9335
9598
|
}
|
|
9336
9599
|
function bucketEdges(graph) {
|
|
9337
9600
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
9338
9601
|
graph.forEachEdge((id, attrs) => {
|
|
9339
9602
|
const e = attrs;
|
|
9340
|
-
const parsed = (0,
|
|
9603
|
+
const parsed = (0, import_types39.parseEdgeId)(id);
|
|
9341
9604
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
9342
9605
|
const source = bucketSourceFor(graph, e);
|
|
9343
9606
|
const key = bucketKey(source, e.target, e.type);
|
|
9344
9607
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
9345
9608
|
switch (provenance) {
|
|
9346
|
-
case
|
|
9609
|
+
case import_types39.Provenance.EXTRACTED:
|
|
9347
9610
|
cur.extracted = e;
|
|
9348
9611
|
break;
|
|
9349
|
-
case
|
|
9612
|
+
case import_types39.Provenance.OBSERVED:
|
|
9350
9613
|
cur.observed = e;
|
|
9351
9614
|
break;
|
|
9352
|
-
case
|
|
9615
|
+
case import_types39.Provenance.INFERRED:
|
|
9353
9616
|
cur.inferred = e;
|
|
9354
9617
|
break;
|
|
9355
9618
|
default:
|
|
9356
|
-
if (e.provenance ===
|
|
9619
|
+
if (e.provenance === import_types39.Provenance.STALE) cur.stale = e;
|
|
9357
9620
|
}
|
|
9358
9621
|
buckets2.set(key, cur);
|
|
9359
9622
|
});
|
|
@@ -9362,17 +9625,17 @@ function bucketEdges(graph) {
|
|
|
9362
9625
|
function nodeIsFrontier(graph, nodeId) {
|
|
9363
9626
|
if (!graph.hasNode(nodeId)) return false;
|
|
9364
9627
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
9365
|
-
return attrs.type ===
|
|
9628
|
+
return attrs.type === import_types39.NodeType.FrontierNode;
|
|
9366
9629
|
}
|
|
9367
9630
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
9368
9631
|
if (!graph.hasNode(nodeId)) return false;
|
|
9369
9632
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
9370
|
-
return attrs.type ===
|
|
9633
|
+
return attrs.type === import_types39.NodeType.WebSocketChannelNode;
|
|
9371
9634
|
}
|
|
9372
9635
|
function nodeIsSymbol(graph, nodeId) {
|
|
9373
9636
|
if (!graph.hasNode(nodeId)) return false;
|
|
9374
9637
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
9375
|
-
return attrs.type ===
|
|
9638
|
+
return attrs.type === import_types39.NodeType.SymbolNode;
|
|
9376
9639
|
}
|
|
9377
9640
|
function clampConfidence(n) {
|
|
9378
9641
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -9392,14 +9655,14 @@ function gradedConfidence(edge) {
|
|
|
9392
9655
|
return clampConfidence(confidenceForEdge(edge));
|
|
9393
9656
|
}
|
|
9394
9657
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9658
|
+
import_types39.EdgeType.CALLS,
|
|
9659
|
+
import_types39.EdgeType.CONNECTS_TO,
|
|
9660
|
+
import_types39.EdgeType.PUBLISHES_TO,
|
|
9661
|
+
import_types39.EdgeType.CONSUMES_FROM
|
|
9399
9662
|
]);
|
|
9400
9663
|
function detectMissingDivergences(graph, bucket) {
|
|
9401
9664
|
const out = [];
|
|
9402
|
-
if (bucket.type ===
|
|
9665
|
+
if (bucket.type === import_types39.EdgeType.CONTAINS) return out;
|
|
9403
9666
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
9404
9667
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
9405
9668
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
@@ -9441,7 +9704,7 @@ function declaredHostFor(svc) {
|
|
|
9441
9704
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
9442
9705
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
9443
9706
|
const e = graph.getEdgeAttributes(edgeId);
|
|
9444
|
-
if (e.type ===
|
|
9707
|
+
if (e.type === import_types39.EdgeType.CONFIGURED_BY && e.provenance === import_types39.Provenance.EXTRACTED) {
|
|
9445
9708
|
return true;
|
|
9446
9709
|
}
|
|
9447
9710
|
}
|
|
@@ -9454,10 +9717,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
9454
9717
|
const out = [];
|
|
9455
9718
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
9456
9719
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
9457
|
-
if (edge.type !==
|
|
9458
|
-
if (edge.provenance !==
|
|
9720
|
+
if (edge.type !== import_types39.EdgeType.CONNECTS_TO) continue;
|
|
9721
|
+
if (edge.provenance !== import_types39.Provenance.OBSERVED) continue;
|
|
9459
9722
|
const target = graph.getNodeAttributes(edge.target);
|
|
9460
|
-
if (target.type !==
|
|
9723
|
+
if (target.type !== import_types39.NodeType.DatabaseNode) continue;
|
|
9461
9724
|
const observedHost = target.host?.trim();
|
|
9462
9725
|
if (!observedHost) continue;
|
|
9463
9726
|
if (observedHost === declaredHost) continue;
|
|
@@ -9479,10 +9742,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
9479
9742
|
const deps = svc.dependencies ?? {};
|
|
9480
9743
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
9481
9744
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
9482
|
-
if (edge.type !==
|
|
9483
|
-
if (edge.provenance !==
|
|
9745
|
+
if (edge.type !== import_types39.EdgeType.CONNECTS_TO) continue;
|
|
9746
|
+
if (edge.provenance !== import_types39.Provenance.OBSERVED) continue;
|
|
9484
9747
|
const target = graph.getNodeAttributes(edge.target);
|
|
9485
|
-
if (target.type !==
|
|
9748
|
+
if (target.type !== import_types39.NodeType.DatabaseNode) continue;
|
|
9486
9749
|
for (const pair of compatPairs()) {
|
|
9487
9750
|
if (pair.engine !== target.engine) continue;
|
|
9488
9751
|
const declared = deps[pair.driver];
|
|
@@ -9532,6 +9795,44 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
9532
9795
|
}
|
|
9533
9796
|
return out;
|
|
9534
9797
|
}
|
|
9798
|
+
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.";
|
|
9799
|
+
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.";
|
|
9800
|
+
function detectColumnDrift(node) {
|
|
9801
|
+
const columns = node.columns;
|
|
9802
|
+
if (!columns || columns.length === 0) return [];
|
|
9803
|
+
const anyDeclared = columns.some(columnIsDeclared);
|
|
9804
|
+
const anyObserved = columns.some(columnIsObserved);
|
|
9805
|
+
if (!anyDeclared || !anyObserved) return [];
|
|
9806
|
+
const out = [];
|
|
9807
|
+
for (const col of columns) {
|
|
9808
|
+
const declared = columnIsDeclared(col);
|
|
9809
|
+
const observed = columnIsObserved(col);
|
|
9810
|
+
if (declared && !observed) {
|
|
9811
|
+
out.push({
|
|
9812
|
+
type: "missing-observed",
|
|
9813
|
+
source: node.id,
|
|
9814
|
+
target: node.id,
|
|
9815
|
+
table: node.id,
|
|
9816
|
+
column: col.name,
|
|
9817
|
+
confidence: clampConfidence(col.confidence),
|
|
9818
|
+
reason: `Schema declares column ${node.name}.${col.name} but no production statement has touched it.`,
|
|
9819
|
+
recommendation: RECOMMENDATION_COLUMN_MISSING_OBSERVED
|
|
9820
|
+
});
|
|
9821
|
+
} else if (observed && !declared) {
|
|
9822
|
+
out.push({
|
|
9823
|
+
type: "missing-extracted",
|
|
9824
|
+
source: node.id,
|
|
9825
|
+
target: node.id,
|
|
9826
|
+
table: node.id,
|
|
9827
|
+
column: col.name,
|
|
9828
|
+
confidence: clampConfidence(col.confidence),
|
|
9829
|
+
reason: `Production touched column ${node.name}.${col.name} but the schema does not declare it.`,
|
|
9830
|
+
recommendation: RECOMMENDATION_COLUMN_MISSING_EXTRACTED
|
|
9831
|
+
});
|
|
9832
|
+
}
|
|
9833
|
+
}
|
|
9834
|
+
return out;
|
|
9835
|
+
}
|
|
9535
9836
|
function involvesNode(d, nodeId) {
|
|
9536
9837
|
return d.source === nodeId || d.target === nodeId;
|
|
9537
9838
|
}
|
|
@@ -9541,7 +9842,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
9541
9842
|
for (const d of all) {
|
|
9542
9843
|
if (d.type !== "host-mismatch") continue;
|
|
9543
9844
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
9544
|
-
declaredHalf.add((0,
|
|
9845
|
+
declaredHalf.add((0, import_types39.databaseId)(d.extractedHost));
|
|
9545
9846
|
}
|
|
9546
9847
|
if (observedHalf.size === 0) return all;
|
|
9547
9848
|
return all.filter((d) => {
|
|
@@ -9560,10 +9861,15 @@ function computeDivergences(graph, opts = {}) {
|
|
|
9560
9861
|
}
|
|
9561
9862
|
graph.forEachNode((nodeId, attrs) => {
|
|
9562
9863
|
const n = attrs;
|
|
9563
|
-
if (n.type
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9864
|
+
if (n.type === import_types39.NodeType.ServiceNode) {
|
|
9865
|
+
const svc = n;
|
|
9866
|
+
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
9867
|
+
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
9868
|
+
return;
|
|
9869
|
+
}
|
|
9870
|
+
if (n.type === import_types39.NodeType.InfraNode && n.kind === "sql-table") {
|
|
9871
|
+
for (const d of detectColumnDrift(n)) all.push(d);
|
|
9872
|
+
}
|
|
9567
9873
|
});
|
|
9568
9874
|
const reconciled = suppressHostMismatchHalves(all);
|
|
9569
9875
|
let filtered = reconciled;
|
|
@@ -9592,9 +9898,12 @@ function computeDivergences(graph, opts = {}) {
|
|
|
9592
9898
|
if (lead !== 0) return lead;
|
|
9593
9899
|
if (a.type !== b.type) return a.type.localeCompare(b.type);
|
|
9594
9900
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
9595
|
-
return a.target.localeCompare(b.target);
|
|
9901
|
+
if (a.target !== b.target) return a.target.localeCompare(b.target);
|
|
9902
|
+
const ac = "column" in a && a.column ? a.column : "";
|
|
9903
|
+
const bc = "column" in b && b.column ? b.column : "";
|
|
9904
|
+
return ac.localeCompare(bc);
|
|
9596
9905
|
});
|
|
9597
|
-
return
|
|
9906
|
+
return import_types39.DivergenceResultSchema.parse({
|
|
9598
9907
|
divergences: filtered,
|
|
9599
9908
|
totalAffected: filtered.length,
|
|
9600
9909
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -9604,9 +9913,9 @@ function computeDivergences(graph, opts = {}) {
|
|
|
9604
9913
|
// src/persist.ts
|
|
9605
9914
|
init_cjs_shims();
|
|
9606
9915
|
var import_node_fs26 = require("fs");
|
|
9607
|
-
var
|
|
9608
|
-
var
|
|
9609
|
-
var SCHEMA_VERSION =
|
|
9916
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
9917
|
+
var import_types40 = require("@neat.is/types");
|
|
9918
|
+
var SCHEMA_VERSION = 6;
|
|
9610
9919
|
function migrateV1ToV2(payload) {
|
|
9611
9920
|
const nodes = payload.graph.nodes;
|
|
9612
9921
|
if (Array.isArray(nodes)) {
|
|
@@ -9624,18 +9933,30 @@ function migrateV3ToV4(payload) {
|
|
|
9624
9933
|
function migrateV4ToV5(payload) {
|
|
9625
9934
|
return { ...payload, schemaVersion: 5 };
|
|
9626
9935
|
}
|
|
9936
|
+
function migrateV5ToV6(payload) {
|
|
9937
|
+
const nodes = payload.graph.nodes;
|
|
9938
|
+
if (Array.isArray(nodes)) {
|
|
9939
|
+
for (const node of nodes) {
|
|
9940
|
+
const attrs = node.attributes;
|
|
9941
|
+
if (!attrs || attrs.type !== import_types40.NodeType.InfraNode) continue;
|
|
9942
|
+
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
9943
|
+
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
9944
|
+
}
|
|
9945
|
+
}
|
|
9946
|
+
return { ...payload, schemaVersion: 6 };
|
|
9947
|
+
}
|
|
9627
9948
|
function migrateV2ToV3(payload) {
|
|
9628
9949
|
const edges = payload.graph.edges;
|
|
9629
9950
|
if (Array.isArray(edges)) {
|
|
9630
9951
|
for (const edge of edges) {
|
|
9631
9952
|
const attrs = edge.attributes;
|
|
9632
9953
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
9633
|
-
attrs.provenance =
|
|
9954
|
+
attrs.provenance = import_types40.Provenance.OBSERVED;
|
|
9634
9955
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
9635
9956
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
9636
9957
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
9637
9958
|
if (type && source && target) {
|
|
9638
|
-
const newId = (0,
|
|
9959
|
+
const newId = (0, import_types40.observedEdgeId)(source, target, type);
|
|
9639
9960
|
attrs.id = newId;
|
|
9640
9961
|
if (edge.key) edge.key = newId;
|
|
9641
9962
|
}
|
|
@@ -9644,7 +9965,7 @@ function migrateV2ToV3(payload) {
|
|
|
9644
9965
|
return { ...payload, schemaVersion: 3 };
|
|
9645
9966
|
}
|
|
9646
9967
|
async function ensureDir(filePath) {
|
|
9647
|
-
await import_node_fs26.promises.mkdir(
|
|
9968
|
+
await import_node_fs26.promises.mkdir(import_node_path52.default.dirname(filePath), { recursive: true });
|
|
9648
9969
|
}
|
|
9649
9970
|
async function saveGraphToDisk(graph, outPath) {
|
|
9650
9971
|
await ensureDir(outPath);
|
|
@@ -9678,6 +9999,9 @@ async function loadGraphFromDisk(graph, outPath) {
|
|
|
9678
9999
|
if (payload.schemaVersion === 4) {
|
|
9679
10000
|
payload = migrateV4ToV5(payload);
|
|
9680
10001
|
}
|
|
10002
|
+
if (payload.schemaVersion === 5) {
|
|
10003
|
+
payload = migrateV5ToV6(payload);
|
|
10004
|
+
}
|
|
9681
10005
|
if (payload.schemaVersion !== SCHEMA_VERSION) {
|
|
9682
10006
|
throw new Error(
|
|
9683
10007
|
`persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`
|
|
@@ -9729,7 +10053,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
9729
10053
|
// src/gitignore.ts
|
|
9730
10054
|
init_cjs_shims();
|
|
9731
10055
|
var import_node_fs27 = require("fs");
|
|
9732
|
-
var
|
|
10056
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
9733
10057
|
var NEAT_OUT_LINE = "neat-out/";
|
|
9734
10058
|
var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
|
|
9735
10059
|
function isNeatOutLine(line) {
|
|
@@ -9737,7 +10061,7 @@ function isNeatOutLine(line) {
|
|
|
9737
10061
|
return trimmed === "neat-out/" || trimmed === "neat-out";
|
|
9738
10062
|
}
|
|
9739
10063
|
async function ensureNeatOutIgnored(projectDir) {
|
|
9740
|
-
const file =
|
|
10064
|
+
const file = import_node_path53.default.join(projectDir, ".gitignore");
|
|
9741
10065
|
let existing = null;
|
|
9742
10066
|
try {
|
|
9743
10067
|
existing = await import_node_fs27.promises.readFile(file, "utf8");
|
|
@@ -9764,7 +10088,7 @@ ${NEAT_OUT_LINE}
|
|
|
9764
10088
|
|
|
9765
10089
|
// src/summary.ts
|
|
9766
10090
|
init_cjs_shims();
|
|
9767
|
-
var
|
|
10091
|
+
var import_types41 = require("@neat.is/types");
|
|
9768
10092
|
function renderOtelEnvBlock() {
|
|
9769
10093
|
return [
|
|
9770
10094
|
"for prod OTel routing, set these in your deploy platform's env:",
|
|
@@ -9774,19 +10098,19 @@ function renderOtelEnvBlock() {
|
|
|
9774
10098
|
}
|
|
9775
10099
|
function findIncompatServices(nodes) {
|
|
9776
10100
|
return nodes.filter(
|
|
9777
|
-
(n) => n.type ===
|
|
10101
|
+
(n) => n.type === import_types41.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
|
|
9778
10102
|
);
|
|
9779
10103
|
}
|
|
9780
10104
|
function servicesWithoutObserved(nodes, edges) {
|
|
9781
10105
|
const seen = /* @__PURE__ */ new Set();
|
|
9782
10106
|
for (const e of edges) {
|
|
9783
|
-
if (e.provenance ===
|
|
10107
|
+
if (e.provenance === import_types41.Provenance.OBSERVED) {
|
|
9784
10108
|
seen.add(e.source);
|
|
9785
10109
|
seen.add(e.target);
|
|
9786
10110
|
}
|
|
9787
10111
|
}
|
|
9788
10112
|
return nodes.filter(
|
|
9789
|
-
(n) => n.type ===
|
|
10113
|
+
(n) => n.type === import_types41.NodeType.ServiceNode && !seen.has(n.id)
|
|
9790
10114
|
);
|
|
9791
10115
|
}
|
|
9792
10116
|
function formatDivergence(d) {
|
|
@@ -9861,26 +10185,26 @@ function formatIncompat(inc) {
|
|
|
9861
10185
|
// src/watch.ts
|
|
9862
10186
|
init_cjs_shims();
|
|
9863
10187
|
var import_node_fs36 = __toESM(require("fs"), 1);
|
|
9864
|
-
var
|
|
10188
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
9865
10189
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
9866
10190
|
|
|
9867
10191
|
// src/api.ts
|
|
9868
10192
|
init_cjs_shims();
|
|
9869
10193
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
9870
10194
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
9871
|
-
var
|
|
10195
|
+
var import_types59 = require("@neat.is/types");
|
|
9872
10196
|
|
|
9873
10197
|
// src/extend/index.ts
|
|
9874
10198
|
init_cjs_shims();
|
|
9875
10199
|
var import_node_fs29 = require("fs");
|
|
9876
|
-
var
|
|
10200
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
9877
10201
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
9878
10202
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
9879
10203
|
|
|
9880
10204
|
// src/installers/package-manager.ts
|
|
9881
10205
|
init_cjs_shims();
|
|
9882
10206
|
var import_node_fs28 = require("fs");
|
|
9883
|
-
var
|
|
10207
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
9884
10208
|
var import_node_child_process = require("child_process");
|
|
9885
10209
|
var LOCKFILE_PRIORITY = [
|
|
9886
10210
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -9902,22 +10226,22 @@ async function exists2(p) {
|
|
|
9902
10226
|
}
|
|
9903
10227
|
}
|
|
9904
10228
|
async function detectPackageManager(serviceDir) {
|
|
9905
|
-
let dir =
|
|
10229
|
+
let dir = import_node_path54.default.resolve(serviceDir);
|
|
9906
10230
|
const stops = /* @__PURE__ */ new Set();
|
|
9907
10231
|
for (let i = 0; i < 64; i++) {
|
|
9908
10232
|
if (stops.has(dir)) break;
|
|
9909
10233
|
stops.add(dir);
|
|
9910
10234
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
9911
|
-
const lockPath =
|
|
10235
|
+
const lockPath = import_node_path54.default.join(dir, candidate.lockfile);
|
|
9912
10236
|
if (await exists2(lockPath)) {
|
|
9913
10237
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
9914
10238
|
}
|
|
9915
10239
|
}
|
|
9916
|
-
const parent =
|
|
10240
|
+
const parent = import_node_path54.default.dirname(dir);
|
|
9917
10241
|
if (parent === dir) break;
|
|
9918
10242
|
dir = parent;
|
|
9919
10243
|
}
|
|
9920
|
-
return { pm: "npm", cwd:
|
|
10244
|
+
return { pm: "npm", cwd: import_node_path54.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
9921
10245
|
}
|
|
9922
10246
|
async function runPackageManagerInstall(cmd) {
|
|
9923
10247
|
return new Promise((resolve) => {
|
|
@@ -9966,7 +10290,7 @@ async function fileExists2(p) {
|
|
|
9966
10290
|
}
|
|
9967
10291
|
}
|
|
9968
10292
|
async function readPackageJson(scanPath) {
|
|
9969
|
-
const pkgPath =
|
|
10293
|
+
const pkgPath = import_node_path55.default.join(scanPath, "package.json");
|
|
9970
10294
|
const raw = await import_node_fs29.promises.readFile(pkgPath, "utf8");
|
|
9971
10295
|
return JSON.parse(raw);
|
|
9972
10296
|
}
|
|
@@ -9985,11 +10309,11 @@ async function findHookFiles(scanPath) {
|
|
|
9985
10309
|
for (const entry2 of entries) {
|
|
9986
10310
|
if (entry2.isDirectory()) {
|
|
9987
10311
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
9988
|
-
await walk6(
|
|
10312
|
+
await walk6(import_node_path55.default.join(dir, entry2.name));
|
|
9989
10313
|
} else if (entry2.isFile()) {
|
|
9990
10314
|
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
9991
|
-
const rel =
|
|
9992
|
-
found.push(rel.split(
|
|
10315
|
+
const rel = import_node_path55.default.relative(scanPath, import_node_path55.default.join(dir, entry2.name));
|
|
10316
|
+
found.push(rel.split(import_node_path55.default.sep).join("/"));
|
|
9993
10317
|
}
|
|
9994
10318
|
}
|
|
9995
10319
|
}
|
|
@@ -10000,7 +10324,7 @@ async function findHookFiles(scanPath) {
|
|
|
10000
10324
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
10001
10325
|
let fallback = null;
|
|
10002
10326
|
for (const file of hookFiles) {
|
|
10003
|
-
const content = await import_node_fs29.promises.readFile(
|
|
10327
|
+
const content = await import_node_fs29.promises.readFile(import_node_path55.default.join(scanPath, file), "utf8");
|
|
10004
10328
|
const patched = splicedContent(content, snippet2);
|
|
10005
10329
|
if (patched !== null) return { file, content, patched };
|
|
10006
10330
|
if (fallback === null) fallback = { file, content };
|
|
@@ -10008,11 +10332,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
10008
10332
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
10009
10333
|
}
|
|
10010
10334
|
function extendLogPath() {
|
|
10011
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
10335
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path55.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
10012
10336
|
}
|
|
10013
10337
|
async function appendExtendLog(entry2) {
|
|
10014
10338
|
const logPath = extendLogPath();
|
|
10015
|
-
await import_node_fs29.promises.mkdir(
|
|
10339
|
+
await import_node_fs29.promises.mkdir(import_node_path55.default.dirname(logPath), { recursive: true });
|
|
10016
10340
|
await import_node_fs29.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
10017
10341
|
}
|
|
10018
10342
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -10071,7 +10395,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
10071
10395
|
}
|
|
10072
10396
|
async function describeProjectInstrumentation(ctx) {
|
|
10073
10397
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
10074
|
-
const envNeat = await fileExists2(
|
|
10398
|
+
const envNeat = await fileExists2(import_node_path55.default.join(ctx.scanPath, ".env.neat"));
|
|
10075
10399
|
const registryInstrPackages = new Set(
|
|
10076
10400
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
10077
10401
|
);
|
|
@@ -10093,7 +10417,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
10093
10417
|
);
|
|
10094
10418
|
}
|
|
10095
10419
|
for (const file of hookFiles) {
|
|
10096
|
-
const content = await import_node_fs29.promises.readFile(
|
|
10420
|
+
const content = await import_node_fs29.promises.readFile(import_node_path55.default.join(ctx.scanPath, file), "utf8");
|
|
10097
10421
|
if (content.includes(args.registration_snippet)) {
|
|
10098
10422
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
10099
10423
|
}
|
|
@@ -10105,10 +10429,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
10105
10429
|
);
|
|
10106
10430
|
}
|
|
10107
10431
|
const primaryFile = primary.file;
|
|
10108
|
-
const primaryPath =
|
|
10432
|
+
const primaryPath = import_node_path55.default.join(ctx.scanPath, primaryFile);
|
|
10109
10433
|
const filesTouched = [];
|
|
10110
10434
|
const depsAdded = [];
|
|
10111
|
-
const pkgPath =
|
|
10435
|
+
const pkgPath = import_node_path55.default.join(ctx.scanPath, "package.json");
|
|
10112
10436
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
10113
10437
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
10114
10438
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -10147,7 +10471,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
10147
10471
|
};
|
|
10148
10472
|
}
|
|
10149
10473
|
for (const file of hookFiles) {
|
|
10150
|
-
const content = await import_node_fs29.promises.readFile(
|
|
10474
|
+
const content = await import_node_fs29.promises.readFile(import_node_path55.default.join(ctx.scanPath, file), "utf8");
|
|
10151
10475
|
if (content.includes(args.registration_snippet)) {
|
|
10152
10476
|
return {
|
|
10153
10477
|
library: args.library,
|
|
@@ -10188,7 +10512,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
10188
10512
|
if (!match) {
|
|
10189
10513
|
return { undone: false, message: "no apply found for library" };
|
|
10190
10514
|
}
|
|
10191
|
-
const pkgPath =
|
|
10515
|
+
const pkgPath = import_node_path55.default.join(ctx.scanPath, "package.json");
|
|
10192
10516
|
if (await fileExists2(pkgPath)) {
|
|
10193
10517
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
10194
10518
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -10199,7 +10523,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
10199
10523
|
}
|
|
10200
10524
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
10201
10525
|
for (const file of hookFiles) {
|
|
10202
|
-
const filePath =
|
|
10526
|
+
const filePath = import_node_path55.default.join(ctx.scanPath, file);
|
|
10203
10527
|
const content = await import_node_fs29.promises.readFile(filePath, "utf8");
|
|
10204
10528
|
if (content.includes(match.registration_snippet)) {
|
|
10205
10529
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -10337,23 +10661,23 @@ function canonicalJson(value) {
|
|
|
10337
10661
|
|
|
10338
10662
|
// src/projects.ts
|
|
10339
10663
|
init_cjs_shims();
|
|
10340
|
-
var
|
|
10664
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
10341
10665
|
function pathsForProject(project, baseDir) {
|
|
10342
10666
|
if (project === DEFAULT_PROJECT) {
|
|
10343
10667
|
return {
|
|
10344
|
-
snapshotPath:
|
|
10345
|
-
errorsPath:
|
|
10346
|
-
staleEventsPath:
|
|
10347
|
-
embeddingsCachePath:
|
|
10348
|
-
policyViolationsPath:
|
|
10668
|
+
snapshotPath: import_node_path56.default.join(baseDir, "graph.json"),
|
|
10669
|
+
errorsPath: import_node_path56.default.join(baseDir, "errors.ndjson"),
|
|
10670
|
+
staleEventsPath: import_node_path56.default.join(baseDir, "stale-events.ndjson"),
|
|
10671
|
+
embeddingsCachePath: import_node_path56.default.join(baseDir, "embeddings.json"),
|
|
10672
|
+
policyViolationsPath: import_node_path56.default.join(baseDir, "policy-violations.ndjson")
|
|
10349
10673
|
};
|
|
10350
10674
|
}
|
|
10351
10675
|
return {
|
|
10352
|
-
snapshotPath:
|
|
10353
|
-
errorsPath:
|
|
10354
|
-
staleEventsPath:
|
|
10355
|
-
embeddingsCachePath:
|
|
10356
|
-
policyViolationsPath:
|
|
10676
|
+
snapshotPath: import_node_path56.default.join(baseDir, `${project}.json`),
|
|
10677
|
+
errorsPath: import_node_path56.default.join(baseDir, `errors.${project}.ndjson`),
|
|
10678
|
+
staleEventsPath: import_node_path56.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
10679
|
+
embeddingsCachePath: import_node_path56.default.join(baseDir, `embeddings.${project}.json`),
|
|
10680
|
+
policyViolationsPath: import_node_path56.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
10357
10681
|
};
|
|
10358
10682
|
}
|
|
10359
10683
|
var Projects = class {
|
|
@@ -10391,26 +10715,26 @@ var Projects = class {
|
|
|
10391
10715
|
init_cjs_shims();
|
|
10392
10716
|
var import_node_fs31 = require("fs");
|
|
10393
10717
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
10394
|
-
var
|
|
10395
|
-
var
|
|
10718
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
10719
|
+
var import_types42 = require("@neat.is/types");
|
|
10396
10720
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
10397
10721
|
var LOCK_RETRY_MS = 50;
|
|
10398
10722
|
function neatHome() {
|
|
10399
10723
|
const override = process.env.NEAT_HOME;
|
|
10400
|
-
if (override && override.length > 0) return
|
|
10401
|
-
return
|
|
10724
|
+
if (override && override.length > 0) return import_node_path57.default.resolve(override);
|
|
10725
|
+
return import_node_path57.default.join(import_node_os3.default.homedir(), ".neat");
|
|
10402
10726
|
}
|
|
10403
10727
|
function registryPath() {
|
|
10404
|
-
return
|
|
10728
|
+
return import_node_path57.default.join(neatHome(), "projects.json");
|
|
10405
10729
|
}
|
|
10406
10730
|
function registryLockPath() {
|
|
10407
|
-
return
|
|
10731
|
+
return import_node_path57.default.join(neatHome(), "projects.json.lock");
|
|
10408
10732
|
}
|
|
10409
10733
|
function daemonPidPath() {
|
|
10410
|
-
return
|
|
10734
|
+
return import_node_path57.default.join(neatHome(), "neatd.pid");
|
|
10411
10735
|
}
|
|
10412
10736
|
function daemonsDir() {
|
|
10413
|
-
return
|
|
10737
|
+
return import_node_path57.default.join(neatHome(), "daemons");
|
|
10414
10738
|
}
|
|
10415
10739
|
function isFiniteInt(v) {
|
|
10416
10740
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -10451,7 +10775,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
10451
10775
|
const out = [];
|
|
10452
10776
|
for (const name of names) {
|
|
10453
10777
|
if (!name.endsWith(".json")) continue;
|
|
10454
|
-
const file =
|
|
10778
|
+
const file = import_node_path57.default.join(dir, name);
|
|
10455
10779
|
let raw;
|
|
10456
10780
|
try {
|
|
10457
10781
|
raw = await import_node_fs31.promises.readFile(file, "utf8");
|
|
@@ -10572,7 +10896,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
10572
10896
|
}
|
|
10573
10897
|
}
|
|
10574
10898
|
async function normalizeProjectPath(input) {
|
|
10575
|
-
const resolved =
|
|
10899
|
+
const resolved = import_node_path57.default.resolve(input);
|
|
10576
10900
|
try {
|
|
10577
10901
|
return await import_node_fs31.promises.realpath(resolved);
|
|
10578
10902
|
} catch {
|
|
@@ -10580,7 +10904,7 @@ async function normalizeProjectPath(input) {
|
|
|
10580
10904
|
}
|
|
10581
10905
|
}
|
|
10582
10906
|
async function writeAtomically(target, contents) {
|
|
10583
|
-
await import_node_fs31.promises.mkdir(
|
|
10907
|
+
await import_node_fs31.promises.mkdir(import_node_path57.default.dirname(target), { recursive: true });
|
|
10584
10908
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
10585
10909
|
const fd = await import_node_fs31.promises.open(tmp, "w");
|
|
10586
10910
|
try {
|
|
@@ -10593,7 +10917,7 @@ async function writeAtomically(target, contents) {
|
|
|
10593
10917
|
}
|
|
10594
10918
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
10595
10919
|
const deadline = Date.now() + timeoutMs;
|
|
10596
|
-
await import_node_fs31.promises.mkdir(
|
|
10920
|
+
await import_node_fs31.promises.mkdir(import_node_path57.default.dirname(lockPath), { recursive: true });
|
|
10597
10921
|
let probedHolder = false;
|
|
10598
10922
|
while (true) {
|
|
10599
10923
|
try {
|
|
@@ -10646,10 +10970,10 @@ async function readRegistry() {
|
|
|
10646
10970
|
throw err;
|
|
10647
10971
|
}
|
|
10648
10972
|
const parsed = JSON.parse(raw);
|
|
10649
|
-
return
|
|
10973
|
+
return import_types42.RegistryFileSchema.parse(parsed);
|
|
10650
10974
|
}
|
|
10651
10975
|
async function writeRegistry(reg) {
|
|
10652
|
-
const validated =
|
|
10976
|
+
const validated = import_types42.RegistryFileSchema.parse(reg);
|
|
10653
10977
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
10654
10978
|
}
|
|
10655
10979
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -10835,7 +11159,7 @@ init_auth();
|
|
|
10835
11159
|
// src/connectors-config.ts
|
|
10836
11160
|
init_cjs_shims();
|
|
10837
11161
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10838
|
-
var
|
|
11162
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
10839
11163
|
var import_node_fs32 = require("fs");
|
|
10840
11164
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10841
11165
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -10850,11 +11174,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10850
11174
|
};
|
|
10851
11175
|
function neatHome2() {
|
|
10852
11176
|
const override = process.env.NEAT_HOME;
|
|
10853
|
-
if (override && override.length > 0) return
|
|
10854
|
-
return
|
|
11177
|
+
if (override && override.length > 0) return import_node_path58.default.resolve(override);
|
|
11178
|
+
return import_node_path58.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10855
11179
|
}
|
|
10856
11180
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10857
|
-
return
|
|
11181
|
+
return import_node_path58.default.join(home, "connectors.json");
|
|
10858
11182
|
}
|
|
10859
11183
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10860
11184
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -10985,7 +11309,7 @@ function connectorMatchesProject(entry2, project) {
|
|
|
10985
11309
|
var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
|
|
10986
11310
|
var CONNECTORS_LOCK_RETRY_MS = 50;
|
|
10987
11311
|
function connectorsConfigLockPath(home = neatHome2()) {
|
|
10988
|
-
return
|
|
11312
|
+
return import_node_path58.default.join(home, "connectors.json.lock");
|
|
10989
11313
|
}
|
|
10990
11314
|
function isEnvRef(value) {
|
|
10991
11315
|
return value.length > 1 && value.startsWith("$");
|
|
@@ -10998,7 +11322,7 @@ function redactCredentialRef(ref) {
|
|
|
10998
11322
|
return out;
|
|
10999
11323
|
}
|
|
11000
11324
|
async function writeConfigAtomically0600(file, contents) {
|
|
11001
|
-
await import_node_fs32.promises.mkdir(
|
|
11325
|
+
await import_node_fs32.promises.mkdir(import_node_path58.default.dirname(file), { recursive: true });
|
|
11002
11326
|
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
11003
11327
|
const fd = await import_node_fs32.promises.open(tmp, "w", 384);
|
|
11004
11328
|
try {
|
|
@@ -11012,7 +11336,7 @@ async function writeConfigAtomically0600(file, contents) {
|
|
|
11012
11336
|
}
|
|
11013
11337
|
async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
|
|
11014
11338
|
const deadline = Date.now() + timeoutMs;
|
|
11015
|
-
await import_node_fs32.promises.mkdir(
|
|
11339
|
+
await import_node_fs32.promises.mkdir(import_node_path58.default.dirname(lockPath), { recursive: true });
|
|
11016
11340
|
for (; ; ) {
|
|
11017
11341
|
try {
|
|
11018
11342
|
const fd = await import_node_fs32.promises.open(lockPath, "wx");
|
|
@@ -11162,15 +11486,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
11162
11486
|
|
|
11163
11487
|
// src/connectors/index.ts
|
|
11164
11488
|
init_cjs_shims();
|
|
11165
|
-
var
|
|
11489
|
+
var import_types43 = require("@neat.is/types");
|
|
11166
11490
|
var NO_ENV = "unknown";
|
|
11167
11491
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
11168
11492
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
11169
11493
|
const sites = [];
|
|
11170
11494
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
11171
11495
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
11172
|
-
if (edge.provenance !==
|
|
11173
|
-
const parsed = (0,
|
|
11496
|
+
if (edge.provenance !== import_types43.Provenance.EXTRACTED) continue;
|
|
11497
|
+
const parsed = (0, import_types43.parseFileId)(edge.source);
|
|
11174
11498
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
11175
11499
|
const site = { relPath: edge.evidence.file };
|
|
11176
11500
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -11181,7 +11505,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
11181
11505
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
11182
11506
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
11183
11507
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
11184
|
-
if (attrs.type !==
|
|
11508
|
+
if (attrs.type !== import_types43.NodeType.RouteNode || !attrs.path) return void 0;
|
|
11185
11509
|
const site = { relPath: attrs.path };
|
|
11186
11510
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
11187
11511
|
return site;
|
|
@@ -11201,6 +11525,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
11201
11525
|
const { kind, name, provider } = resolved.ensureInfraNode;
|
|
11202
11526
|
ensureInfraNode(graph, kind, name, provider);
|
|
11203
11527
|
}
|
|
11528
|
+
mergeObservedColumns(graph, resolved.targetNodeId, signal.columns);
|
|
11204
11529
|
const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV);
|
|
11205
11530
|
const callSite = signal.callSite ? { relPath: signal.callSite.file, line: signal.callSite.line } : routeCallSiteFor(graph, resolved.targetNodeId) ?? staticCallSiteFor(graph, resolved.serviceName, resolved.targetNodeId);
|
|
11206
11531
|
const sourceId = callSite ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite) : serviceNodeId;
|
|
@@ -11631,6 +11956,7 @@ async function fetchSupabaseEdgeLogs(config, token, startIso, endIso, fetchImpl
|
|
|
11631
11956
|
|
|
11632
11957
|
// src/connectors/supabase/map.ts
|
|
11633
11958
|
init_cjs_shims();
|
|
11959
|
+
init_otel();
|
|
11634
11960
|
|
|
11635
11961
|
// src/connectors/supabase/types.ts
|
|
11636
11962
|
init_cjs_shims();
|
|
@@ -11656,10 +11982,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
11656
11982
|
// src/connectors/supabase/map.ts
|
|
11657
11983
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
11658
11984
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
11659
|
-
function targetFromRestPath(
|
|
11660
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
11985
|
+
function targetFromRestPath(path71) {
|
|
11986
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path71);
|
|
11661
11987
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
11662
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
11988
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path71);
|
|
11663
11989
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
11664
11990
|
return null;
|
|
11665
11991
|
}
|
|
@@ -11723,12 +12049,14 @@ function diffPgStatStatementsToSignals(rows, previous, nowIso2) {
|
|
|
11723
12049
|
if (delta <= 0) continue;
|
|
11724
12050
|
const table = tableNameFromQueryText(row.query);
|
|
11725
12051
|
if (!table) continue;
|
|
12052
|
+
const columns = columnsFromSqlStatement(row.query);
|
|
11726
12053
|
signals.push({
|
|
11727
12054
|
targetKind: SUPABASE_TABLE_TARGET_KIND,
|
|
11728
12055
|
targetName: table,
|
|
11729
12056
|
callCount: delta,
|
|
11730
12057
|
errorCount: 0,
|
|
11731
|
-
lastObservedIso: nowIso2
|
|
12058
|
+
lastObservedIso: nowIso2,
|
|
12059
|
+
...columns.length > 0 ? { columns } : {}
|
|
11732
12060
|
});
|
|
11733
12061
|
}
|
|
11734
12062
|
for (const queryid of [...previous.keys()]) {
|
|
@@ -11768,23 +12096,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
11768
12096
|
|
|
11769
12097
|
// src/connectors/supabase/resolve.ts
|
|
11770
12098
|
init_cjs_shims();
|
|
11771
|
-
var
|
|
12099
|
+
var import_types45 = require("@neat.is/types");
|
|
11772
12100
|
function createSupabaseResolveTarget(graph, config) {
|
|
11773
12101
|
return (signal, _ctx) => {
|
|
11774
12102
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
11775
12103
|
return null;
|
|
11776
12104
|
}
|
|
11777
|
-
const subResourceId = (0,
|
|
12105
|
+
const subResourceId = (0, import_types45.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
11778
12106
|
if (graph.hasNode(subResourceId)) {
|
|
11779
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
12107
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11780
12108
|
}
|
|
11781
|
-
const bareResourceId = (0,
|
|
12109
|
+
const bareResourceId = (0, import_types45.infraId)(signal.targetKind, signal.targetName);
|
|
11782
12110
|
if (graph.hasNode(bareResourceId)) {
|
|
11783
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
12111
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11784
12112
|
}
|
|
11785
|
-
const projectLevelId = (0,
|
|
12113
|
+
const projectLevelId = (0, import_types45.infraId)("supabase", config.nodeRef);
|
|
11786
12114
|
if (graph.hasNode(projectLevelId)) {
|
|
11787
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
12115
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11788
12116
|
}
|
|
11789
12117
|
return null;
|
|
11790
12118
|
};
|
|
@@ -11877,7 +12205,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
11877
12205
|
|
|
11878
12206
|
// src/connectors/railway/index.ts
|
|
11879
12207
|
init_cjs_shims();
|
|
11880
|
-
var
|
|
12208
|
+
var import_types49 = require("@neat.is/types");
|
|
11881
12209
|
|
|
11882
12210
|
// src/connectors/railway/client.ts
|
|
11883
12211
|
init_cjs_shims();
|
|
@@ -12028,7 +12356,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
12028
12356
|
const out = [];
|
|
12029
12357
|
graph.forEachNode((_id, attrs) => {
|
|
12030
12358
|
const node = attrs;
|
|
12031
|
-
if (node.type !==
|
|
12359
|
+
if (node.type !== import_types49.NodeType.RouteNode) return;
|
|
12032
12360
|
const route = attrs;
|
|
12033
12361
|
if (route.service !== serviceName) return;
|
|
12034
12362
|
out.push({
|
|
@@ -12132,12 +12460,12 @@ function createRailwayResolveTarget(config) {
|
|
|
12132
12460
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
12133
12461
|
if (!serviceName) return null;
|
|
12134
12462
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
12135
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
12463
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types49.EdgeType.CALLS };
|
|
12136
12464
|
}
|
|
12137
12465
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
12138
12466
|
const peerName = config.serviceNameById[signal.targetName];
|
|
12139
12467
|
if (!peerName) return null;
|
|
12140
|
-
return { targetNodeId: (0,
|
|
12468
|
+
return { targetNodeId: (0, import_types49.serviceId)(peerName), serviceName, edgeType: import_types49.EdgeType.CONNECTS_TO };
|
|
12141
12469
|
}
|
|
12142
12470
|
return null;
|
|
12143
12471
|
};
|
|
@@ -12261,9 +12589,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
12261
12589
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
12262
12590
|
if (secondSep === -1) return null;
|
|
12263
12591
|
const method = rest.slice(0, secondSep);
|
|
12264
|
-
const
|
|
12265
|
-
if (!resourceName || !method || !
|
|
12266
|
-
return { resourceName, method, path:
|
|
12592
|
+
const path71 = rest.slice(secondSep + 1);
|
|
12593
|
+
if (!resourceName || !method || !path71) return null;
|
|
12594
|
+
return { resourceName, method, path: path71 };
|
|
12267
12595
|
}
|
|
12268
12596
|
function resourceNameFor(type, labels) {
|
|
12269
12597
|
if (!labels) return null;
|
|
@@ -12301,14 +12629,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
12301
12629
|
if (!req) return null;
|
|
12302
12630
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
12303
12631
|
const method = req.requestMethod.toUpperCase();
|
|
12304
|
-
const
|
|
12305
|
-
if (
|
|
12632
|
+
const path71 = pathFromRequestUrl(req.requestUrl);
|
|
12633
|
+
if (path71 === null) return null;
|
|
12306
12634
|
const timestamp = entry2.timestamp;
|
|
12307
12635
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
12308
12636
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
12309
12637
|
return {
|
|
12310
12638
|
targetKind: resourceType,
|
|
12311
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
12639
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path71 }),
|
|
12312
12640
|
callCount: 1,
|
|
12313
12641
|
errorCount: isError ? 1 : 0,
|
|
12314
12642
|
lastObservedIso: timestamp
|
|
@@ -12325,7 +12653,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
12325
12653
|
|
|
12326
12654
|
// src/connectors/firebase/resolve.ts
|
|
12327
12655
|
init_cjs_shims();
|
|
12328
|
-
var
|
|
12656
|
+
var import_types50 = require("@neat.is/types");
|
|
12329
12657
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
12330
12658
|
switch (resourceType) {
|
|
12331
12659
|
case "cloud_function":
|
|
@@ -12340,7 +12668,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
12340
12668
|
const entries = [];
|
|
12341
12669
|
graph.forEachNode((_id, attrs) => {
|
|
12342
12670
|
const node = attrs;
|
|
12343
|
-
if (node.type !==
|
|
12671
|
+
if (node.type !== import_types50.NodeType.RouteNode) return;
|
|
12344
12672
|
const route = attrs;
|
|
12345
12673
|
if (route.service !== serviceName) return;
|
|
12346
12674
|
entries.push({
|
|
@@ -12372,7 +12700,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
12372
12700
|
return {
|
|
12373
12701
|
targetNodeId: match.routeNodeId,
|
|
12374
12702
|
serviceName,
|
|
12375
|
-
edgeType:
|
|
12703
|
+
edgeType: import_types50.EdgeType.CALLS
|
|
12376
12704
|
};
|
|
12377
12705
|
};
|
|
12378
12706
|
}
|
|
@@ -12399,7 +12727,7 @@ init_cjs_shims();
|
|
|
12399
12727
|
|
|
12400
12728
|
// src/connectors/cloudflare/connector.ts
|
|
12401
12729
|
init_cjs_shims();
|
|
12402
|
-
var
|
|
12730
|
+
var import_types52 = require("@neat.is/types");
|
|
12403
12731
|
|
|
12404
12732
|
// src/connectors/cloudflare/client.ts
|
|
12405
12733
|
init_cjs_shims();
|
|
@@ -12515,7 +12843,7 @@ function mapEventToSignal(event) {
|
|
|
12515
12843
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
12516
12844
|
const statusCode = metadata?.statusCode;
|
|
12517
12845
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
12518
|
-
const
|
|
12846
|
+
const path71 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
12519
12847
|
return {
|
|
12520
12848
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
12521
12849
|
targetName: scriptName,
|
|
@@ -12523,7 +12851,7 @@ function mapEventToSignal(event) {
|
|
|
12523
12851
|
errorCount: isError ? 1 : 0,
|
|
12524
12852
|
lastObservedIso: observedAt.toISOString(),
|
|
12525
12853
|
method,
|
|
12526
|
-
...
|
|
12854
|
+
...path71 ? { path: path71 } : {},
|
|
12527
12855
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
12528
12856
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
12529
12857
|
};
|
|
@@ -12563,19 +12891,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
12563
12891
|
graph.forEachNode((id, attrs) => {
|
|
12564
12892
|
if (found) return;
|
|
12565
12893
|
const a = attrs;
|
|
12566
|
-
if (a.type ===
|
|
12894
|
+
if (a.type === import_types52.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
12567
12895
|
found = id;
|
|
12568
12896
|
}
|
|
12569
12897
|
});
|
|
12570
12898
|
return found;
|
|
12571
12899
|
}
|
|
12572
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
12573
|
-
const normalizedPath = normalizePathTemplate(
|
|
12900
|
+
function findMatchingRouteNode(graph, serviceName, method, path71) {
|
|
12901
|
+
const normalizedPath = normalizePathTemplate(path71);
|
|
12574
12902
|
let found = null;
|
|
12575
12903
|
graph.forEachNode((id, attrs) => {
|
|
12576
12904
|
if (found) return;
|
|
12577
12905
|
const a = attrs;
|
|
12578
|
-
if (a.type !==
|
|
12906
|
+
if (a.type !== import_types52.NodeType.RouteNode || a.service !== serviceName) return;
|
|
12579
12907
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
12580
12908
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
12581
12909
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -12587,18 +12915,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12587
12915
|
return (signal) => {
|
|
12588
12916
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
12589
12917
|
const scriptName = signal.targetName;
|
|
12590
|
-
const { method, path:
|
|
12918
|
+
const { method, path: path71 } = signal;
|
|
12591
12919
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
12592
|
-
if (!method || !
|
|
12593
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
12920
|
+
if (!method || !path71) return wholeFileId;
|
|
12921
|
+
return findMatchingRouteNode(graph, serviceName, method, path71) ?? wholeFileId;
|
|
12594
12922
|
};
|
|
12595
12923
|
const mapping = config.workers?.[scriptName];
|
|
12596
12924
|
if (mapping) {
|
|
12597
|
-
const wholeFileId = (0,
|
|
12925
|
+
const wholeFileId = (0, import_types52.fileId)(mapping.service, mapping.entryFile);
|
|
12598
12926
|
return {
|
|
12599
12927
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
12600
12928
|
serviceName: mapping.service,
|
|
12601
|
-
edgeType:
|
|
12929
|
+
edgeType: import_types52.EdgeType.CALLS
|
|
12602
12930
|
};
|
|
12603
12931
|
}
|
|
12604
12932
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -12607,13 +12935,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12607
12935
|
return {
|
|
12608
12936
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
12609
12937
|
serviceName: fileNode.service,
|
|
12610
|
-
edgeType:
|
|
12938
|
+
edgeType: import_types52.EdgeType.CALLS
|
|
12611
12939
|
};
|
|
12612
12940
|
}
|
|
12613
12941
|
return {
|
|
12614
|
-
targetNodeId: (0,
|
|
12942
|
+
targetNodeId: (0, import_types52.infraId)("cloudflare-worker", scriptName),
|
|
12615
12943
|
serviceName: scriptName,
|
|
12616
|
-
edgeType:
|
|
12944
|
+
edgeType: import_types52.EdgeType.CALLS,
|
|
12617
12945
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
12618
12946
|
};
|
|
12619
12947
|
};
|
|
@@ -12791,12 +13119,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
12791
13119
|
if (!prior || calls <= prior.calls) continue;
|
|
12792
13120
|
const table = tableFromSqlStatement(row.query);
|
|
12793
13121
|
if (!table) continue;
|
|
13122
|
+
const columns = columnsFromSqlStatement(row.query);
|
|
12794
13123
|
signals.push({
|
|
12795
13124
|
targetKind: NEON_SQL_TABLE_TARGET_KIND,
|
|
12796
13125
|
targetName: table,
|
|
12797
13126
|
callCount: calls - prior.calls,
|
|
12798
13127
|
errorCount: 0,
|
|
12799
|
-
lastObservedIso: observedAtIso
|
|
13128
|
+
lastObservedIso: observedAtIso,
|
|
13129
|
+
...columns.length > 0 ? { columns } : {}
|
|
12800
13130
|
});
|
|
12801
13131
|
}
|
|
12802
13132
|
for (const queryid of previous.keys()) {
|
|
@@ -12807,14 +13137,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
12807
13137
|
|
|
12808
13138
|
// src/connectors/neon/resolve.ts
|
|
12809
13139
|
init_cjs_shims();
|
|
12810
|
-
var
|
|
13140
|
+
var import_types56 = require("@neat.is/types");
|
|
12811
13141
|
function createNeonResolveTarget(config) {
|
|
12812
13142
|
return (signal) => {
|
|
12813
13143
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
12814
13144
|
return {
|
|
12815
|
-
targetNodeId: (0,
|
|
13145
|
+
targetNodeId: (0, import_types56.infraId)("sql-table", signal.targetName),
|
|
12816
13146
|
serviceName: config.serviceName,
|
|
12817
|
-
edgeType:
|
|
13147
|
+
edgeType: import_types56.EdgeType.CALLS,
|
|
12818
13148
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
12819
13149
|
};
|
|
12820
13150
|
};
|
|
@@ -13457,11 +13787,11 @@ function registerRoutes(scope, ctx) {
|
|
|
13457
13787
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
13458
13788
|
const parsed = [];
|
|
13459
13789
|
for (const c of candidates) {
|
|
13460
|
-
const r =
|
|
13790
|
+
const r = import_types59.DivergenceTypeSchema.safeParse(c);
|
|
13461
13791
|
if (!r.success) {
|
|
13462
13792
|
return reply.code(400).send({
|
|
13463
13793
|
error: `unknown divergence type "${c}"`,
|
|
13464
|
-
allowed:
|
|
13794
|
+
allowed: import_types59.DivergenceTypeSchema.options
|
|
13465
13795
|
});
|
|
13466
13796
|
}
|
|
13467
13797
|
parsed.push(r.data);
|
|
@@ -13770,7 +14100,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13770
14100
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
13771
14101
|
let violations = await log.readAll();
|
|
13772
14102
|
if (req.query.severity) {
|
|
13773
|
-
const sev =
|
|
14103
|
+
const sev = import_types59.PolicySeveritySchema.safeParse(req.query.severity);
|
|
13774
14104
|
if (!sev.success) {
|
|
13775
14105
|
return reply.code(400).send({
|
|
13776
14106
|
error: "invalid severity",
|
|
@@ -13809,7 +14139,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13809
14139
|
scope.post("/policies/check", async (req, reply) => {
|
|
13810
14140
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
13811
14141
|
if (!proj) return;
|
|
13812
|
-
const parsed =
|
|
14142
|
+
const parsed = import_types59.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
13813
14143
|
if (!parsed.success) {
|
|
13814
14144
|
return reply.code(400).send({
|
|
13815
14145
|
error: "invalid /policies/check body",
|
|
@@ -14131,7 +14461,7 @@ init_otel();
|
|
|
14131
14461
|
// src/daemon.ts
|
|
14132
14462
|
init_cjs_shims();
|
|
14133
14463
|
var import_node_fs34 = require("fs");
|
|
14134
|
-
var
|
|
14464
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
14135
14465
|
var import_node_module = require("module");
|
|
14136
14466
|
init_otel();
|
|
14137
14467
|
init_auth();
|
|
@@ -14139,28 +14469,28 @@ init_auth();
|
|
|
14139
14469
|
// src/unrouted.ts
|
|
14140
14470
|
init_cjs_shims();
|
|
14141
14471
|
var import_node_fs33 = require("fs");
|
|
14142
|
-
var
|
|
14472
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14143
14473
|
|
|
14144
14474
|
// src/daemon.ts
|
|
14145
|
-
var
|
|
14475
|
+
var import_types60 = require("@neat.is/types");
|
|
14146
14476
|
function daemonJsonPath(scanPath) {
|
|
14147
|
-
return
|
|
14477
|
+
return import_node_path60.default.join(scanPath, "neat-out", "daemon.json");
|
|
14148
14478
|
}
|
|
14149
14479
|
function daemonsDiscoveryDir(home) {
|
|
14150
14480
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
14151
|
-
return
|
|
14481
|
+
return import_node_path60.default.join(base, "daemons");
|
|
14152
14482
|
}
|
|
14153
14483
|
function daemonDiscoveryPath(project, home) {
|
|
14154
|
-
return
|
|
14484
|
+
return import_node_path60.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
14155
14485
|
}
|
|
14156
14486
|
function sanitizeDiscoveryName(project) {
|
|
14157
14487
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
14158
14488
|
}
|
|
14159
14489
|
function neatHomeFromEnv() {
|
|
14160
14490
|
const env = process.env.NEAT_HOME;
|
|
14161
|
-
if (env && env.length > 0) return
|
|
14491
|
+
if (env && env.length > 0) return import_node_path60.default.resolve(env);
|
|
14162
14492
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
14163
|
-
return
|
|
14493
|
+
return import_node_path60.default.join(home, ".neat");
|
|
14164
14494
|
}
|
|
14165
14495
|
async function readDaemonRecord(scanPath) {
|
|
14166
14496
|
try {
|
|
@@ -14231,7 +14561,7 @@ init_otel_grpc();
|
|
|
14231
14561
|
// src/search.ts
|
|
14232
14562
|
init_cjs_shims();
|
|
14233
14563
|
var import_node_fs35 = require("fs");
|
|
14234
|
-
var
|
|
14564
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
14235
14565
|
var import_node_crypto4 = require("crypto");
|
|
14236
14566
|
var DEFAULT_LIMIT = 10;
|
|
14237
14567
|
var NOMIC_DIM = 768;
|
|
@@ -14394,7 +14724,7 @@ async function readCache(cachePath) {
|
|
|
14394
14724
|
}
|
|
14395
14725
|
}
|
|
14396
14726
|
async function writeCache(cachePath, cache) {
|
|
14397
|
-
await import_node_fs35.promises.mkdir(
|
|
14727
|
+
await import_node_fs35.promises.mkdir(import_node_path61.default.dirname(cachePath), { recursive: true });
|
|
14398
14728
|
await import_node_fs35.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
14399
14729
|
}
|
|
14400
14730
|
var VectorIndex = class {
|
|
@@ -14552,8 +14882,8 @@ var ALL_PHASES = [
|
|
|
14552
14882
|
];
|
|
14553
14883
|
function classifyChange(relPath) {
|
|
14554
14884
|
const phases = /* @__PURE__ */ new Set();
|
|
14555
|
-
const base =
|
|
14556
|
-
const segments = relPath.split(
|
|
14885
|
+
const base = import_node_path62.default.basename(relPath).toLowerCase();
|
|
14886
|
+
const segments = relPath.split(import_node_path62.default.sep).map((s) => s.toLowerCase());
|
|
14557
14887
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
14558
14888
|
phases.add("services");
|
|
14559
14889
|
phases.add("aliases");
|
|
@@ -14681,9 +15011,9 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
14681
15011
|
for (const e of entries) {
|
|
14682
15012
|
if (count >= limit) return;
|
|
14683
15013
|
if (!e.isDirectory()) continue;
|
|
14684
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
15014
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path62.default.join(dir, e.name) + import_node_path62.default.sep))) continue;
|
|
14685
15015
|
count++;
|
|
14686
|
-
if (depth < 2) visit(
|
|
15016
|
+
if (depth < 2) visit(import_node_path62.default.join(dir, e.name), depth + 1);
|
|
14687
15017
|
}
|
|
14688
15018
|
};
|
|
14689
15019
|
visit(scanPath, 0);
|
|
@@ -14701,8 +15031,8 @@ async function startWatch(graph, opts) {
|
|
|
14701
15031
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
14702
15032
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
14703
15033
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
14704
|
-
const policyFilePath =
|
|
14705
|
-
const policyViolationsPath =
|
|
15034
|
+
const policyFilePath = import_node_path62.default.join(opts.scanPath, "policy.json");
|
|
15035
|
+
const policyViolationsPath = import_node_path62.default.join(import_node_path62.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
14706
15036
|
let policies = [];
|
|
14707
15037
|
try {
|
|
14708
15038
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -14762,7 +15092,7 @@ async function startWatch(graph, opts) {
|
|
|
14762
15092
|
assertBindAuthority(host, auth.authToken);
|
|
14763
15093
|
const port = opts.port ?? 8080;
|
|
14764
15094
|
const otelPort = opts.otelPort ?? 4318;
|
|
14765
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
15095
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path62.default.join(import_node_path62.default.dirname(opts.outPath), "embeddings.json");
|
|
14766
15096
|
let searchIndex;
|
|
14767
15097
|
try {
|
|
14768
15098
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -14780,7 +15110,7 @@ async function startWatch(graph, opts) {
|
|
|
14780
15110
|
// Paths are derived from the explicit options the watch caller passes
|
|
14781
15111
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
14782
15112
|
// fields so the registry shape is complete.
|
|
14783
|
-
...pathsForProject(projectName,
|
|
15113
|
+
...pathsForProject(projectName, import_node_path62.default.dirname(opts.outPath)),
|
|
14784
15114
|
snapshotPath: opts.outPath,
|
|
14785
15115
|
errorsPath: opts.errorsPath,
|
|
14786
15116
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -14898,9 +15228,9 @@ async function startWatch(graph, opts) {
|
|
|
14898
15228
|
};
|
|
14899
15229
|
const onPath = (absPath) => {
|
|
14900
15230
|
if (shouldIgnore(absPath)) return;
|
|
14901
|
-
const rel =
|
|
15231
|
+
const rel = import_node_path62.default.relative(opts.scanPath, absPath);
|
|
14902
15232
|
if (!rel || rel.startsWith("..")) return;
|
|
14903
|
-
pendingPaths.add(rel.split(
|
|
15233
|
+
pendingPaths.add(rel.split(import_node_path62.default.sep).join("/"));
|
|
14904
15234
|
const phases = classifyChange(rel);
|
|
14905
15235
|
if (phases.size === 0) {
|
|
14906
15236
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -14958,7 +15288,7 @@ async function startWatch(graph, opts) {
|
|
|
14958
15288
|
// src/deploy/detect.ts
|
|
14959
15289
|
init_cjs_shims();
|
|
14960
15290
|
var import_node_fs37 = require("fs");
|
|
14961
|
-
var
|
|
15291
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
14962
15292
|
var import_node_child_process2 = require("child_process");
|
|
14963
15293
|
var import_node_crypto5 = require("crypto");
|
|
14964
15294
|
function generateToken() {
|
|
@@ -15058,7 +15388,7 @@ async function runDeploy(opts = {}) {
|
|
|
15058
15388
|
const token = generateToken();
|
|
15059
15389
|
switch (substrate) {
|
|
15060
15390
|
case "docker-compose": {
|
|
15061
|
-
const artifactPath =
|
|
15391
|
+
const artifactPath = import_node_path63.default.join(cwd, "docker-compose.neat.yml");
|
|
15062
15392
|
const contents = emitDockerCompose(cwd);
|
|
15063
15393
|
await import_node_fs37.promises.writeFile(artifactPath, contents, "utf8");
|
|
15064
15394
|
return {
|
|
@@ -15066,11 +15396,11 @@ async function runDeploy(opts = {}) {
|
|
|
15066
15396
|
artifactPath,
|
|
15067
15397
|
token,
|
|
15068
15398
|
contents,
|
|
15069
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
15399
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path63.default.basename(artifactPath)} up -d`
|
|
15070
15400
|
};
|
|
15071
15401
|
}
|
|
15072
15402
|
case "systemd": {
|
|
15073
|
-
const artifactPath =
|
|
15403
|
+
const artifactPath = import_node_path63.default.join(cwd, "neat.service");
|
|
15074
15404
|
const contents = emitSystemdUnit(cwd);
|
|
15075
15405
|
await import_node_fs37.promises.writeFile(artifactPath, contents, "utf8");
|
|
15076
15406
|
return {
|
|
@@ -15106,13 +15436,13 @@ init_cjs_shims();
|
|
|
15106
15436
|
// src/installers/javascript.ts
|
|
15107
15437
|
init_cjs_shims();
|
|
15108
15438
|
var import_node_fs38 = require("fs");
|
|
15109
|
-
var
|
|
15439
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
15110
15440
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
15111
15441
|
|
|
15112
15442
|
// src/installers/templates.ts
|
|
15113
15443
|
init_cjs_shims();
|
|
15114
15444
|
var OTEL_INIT_HEADER = "// Generated by `neat init --apply` (ADR-069). OpenTelemetry auto-instrumentation hook.";
|
|
15115
|
-
var OTEL_INIT_STAMP = "// neat-template-version:
|
|
15445
|
+
var OTEL_INIT_STAMP = "// neat-template-version: 8 \u2014 CommonJS TypeScript uses a synchronous bootstrap (#910); OTel init degrades to no-OBSERVED when dependencies are absent (#820); daemon.json endpoint resolution (ADR-096) + layered file-first capture (ADR-090).";
|
|
15116
15446
|
var OTEL_OTLP_HEADERS_JS = "if (process.env.NEAT_OTEL_TOKEN) process.env.OTEL_EXPORTER_OTLP_HEADERS ||= 'Authorization=Bearer ' + process.env.NEAT_OTEL_TOKEN";
|
|
15117
15447
|
var OTEL_OTLP_PROTOCOL_JS = "process.env.OTEL_EXPORTER_OTLP_PROTOCOL ||= 'http/json'";
|
|
15118
15448
|
var OTEL_ENDPOINT_RESOLVER_CJS = `;(function () {
|
|
@@ -15476,6 +15806,13 @@ ${neatWireCaptureSource(false)}
|
|
|
15476
15806
|
}
|
|
15477
15807
|
}
|
|
15478
15808
|
`;
|
|
15809
|
+
var OTEL_INIT_TS_CJS = OTEL_INIT_CJS.replace(
|
|
15810
|
+
`${OTEL_INIT_HEADER}
|
|
15811
|
+
${OTEL_INIT_STAMP}`,
|
|
15812
|
+
`${OTEL_INIT_HEADER}
|
|
15813
|
+
${OTEL_INIT_STAMP}
|
|
15814
|
+
// @ts-nocheck \u2014 generated CommonJS runtime shim.`
|
|
15815
|
+
);
|
|
15479
15816
|
var OTEL_INIT_ESM = `${OTEL_INIT_HEADER}
|
|
15480
15817
|
${OTEL_INIT_STAMP}
|
|
15481
15818
|
${OTEL_ESM_NODE_IMPORTS}
|
|
@@ -15747,6 +16084,13 @@ function detectNonBundledInstrumentations(pkg) {
|
|
|
15747
16084
|
registration: "instrumentations.push(new (require('@prisma/instrumentation').PrismaInstrumentation)())"
|
|
15748
16085
|
});
|
|
15749
16086
|
}
|
|
16087
|
+
if (getMajor(deps["@nestjs/core"]) >= 11) {
|
|
16088
|
+
out.push({
|
|
16089
|
+
pkg: "@opentelemetry/instrumentation-nestjs-core",
|
|
16090
|
+
version: "^0.67.0",
|
|
16091
|
+
registration: "instrumentations.push(new (require('@opentelemetry/instrumentation-nestjs-core').NestInstrumentation)())"
|
|
16092
|
+
});
|
|
16093
|
+
}
|
|
15750
16094
|
return out;
|
|
15751
16095
|
}
|
|
15752
16096
|
var OTEL_ENV = {
|
|
@@ -15759,11 +16103,11 @@ var OTEL_ENV = {
|
|
|
15759
16103
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
15760
16104
|
};
|
|
15761
16105
|
function serviceNodeName(pkg, serviceDir) {
|
|
15762
|
-
return pkg.name ??
|
|
16106
|
+
return pkg.name ?? import_node_path64.default.basename(serviceDir);
|
|
15763
16107
|
}
|
|
15764
16108
|
function projectToken(pkg, serviceDir, project) {
|
|
15765
16109
|
if (project && project.length > 0) return project;
|
|
15766
|
-
return pkg.name ??
|
|
16110
|
+
return pkg.name ?? import_node_path64.default.basename(serviceDir);
|
|
15767
16111
|
}
|
|
15768
16112
|
async function readJsonFile(p) {
|
|
15769
16113
|
try {
|
|
@@ -15776,16 +16120,16 @@ async function readJsonFile(p) {
|
|
|
15776
16120
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
15777
16121
|
const deps = allDeps(pkg);
|
|
15778
16122
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
15779
|
-
const appJson = await readJsonFile(
|
|
16123
|
+
const appJson = await readJsonFile(import_node_path64.default.join(pkgRoot, "app.json"));
|
|
15780
16124
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
15781
16125
|
return "react-native";
|
|
15782
16126
|
}
|
|
15783
|
-
if (await exists3(
|
|
16127
|
+
if (await exists3(import_node_path64.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path64.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path64.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
15784
16128
|
return "browser-bundle";
|
|
15785
16129
|
}
|
|
15786
|
-
if (await exists3(
|
|
15787
|
-
if (await exists3(
|
|
15788
|
-
if (await exists3(
|
|
16130
|
+
if (await exists3(import_node_path64.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
16131
|
+
if (await exists3(import_node_path64.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
16132
|
+
if (await exists3(import_node_path64.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path64.default.join(pkgRoot, "deno.lock"))) {
|
|
15789
16133
|
return "deno";
|
|
15790
16134
|
}
|
|
15791
16135
|
const engines = pkg.engines ?? {};
|
|
@@ -15794,7 +16138,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
|
|
|
15794
16138
|
}
|
|
15795
16139
|
async function readPackageJson2(serviceDir) {
|
|
15796
16140
|
try {
|
|
15797
|
-
const raw = await import_node_fs38.promises.readFile(
|
|
16141
|
+
const raw = await import_node_fs38.promises.readFile(import_node_path64.default.join(serviceDir, "package.json"), "utf8");
|
|
15798
16142
|
return JSON.parse(raw);
|
|
15799
16143
|
} catch {
|
|
15800
16144
|
return null;
|
|
@@ -15838,7 +16182,7 @@ function needsVersionUpgrade(installed, expected) {
|
|
|
15838
16182
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
15839
16183
|
async function findNextConfig(serviceDir) {
|
|
15840
16184
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
15841
|
-
const candidate =
|
|
16185
|
+
const candidate = import_node_path64.default.join(serviceDir, name);
|
|
15842
16186
|
if (await exists3(candidate)) return candidate;
|
|
15843
16187
|
}
|
|
15844
16188
|
return null;
|
|
@@ -15907,7 +16251,7 @@ function hasRemixDependency(pkg) {
|
|
|
15907
16251
|
}
|
|
15908
16252
|
async function findRemixEntry(serviceDir) {
|
|
15909
16253
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
15910
|
-
const candidate =
|
|
16254
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
15911
16255
|
if (await exists3(candidate)) return candidate;
|
|
15912
16256
|
}
|
|
15913
16257
|
return null;
|
|
@@ -15919,14 +16263,14 @@ function hasSvelteKitDependency(pkg) {
|
|
|
15919
16263
|
}
|
|
15920
16264
|
async function findSvelteKitHooks(serviceDir) {
|
|
15921
16265
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
15922
|
-
const candidate =
|
|
16266
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
15923
16267
|
if (await exists3(candidate)) return candidate;
|
|
15924
16268
|
}
|
|
15925
16269
|
return null;
|
|
15926
16270
|
}
|
|
15927
16271
|
async function findSvelteKitConfig(serviceDir) {
|
|
15928
16272
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
15929
|
-
const candidate =
|
|
16273
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
15930
16274
|
if (await exists3(candidate)) return candidate;
|
|
15931
16275
|
}
|
|
15932
16276
|
return null;
|
|
@@ -15937,7 +16281,7 @@ function hasNuxtDependency(pkg) {
|
|
|
15937
16281
|
}
|
|
15938
16282
|
async function findNuxtConfig(serviceDir) {
|
|
15939
16283
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
15940
|
-
const candidate =
|
|
16284
|
+
const candidate = import_node_path64.default.join(serviceDir, name);
|
|
15941
16285
|
if (await exists3(candidate)) return candidate;
|
|
15942
16286
|
}
|
|
15943
16287
|
return null;
|
|
@@ -15948,7 +16292,7 @@ function hasAstroDependency(pkg) {
|
|
|
15948
16292
|
}
|
|
15949
16293
|
async function findAstroConfig(serviceDir) {
|
|
15950
16294
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
15951
|
-
const candidate =
|
|
16295
|
+
const candidate = import_node_path64.default.join(serviceDir, name);
|
|
15952
16296
|
if (await exists3(candidate)) return candidate;
|
|
15953
16297
|
}
|
|
15954
16298
|
return null;
|
|
@@ -15962,7 +16306,7 @@ function parseNextMajor(range) {
|
|
|
15962
16306
|
return Number.isFinite(n) ? n : null;
|
|
15963
16307
|
}
|
|
15964
16308
|
async function isTypeScriptProject(serviceDir) {
|
|
15965
|
-
return exists3(
|
|
16309
|
+
return exists3(import_node_path64.default.join(serviceDir, "tsconfig.json"));
|
|
15966
16310
|
}
|
|
15967
16311
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
15968
16312
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -16011,7 +16355,7 @@ function entryFromScript(script) {
|
|
|
16011
16355
|
}
|
|
16012
16356
|
async function resolveEntry(serviceDir, pkg) {
|
|
16013
16357
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
16014
|
-
const candidate =
|
|
16358
|
+
const candidate = import_node_path64.default.resolve(serviceDir, pkg.main);
|
|
16015
16359
|
if (await exists3(candidate)) return candidate;
|
|
16016
16360
|
}
|
|
16017
16361
|
if (pkg.bin) {
|
|
@@ -16025,59 +16369,60 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
16025
16369
|
if (typeof first === "string") binEntry = first;
|
|
16026
16370
|
}
|
|
16027
16371
|
if (binEntry) {
|
|
16028
|
-
const candidate =
|
|
16372
|
+
const candidate = import_node_path64.default.resolve(serviceDir, binEntry);
|
|
16029
16373
|
if (await exists3(candidate)) return candidate;
|
|
16030
16374
|
}
|
|
16031
16375
|
}
|
|
16032
16376
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
16033
16377
|
if (startEntry) {
|
|
16034
|
-
const candidate =
|
|
16378
|
+
const candidate = import_node_path64.default.resolve(serviceDir, startEntry);
|
|
16035
16379
|
if (await exists3(candidate)) return candidate;
|
|
16036
16380
|
}
|
|
16037
16381
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
16038
16382
|
if (devEntry) {
|
|
16039
|
-
const candidate =
|
|
16383
|
+
const candidate = import_node_path64.default.resolve(serviceDir, devEntry);
|
|
16040
16384
|
if (await exists3(candidate)) return candidate;
|
|
16041
16385
|
}
|
|
16042
16386
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
16043
|
-
const candidate =
|
|
16387
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
16044
16388
|
if (await exists3(candidate)) return candidate;
|
|
16045
16389
|
}
|
|
16046
16390
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
16047
|
-
const candidate =
|
|
16391
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
16048
16392
|
if (await exists3(candidate)) return candidate;
|
|
16049
16393
|
}
|
|
16050
16394
|
for (const rel of ROOT_NAMED_CANDIDATES) {
|
|
16051
|
-
const candidate =
|
|
16395
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
16052
16396
|
if (await exists3(candidate)) return candidate;
|
|
16053
16397
|
}
|
|
16054
16398
|
for (const name of INDEX_CANDIDATES) {
|
|
16055
|
-
const candidate =
|
|
16399
|
+
const candidate = import_node_path64.default.join(serviceDir, name);
|
|
16056
16400
|
if (await exists3(candidate)) return candidate;
|
|
16057
16401
|
}
|
|
16058
16402
|
return null;
|
|
16059
16403
|
}
|
|
16060
16404
|
function dispatchEntry(entryFile, pkg) {
|
|
16061
|
-
const ext =
|
|
16062
|
-
if (ext === ".ts" || ext === ".tsx") return "ts";
|
|
16405
|
+
const ext = import_node_path64.default.extname(entryFile).toLowerCase();
|
|
16406
|
+
if (ext === ".ts" || ext === ".tsx") return pkg.type === "module" ? "ts" : "ts-cjs";
|
|
16063
16407
|
if (ext === ".mjs") return "esm";
|
|
16064
16408
|
if (ext === ".cjs") return "cjs";
|
|
16065
16409
|
return pkg.type === "module" ? "esm" : "cjs";
|
|
16066
16410
|
}
|
|
16067
16411
|
function otelInitFilename(flavor) {
|
|
16068
|
-
if (flavor === "ts") return "otel-init.ts";
|
|
16412
|
+
if (flavor === "ts" || flavor === "ts-cjs") return "otel-init.ts";
|
|
16069
16413
|
if (flavor === "esm") return "otel-init.mjs";
|
|
16070
16414
|
return "otel-init.cjs";
|
|
16071
16415
|
}
|
|
16072
16416
|
function otelInitContents(flavor) {
|
|
16073
16417
|
if (flavor === "ts") return OTEL_INIT_TS;
|
|
16418
|
+
if (flavor === "ts-cjs") return OTEL_INIT_TS_CJS;
|
|
16074
16419
|
if (flavor === "esm") return OTEL_INIT_ESM;
|
|
16075
16420
|
return OTEL_INIT_CJS;
|
|
16076
16421
|
}
|
|
16077
16422
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
16078
|
-
let rel =
|
|
16423
|
+
let rel = import_node_path64.default.relative(import_node_path64.default.dirname(entryFile), otelInitFile);
|
|
16079
16424
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
16080
|
-
rel = rel.split(
|
|
16425
|
+
rel = rel.split(import_node_path64.default.sep).join("/");
|
|
16081
16426
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
16082
16427
|
if (flavor === "esm") return `import '${rel}'`;
|
|
16083
16428
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -16090,27 +16435,27 @@ function lineIsOtelInjection(line) {
|
|
|
16090
16435
|
}
|
|
16091
16436
|
async function detectsSrcLayout(serviceDir) {
|
|
16092
16437
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
16093
|
-
exists3(
|
|
16094
|
-
exists3(
|
|
16095
|
-
exists3(
|
|
16096
|
-
exists3(
|
|
16438
|
+
exists3(import_node_path64.default.join(serviceDir, "src", "app")),
|
|
16439
|
+
exists3(import_node_path64.default.join(serviceDir, "src", "pages")),
|
|
16440
|
+
exists3(import_node_path64.default.join(serviceDir, "app")),
|
|
16441
|
+
exists3(import_node_path64.default.join(serviceDir, "pages"))
|
|
16097
16442
|
]);
|
|
16098
16443
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
16099
16444
|
}
|
|
16100
16445
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
16101
16446
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
16102
16447
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
16103
|
-
const baseDir = srcLayout ?
|
|
16104
|
-
const instrumentationFile =
|
|
16105
|
-
const instrumentationNodeFile =
|
|
16448
|
+
const baseDir = srcLayout ? import_node_path64.default.join(serviceDir, "src") : serviceDir;
|
|
16449
|
+
const instrumentationFile = import_node_path64.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
16450
|
+
const instrumentationNodeFile = import_node_path64.default.join(
|
|
16106
16451
|
baseDir,
|
|
16107
16452
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
16108
16453
|
);
|
|
16109
|
-
const instrumentationEdgeFile =
|
|
16454
|
+
const instrumentationEdgeFile = import_node_path64.default.join(
|
|
16110
16455
|
baseDir,
|
|
16111
16456
|
useTs ? "instrumentation.edge.ts" : "instrumentation.edge.js"
|
|
16112
16457
|
);
|
|
16113
|
-
const envNeatFile =
|
|
16458
|
+
const envNeatFile = import_node_path64.default.join(baseDir, ".env.neat");
|
|
16114
16459
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
16115
16460
|
const dependencyEdits = [];
|
|
16116
16461
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -16235,7 +16580,7 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
16235
16580
|
return edits;
|
|
16236
16581
|
}
|
|
16237
16582
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
16238
|
-
const envNeatFile =
|
|
16583
|
+
const envNeatFile = import_node_path64.default.join(serviceDir, ".env.neat");
|
|
16239
16584
|
if (!await exists3(envNeatFile)) {
|
|
16240
16585
|
generatedFiles.push({
|
|
16241
16586
|
file: envNeatFile,
|
|
@@ -16270,7 +16615,7 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
16270
16615
|
}
|
|
16271
16616
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
16272
16617
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
16273
|
-
const otelServerFile =
|
|
16618
|
+
const otelServerFile = import_node_path64.default.join(
|
|
16274
16619
|
serviceDir,
|
|
16275
16620
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
16276
16621
|
);
|
|
@@ -16327,11 +16672,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
16327
16672
|
}
|
|
16328
16673
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
16329
16674
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
16330
|
-
const otelInitFile =
|
|
16675
|
+
const otelInitFile = import_node_path64.default.join(
|
|
16331
16676
|
serviceDir,
|
|
16332
16677
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
16333
16678
|
);
|
|
16334
|
-
const resolvedHooksFile = hooksFile ??
|
|
16679
|
+
const resolvedHooksFile = hooksFile ?? import_node_path64.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
16335
16680
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
16336
16681
|
const generatedFiles = [];
|
|
16337
16682
|
const entrypointEdits = [];
|
|
@@ -16393,11 +16738,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
16393
16738
|
}
|
|
16394
16739
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
16395
16740
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
16396
|
-
const otelPluginFile =
|
|
16741
|
+
const otelPluginFile = import_node_path64.default.join(
|
|
16397
16742
|
serviceDir,
|
|
16398
16743
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
16399
16744
|
);
|
|
16400
|
-
const otelInitFile =
|
|
16745
|
+
const otelInitFile = import_node_path64.default.join(
|
|
16401
16746
|
serviceDir,
|
|
16402
16747
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
16403
16748
|
);
|
|
@@ -16448,19 +16793,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
16448
16793
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
16449
16794
|
async function findAstroMiddleware(serviceDir) {
|
|
16450
16795
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
16451
|
-
const candidate =
|
|
16796
|
+
const candidate = import_node_path64.default.join(serviceDir, rel);
|
|
16452
16797
|
if (await exists3(candidate)) return candidate;
|
|
16453
16798
|
}
|
|
16454
16799
|
return null;
|
|
16455
16800
|
}
|
|
16456
16801
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
16457
16802
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
16458
|
-
const otelInitFile =
|
|
16803
|
+
const otelInitFile = import_node_path64.default.join(
|
|
16459
16804
|
serviceDir,
|
|
16460
16805
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
16461
16806
|
);
|
|
16462
16807
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
16463
|
-
const middlewareFile = existingMiddleware ??
|
|
16808
|
+
const middlewareFile = existingMiddleware ?? import_node_path64.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
16464
16809
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
16465
16810
|
const generatedFiles = [];
|
|
16466
16811
|
const entrypointEdits = [];
|
|
@@ -16556,7 +16901,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
16556
16901
|
}
|
|
16557
16902
|
async function plan(serviceDir, opts) {
|
|
16558
16903
|
const pkg = await readPackageJson2(serviceDir);
|
|
16559
|
-
const manifestPath =
|
|
16904
|
+
const manifestPath = import_node_path64.default.join(serviceDir, "package.json");
|
|
16560
16905
|
const project = opts?.project;
|
|
16561
16906
|
const empty = {
|
|
16562
16907
|
language: "javascript",
|
|
@@ -16591,8 +16936,8 @@ async function plan(serviceDir, opts) {
|
|
|
16591
16936
|
return { ...empty, libOnly: true };
|
|
16592
16937
|
}
|
|
16593
16938
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
16594
|
-
const otelInitFile =
|
|
16595
|
-
const envNeatFile =
|
|
16939
|
+
const otelInitFile = import_node_path64.default.join(import_node_path64.default.dirname(entryFile), otelInitFilename(flavor));
|
|
16940
|
+
const envNeatFile = import_node_path64.default.join(serviceDir, ".env.neat");
|
|
16596
16941
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
16597
16942
|
const dependencyEdits = [];
|
|
16598
16943
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -16661,13 +17006,13 @@ async function plan(serviceDir, opts) {
|
|
|
16661
17006
|
};
|
|
16662
17007
|
}
|
|
16663
17008
|
function isAllowedWritePath(serviceDir, target) {
|
|
16664
|
-
const rel =
|
|
17009
|
+
const rel = import_node_path64.default.relative(serviceDir, target);
|
|
16665
17010
|
if (rel.startsWith("..")) return false;
|
|
16666
|
-
const base =
|
|
17011
|
+
const base = import_node_path64.default.basename(target);
|
|
16667
17012
|
if (base === "package.json") return true;
|
|
16668
17013
|
if (base === ".env.neat") return true;
|
|
16669
17014
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
16670
|
-
const relPosix = rel.split(
|
|
17015
|
+
const relPosix = rel.split(import_node_path64.default.sep).join("/");
|
|
16671
17016
|
if (/^instrumentation(?:\.(?:node|edge))?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
16672
17017
|
if (relPosix === base) return true;
|
|
16673
17018
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -16684,7 +17029,7 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
16684
17029
|
return false;
|
|
16685
17030
|
}
|
|
16686
17031
|
async function writeAtomic(file, contents) {
|
|
16687
|
-
await import_node_fs38.promises.mkdir(
|
|
17032
|
+
await import_node_fs38.promises.mkdir(import_node_path64.default.dirname(file), { recursive: true });
|
|
16688
17033
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
16689
17034
|
await import_node_fs38.promises.writeFile(tmp, contents, "utf8");
|
|
16690
17035
|
await import_node_fs38.promises.rename(tmp, file);
|
|
@@ -16868,7 +17213,7 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
16868
17213
|
...removed.map((f) => `removed: ${f}`),
|
|
16869
17214
|
""
|
|
16870
17215
|
];
|
|
16871
|
-
const rollbackPath =
|
|
17216
|
+
const rollbackPath = import_node_path64.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
16872
17217
|
await import_node_fs38.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
16873
17218
|
}
|
|
16874
17219
|
function injectInstrumentationHook(raw) {
|
|
@@ -16899,7 +17244,7 @@ var javascriptInstaller = {
|
|
|
16899
17244
|
// src/installers/python.ts
|
|
16900
17245
|
init_cjs_shims();
|
|
16901
17246
|
var import_node_fs39 = require("fs");
|
|
16902
|
-
var
|
|
17247
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
16903
17248
|
var SDK_PACKAGES2 = [
|
|
16904
17249
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
16905
17250
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -16997,7 +17342,7 @@ async function writeFileAtomic(file, contents) {
|
|
|
16997
17342
|
await import_node_fs39.promises.rename(tmp, file);
|
|
16998
17343
|
}
|
|
16999
17344
|
async function resolvePyEntrypoint(serviceDir) {
|
|
17000
|
-
const procfile =
|
|
17345
|
+
const procfile = import_node_path65.default.join(serviceDir, "Procfile");
|
|
17001
17346
|
if (await exists4(procfile)) {
|
|
17002
17347
|
const raw = await import_node_fs39.promises.readFile(procfile, "utf8");
|
|
17003
17348
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -17007,20 +17352,20 @@ async function resolvePyEntrypoint(serviceDir) {
|
|
|
17007
17352
|
const asgi = cmd.match(/\b(?:uvicorn|gunicorn|hypercorn|daphne)\s+([\w.]+):/);
|
|
17008
17353
|
if (asgi) {
|
|
17009
17354
|
const modPath = asgi[1].replace(/\./g, "/");
|
|
17010
|
-
const asFile =
|
|
17355
|
+
const asFile = import_node_path65.default.join(serviceDir, `${modPath}.py`);
|
|
17011
17356
|
if (await exists4(asFile)) return asFile;
|
|
17012
|
-
const asPkg =
|
|
17357
|
+
const asPkg = import_node_path65.default.join(serviceDir, modPath, "__init__.py");
|
|
17013
17358
|
if (await exists4(asPkg)) return asPkg;
|
|
17014
17359
|
}
|
|
17015
17360
|
const runFile = cmd.match(/\b(?:python3?|fastapi\s+(?:run|dev))\s+([\w./-]+\.py)\b/);
|
|
17016
17361
|
if (runFile) {
|
|
17017
|
-
const p =
|
|
17362
|
+
const p = import_node_path65.default.join(serviceDir, runFile[1]);
|
|
17018
17363
|
if (await exists4(p)) return p;
|
|
17019
17364
|
}
|
|
17020
17365
|
}
|
|
17021
17366
|
}
|
|
17022
17367
|
for (const name of ["main.py", "app.py", "asgi.py", "wsgi.py", "manage.py", "server.py"]) {
|
|
17023
|
-
const p =
|
|
17368
|
+
const p = import_node_path65.default.join(serviceDir, name);
|
|
17024
17369
|
if (await exists4(p)) return p;
|
|
17025
17370
|
}
|
|
17026
17371
|
return null;
|
|
@@ -17046,7 +17391,7 @@ async function exists4(p) {
|
|
|
17046
17391
|
async function detect2(serviceDir) {
|
|
17047
17392
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
17048
17393
|
for (const m of markers) {
|
|
17049
|
-
if (await exists4(
|
|
17394
|
+
if (await exists4(import_node_path65.default.join(serviceDir, m))) return true;
|
|
17050
17395
|
}
|
|
17051
17396
|
return false;
|
|
17052
17397
|
}
|
|
@@ -17056,7 +17401,7 @@ function reqPackageName(line) {
|
|
|
17056
17401
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
17057
17402
|
}
|
|
17058
17403
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
17059
|
-
const file =
|
|
17404
|
+
const file = import_node_path65.default.join(serviceDir, "requirements.txt");
|
|
17060
17405
|
if (!await exists4(file)) return null;
|
|
17061
17406
|
const raw = await import_node_fs39.promises.readFile(file, "utf8");
|
|
17062
17407
|
const presentNames = new Set(
|
|
@@ -17066,7 +17411,7 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
17066
17411
|
return { manifest: file, missing: [...missing] };
|
|
17067
17412
|
}
|
|
17068
17413
|
async function planProcfileEdits(serviceDir) {
|
|
17069
|
-
const procfile =
|
|
17414
|
+
const procfile = import_node_path65.default.join(serviceDir, "Procfile");
|
|
17070
17415
|
if (!await exists4(procfile)) return [];
|
|
17071
17416
|
const raw = await import_node_fs39.promises.readFile(procfile, "utf8");
|
|
17072
17417
|
const edits = [];
|
|
@@ -17104,7 +17449,7 @@ async function plan2(serviceDir) {
|
|
|
17104
17449
|
}
|
|
17105
17450
|
const entrypointEdits = await planProcfileEdits(serviceDir);
|
|
17106
17451
|
const entryFile = await resolvePyEntrypoint(serviceDir);
|
|
17107
|
-
const generatedFiles = entryFile ? [{ file:
|
|
17452
|
+
const generatedFiles = entryFile ? [{ file: import_node_path65.default.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }] : [];
|
|
17108
17453
|
if (dependencyEdits.length === 0 && entrypointEdits.length === 0 && !entryFile) {
|
|
17109
17454
|
return empty;
|
|
17110
17455
|
}
|
|
@@ -17172,7 +17517,7 @@ async function apply2(installPlan) {
|
|
|
17172
17517
|
if (raw === void 0) {
|
|
17173
17518
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
17174
17519
|
}
|
|
17175
|
-
const base =
|
|
17520
|
+
const base = import_node_path65.default.basename(file);
|
|
17176
17521
|
if (base === "requirements.txt") {
|
|
17177
17522
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
17178
17523
|
if (edits.length > 0) {
|
|
@@ -17227,7 +17572,7 @@ async function rollback2(installPlan, originals, createdFiles = []) {
|
|
|
17227
17572
|
...removed.map((f) => `removed: ${f}`),
|
|
17228
17573
|
""
|
|
17229
17574
|
];
|
|
17230
|
-
const rollbackPath =
|
|
17575
|
+
const rollbackPath = import_node_path65.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
17231
17576
|
await import_node_fs39.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
17232
17577
|
}
|
|
17233
17578
|
var pythonInstaller = {
|
|
@@ -17240,7 +17585,7 @@ var pythonInstaller = {
|
|
|
17240
17585
|
// src/installers/go.ts
|
|
17241
17586
|
init_cjs_shims();
|
|
17242
17587
|
var import_node_fs40 = require("fs");
|
|
17243
|
-
var
|
|
17588
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
17244
17589
|
var GO_DEPS = [
|
|
17245
17590
|
{ name: "go.opentelemetry.io/otel", version: "v1.38.0" },
|
|
17246
17591
|
{ name: "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp", version: "v1.38.0" },
|
|
@@ -17250,13 +17595,13 @@ async function exists5(file) {
|
|
|
17250
17595
|
return import_node_fs40.promises.stat(file).then(() => true, () => false);
|
|
17251
17596
|
}
|
|
17252
17597
|
async function findMain(serviceDir) {
|
|
17253
|
-
const root =
|
|
17598
|
+
const root = import_node_path66.default.join(serviceDir, "main.go");
|
|
17254
17599
|
if (await exists5(root)) return root;
|
|
17255
|
-
const cmd =
|
|
17600
|
+
const cmd = import_node_path66.default.join(serviceDir, "cmd");
|
|
17256
17601
|
const entries = await import_node_fs40.promises.readdir(cmd, { withFileTypes: true }).catch(() => []);
|
|
17257
17602
|
for (const entry2 of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
17258
17603
|
if (!entry2.isDirectory()) continue;
|
|
17259
|
-
const candidate =
|
|
17604
|
+
const candidate = import_node_path66.default.join(cmd, entry2.name, "main.go");
|
|
17260
17605
|
if (await exists5(candidate)) return candidate;
|
|
17261
17606
|
}
|
|
17262
17607
|
return null;
|
|
@@ -17331,17 +17676,17 @@ func init() {
|
|
|
17331
17676
|
`;
|
|
17332
17677
|
}
|
|
17333
17678
|
async function detect3(serviceDir) {
|
|
17334
|
-
return exists5(
|
|
17679
|
+
return exists5(import_node_path66.default.join(serviceDir, "go.mod"));
|
|
17335
17680
|
}
|
|
17336
17681
|
async function plan3(serviceDir) {
|
|
17337
|
-
const manifest =
|
|
17682
|
+
const manifest = import_node_path66.default.join(serviceDir, "go.mod");
|
|
17338
17683
|
const raw = await import_node_fs40.promises.readFile(manifest, "utf8");
|
|
17339
17684
|
const main2 = await findMain(serviceDir);
|
|
17340
17685
|
const dependencyEdits = GO_DEPS.filter((dep) => !raw.includes(dep.name)).map((dep) => ({ file: manifest, kind: "add", ...dep }));
|
|
17341
17686
|
if (!main2) return { language: "go", serviceDir, dependencyEdits: [], entrypointEdits: [], envEdits: [], libOnly: true };
|
|
17342
17687
|
const source = await import_node_fs40.promises.readFile(main2, "utf8");
|
|
17343
17688
|
const packageName = source.match(/^\s*package\s+(\w+)\s*$/m)?.[1] ?? "main";
|
|
17344
|
-
const generated =
|
|
17689
|
+
const generated = import_node_path66.default.join(import_node_path66.default.dirname(main2), "neat_otel.go");
|
|
17345
17690
|
const generatedFiles = await exists5(generated) ? [] : [{ file: generated, contents: neatOtelGo(packageName) }];
|
|
17346
17691
|
return { language: "go", serviceDir, dependencyEdits, entrypointEdits: [], envEdits: [], generatedFiles, entryFile: main2 };
|
|
17347
17692
|
}
|
|
@@ -17483,7 +17828,7 @@ init_cjs_shims();
|
|
|
17483
17828
|
var import_node_fs41 = require("fs");
|
|
17484
17829
|
var import_node_http = __toESM(require("http"), 1);
|
|
17485
17830
|
var import_node_net = __toESM(require("net"), 1);
|
|
17486
|
-
var
|
|
17831
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
17487
17832
|
var import_node_url4 = require("url");
|
|
17488
17833
|
var import_node_child_process3 = require("child_process");
|
|
17489
17834
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
@@ -17493,7 +17838,7 @@ async function extractAndPersist(opts) {
|
|
|
17493
17838
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
17494
17839
|
resetGraph(graphKey);
|
|
17495
17840
|
const graph = getGraph(graphKey);
|
|
17496
|
-
const projectPaths = pathsForProject(graphKey,
|
|
17841
|
+
const projectPaths = pathsForProject(graphKey, import_node_path67.default.join(opts.scanPath, "neat-out"));
|
|
17497
17842
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
17498
17843
|
errorsPath: projectPaths.errorsPath
|
|
17499
17844
|
});
|
|
@@ -17545,7 +17890,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17545
17890
|
libOnly++;
|
|
17546
17891
|
const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : [];
|
|
17547
17892
|
if (appDeps.length > 0) {
|
|
17548
|
-
const svcName =
|
|
17893
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17549
17894
|
const list = appDeps.join(", ");
|
|
17550
17895
|
console.warn(
|
|
17551
17896
|
`neat: runtime layer won't engage for ${svcName}: no entry point found.
|
|
@@ -17558,7 +17903,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17558
17903
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
17559
17904
|
} else if (outcome.outcome === "react-native") {
|
|
17560
17905
|
reactNative++;
|
|
17561
|
-
const svcName =
|
|
17906
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17562
17907
|
console.log(
|
|
17563
17908
|
`neat: ${svc.dir} detected as React Native / Expo
|
|
17564
17909
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -17569,7 +17914,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17569
17914
|
);
|
|
17570
17915
|
} else if (outcome.outcome === "bun") {
|
|
17571
17916
|
bun++;
|
|
17572
|
-
const svcName =
|
|
17917
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17573
17918
|
console.log(
|
|
17574
17919
|
`neat: ${svc.dir} detected as Bun
|
|
17575
17920
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -17580,7 +17925,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17580
17925
|
);
|
|
17581
17926
|
} else if (outcome.outcome === "deno") {
|
|
17582
17927
|
deno++;
|
|
17583
|
-
const svcName =
|
|
17928
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17584
17929
|
console.log(
|
|
17585
17930
|
`neat: ${svc.dir} detected as Deno
|
|
17586
17931
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -17591,7 +17936,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17591
17936
|
);
|
|
17592
17937
|
} else if (outcome.outcome === "cloudflare-workers") {
|
|
17593
17938
|
cloudflareWorkers++;
|
|
17594
|
-
const svcName =
|
|
17939
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17595
17940
|
console.log(
|
|
17596
17941
|
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
17597
17942
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -17602,7 +17947,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17602
17947
|
);
|
|
17603
17948
|
} else if (outcome.outcome === "electron") {
|
|
17604
17949
|
electron++;
|
|
17605
|
-
const svcName =
|
|
17950
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17606
17951
|
console.log(
|
|
17607
17952
|
`neat: ${svc.dir} detected as Electron
|
|
17608
17953
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -17615,7 +17960,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
17615
17960
|
if (svc.pkg && (outcome.outcome === "instrumented" || outcome.outcome === "already-instrumented")) {
|
|
17616
17961
|
const gaps = uninstrumentedLibraries(svc.pkg);
|
|
17617
17962
|
if (gaps.length > 0) {
|
|
17618
|
-
const svcName =
|
|
17963
|
+
const svcName = import_node_path67.default.basename(svc.dir);
|
|
17619
17964
|
const list = gaps.join(", ");
|
|
17620
17965
|
const subject = gaps.length === 1 ? "this library" : "these libraries";
|
|
17621
17966
|
const aux = gaps.length === 1 ? "isn't" : "aren't";
|
|
@@ -17821,8 +18166,8 @@ async function persistedPortsFor(scanPath) {
|
|
|
17821
18166
|
return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web };
|
|
17822
18167
|
}
|
|
17823
18168
|
async function acquireSpawnLock(scanPath) {
|
|
17824
|
-
const lockPath =
|
|
17825
|
-
await import_node_fs41.promises.mkdir(
|
|
18169
|
+
const lockPath = import_node_path67.default.join(scanPath, "neat-out", "daemon.spawn.lock");
|
|
18170
|
+
await import_node_fs41.promises.mkdir(import_node_path67.default.dirname(lockPath), { recursive: true });
|
|
17826
18171
|
const STALE_LOCK_MS = 6e4;
|
|
17827
18172
|
try {
|
|
17828
18173
|
const fd = await import_node_fs41.promises.open(lockPath, "wx");
|
|
@@ -17867,13 +18212,13 @@ async function healthIsForProject(restPort, project) {
|
|
|
17867
18212
|
return false;
|
|
17868
18213
|
}
|
|
17869
18214
|
function daemonLogPath(projectPath2) {
|
|
17870
|
-
return
|
|
18215
|
+
return import_node_path67.default.join(projectPath2, "neat-out", "daemon.log");
|
|
17871
18216
|
}
|
|
17872
18217
|
function spawnDaemonDetached(spec) {
|
|
17873
|
-
const here =
|
|
18218
|
+
const here = import_node_path67.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
|
|
17874
18219
|
const candidates = [
|
|
17875
|
-
|
|
17876
|
-
|
|
18220
|
+
import_node_path67.default.join(here, "neatd.cjs"),
|
|
18221
|
+
import_node_path67.default.join(here, "neatd.js")
|
|
17877
18222
|
];
|
|
17878
18223
|
let entry2 = null;
|
|
17879
18224
|
const fsSync = require("fs");
|
|
@@ -17903,7 +18248,7 @@ function spawnDaemonDetached(spec) {
|
|
|
17903
18248
|
let logFd = null;
|
|
17904
18249
|
if (spec) {
|
|
17905
18250
|
const logPath = daemonLogPath(spec.projectPath);
|
|
17906
|
-
fsSync.mkdirSync(
|
|
18251
|
+
fsSync.mkdirSync(import_node_path67.default.dirname(logPath), { recursive: true });
|
|
17907
18252
|
logFd = fsSync.openSync(logPath, "a");
|
|
17908
18253
|
}
|
|
17909
18254
|
const child = (0, import_node_child_process3.spawn)(process.execPath, [entry2, "start"], {
|
|
@@ -18102,7 +18447,7 @@ async function runOrchestrator(opts) {
|
|
|
18102
18447
|
result.steps.browser = openBrowser(dashboardUrl);
|
|
18103
18448
|
}
|
|
18104
18449
|
const daemonRunning = result.steps.daemon === "spawned" || result.steps.daemon === "already-running";
|
|
18105
|
-
const daemonLog = daemonRunning ?
|
|
18450
|
+
const daemonLog = daemonRunning ? import_node_path67.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
|
|
18106
18451
|
printSummary(result, graph, dashboardUrl, daemonLog);
|
|
18107
18452
|
return result;
|
|
18108
18453
|
}
|
|
@@ -18561,7 +18906,7 @@ async function runConnectorCommand(rawArgs, deps = {}) {
|
|
|
18561
18906
|
|
|
18562
18907
|
// src/hooks-cli.ts
|
|
18563
18908
|
init_cjs_shims();
|
|
18564
|
-
var
|
|
18909
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
18565
18910
|
var import_node_os5 = __toESM(require("os"), 1);
|
|
18566
18911
|
var import_node_fs42 = require("fs");
|
|
18567
18912
|
var import_node_url5 = require("url");
|
|
@@ -18570,14 +18915,14 @@ var GUIDE_FILENAME = "GRAPH_FIRST.md";
|
|
|
18570
18915
|
var GUIDE_INSTALL_NAME = "neat-graph-first.md";
|
|
18571
18916
|
var HOOK_MATCHER = "Grep|Glob|Bash";
|
|
18572
18917
|
function moduleDir() {
|
|
18573
|
-
return typeof __dirname !== "undefined" ? __dirname :
|
|
18918
|
+
return typeof __dirname !== "undefined" ? __dirname : import_node_path68.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
|
|
18574
18919
|
}
|
|
18575
18920
|
async function readSkillAsset(rel) {
|
|
18576
18921
|
const here = moduleDir();
|
|
18577
18922
|
const candidates = [
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18923
|
+
import_node_path68.default.resolve(here, "../../claude-skill", rel),
|
|
18924
|
+
import_node_path68.default.resolve(here, "../../../claude-skill", rel),
|
|
18925
|
+
import_node_path68.default.resolve(here, "../claude-skill", rel)
|
|
18581
18926
|
];
|
|
18582
18927
|
for (const candidate of candidates) {
|
|
18583
18928
|
try {
|
|
@@ -18591,17 +18936,17 @@ async function readSkillAsset(rel) {
|
|
|
18591
18936
|
}
|
|
18592
18937
|
function neatHome3() {
|
|
18593
18938
|
const override = process.env.NEAT_HOME;
|
|
18594
|
-
if (override && override.length > 0) return
|
|
18595
|
-
return
|
|
18939
|
+
if (override && override.length > 0) return import_node_path68.default.resolve(override);
|
|
18940
|
+
return import_node_path68.default.join(import_node_os5.default.homedir(), ".neat");
|
|
18596
18941
|
}
|
|
18597
18942
|
function claudeSettingsPath() {
|
|
18598
18943
|
const override = process.env.NEAT_CLAUDE_SETTINGS;
|
|
18599
|
-
if (override && override.length > 0) return
|
|
18944
|
+
if (override && override.length > 0) return import_node_path68.default.resolve(override);
|
|
18600
18945
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_node_os5.default.homedir();
|
|
18601
|
-
return
|
|
18946
|
+
return import_node_path68.default.join(home, ".claude", "settings.json");
|
|
18602
18947
|
}
|
|
18603
18948
|
function installedHookPath() {
|
|
18604
|
-
return
|
|
18949
|
+
return import_node_path68.default.join(neatHome3(), "hooks", HOOK_FILENAME);
|
|
18605
18950
|
}
|
|
18606
18951
|
function isNeatSearchEntry(entry2) {
|
|
18607
18952
|
return (entry2.hooks ?? []).some(
|
|
@@ -18634,9 +18979,9 @@ async function runHooks(opts) {
|
|
|
18634
18979
|
const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
|
|
18635
18980
|
const guide = await readSkillAsset(GUIDE_FILENAME);
|
|
18636
18981
|
const scriptPath = installedHookPath();
|
|
18637
|
-
await import_node_fs42.promises.mkdir(
|
|
18982
|
+
await import_node_fs42.promises.mkdir(import_node_path68.default.dirname(scriptPath), { recursive: true });
|
|
18638
18983
|
await import_node_fs42.promises.writeFile(scriptPath, hookScript, { mode: 493 });
|
|
18639
|
-
const guidePath =
|
|
18984
|
+
const guidePath = import_node_path68.default.join(neatHome3(), GUIDE_INSTALL_NAME);
|
|
18640
18985
|
await import_node_fs42.promises.writeFile(guidePath, guide, "utf8");
|
|
18641
18986
|
const settingsFile = claudeSettingsPath();
|
|
18642
18987
|
let settings = {};
|
|
@@ -18663,7 +19008,7 @@ async function runHooks(opts) {
|
|
|
18663
19008
|
...settings,
|
|
18664
19009
|
hooks: { ...hooks, PreToolUse: preToolUse }
|
|
18665
19010
|
};
|
|
18666
|
-
await import_node_fs42.promises.mkdir(
|
|
19011
|
+
await import_node_fs42.promises.mkdir(import_node_path68.default.dirname(settingsFile), { recursive: true });
|
|
18667
19012
|
await import_node_fs42.promises.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
18668
19013
|
console.log(`neat hooks: installed the search-nudge hook`);
|
|
18669
19014
|
console.log(` script: ${scriptPath}`);
|
|
@@ -18735,11 +19080,11 @@ async function runHooksCommand(args) {
|
|
|
18735
19080
|
|
|
18736
19081
|
// src/cli-verbs.ts
|
|
18737
19082
|
init_cjs_shims();
|
|
18738
|
-
var
|
|
19083
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
18739
19084
|
|
|
18740
19085
|
// src/cli-client.ts
|
|
18741
19086
|
init_cjs_shims();
|
|
18742
|
-
var
|
|
19087
|
+
var import_types61 = require("@neat.is/types");
|
|
18743
19088
|
var HttpError = class extends Error {
|
|
18744
19089
|
constructor(status2, message, responseBody = "") {
|
|
18745
19090
|
super(message);
|
|
@@ -18764,10 +19109,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
18764
19109
|
const root = baseUrl.replace(/\/$/, "");
|
|
18765
19110
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
18766
19111
|
return {
|
|
18767
|
-
async get(
|
|
19112
|
+
async get(path71) {
|
|
18768
19113
|
let res;
|
|
18769
19114
|
try {
|
|
18770
|
-
res = await fetch(`${root}${
|
|
19115
|
+
res = await fetch(`${root}${path71}`, {
|
|
18771
19116
|
headers: { ...authHeader }
|
|
18772
19117
|
});
|
|
18773
19118
|
} catch (err) {
|
|
@@ -18779,16 +19124,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
18779
19124
|
const body = await res.text().catch(() => "");
|
|
18780
19125
|
throw new HttpError(
|
|
18781
19126
|
res.status,
|
|
18782
|
-
`${res.status} ${res.statusText} on GET ${
|
|
19127
|
+
`${res.status} ${res.statusText} on GET ${path71}: ${body}`,
|
|
18783
19128
|
body
|
|
18784
19129
|
);
|
|
18785
19130
|
}
|
|
18786
19131
|
return await res.json();
|
|
18787
19132
|
},
|
|
18788
|
-
async post(
|
|
19133
|
+
async post(path71, body) {
|
|
18789
19134
|
let res;
|
|
18790
19135
|
try {
|
|
18791
|
-
res = await fetch(`${root}${
|
|
19136
|
+
res = await fetch(`${root}${path71}`, {
|
|
18792
19137
|
method: "POST",
|
|
18793
19138
|
headers: { "content-type": "application/json", ...authHeader },
|
|
18794
19139
|
body: JSON.stringify(body)
|
|
@@ -18802,7 +19147,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
18802
19147
|
const text = await res.text().catch(() => "");
|
|
18803
19148
|
throw new HttpError(
|
|
18804
19149
|
res.status,
|
|
18805
|
-
`${res.status} ${res.statusText} on POST ${
|
|
19150
|
+
`${res.status} ${res.statusText} on POST ${path71}: ${text}`,
|
|
18806
19151
|
text
|
|
18807
19152
|
);
|
|
18808
19153
|
}
|
|
@@ -18816,12 +19161,12 @@ function projectPath(project, suffix) {
|
|
|
18816
19161
|
}
|
|
18817
19162
|
async function runRootCause(client, input) {
|
|
18818
19163
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
18819
|
-
const
|
|
19164
|
+
const path71 = projectPath(
|
|
18820
19165
|
input.project,
|
|
18821
19166
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
18822
19167
|
);
|
|
18823
19168
|
try {
|
|
18824
|
-
const result = await client.get(
|
|
19169
|
+
const result = await client.get(path71);
|
|
18825
19170
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
18826
19171
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
18827
19172
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -18847,12 +19192,12 @@ async function runRootCause(client, input) {
|
|
|
18847
19192
|
}
|
|
18848
19193
|
async function runBlastRadius(client, input) {
|
|
18849
19194
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
18850
|
-
const
|
|
19195
|
+
const path71 = projectPath(
|
|
18851
19196
|
input.project,
|
|
18852
19197
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
18853
19198
|
);
|
|
18854
19199
|
try {
|
|
18855
|
-
const result = await client.get(
|
|
19200
|
+
const result = await client.get(path71);
|
|
18856
19201
|
if (result.totalAffected === 0) {
|
|
18857
19202
|
return {
|
|
18858
19203
|
summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
|
|
@@ -18881,17 +19226,17 @@ async function runBlastRadius(client, input) {
|
|
|
18881
19226
|
}
|
|
18882
19227
|
}
|
|
18883
19228
|
function formatBlastEntry(n) {
|
|
18884
|
-
const tag = n.edgeProvenance ===
|
|
19229
|
+
const tag = n.edgeProvenance === import_types61.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
18885
19230
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
18886
19231
|
}
|
|
18887
19232
|
async function runDependencies(client, input) {
|
|
18888
19233
|
const depth = input.depth ?? 3;
|
|
18889
|
-
const
|
|
19234
|
+
const path71 = projectPath(
|
|
18890
19235
|
input.project,
|
|
18891
19236
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
18892
19237
|
);
|
|
18893
19238
|
try {
|
|
18894
|
-
const result = await client.get(
|
|
19239
|
+
const result = await client.get(path71);
|
|
18895
19240
|
if (result.total === 0) {
|
|
18896
19241
|
return {
|
|
18897
19242
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -18938,7 +19283,7 @@ async function runObservedDependencies(client, input) {
|
|
|
18938
19283
|
if (result.observed) {
|
|
18939
19284
|
return {
|
|
18940
19285
|
summary: `${input.nodeId} makes no outbound runtime calls, but OTel has observed it receiving traffic on ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 it's a pure receiver.`,
|
|
18941
|
-
provenance:
|
|
19286
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
18942
19287
|
};
|
|
18943
19288
|
}
|
|
18944
19289
|
const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
@@ -18948,7 +19293,7 @@ async function runObservedDependencies(client, input) {
|
|
|
18948
19293
|
return {
|
|
18949
19294
|
summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
18950
19295
|
block: blockLines.join("\n"),
|
|
18951
|
-
provenance:
|
|
19296
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
18952
19297
|
};
|
|
18953
19298
|
} catch (err) {
|
|
18954
19299
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -18983,9 +19328,9 @@ function formatDuration(ms) {
|
|
|
18983
19328
|
return `${Math.round(h / 24)}d`;
|
|
18984
19329
|
}
|
|
18985
19330
|
async function runIncidents(client, input) {
|
|
18986
|
-
const
|
|
19331
|
+
const path71 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
18987
19332
|
try {
|
|
18988
|
-
const body = await client.get(
|
|
19333
|
+
const body = await client.get(path71);
|
|
18989
19334
|
const events = body.events;
|
|
18990
19335
|
if (events.length === 0) {
|
|
18991
19336
|
return {
|
|
@@ -19002,7 +19347,7 @@ async function runIncidents(client, input) {
|
|
|
19002
19347
|
return {
|
|
19003
19348
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
19004
19349
|
block: blockLines.join("\n"),
|
|
19005
|
-
provenance:
|
|
19350
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
19006
19351
|
};
|
|
19007
19352
|
} catch (err) {
|
|
19008
19353
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -19111,7 +19456,7 @@ async function runStaleEdges(client, input) {
|
|
|
19111
19456
|
return {
|
|
19112
19457
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
19113
19458
|
block: blockLines.join("\n"),
|
|
19114
|
-
provenance:
|
|
19459
|
+
provenance: import_types61.Provenance.STALE
|
|
19115
19460
|
};
|
|
19116
19461
|
}
|
|
19117
19462
|
async function runPolicies(client, input) {
|
|
@@ -19179,6 +19524,9 @@ function formatDivergenceLine(d) {
|
|
|
19179
19524
|
switch (d.type) {
|
|
19180
19525
|
case "missing-observed":
|
|
19181
19526
|
case "missing-extracted":
|
|
19527
|
+
if (d.column) {
|
|
19528
|
+
return ` \u2022 [${d.type}] ${d.table ?? d.source} column ${d.column} \u2014 confidence ${d.confidence.toFixed(2)}`;
|
|
19529
|
+
}
|
|
19182
19530
|
return ` \u2022 [${d.type}] ${d.source} \u2192 ${d.target} (${d.edgeType}) \u2014 confidence ${d.confidence.toFixed(2)}`;
|
|
19183
19531
|
case "version-mismatch":
|
|
19184
19532
|
return ` \u2022 [${d.type}] ${d.source} \u2192 ${d.target} \u2014 declared ${d.extractedVersion}, observed engine ${d.observedVersion} (${d.compatibility})`;
|
|
@@ -19275,7 +19623,7 @@ async function resolveProjectEntry(opts) {
|
|
|
19275
19623
|
const cwd = opts.cwd ?? process.cwd();
|
|
19276
19624
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
19277
19625
|
for (const entry2 of entries) {
|
|
19278
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
19626
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path69.default.sep}`)) {
|
|
19279
19627
|
return entry2;
|
|
19280
19628
|
}
|
|
19281
19629
|
}
|
|
@@ -19428,7 +19776,7 @@ async function runSync(opts) {
|
|
|
19428
19776
|
}
|
|
19429
19777
|
|
|
19430
19778
|
// src/cli.ts
|
|
19431
|
-
var
|
|
19779
|
+
var import_types62 = require("@neat.is/types");
|
|
19432
19780
|
function isNpxInvocation() {
|
|
19433
19781
|
if (process.env.npm_command === "exec") return true;
|
|
19434
19782
|
const execpath = process.env.npm_execpath ?? "";
|
|
@@ -19739,12 +20087,12 @@ async function runInit(opts) {
|
|
|
19739
20087
|
printDiscoveryReport(opts, services);
|
|
19740
20088
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
19741
20089
|
const patch = renderPatch(sections);
|
|
19742
|
-
const patchPath =
|
|
20090
|
+
const patchPath = import_node_path70.default.join(opts.scanPath, "neat.patch");
|
|
19743
20091
|
if (opts.dryRun) {
|
|
19744
20092
|
await import_node_fs43.promises.writeFile(patchPath, patch, "utf8");
|
|
19745
20093
|
written.push(patchPath);
|
|
19746
20094
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
19747
|
-
const gitignorePath =
|
|
20095
|
+
const gitignorePath = import_node_path70.default.join(opts.scanPath, ".gitignore");
|
|
19748
20096
|
const gitignoreExists = await import_node_fs43.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
19749
20097
|
const verb = gitignoreExists ? "append" : "create";
|
|
19750
20098
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
@@ -19756,9 +20104,9 @@ async function runInit(opts) {
|
|
|
19756
20104
|
const graph = getGraph(graphKey);
|
|
19757
20105
|
const projectPaths = pathsForProject(
|
|
19758
20106
|
graphKey,
|
|
19759
|
-
|
|
20107
|
+
import_node_path70.default.join(opts.scanPath, "neat-out")
|
|
19760
20108
|
);
|
|
19761
|
-
const errorsPath =
|
|
20109
|
+
const errorsPath = import_node_path70.default.join(import_node_path70.default.dirname(opts.outPath), import_node_path70.default.basename(projectPaths.errorsPath));
|
|
19762
20110
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
19763
20111
|
await saveGraphToDisk(graph, opts.outPath);
|
|
19764
20112
|
written.push(opts.outPath);
|
|
@@ -19877,9 +20225,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
19877
20225
|
};
|
|
19878
20226
|
function claudeConfigPath() {
|
|
19879
20227
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
19880
|
-
if (override && override.length > 0) return
|
|
20228
|
+
if (override && override.length > 0) return import_node_path70.default.resolve(override);
|
|
19881
20229
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
19882
|
-
return
|
|
20230
|
+
return import_node_path70.default.join(home, ".claude.json");
|
|
19883
20231
|
}
|
|
19884
20232
|
async function runSkill(opts) {
|
|
19885
20233
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -19903,7 +20251,7 @@ async function runSkill(opts) {
|
|
|
19903
20251
|
...existing,
|
|
19904
20252
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
19905
20253
|
};
|
|
19906
|
-
await import_node_fs43.promises.mkdir(
|
|
20254
|
+
await import_node_fs43.promises.mkdir(import_node_path70.default.dirname(target), { recursive: true });
|
|
19907
20255
|
await import_node_fs43.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
19908
20256
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
19909
20257
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
@@ -19969,12 +20317,12 @@ async function main() {
|
|
|
19969
20317
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
19970
20318
|
process.exit(2);
|
|
19971
20319
|
}
|
|
19972
|
-
const scanPath =
|
|
20320
|
+
const scanPath = import_node_path70.default.resolve(target);
|
|
19973
20321
|
const projectExplicit = parsed.project !== null;
|
|
19974
|
-
const projectName = projectExplicit ? project :
|
|
20322
|
+
const projectName = projectExplicit ? project : import_node_path70.default.basename(scanPath);
|
|
19975
20323
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
19976
|
-
const fallback = pathsForProject(projectKey,
|
|
19977
|
-
const outPath =
|
|
20324
|
+
const fallback = pathsForProject(projectKey, import_node_path70.default.join(scanPath, "neat-out")).snapshotPath;
|
|
20325
|
+
const outPath = import_node_path70.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
19978
20326
|
const result = await runInit({
|
|
19979
20327
|
scanPath,
|
|
19980
20328
|
outPath,
|
|
@@ -19995,21 +20343,21 @@ async function main() {
|
|
|
19995
20343
|
usage2();
|
|
19996
20344
|
process.exit(2);
|
|
19997
20345
|
}
|
|
19998
|
-
const scanPath =
|
|
20346
|
+
const scanPath = import_node_path70.default.resolve(target);
|
|
19999
20347
|
const stat = await import_node_fs43.promises.stat(scanPath).catch(() => null);
|
|
20000
20348
|
if (!stat || !stat.isDirectory()) {
|
|
20001
20349
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
20002
20350
|
process.exit(2);
|
|
20003
20351
|
}
|
|
20004
|
-
const projectPaths = pathsForProject(project,
|
|
20005
|
-
const outPath =
|
|
20006
|
-
const errorsPath =
|
|
20007
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
20352
|
+
const projectPaths = pathsForProject(project, import_node_path70.default.join(scanPath, "neat-out"));
|
|
20353
|
+
const outPath = import_node_path70.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
20354
|
+
const errorsPath = import_node_path70.default.resolve(
|
|
20355
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path70.default.join(import_node_path70.default.dirname(outPath), import_node_path70.default.basename(projectPaths.errorsPath))
|
|
20008
20356
|
);
|
|
20009
|
-
const staleEventsPath =
|
|
20010
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
20357
|
+
const staleEventsPath = import_node_path70.default.resolve(
|
|
20358
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path70.default.join(import_node_path70.default.dirname(outPath), import_node_path70.default.basename(projectPaths.staleEventsPath))
|
|
20011
20359
|
);
|
|
20012
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
20360
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path70.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
20013
20361
|
const handle = await startWatch(getGraph(project), {
|
|
20014
20362
|
scanPath,
|
|
20015
20363
|
outPath,
|
|
@@ -20018,7 +20366,7 @@ async function main() {
|
|
|
20018
20366
|
project,
|
|
20019
20367
|
// Resolve NEAT_HOME so a `neat watch` picks up connectors added to
|
|
20020
20368
|
// ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.
|
|
20021
|
-
neatHome: process.env.NEAT_HOME ?
|
|
20369
|
+
neatHome: process.env.NEAT_HOME ? import_node_path70.default.resolve(process.env.NEAT_HOME) : import_node_path70.default.join(import_node_os6.default.homedir(), ".neat"),
|
|
20022
20370
|
...embeddingsCachePath ? { embeddingsCachePath } : {},
|
|
20023
20371
|
host: process.env.HOST ?? "0.0.0.0",
|
|
20024
20372
|
port: Number(process.env.PORT ?? 8080),
|
|
@@ -20195,11 +20543,11 @@ async function main() {
|
|
|
20195
20543
|
process.exit(1);
|
|
20196
20544
|
}
|
|
20197
20545
|
async function tryOrchestrator(cmd, parsed) {
|
|
20198
|
-
const scanPath =
|
|
20546
|
+
const scanPath = import_node_path70.default.resolve(cmd);
|
|
20199
20547
|
const stat = await import_node_fs43.promises.stat(scanPath).catch(() => null);
|
|
20200
20548
|
if (!stat || !stat.isDirectory()) return null;
|
|
20201
20549
|
const projectExplicit = parsed.project !== null;
|
|
20202
|
-
const projectName = projectExplicit ? parsed.project :
|
|
20550
|
+
const projectName = projectExplicit ? parsed.project : import_node_path70.default.basename(scanPath);
|
|
20203
20551
|
const result = await runOrchestrator({
|
|
20204
20552
|
scanPath,
|
|
20205
20553
|
project: projectName,
|
|
@@ -20388,10 +20736,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
20388
20736
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
20389
20737
|
const out = [];
|
|
20390
20738
|
for (const p of parts) {
|
|
20391
|
-
const r =
|
|
20739
|
+
const r = import_types62.DivergenceTypeSchema.safeParse(p);
|
|
20392
20740
|
if (!r.success) {
|
|
20393
20741
|
console.error(
|
|
20394
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
20742
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types62.DivergenceTypeSchema.options.join(", ")}`
|
|
20395
20743
|
);
|
|
20396
20744
|
return 2;
|
|
20397
20745
|
}
|