@neat.is/core 0.6.0 → 0.6.2-dev.20260722
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-BZ3AJVAC.js → chunk-2MAGU6RB.js} +11 -2
- package/dist/chunk-2MAGU6RB.js.map +1 -0
- package/dist/{chunk-5PVQJLPR.js → chunk-64JJOXES.js} +3 -3
- package/dist/{chunk-MVINCLQM.js → chunk-OY7FGJAX.js} +2 -2
- package/dist/{chunk-CS4GHQO3.js → chunk-ZZ3VUCWL.js} +1581 -1329
- package/dist/chunk-ZZ3VUCWL.js.map +1 -0
- package/dist/cli.cjs +730 -468
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +579 -317
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +588 -326
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-XS45HBET.js → otel-grpc-AHNPM5LX.js} +3 -3
- package/dist/server.cjs +2683 -2417
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-BZ3AJVAC.js.map +0 -1
- package/dist/chunk-CS4GHQO3.js.map +0 -1
- /package/dist/{chunk-5PVQJLPR.js.map → chunk-64JJOXES.js.map} +0 -0
- /package/dist/{chunk-MVINCLQM.js.map → chunk-OY7FGJAX.js.map} +0 -0
- /package/dist/{otel-grpc-XS45HBET.js.map → otel-grpc-AHNPM5LX.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -60,8 +60,8 @@ function mountBearerAuth(app, opts) {
|
|
|
60
60
|
]);
|
|
61
61
|
const publicRead = opts.publicRead === true;
|
|
62
62
|
app.addHook("preHandler", (req, reply, done) => {
|
|
63
|
-
const
|
|
64
|
-
if (exactUnauthPaths.has(
|
|
63
|
+
const path53 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
64
|
+
if (exactUnauthPaths.has(path53) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path53)) {
|
|
65
65
|
done();
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
@@ -193,8 +193,8 @@ function reshapeGrpcRequest(req) {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
function resolveProtoRoot() {
|
|
196
|
-
const here =
|
|
197
|
-
return
|
|
196
|
+
const here = import_node_path49.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
197
|
+
return import_node_path49.default.resolve(here, "..", "proto");
|
|
198
198
|
}
|
|
199
199
|
function loadTraceService() {
|
|
200
200
|
const protoRoot = resolveProtoRoot();
|
|
@@ -262,13 +262,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
262
262
|
})
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
var import_node_url,
|
|
265
|
+
var import_node_url, import_node_path49, import_node_crypto2, grpc, protoLoader;
|
|
266
266
|
var init_otel_grpc = __esm({
|
|
267
267
|
"src/otel-grpc.ts"() {
|
|
268
268
|
"use strict";
|
|
269
269
|
init_cjs_shims();
|
|
270
270
|
import_node_url = require("url");
|
|
271
|
-
|
|
271
|
+
import_node_path49 = __toESM(require("path"), 1);
|
|
272
272
|
import_node_crypto2 = require("crypto");
|
|
273
273
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
274
274
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -346,6 +346,14 @@ function normalizeDbSystem(attrs) {
|
|
|
346
346
|
if (typeof raw !== "string") return void 0;
|
|
347
347
|
return raw === "mongoose" ? "mongodb" : raw;
|
|
348
348
|
}
|
|
349
|
+
function tableFromSqlStatement(sql) {
|
|
350
|
+
if (typeof sql !== "string" || sql.length === 0) return null;
|
|
351
|
+
if (/\bjoin\b/i.test(sql)) return null;
|
|
352
|
+
const froms = sql.match(/\bfrom\b/gi);
|
|
353
|
+
if (froms && froms.length > 1) return null;
|
|
354
|
+
const m = /\b(?:from|into|update)\s+(?:"?[\w$]+"?\s*\.\s*)?"?([a-zA-Z_][\w$]*)"?/i.exec(sql);
|
|
355
|
+
return m ? m[1] : null;
|
|
356
|
+
}
|
|
349
357
|
function messagingDestinationOf(attrs) {
|
|
350
358
|
for (const key of ["messaging.destination.name", "messaging.destination"]) {
|
|
351
359
|
const v = attrs[key];
|
|
@@ -366,8 +374,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
366
374
|
const v = attrs[key];
|
|
367
375
|
if (typeof v === "string" && v.length > 0) {
|
|
368
376
|
const q = v.indexOf("?");
|
|
369
|
-
const
|
|
370
|
-
if (
|
|
377
|
+
const path53 = q === -1 ? v : v.slice(0, q);
|
|
378
|
+
if (path53.length > 0) return path53;
|
|
371
379
|
}
|
|
372
380
|
}
|
|
373
381
|
return void 0;
|
|
@@ -403,6 +411,7 @@ function parseOtlpRequest(body) {
|
|
|
403
411
|
dbSystem: normalizeDbSystem(attrs),
|
|
404
412
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
405
413
|
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
414
|
+
dbTable: typeof attrs["db.statement"] === "string" ? tableFromSqlStatement(attrs["db.statement"]) ?? void 0 : void 0,
|
|
406
415
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
407
416
|
messagingDestination: messagingDestinationOf(attrs),
|
|
408
417
|
graphqlOperationName: typeof attrs["graphql.operation.name"] === "string" && attrs["graphql.operation.name"].length > 0 ? attrs["graphql.operation.name"] : void 0,
|
|
@@ -422,10 +431,10 @@ function parseOtlpRequest(body) {
|
|
|
422
431
|
return out;
|
|
423
432
|
}
|
|
424
433
|
function loadProtoRoot() {
|
|
425
|
-
const here =
|
|
426
|
-
const protoRoot =
|
|
434
|
+
const here = import_node_path50.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
435
|
+
const protoRoot = import_node_path50.default.resolve(here, "..", "proto");
|
|
427
436
|
const root = new import_protobufjs.default.Root();
|
|
428
|
-
root.resolvePath = (_origin, target) =>
|
|
437
|
+
root.resolvePath = (_origin, target) => import_node_path50.default.resolve(protoRoot, target);
|
|
429
438
|
root.loadSync(
|
|
430
439
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
431
440
|
{ keepCase: true }
|
|
@@ -661,12 +670,12 @@ function logSpanHandler(span) {
|
|
|
661
670
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
662
671
|
);
|
|
663
672
|
}
|
|
664
|
-
var
|
|
673
|
+
var import_node_path50, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
665
674
|
var init_otel = __esm({
|
|
666
675
|
"src/otel.ts"() {
|
|
667
676
|
"use strict";
|
|
668
677
|
init_cjs_shims();
|
|
669
|
-
|
|
678
|
+
import_node_path50 = __toESM(require("path"), 1);
|
|
670
679
|
import_node_url2 = require("url");
|
|
671
680
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
672
681
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -1256,19 +1265,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1256
1265
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1257
1266
|
let best = { path: [start], edges: [] };
|
|
1258
1267
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1259
|
-
function step(node,
|
|
1260
|
-
if (
|
|
1261
|
-
best = { path: [...
|
|
1268
|
+
function step(node, path53, edges) {
|
|
1269
|
+
if (path53.length > best.path.length) {
|
|
1270
|
+
best = { path: [...path53], edges: [...edges] };
|
|
1262
1271
|
}
|
|
1263
|
-
if (
|
|
1272
|
+
if (path53.length - 1 >= maxDepth) return;
|
|
1264
1273
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1265
1274
|
for (const [srcId, edge] of incoming) {
|
|
1266
1275
|
if (visited.has(srcId)) continue;
|
|
1267
1276
|
visited.add(srcId);
|
|
1268
|
-
|
|
1277
|
+
path53.push(srcId);
|
|
1269
1278
|
edges.push(edge);
|
|
1270
|
-
step(srcId,
|
|
1271
|
-
|
|
1279
|
+
step(srcId, path53, edges);
|
|
1280
|
+
path53.pop();
|
|
1272
1281
|
edges.pop();
|
|
1273
1282
|
visited.delete(srcId);
|
|
1274
1283
|
}
|
|
@@ -1276,11 +1285,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
1276
1285
|
step(start, [start], []);
|
|
1277
1286
|
return best;
|
|
1278
1287
|
}
|
|
1279
|
-
function databaseRootCauseShape(graph, origin,
|
|
1288
|
+
function databaseRootCauseShape(graph, origin, walk4) {
|
|
1280
1289
|
const targetDb = origin;
|
|
1281
1290
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
1282
1291
|
if (candidatePairs.length === 0) return null;
|
|
1283
|
-
for (const id of
|
|
1292
|
+
for (const id of walk4.path) {
|
|
1284
1293
|
const owner = resolveOwningService(graph, id);
|
|
1285
1294
|
if (!owner) continue;
|
|
1286
1295
|
const { id: serviceId6, svc } = owner;
|
|
@@ -1307,8 +1316,8 @@ function databaseRootCauseShape(graph, origin, walk3) {
|
|
|
1307
1316
|
}
|
|
1308
1317
|
return null;
|
|
1309
1318
|
}
|
|
1310
|
-
function serviceRootCauseShape(graph, _origin,
|
|
1311
|
-
for (const id of
|
|
1319
|
+
function serviceRootCauseShape(graph, _origin, walk4) {
|
|
1320
|
+
for (const id of walk4.path) {
|
|
1312
1321
|
const owner = resolveOwningService(graph, id);
|
|
1313
1322
|
if (!owner) continue;
|
|
1314
1323
|
const { id: serviceId6, svc } = owner;
|
|
@@ -1344,10 +1353,10 @@ function serviceRootCauseShape(graph, _origin, walk3) {
|
|
|
1344
1353
|
}
|
|
1345
1354
|
return null;
|
|
1346
1355
|
}
|
|
1347
|
-
function fileRootCauseShape(graph, origin,
|
|
1356
|
+
function fileRootCauseShape(graph, origin, walk4) {
|
|
1348
1357
|
const owner = resolveOwningService(graph, origin.id);
|
|
1349
1358
|
if (!owner) return null;
|
|
1350
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
1359
|
+
return serviceRootCauseShape(graph, owner.svc, walk4);
|
|
1351
1360
|
}
|
|
1352
1361
|
var rootCauseShapes = {
|
|
1353
1362
|
[import_types.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -1359,16 +1368,16 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1359
1368
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
1360
1369
|
const shape = rootCauseShapes[origin.type];
|
|
1361
1370
|
if (shape) {
|
|
1362
|
-
const
|
|
1363
|
-
const match = shape(graph, origin,
|
|
1371
|
+
const walk4 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
1372
|
+
const match = shape(graph, origin, walk4);
|
|
1364
1373
|
if (match) {
|
|
1365
1374
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
1366
1375
|
return import_types.RootCauseResultSchema.parse({
|
|
1367
1376
|
rootCauseNode: match.rootCauseNode,
|
|
1368
1377
|
rootCauseReason: reason,
|
|
1369
|
-
traversalPath:
|
|
1370
|
-
edgeProvenances:
|
|
1371
|
-
confidence: confidenceFromMix(
|
|
1378
|
+
traversalPath: walk4.path,
|
|
1379
|
+
edgeProvenances: walk4.edges.map((e) => e.provenance),
|
|
1380
|
+
confidence: confidenceFromMix(walk4.edges),
|
|
1372
1381
|
fixRecommendation: match.fixRecommendation
|
|
1373
1382
|
});
|
|
1374
1383
|
}
|
|
@@ -1389,8 +1398,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
1389
1398
|
if (relevant.length === 0) return null;
|
|
1390
1399
|
const latest = [...relevant].sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0];
|
|
1391
1400
|
const attrs = latest.attributes ?? {};
|
|
1392
|
-
const filepath =
|
|
1393
|
-
const lineno =
|
|
1401
|
+
const filepath = codeFilepathOf(attrs);
|
|
1402
|
+
const lineno = codeLinenoOf(attrs);
|
|
1394
1403
|
const route = typeof attrs["http.route"] === "string" ? attrs["http.route"] : void 0;
|
|
1395
1404
|
const location = filepath ? `${filepath}${lineno !== void 0 ? `:${lineno}` : ""}` : void 0;
|
|
1396
1405
|
const sameMode = relevant.filter((ev) => ev.errorMessage === latest.errorMessage);
|
|
@@ -1462,26 +1471,26 @@ function dominantFailingCall(graph, serviceId6, visited) {
|
|
|
1462
1471
|
return best;
|
|
1463
1472
|
}
|
|
1464
1473
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1465
|
-
const
|
|
1474
|
+
const path53 = [originServiceId];
|
|
1466
1475
|
const edges = [];
|
|
1467
1476
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1468
1477
|
let current = originServiceId;
|
|
1469
1478
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1470
1479
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1471
1480
|
if (!hop) break;
|
|
1472
|
-
|
|
1481
|
+
path53.push(hop.nextService);
|
|
1473
1482
|
edges.push(hop.edge);
|
|
1474
1483
|
visited.add(hop.nextService);
|
|
1475
1484
|
current = hop.nextService;
|
|
1476
1485
|
}
|
|
1477
1486
|
if (edges.length === 0) return null;
|
|
1478
|
-
return { path:
|
|
1487
|
+
return { path: path53, edges, culprit: current };
|
|
1479
1488
|
}
|
|
1480
1489
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1481
1490
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1482
1491
|
if (!chain) return null;
|
|
1483
1492
|
const culprit = chain.culprit;
|
|
1484
|
-
const
|
|
1493
|
+
const path53 = [...chain.path];
|
|
1485
1494
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1486
1495
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1487
1496
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1489,14 +1498,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1489
1498
|
if (loc) {
|
|
1490
1499
|
let rootCauseNode = culprit;
|
|
1491
1500
|
if (loc.fileNode) {
|
|
1492
|
-
|
|
1501
|
+
path53.push(loc.fileNode);
|
|
1493
1502
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1494
1503
|
rootCauseNode = loc.fileNode;
|
|
1495
1504
|
}
|
|
1496
1505
|
return import_types.RootCauseResultSchema.parse({
|
|
1497
1506
|
rootCauseNode,
|
|
1498
1507
|
rootCauseReason: loc.rootCauseReason,
|
|
1499
|
-
traversalPath:
|
|
1508
|
+
traversalPath: path53,
|
|
1500
1509
|
edgeProvenances,
|
|
1501
1510
|
confidence,
|
|
1502
1511
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1508,7 +1517,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1508
1517
|
return import_types.RootCauseResultSchema.parse({
|
|
1509
1518
|
rootCauseNode: culprit,
|
|
1510
1519
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1511
|
-
traversalPath:
|
|
1520
|
+
traversalPath: path53,
|
|
1512
1521
|
edgeProvenances,
|
|
1513
1522
|
confidence,
|
|
1514
1523
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2266,9 +2275,30 @@ function isLoopbackHost(host) {
|
|
|
2266
2275
|
const h = host.toLowerCase();
|
|
2267
2276
|
return h === "localhost" || h === "ip6-localhost" || h === "::1" || h === "[::1]" || /^127(?:\.\d{1,3}){3}$/.test(h);
|
|
2268
2277
|
}
|
|
2278
|
+
var CODE_FILE_PATH_ATTR = "code.file.path";
|
|
2269
2279
|
var CODE_FILEPATH_ATTR = "code.filepath";
|
|
2280
|
+
var CODE_LINE_NUMBER_ATTR = "code.line.number";
|
|
2270
2281
|
var CODE_LINENO_ATTR = "code.lineno";
|
|
2282
|
+
var CODE_FUNCTION_NAME_ATTR = "code.function.name";
|
|
2271
2283
|
var CODE_FUNCTION_ATTR = "code.function";
|
|
2284
|
+
function codeFilepathOf(attrs) {
|
|
2285
|
+
const stable = attrs[CODE_FILE_PATH_ATTR];
|
|
2286
|
+
if (typeof stable === "string" && stable.length > 0) return stable;
|
|
2287
|
+
const prior = attrs[CODE_FILEPATH_ATTR];
|
|
2288
|
+
return typeof prior === "string" && prior.length > 0 ? prior : void 0;
|
|
2289
|
+
}
|
|
2290
|
+
function codeLinenoOf(attrs) {
|
|
2291
|
+
const stable = attrs[CODE_LINE_NUMBER_ATTR];
|
|
2292
|
+
if (typeof stable === "number" && Number.isFinite(stable)) return stable;
|
|
2293
|
+
const prior = attrs[CODE_LINENO_ATTR];
|
|
2294
|
+
return typeof prior === "number" && Number.isFinite(prior) ? prior : void 0;
|
|
2295
|
+
}
|
|
2296
|
+
function codeFunctionOf(attrs) {
|
|
2297
|
+
const stable = attrs[CODE_FUNCTION_NAME_ATTR];
|
|
2298
|
+
if (typeof stable === "string" && stable.length > 0) return stable;
|
|
2299
|
+
const prior = attrs[CODE_FUNCTION_ATTR];
|
|
2300
|
+
return typeof prior === "string" && prior.length > 0 ? prior : void 0;
|
|
2301
|
+
}
|
|
2272
2302
|
function toPosix(p) {
|
|
2273
2303
|
return p.split("\\").join("/");
|
|
2274
2304
|
}
|
|
@@ -2346,10 +2376,9 @@ function resolveDistToSrc(absFilepath, line) {
|
|
|
2346
2376
|
}
|
|
2347
2377
|
}
|
|
2348
2378
|
function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
2349
|
-
const filepath = span.attributes
|
|
2350
|
-
if (
|
|
2351
|
-
|
|
2352
|
-
let line = typeof linenoRaw === "number" && Number.isFinite(linenoRaw) ? linenoRaw : void 0;
|
|
2379
|
+
const filepath = codeFilepathOf(span.attributes);
|
|
2380
|
+
if (filepath === void 0) return null;
|
|
2381
|
+
let line = codeLinenoOf(span.attributes);
|
|
2353
2382
|
const abs = toPosix(filepath).replace(/^file:\/\//, "");
|
|
2354
2383
|
const resolved = resolveDistToSrc(abs, line);
|
|
2355
2384
|
let effectivePath = filepath;
|
|
@@ -2364,8 +2393,7 @@ function callSiteFromSpan(span, serviceNode, scanPath) {
|
|
|
2364
2393
|
if (!resolved && abs.endsWith(".js") && relPath.startsWith("dist/") && serviceNode?.name) {
|
|
2365
2394
|
warnNoSourceMaps(serviceNode.name);
|
|
2366
2395
|
}
|
|
2367
|
-
const
|
|
2368
|
-
const fn = typeof fnRaw === "string" && fnRaw.length > 0 ? fnRaw : void 0;
|
|
2396
|
+
const fn = codeFunctionOf(span.attributes);
|
|
2369
2397
|
return {
|
|
2370
2398
|
relPath,
|
|
2371
2399
|
...line !== void 0 ? { line } : {},
|
|
@@ -2947,6 +2975,18 @@ async function handleSpan(ctx, span) {
|
|
|
2947
2975
|
callSiteEvidence
|
|
2948
2976
|
);
|
|
2949
2977
|
}
|
|
2978
|
+
if (span.dbTable) {
|
|
2979
|
+
const tableId = ensureInfraNode(ctx.graph, "sql-table", span.dbTable, "self");
|
|
2980
|
+
upsertObservedEdge(
|
|
2981
|
+
ctx.graph,
|
|
2982
|
+
import_types3.EdgeType.CALLS,
|
|
2983
|
+
observedSource(),
|
|
2984
|
+
tableId,
|
|
2985
|
+
ts,
|
|
2986
|
+
isError,
|
|
2987
|
+
callSiteEvidence
|
|
2988
|
+
);
|
|
2989
|
+
}
|
|
2950
2990
|
}
|
|
2951
2991
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
2952
2992
|
const targetId = ensureMessagingDestinationNode(
|
|
@@ -4114,14 +4154,14 @@ function buildServiceHostIndex(services) {
|
|
|
4114
4154
|
}
|
|
4115
4155
|
async function walkSourceFiles(dir) {
|
|
4116
4156
|
const out = [];
|
|
4117
|
-
async function
|
|
4157
|
+
async function walk4(current) {
|
|
4118
4158
|
const entries = await import_node_fs10.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
4119
4159
|
for (const entry of entries) {
|
|
4120
4160
|
const full = import_node_path10.default.join(current, entry.name);
|
|
4121
4161
|
if (entry.isDirectory()) {
|
|
4122
4162
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
4123
4163
|
if (await isPythonVenvDir(full)) continue;
|
|
4124
|
-
await
|
|
4164
|
+
await walk4(full);
|
|
4125
4165
|
} else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path10.default.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
4126
4166
|
// would attribute our instrumentation imports to the user's service.
|
|
4127
4167
|
!isNeatAuthoredSourceFile(entry.name)) {
|
|
@@ -4129,7 +4169,7 @@ async function walkSourceFiles(dir) {
|
|
|
4129
4169
|
}
|
|
4130
4170
|
}
|
|
4131
4171
|
}
|
|
4132
|
-
await
|
|
4172
|
+
await walk4(dir);
|
|
4133
4173
|
return out;
|
|
4134
4174
|
}
|
|
4135
4175
|
async function loadSourceFiles(dir) {
|
|
@@ -5279,20 +5319,20 @@ var import_node_path21 = __toESM(require("path"), 1);
|
|
|
5279
5319
|
var import_types10 = require("@neat.is/types");
|
|
5280
5320
|
async function walkConfigFiles(dir) {
|
|
5281
5321
|
const out = [];
|
|
5282
|
-
async function
|
|
5322
|
+
async function walk4(current) {
|
|
5283
5323
|
const entries = await import_node_fs14.promises.readdir(current, { withFileTypes: true });
|
|
5284
5324
|
for (const entry of entries) {
|
|
5285
5325
|
const full = import_node_path21.default.join(current, entry.name);
|
|
5286
5326
|
if (entry.isDirectory()) {
|
|
5287
5327
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5288
5328
|
if (await isPythonVenvDir(full)) continue;
|
|
5289
|
-
await
|
|
5329
|
+
await walk4(full);
|
|
5290
5330
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
5291
5331
|
out.push(full);
|
|
5292
5332
|
}
|
|
5293
5333
|
}
|
|
5294
5334
|
}
|
|
5295
|
-
await
|
|
5335
|
+
await walk4(dir);
|
|
5296
5336
|
return out;
|
|
5297
5337
|
}
|
|
5298
5338
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -5345,6 +5385,7 @@ init_cjs_shims();
|
|
|
5345
5385
|
var import_node_path22 = __toESM(require("path"), 1);
|
|
5346
5386
|
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
5347
5387
|
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5388
|
+
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
5348
5389
|
var import_types11 = require("@neat.is/types");
|
|
5349
5390
|
var PARSE_CHUNK2 = 16384;
|
|
5350
5391
|
function parseSource2(parser, source) {
|
|
@@ -5357,6 +5398,11 @@ function makeJsParser2() {
|
|
|
5357
5398
|
p.setLanguage(import_tree_sitter_javascript2.default);
|
|
5358
5399
|
return p;
|
|
5359
5400
|
}
|
|
5401
|
+
function makePyParser2() {
|
|
5402
|
+
const p = new import_tree_sitter2.default();
|
|
5403
|
+
p.setLanguage(import_tree_sitter_python2.default);
|
|
5404
|
+
return p;
|
|
5405
|
+
}
|
|
5360
5406
|
var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
5361
5407
|
"get",
|
|
5362
5408
|
"post",
|
|
@@ -5369,6 +5415,7 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
5369
5415
|
]);
|
|
5370
5416
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
5371
5417
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
5418
|
+
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
5372
5419
|
function canonicalizeTemplate(raw) {
|
|
5373
5420
|
let p = raw.split("?")[0].split("#")[0];
|
|
5374
5421
|
if (!p.startsWith("/")) p = "/" + p;
|
|
@@ -5596,8 +5643,102 @@ function nextRoutesFromFile(source, relFile, parser) {
|
|
|
5596
5643
|
}
|
|
5597
5644
|
return [];
|
|
5598
5645
|
}
|
|
5646
|
+
function pyStaticStringText(node) {
|
|
5647
|
+
if (node.type !== "string") return null;
|
|
5648
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
5649
|
+
const child = node.namedChild(i);
|
|
5650
|
+
if (child?.type === "interpolation") return null;
|
|
5651
|
+
if (child?.type === "string_content") return child.text;
|
|
5652
|
+
}
|
|
5653
|
+
return "";
|
|
5654
|
+
}
|
|
5655
|
+
function keywordArrayStrings(argsNode, key) {
|
|
5656
|
+
for (let i = 0; i < argsNode.namedChildCount; i++) {
|
|
5657
|
+
const arg = argsNode.namedChild(i);
|
|
5658
|
+
if (arg?.type !== "keyword_argument") continue;
|
|
5659
|
+
if (arg.childForFieldName("name")?.text !== key) continue;
|
|
5660
|
+
const val = arg.childForFieldName("value");
|
|
5661
|
+
if (!val || val.type !== "list") return [];
|
|
5662
|
+
const out = [];
|
|
5663
|
+
for (let j = 0; j < val.namedChildCount; j++) {
|
|
5664
|
+
const el = val.namedChild(j);
|
|
5665
|
+
if (el?.type === "string") {
|
|
5666
|
+
const s = pyStaticStringText(el);
|
|
5667
|
+
if (s) out.push(s);
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
return out;
|
|
5671
|
+
}
|
|
5672
|
+
return [];
|
|
5673
|
+
}
|
|
5674
|
+
function collectApiRouterPrefixes(root) {
|
|
5675
|
+
const prefixes = /* @__PURE__ */ new Map();
|
|
5676
|
+
walk(root, (node) => {
|
|
5677
|
+
if (node.type !== "assignment") return;
|
|
5678
|
+
const right = node.childForFieldName("right");
|
|
5679
|
+
if (!right || right.type !== "call") return;
|
|
5680
|
+
const fn = right.childForFieldName("function");
|
|
5681
|
+
if (!fn) return;
|
|
5682
|
+
const ctor = fn.type === "attribute" ? fn.childForFieldName("attribute")?.text : fn.text;
|
|
5683
|
+
if (ctor !== "APIRouter") return;
|
|
5684
|
+
const left = node.childForFieldName("left");
|
|
5685
|
+
if (!left || left.type !== "identifier") return;
|
|
5686
|
+
const args = right.childForFieldName("arguments");
|
|
5687
|
+
if (!args) return;
|
|
5688
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
5689
|
+
const arg = args.namedChild(i);
|
|
5690
|
+
if (arg?.type !== "keyword_argument") continue;
|
|
5691
|
+
if (arg.childForFieldName("name")?.text !== "prefix") continue;
|
|
5692
|
+
const val = arg.childForFieldName("value");
|
|
5693
|
+
const p = val ? pyStaticStringText(val) : null;
|
|
5694
|
+
if (p !== null) prefixes.set(left.text, p);
|
|
5695
|
+
}
|
|
5696
|
+
});
|
|
5697
|
+
return prefixes;
|
|
5698
|
+
}
|
|
5699
|
+
function fastapiRoutesFromSource(source, parser) {
|
|
5700
|
+
const tree = parseSource2(parser, source);
|
|
5701
|
+
const prefixes = collectApiRouterPrefixes(tree.rootNode);
|
|
5702
|
+
const out = [];
|
|
5703
|
+
walk(tree.rootNode, (node) => {
|
|
5704
|
+
if (node.type !== "decorator") return;
|
|
5705
|
+
const call = node.namedChild(0);
|
|
5706
|
+
if (!call || call.type !== "call") return;
|
|
5707
|
+
const fn = call.childForFieldName("function");
|
|
5708
|
+
if (!fn || fn.type !== "attribute") return;
|
|
5709
|
+
const method = fn.childForFieldName("attribute")?.text?.toLowerCase();
|
|
5710
|
+
if (!method) return;
|
|
5711
|
+
const isVerb = FASTAPI_METHODS.has(method);
|
|
5712
|
+
if (!isVerb && method !== "api_route") return;
|
|
5713
|
+
const args = call.childForFieldName("arguments");
|
|
5714
|
+
const first = args?.namedChild(0);
|
|
5715
|
+
if (!first || first.type !== "string") return;
|
|
5716
|
+
const rawPath = pyStaticStringText(first);
|
|
5717
|
+
if (rawPath === null || !rawPath.startsWith("/")) return;
|
|
5718
|
+
const obj = fn.childForFieldName("object")?.text;
|
|
5719
|
+
const prefix = obj ? prefixes.get(obj) ?? "" : "";
|
|
5720
|
+
const pathTemplate = canonicalizeTemplate(prefix + rawPath);
|
|
5721
|
+
const line = node.startPosition.row + 1;
|
|
5722
|
+
if (isVerb) {
|
|
5723
|
+
out.push({ method: method.toUpperCase(), pathTemplate, line, framework: "fastapi" });
|
|
5724
|
+
return;
|
|
5725
|
+
}
|
|
5726
|
+
const methods = keywordArrayStrings(args, "methods");
|
|
5727
|
+
const list = methods.length > 0 ? methods : ["ALL"];
|
|
5728
|
+
for (const m of list) {
|
|
5729
|
+
out.push({
|
|
5730
|
+
method: m === "ALL" ? "ALL" : m.toUpperCase(),
|
|
5731
|
+
pathTemplate,
|
|
5732
|
+
line,
|
|
5733
|
+
framework: "fastapi"
|
|
5734
|
+
});
|
|
5735
|
+
}
|
|
5736
|
+
});
|
|
5737
|
+
return out;
|
|
5738
|
+
}
|
|
5599
5739
|
async function addRoutes(graph, services) {
|
|
5600
5740
|
const jsParser = makeJsParser2();
|
|
5741
|
+
const pyParser = makePyParser2();
|
|
5601
5742
|
let nodesAdded = 0;
|
|
5602
5743
|
let edgesAdded = 0;
|
|
5603
5744
|
for (const service of services) {
|
|
@@ -5609,15 +5750,20 @@ async function addRoutes(graph, services) {
|
|
|
5609
5750
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5610
5751
|
const hasHono = deps["hono"] !== void 0;
|
|
5611
5752
|
const hasNext = deps["next"] !== void 0;
|
|
5612
|
-
|
|
5753
|
+
const hasFastapi = deps["fastapi"] !== void 0;
|
|
5754
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasFastapi) continue;
|
|
5613
5755
|
const files = await loadSourceFiles(service.dir);
|
|
5614
5756
|
for (const file of files) {
|
|
5615
5757
|
if (isTestPath(file.path)) continue;
|
|
5616
|
-
|
|
5758
|
+
const ext = import_node_path22.default.extname(file.path);
|
|
5759
|
+
const isPy = ext === ".py";
|
|
5760
|
+
if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy) continue;
|
|
5617
5761
|
const relFile = toPosix2(import_node_path22.default.relative(service.dir, file.path));
|
|
5618
5762
|
let routes;
|
|
5619
5763
|
try {
|
|
5620
|
-
if (
|
|
5764
|
+
if (isPy) {
|
|
5765
|
+
routes = hasFastapi ? fastapiRoutesFromSource(file.content, pyParser) : [];
|
|
5766
|
+
} else if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5621
5767
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5622
5768
|
} else if (hasExpress || hasFastify || hasHono) {
|
|
5623
5769
|
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
@@ -5713,20 +5859,20 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
5713
5859
|
}
|
|
5714
5860
|
async function walkProtoFiles(dir) {
|
|
5715
5861
|
const out = [];
|
|
5716
|
-
async function
|
|
5862
|
+
async function walk4(current) {
|
|
5717
5863
|
const entries = await import_node_fs15.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
5718
5864
|
for (const entry of entries) {
|
|
5719
5865
|
const full = import_node_path23.default.join(current, entry.name);
|
|
5720
5866
|
if (entry.isDirectory()) {
|
|
5721
5867
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5722
5868
|
if (await isPythonVenvDir(full)) continue;
|
|
5723
|
-
await
|
|
5869
|
+
await walk4(full);
|
|
5724
5870
|
} else if (entry.isFile() && import_node_path23.default.extname(entry.name) === PROTO_EXTENSION) {
|
|
5725
5871
|
out.push(full);
|
|
5726
5872
|
}
|
|
5727
5873
|
}
|
|
5728
5874
|
}
|
|
5729
|
-
await
|
|
5875
|
+
await walk4(dir);
|
|
5730
5876
|
return out;
|
|
5731
5877
|
}
|
|
5732
5878
|
async function addGrpcMethods(graph, services) {
|
|
@@ -5794,14 +5940,14 @@ async function addGrpcMethods(graph, services) {
|
|
|
5794
5940
|
|
|
5795
5941
|
// src/extract/calls/index.ts
|
|
5796
5942
|
init_cjs_shims();
|
|
5797
|
-
var
|
|
5943
|
+
var import_types22 = require("@neat.is/types");
|
|
5798
5944
|
|
|
5799
5945
|
// src/extract/calls/http.ts
|
|
5800
5946
|
init_cjs_shims();
|
|
5801
5947
|
var import_node_path24 = __toESM(require("path"), 1);
|
|
5802
5948
|
var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
|
|
5803
5949
|
var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5804
|
-
var
|
|
5950
|
+
var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
|
|
5805
5951
|
var import_types13 = require("@neat.is/types");
|
|
5806
5952
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
5807
5953
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
@@ -5856,14 +6002,14 @@ function makeJsParser3() {
|
|
|
5856
6002
|
p.setLanguage(import_tree_sitter_javascript3.default);
|
|
5857
6003
|
return p;
|
|
5858
6004
|
}
|
|
5859
|
-
function
|
|
6005
|
+
function makePyParser3() {
|
|
5860
6006
|
const p = new import_tree_sitter3.default();
|
|
5861
|
-
p.setLanguage(
|
|
6007
|
+
p.setLanguage(import_tree_sitter_python3.default);
|
|
5862
6008
|
return p;
|
|
5863
6009
|
}
|
|
5864
6010
|
async function addHttpCallEdges(graph, services) {
|
|
5865
6011
|
const jsParser = makeJsParser3();
|
|
5866
|
-
const pyParser =
|
|
6012
|
+
const pyParser = makePyParser3();
|
|
5867
6013
|
const { knownHosts, hostToNodeId } = buildServiceHostIndex(services);
|
|
5868
6014
|
let nodesAdded = 0;
|
|
5869
6015
|
let edgesAdded = 0;
|
|
@@ -6803,15 +6949,130 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
6803
6949
|
return out;
|
|
6804
6950
|
}
|
|
6805
6951
|
|
|
6952
|
+
// src/extract/calls/sqlalchemy.ts
|
|
6953
|
+
init_cjs_shims();
|
|
6954
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
6955
|
+
var import_tree_sitter5 = __toESM(require("tree-sitter"), 1);
|
|
6956
|
+
var import_tree_sitter_python4 = __toESM(require("tree-sitter-python"), 1);
|
|
6957
|
+
var import_types21 = require("@neat.is/types");
|
|
6958
|
+
var SQLALCHEMY_IMPORT_RE = /(?:from|import)\s+(?:flask_sqlalchemy|sqlalchemy)\b/;
|
|
6959
|
+
var PARSE_CHUNK5 = 16384;
|
|
6960
|
+
function makePyParser4() {
|
|
6961
|
+
const p = new import_tree_sitter5.default();
|
|
6962
|
+
p.setLanguage(import_tree_sitter_python4.default);
|
|
6963
|
+
return p;
|
|
6964
|
+
}
|
|
6965
|
+
function parseSource5(parser, source) {
|
|
6966
|
+
return parser.parse(
|
|
6967
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK5)
|
|
6968
|
+
);
|
|
6969
|
+
}
|
|
6970
|
+
function flaskSqlalchemyTableName(className) {
|
|
6971
|
+
return className.replace(/((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))/g, "_$1").toLowerCase().replace(/^_+/, "");
|
|
6972
|
+
}
|
|
6973
|
+
function namedChildren(node) {
|
|
6974
|
+
const out = [];
|
|
6975
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
6976
|
+
const c = node.namedChild(i);
|
|
6977
|
+
if (c) out.push(c);
|
|
6978
|
+
}
|
|
6979
|
+
return out;
|
|
6980
|
+
}
|
|
6981
|
+
function pyStaticStringText2(node) {
|
|
6982
|
+
if (node.type !== "string") return null;
|
|
6983
|
+
for (const child of namedChildren(node)) {
|
|
6984
|
+
if (child.type === "interpolation") return null;
|
|
6985
|
+
if (child.type === "string_content") return child.text;
|
|
6986
|
+
}
|
|
6987
|
+
return "";
|
|
6988
|
+
}
|
|
6989
|
+
function explicitTablename(body) {
|
|
6990
|
+
for (const stmt of namedChildren(body)) {
|
|
6991
|
+
if (stmt.type !== "expression_statement") continue;
|
|
6992
|
+
const assign = stmt.namedChild(0);
|
|
6993
|
+
if (assign?.type !== "assignment") continue;
|
|
6994
|
+
if (assign.childForFieldName("left")?.text !== "__tablename__") continue;
|
|
6995
|
+
const right = assign.childForFieldName("right");
|
|
6996
|
+
if (right?.type === "string") {
|
|
6997
|
+
const s = pyStaticStringText2(right);
|
|
6998
|
+
return s ? { name: s } : "computed";
|
|
6999
|
+
}
|
|
7000
|
+
return "computed";
|
|
7001
|
+
}
|
|
7002
|
+
return null;
|
|
7003
|
+
}
|
|
7004
|
+
function extendsFlaskModel(cls) {
|
|
7005
|
+
const supers = cls.childForFieldName("superclasses");
|
|
7006
|
+
if (!supers) return false;
|
|
7007
|
+
for (const a of namedChildren(supers)) {
|
|
7008
|
+
const t = a.text;
|
|
7009
|
+
if (t === "db.Model" || t === "Model" || t.endsWith(".Model")) return true;
|
|
7010
|
+
}
|
|
7011
|
+
return false;
|
|
7012
|
+
}
|
|
7013
|
+
function walk3(node, visit) {
|
|
7014
|
+
visit(node);
|
|
7015
|
+
for (const c of namedChildren(node)) walk3(c, visit);
|
|
7016
|
+
}
|
|
7017
|
+
function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
7018
|
+
if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return [];
|
|
7019
|
+
const tree = parseSource5(makePyParser4(), file.content);
|
|
7020
|
+
const out = [];
|
|
7021
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7022
|
+
const push = (name, line) => {
|
|
7023
|
+
if (seen.has(name)) return;
|
|
7024
|
+
seen.add(name);
|
|
7025
|
+
out.push({
|
|
7026
|
+
infraId: (0, import_types21.infraId)("sql-table", name),
|
|
7027
|
+
name,
|
|
7028
|
+
kind: "sql-table",
|
|
7029
|
+
edgeType: "CALLS",
|
|
7030
|
+
confidenceKind: "verified-call-site",
|
|
7031
|
+
evidence: {
|
|
7032
|
+
file: import_node_path32.default.relative(serviceDir, file.path),
|
|
7033
|
+
line,
|
|
7034
|
+
snippet: snippet(file.content, line)
|
|
7035
|
+
}
|
|
7036
|
+
});
|
|
7037
|
+
};
|
|
7038
|
+
walk3(tree.rootNode, (node) => {
|
|
7039
|
+
if (node.type === "class_definition") {
|
|
7040
|
+
const body = node.childForFieldName("body");
|
|
7041
|
+
const nameNode = node.childForFieldName("name");
|
|
7042
|
+
if (!body || !nameNode) return;
|
|
7043
|
+
const line = node.startPosition.row + 1;
|
|
7044
|
+
const explicit = explicitTablename(body);
|
|
7045
|
+
if (explicit === "computed") return;
|
|
7046
|
+
if (explicit) {
|
|
7047
|
+
push(explicit.name, line);
|
|
7048
|
+
return;
|
|
7049
|
+
}
|
|
7050
|
+
if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line);
|
|
7051
|
+
return;
|
|
7052
|
+
}
|
|
7053
|
+
if (node.type === "call") {
|
|
7054
|
+
const fn = node.childForFieldName("function");
|
|
7055
|
+
const fnText = fn?.text;
|
|
7056
|
+
if (fnText !== "Table" && fnText !== "sa.Table" && fnText !== "sqlalchemy.Table") return;
|
|
7057
|
+
const first = node.childForFieldName("arguments")?.namedChild(0);
|
|
7058
|
+
if (first?.type === "string") {
|
|
7059
|
+
const s = pyStaticStringText2(first);
|
|
7060
|
+
if (s) push(s, node.startPosition.row + 1);
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7063
|
+
});
|
|
7064
|
+
return out;
|
|
7065
|
+
}
|
|
7066
|
+
|
|
6806
7067
|
// src/extract/calls/index.ts
|
|
6807
7068
|
function edgeTypeFromEndpoint(ep) {
|
|
6808
7069
|
switch (ep.edgeType) {
|
|
6809
7070
|
case "PUBLISHES_TO":
|
|
6810
|
-
return
|
|
7071
|
+
return import_types22.EdgeType.PUBLISHES_TO;
|
|
6811
7072
|
case "CONSUMES_FROM":
|
|
6812
|
-
return
|
|
7073
|
+
return import_types22.EdgeType.CONSUMES_FROM;
|
|
6813
7074
|
default:
|
|
6814
|
-
return
|
|
7075
|
+
return import_types22.EdgeType.CALLS;
|
|
6815
7076
|
}
|
|
6816
7077
|
}
|
|
6817
7078
|
function isAwsKind(kind) {
|
|
@@ -6835,6 +7096,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6835
7096
|
endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
|
|
6836
7097
|
endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
|
|
6837
7098
|
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
7099
|
+
endpoints.push(...sqlalchemyEndpointsFromFile(maskedFile, service.dir));
|
|
6838
7100
|
}
|
|
6839
7101
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
6840
7102
|
if (endpoints.length === 0) continue;
|
|
@@ -6843,7 +7105,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6843
7105
|
if (!graph.hasNode(ep.infraId)) {
|
|
6844
7106
|
const node = {
|
|
6845
7107
|
id: ep.infraId,
|
|
6846
|
-
type:
|
|
7108
|
+
type: import_types22.NodeType.InfraNode,
|
|
6847
7109
|
name: ep.name,
|
|
6848
7110
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
6849
7111
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -6855,7 +7117,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6855
7117
|
nodesAdded++;
|
|
6856
7118
|
}
|
|
6857
7119
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
6858
|
-
const confidence = (0,
|
|
7120
|
+
const confidence = (0, import_types22.confidenceForExtracted)(ep.confidenceKind);
|
|
6859
7121
|
const relFile = toPosix2(ep.evidence.file);
|
|
6860
7122
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
6861
7123
|
graph,
|
|
@@ -6865,7 +7127,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6865
7127
|
);
|
|
6866
7128
|
nodesAdded += n;
|
|
6867
7129
|
edgesAdded += e;
|
|
6868
|
-
if (!(0,
|
|
7130
|
+
if (!(0, import_types22.passesExtractedFloor)(confidence)) {
|
|
6869
7131
|
noteExtractedDropped({
|
|
6870
7132
|
source: fileNodeId,
|
|
6871
7133
|
target: ep.infraId,
|
|
@@ -6885,7 +7147,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6885
7147
|
source: fileNodeId,
|
|
6886
7148
|
target: ep.infraId,
|
|
6887
7149
|
type: edgeType,
|
|
6888
|
-
provenance:
|
|
7150
|
+
provenance: import_types22.Provenance.EXTRACTED,
|
|
6889
7151
|
confidence,
|
|
6890
7152
|
evidence: ep.evidence
|
|
6891
7153
|
};
|
|
@@ -6911,16 +7173,16 @@ init_cjs_shims();
|
|
|
6911
7173
|
|
|
6912
7174
|
// src/extract/infra/docker-compose.ts
|
|
6913
7175
|
init_cjs_shims();
|
|
6914
|
-
var
|
|
6915
|
-
var
|
|
7176
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
7177
|
+
var import_types24 = require("@neat.is/types");
|
|
6916
7178
|
|
|
6917
7179
|
// src/extract/infra/shared.ts
|
|
6918
7180
|
init_cjs_shims();
|
|
6919
|
-
var
|
|
7181
|
+
var import_types23 = require("@neat.is/types");
|
|
6920
7182
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
6921
7183
|
return {
|
|
6922
|
-
id: (0,
|
|
6923
|
-
type:
|
|
7184
|
+
id: (0, import_types23.infraId)(kind, name),
|
|
7185
|
+
type: import_types23.NodeType.InfraNode,
|
|
6924
7186
|
name,
|
|
6925
7187
|
provider,
|
|
6926
7188
|
kind,
|
|
@@ -6964,8 +7226,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
6964
7226
|
source: anchorId,
|
|
6965
7227
|
target: node.id,
|
|
6966
7228
|
type: edgeType,
|
|
6967
|
-
provenance:
|
|
6968
|
-
confidence: (0,
|
|
7229
|
+
provenance: import_types23.Provenance.EXTRACTED,
|
|
7230
|
+
confidence: (0, import_types23.confidenceForExtracted)("structural"),
|
|
6969
7231
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
6970
7232
|
};
|
|
6971
7233
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -6982,7 +7244,7 @@ function dependsOnList(value) {
|
|
|
6982
7244
|
}
|
|
6983
7245
|
function serviceNameToServiceNode(name, services) {
|
|
6984
7246
|
for (const s of services) {
|
|
6985
|
-
if (s.node.name === name ||
|
|
7247
|
+
if (s.node.name === name || import_node_path33.default.basename(s.dir) === name) return s.node.id;
|
|
6986
7248
|
}
|
|
6987
7249
|
return null;
|
|
6988
7250
|
}
|
|
@@ -6991,7 +7253,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6991
7253
|
let edgesAdded = 0;
|
|
6992
7254
|
let composePath = null;
|
|
6993
7255
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
6994
|
-
const abs =
|
|
7256
|
+
const abs = import_node_path33.default.join(scanPath, name);
|
|
6995
7257
|
if (await exists(abs)) {
|
|
6996
7258
|
composePath = abs;
|
|
6997
7259
|
break;
|
|
@@ -7004,13 +7266,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7004
7266
|
} catch (err) {
|
|
7005
7267
|
recordExtractionError(
|
|
7006
7268
|
"infra docker-compose",
|
|
7007
|
-
|
|
7269
|
+
import_node_path33.default.relative(scanPath, composePath),
|
|
7008
7270
|
err
|
|
7009
7271
|
);
|
|
7010
7272
|
return { nodesAdded, edgesAdded };
|
|
7011
7273
|
}
|
|
7012
7274
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
7013
|
-
const evidenceFile =
|
|
7275
|
+
const evidenceFile = import_node_path33.default.relative(scanPath, composePath).split(import_node_path33.default.sep).join("/");
|
|
7014
7276
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
7015
7277
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
7016
7278
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -7032,15 +7294,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7032
7294
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
7033
7295
|
const targetId = composeNameToNodeId.get(dep);
|
|
7034
7296
|
if (!targetId) continue;
|
|
7035
|
-
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId,
|
|
7297
|
+
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId, import_types24.EdgeType.DEPENDS_ON);
|
|
7036
7298
|
if (graph.hasEdge(edgeId)) continue;
|
|
7037
7299
|
const edge = {
|
|
7038
7300
|
id: edgeId,
|
|
7039
7301
|
source: sourceId,
|
|
7040
7302
|
target: targetId,
|
|
7041
|
-
type:
|
|
7042
|
-
provenance:
|
|
7043
|
-
confidence: (0,
|
|
7303
|
+
type: import_types24.EdgeType.DEPENDS_ON,
|
|
7304
|
+
provenance: import_types24.Provenance.EXTRACTED,
|
|
7305
|
+
confidence: (0, import_types24.confidenceForExtracted)("structural"),
|
|
7044
7306
|
evidence: { file: evidenceFile }
|
|
7045
7307
|
};
|
|
7046
7308
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7052,9 +7314,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7052
7314
|
|
|
7053
7315
|
// src/extract/infra/dockerfile.ts
|
|
7054
7316
|
init_cjs_shims();
|
|
7055
|
-
var
|
|
7317
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
7056
7318
|
var import_node_fs16 = require("fs");
|
|
7057
|
-
var
|
|
7319
|
+
var import_types25 = require("@neat.is/types");
|
|
7058
7320
|
function readDockerfile(content) {
|
|
7059
7321
|
let image = null;
|
|
7060
7322
|
const ports = [];
|
|
@@ -7083,7 +7345,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7083
7345
|
let nodesAdded = 0;
|
|
7084
7346
|
let edgesAdded = 0;
|
|
7085
7347
|
for (const service of services) {
|
|
7086
|
-
const dockerfilePath =
|
|
7348
|
+
const dockerfilePath = import_node_path34.default.join(service.dir, "Dockerfile");
|
|
7087
7349
|
if (!await exists(dockerfilePath)) continue;
|
|
7088
7350
|
let content;
|
|
7089
7351
|
try {
|
|
@@ -7091,7 +7353,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7091
7353
|
} catch (err) {
|
|
7092
7354
|
recordExtractionError(
|
|
7093
7355
|
"infra dockerfile",
|
|
7094
|
-
|
|
7356
|
+
import_node_path34.default.relative(scanPath, dockerfilePath),
|
|
7095
7357
|
err
|
|
7096
7358
|
);
|
|
7097
7359
|
continue;
|
|
@@ -7103,8 +7365,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7103
7365
|
graph.addNode(node.id, node);
|
|
7104
7366
|
nodesAdded++;
|
|
7105
7367
|
}
|
|
7106
|
-
const relDockerfile = toPosix2(
|
|
7107
|
-
const evidenceFile = toPosix2(
|
|
7368
|
+
const relDockerfile = toPosix2(import_node_path34.default.relative(service.dir, dockerfilePath));
|
|
7369
|
+
const evidenceFile = toPosix2(import_node_path34.default.relative(scanPath, dockerfilePath));
|
|
7108
7370
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7109
7371
|
graph,
|
|
7110
7372
|
service.pkg.name,
|
|
@@ -7113,15 +7375,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7113
7375
|
);
|
|
7114
7376
|
nodesAdded += fn;
|
|
7115
7377
|
edgesAdded += fe;
|
|
7116
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
7378
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types25.EdgeType.RUNS_ON);
|
|
7117
7379
|
if (!graph.hasEdge(edgeId)) {
|
|
7118
7380
|
const edge = {
|
|
7119
7381
|
id: edgeId,
|
|
7120
7382
|
source: fileNodeId,
|
|
7121
7383
|
target: node.id,
|
|
7122
|
-
type:
|
|
7123
|
-
provenance:
|
|
7124
|
-
confidence: (0,
|
|
7384
|
+
type: import_types25.EdgeType.RUNS_ON,
|
|
7385
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7386
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7125
7387
|
evidence: {
|
|
7126
7388
|
file: evidenceFile,
|
|
7127
7389
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -7136,15 +7398,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7136
7398
|
graph.addNode(portNode.id, portNode);
|
|
7137
7399
|
nodesAdded++;
|
|
7138
7400
|
}
|
|
7139
|
-
const portEdgeId = (0, import_types4.extractedEdgeId)(fileNodeId, portNode.id,
|
|
7401
|
+
const portEdgeId = (0, import_types4.extractedEdgeId)(fileNodeId, portNode.id, import_types25.EdgeType.CONNECTS_TO);
|
|
7140
7402
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
7141
7403
|
const portEdge = {
|
|
7142
7404
|
id: portEdgeId,
|
|
7143
7405
|
source: fileNodeId,
|
|
7144
7406
|
target: portNode.id,
|
|
7145
|
-
type:
|
|
7146
|
-
provenance:
|
|
7147
|
-
confidence: (0,
|
|
7407
|
+
type: import_types25.EdgeType.CONNECTS_TO,
|
|
7408
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7409
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7148
7410
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
7149
7411
|
};
|
|
7150
7412
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -7157,8 +7419,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7157
7419
|
// src/extract/infra/terraform.ts
|
|
7158
7420
|
init_cjs_shims();
|
|
7159
7421
|
var import_node_fs17 = require("fs");
|
|
7160
|
-
var
|
|
7161
|
-
var
|
|
7422
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
7423
|
+
var import_types26 = require("@neat.is/types");
|
|
7162
7424
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
7163
7425
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
7164
7426
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -7168,11 +7430,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
7168
7430
|
for (const entry of entries) {
|
|
7169
7431
|
if (entry.isDirectory()) {
|
|
7170
7432
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
7171
|
-
const child =
|
|
7433
|
+
const child = import_node_path35.default.join(start, entry.name);
|
|
7172
7434
|
if (await isPythonVenvDir(child)) continue;
|
|
7173
7435
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
7174
7436
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
7175
|
-
out.push(
|
|
7437
|
+
out.push(import_node_path35.default.join(start, entry.name));
|
|
7176
7438
|
}
|
|
7177
7439
|
}
|
|
7178
7440
|
return out;
|
|
@@ -7204,7 +7466,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7204
7466
|
const files = await walkTfFiles(scanPath);
|
|
7205
7467
|
for (const file of files) {
|
|
7206
7468
|
const content = await import_node_fs17.promises.readFile(file, "utf8");
|
|
7207
|
-
const evidenceFile = toPosix2(
|
|
7469
|
+
const evidenceFile = toPosix2(import_node_path35.default.relative(scanPath, file));
|
|
7208
7470
|
const resources = [];
|
|
7209
7471
|
const byKey = /* @__PURE__ */ new Map();
|
|
7210
7472
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -7239,16 +7501,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7239
7501
|
if (!target) continue;
|
|
7240
7502
|
if (seen.has(target.nodeId)) continue;
|
|
7241
7503
|
seen.add(target.nodeId);
|
|
7242
|
-
const edgeId = (0, import_types4.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
7504
|
+
const edgeId = (0, import_types4.extractedEdgeId)(resource.nodeId, target.nodeId, import_types26.EdgeType.DEPENDS_ON);
|
|
7243
7505
|
if (graph.hasEdge(edgeId)) continue;
|
|
7244
7506
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
7245
7507
|
const edge = {
|
|
7246
7508
|
id: edgeId,
|
|
7247
7509
|
source: resource.nodeId,
|
|
7248
7510
|
target: target.nodeId,
|
|
7249
|
-
type:
|
|
7250
|
-
provenance:
|
|
7251
|
-
confidence: (0,
|
|
7511
|
+
type: import_types26.EdgeType.DEPENDS_ON,
|
|
7512
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7513
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7252
7514
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
7253
7515
|
};
|
|
7254
7516
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7262,7 +7524,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7262
7524
|
// src/extract/infra/k8s.ts
|
|
7263
7525
|
init_cjs_shims();
|
|
7264
7526
|
var import_node_fs18 = require("fs");
|
|
7265
|
-
var
|
|
7527
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
7266
7528
|
var import_yaml3 = require("yaml");
|
|
7267
7529
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
7268
7530
|
Service: "k8s-service",
|
|
@@ -7280,11 +7542,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
7280
7542
|
for (const entry of entries) {
|
|
7281
7543
|
if (entry.isDirectory()) {
|
|
7282
7544
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
7283
|
-
const child =
|
|
7545
|
+
const child = import_node_path36.default.join(start, entry.name);
|
|
7284
7546
|
if (await isPythonVenvDir(child)) continue;
|
|
7285
7547
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
7286
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
7287
|
-
out.push(
|
|
7548
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path36.default.extname(entry.name))) {
|
|
7549
|
+
out.push(import_node_path36.default.join(start, entry.name));
|
|
7288
7550
|
}
|
|
7289
7551
|
}
|
|
7290
7552
|
return out;
|
|
@@ -7318,13 +7580,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
7318
7580
|
// src/extract/infra/cloudflare.ts
|
|
7319
7581
|
init_cjs_shims();
|
|
7320
7582
|
var import_node_fs19 = require("fs");
|
|
7321
|
-
var
|
|
7583
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
7322
7584
|
var import_smol_toml2 = require("smol-toml");
|
|
7323
|
-
var
|
|
7585
|
+
var import_types27 = require("@neat.is/types");
|
|
7324
7586
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
7325
7587
|
async function readWranglerConfig(dir) {
|
|
7326
7588
|
for (const filename of WRANGLER_FILENAMES) {
|
|
7327
|
-
const abs =
|
|
7589
|
+
const abs = import_node_path37.default.join(dir, filename);
|
|
7328
7590
|
if (!await exists(abs)) continue;
|
|
7329
7591
|
const raw = await import_node_fs19.promises.readFile(abs, "utf8");
|
|
7330
7592
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7368,8 +7630,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
7368
7630
|
source: anchorId,
|
|
7369
7631
|
target: node.id,
|
|
7370
7632
|
type: edgeType,
|
|
7371
|
-
provenance:
|
|
7372
|
-
confidence: (0,
|
|
7633
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7634
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7373
7635
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
7374
7636
|
};
|
|
7375
7637
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7387,11 +7649,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7387
7649
|
try {
|
|
7388
7650
|
read = await readWranglerConfig(service.dir);
|
|
7389
7651
|
} catch (err) {
|
|
7390
|
-
recordExtractionError("infra cloudflare",
|
|
7652
|
+
recordExtractionError("infra cloudflare", import_node_path37.default.relative(scanPath, service.dir), err);
|
|
7391
7653
|
continue;
|
|
7392
7654
|
}
|
|
7393
7655
|
if (!read || !read.config.name) continue;
|
|
7394
|
-
const evidenceFile = toPosix2(
|
|
7656
|
+
const evidenceFile = toPosix2(import_node_path37.default.relative(scanPath, import_node_path37.default.join(service.dir, read.relFile)));
|
|
7395
7657
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
7396
7658
|
}
|
|
7397
7659
|
for (const worker of discovered) {
|
|
@@ -7403,7 +7665,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7403
7665
|
}
|
|
7404
7666
|
let anchorId = service.node.id;
|
|
7405
7667
|
if (config.main) {
|
|
7406
|
-
const entryRelPath = toPosix2(
|
|
7668
|
+
const entryRelPath = toPosix2(import_node_path37.default.normalize(config.main));
|
|
7407
7669
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7408
7670
|
graph,
|
|
7409
7671
|
service.pkg.name,
|
|
@@ -7430,15 +7692,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7430
7692
|
nodesAdded++;
|
|
7431
7693
|
}
|
|
7432
7694
|
if (runtimeNode.id !== anchorId) {
|
|
7433
|
-
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
7695
|
+
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id, import_types27.EdgeType.RUNS_ON);
|
|
7434
7696
|
if (!graph.hasEdge(runsOnId)) {
|
|
7435
7697
|
const edge = {
|
|
7436
7698
|
id: runsOnId,
|
|
7437
7699
|
source: anchorId,
|
|
7438
7700
|
target: runtimeNode.id,
|
|
7439
|
-
type:
|
|
7440
|
-
provenance:
|
|
7441
|
-
confidence: (0,
|
|
7701
|
+
type: import_types27.EdgeType.RUNS_ON,
|
|
7702
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7703
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7442
7704
|
evidence: {
|
|
7443
7705
|
file: evidenceFile,
|
|
7444
7706
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -7452,7 +7714,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7452
7714
|
const result = addResourceEdge(
|
|
7453
7715
|
graph,
|
|
7454
7716
|
anchorId,
|
|
7455
|
-
|
|
7717
|
+
import_types27.EdgeType.CONNECTS_TO,
|
|
7456
7718
|
"cloudflare-route",
|
|
7457
7719
|
route,
|
|
7458
7720
|
evidenceFile,
|
|
@@ -7476,7 +7738,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7476
7738
|
const result = addResourceEdge(
|
|
7477
7739
|
graph,
|
|
7478
7740
|
anchorId,
|
|
7479
|
-
|
|
7741
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7480
7742
|
group.kind,
|
|
7481
7743
|
name,
|
|
7482
7744
|
evidenceFile,
|
|
@@ -7490,7 +7752,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7490
7752
|
const result = addResourceEdge(
|
|
7491
7753
|
graph,
|
|
7492
7754
|
anchorId,
|
|
7493
|
-
|
|
7755
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7494
7756
|
"cloudflare-cron",
|
|
7495
7757
|
cron,
|
|
7496
7758
|
evidenceFile,
|
|
@@ -7503,7 +7765,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7503
7765
|
const result = addResourceEdge(
|
|
7504
7766
|
graph,
|
|
7505
7767
|
anchorId,
|
|
7506
|
-
|
|
7768
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7507
7769
|
"cloudflare-env-var",
|
|
7508
7770
|
varName,
|
|
7509
7771
|
evidenceFile,
|
|
@@ -7516,15 +7778,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7516
7778
|
if (!svc.service) continue;
|
|
7517
7779
|
const target = workerIndex.get(svc.service);
|
|
7518
7780
|
if (target && target.anchorId !== anchorId) {
|
|
7519
|
-
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId,
|
|
7781
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId, import_types27.EdgeType.CALLS);
|
|
7520
7782
|
if (!graph.hasEdge(edgeId)) {
|
|
7521
7783
|
const edge = {
|
|
7522
7784
|
id: edgeId,
|
|
7523
7785
|
source: anchorId,
|
|
7524
7786
|
target: target.anchorId,
|
|
7525
|
-
type:
|
|
7526
|
-
provenance:
|
|
7527
|
-
confidence: (0,
|
|
7787
|
+
type: import_types27.EdgeType.CALLS,
|
|
7788
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7789
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7528
7790
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
7529
7791
|
};
|
|
7530
7792
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7535,7 +7797,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7535
7797
|
const result = addResourceEdge(
|
|
7536
7798
|
graph,
|
|
7537
7799
|
anchorId,
|
|
7538
|
-
|
|
7800
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7539
7801
|
"cloudflare-service-binding",
|
|
7540
7802
|
svc.service,
|
|
7541
7803
|
evidenceFile,
|
|
@@ -7551,12 +7813,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7551
7813
|
// src/extract/infra/vercel.ts
|
|
7552
7814
|
init_cjs_shims();
|
|
7553
7815
|
var import_node_fs20 = require("fs");
|
|
7554
|
-
var
|
|
7555
|
-
var
|
|
7816
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7817
|
+
var import_types28 = require("@neat.is/types");
|
|
7556
7818
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
7557
7819
|
async function readVercelConfig(dir) {
|
|
7558
7820
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
7559
|
-
const abs =
|
|
7821
|
+
const abs = import_node_path38.default.join(dir, filename);
|
|
7560
7822
|
if (!await exists(abs)) continue;
|
|
7561
7823
|
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
7562
7824
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7565,7 +7827,7 @@ async function readVercelConfig(dir) {
|
|
|
7565
7827
|
return null;
|
|
7566
7828
|
}
|
|
7567
7829
|
async function readLinkedProjectName(dir) {
|
|
7568
|
-
const abs =
|
|
7830
|
+
const abs = import_node_path38.default.join(dir, ".vercel", "project.json");
|
|
7569
7831
|
if (!await exists(abs)) return void 0;
|
|
7570
7832
|
const parsed = JSON.parse(await import_node_fs20.promises.readFile(abs, "utf8"));
|
|
7571
7833
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -7583,7 +7845,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7583
7845
|
read = await readVercelConfig(service.dir);
|
|
7584
7846
|
projectName = await readLinkedProjectName(service.dir);
|
|
7585
7847
|
} catch (err) {
|
|
7586
|
-
recordExtractionError("infra vercel",
|
|
7848
|
+
recordExtractionError("infra vercel", import_node_path38.default.relative(scanPath, service.dir), err);
|
|
7587
7849
|
continue;
|
|
7588
7850
|
}
|
|
7589
7851
|
if (!read && !projectName) continue;
|
|
@@ -7599,7 +7861,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7599
7861
|
const anchorId = service.node.id;
|
|
7600
7862
|
if (!read) continue;
|
|
7601
7863
|
const { config, relFile, raw } = read;
|
|
7602
|
-
const evidenceFile = toPosix2(
|
|
7864
|
+
const evidenceFile = toPosix2(import_node_path38.default.relative(scanPath, import_node_path38.default.join(service.dir, relFile)));
|
|
7603
7865
|
const add = (edgeType, kind, name) => {
|
|
7604
7866
|
if (!name) return;
|
|
7605
7867
|
const result = emitPlatformResourceEdge(
|
|
@@ -7615,12 +7877,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7615
7877
|
nodesAdded += result.nodesAdded;
|
|
7616
7878
|
edgesAdded += result.edgesAdded;
|
|
7617
7879
|
};
|
|
7618
|
-
add(
|
|
7619
|
-
for (const cron of config.crons ?? []) add(
|
|
7620
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
7621
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
7880
|
+
add(import_types28.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
7881
|
+
for (const cron of config.crons ?? []) add(import_types28.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
7882
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types28.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7883
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types28.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7622
7884
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
7623
|
-
add(
|
|
7885
|
+
add(import_types28.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
7624
7886
|
}
|
|
7625
7887
|
}
|
|
7626
7888
|
return { nodesAdded, edgesAdded };
|
|
@@ -7629,13 +7891,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7629
7891
|
// src/extract/infra/railway.ts
|
|
7630
7892
|
init_cjs_shims();
|
|
7631
7893
|
var import_node_fs21 = require("fs");
|
|
7632
|
-
var
|
|
7894
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7633
7895
|
var import_smol_toml3 = require("smol-toml");
|
|
7634
|
-
var
|
|
7896
|
+
var import_types29 = require("@neat.is/types");
|
|
7635
7897
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
7636
7898
|
async function readRailwayConfig(dir) {
|
|
7637
7899
|
for (const filename of RAILWAY_FILENAMES) {
|
|
7638
|
-
const abs =
|
|
7900
|
+
const abs = import_node_path39.default.join(dir, filename);
|
|
7639
7901
|
if (!await exists(abs)) continue;
|
|
7640
7902
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
7641
7903
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7651,7 +7913,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7651
7913
|
try {
|
|
7652
7914
|
read = await readRailwayConfig(service.dir);
|
|
7653
7915
|
} catch (err) {
|
|
7654
|
-
recordExtractionError("infra railway",
|
|
7916
|
+
recordExtractionError("infra railway", import_node_path39.default.relative(scanPath, service.dir), err);
|
|
7655
7917
|
continue;
|
|
7656
7918
|
}
|
|
7657
7919
|
if (!read) continue;
|
|
@@ -7661,7 +7923,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7661
7923
|
}
|
|
7662
7924
|
const anchorId = service.node.id;
|
|
7663
7925
|
const { config, relFile, raw } = read;
|
|
7664
|
-
const evidenceFile = toPosix2(
|
|
7926
|
+
const evidenceFile = toPosix2(import_node_path39.default.relative(scanPath, import_node_path39.default.join(service.dir, relFile)));
|
|
7665
7927
|
const add = (edgeType, kind, name) => {
|
|
7666
7928
|
if (!name) return;
|
|
7667
7929
|
const result = emitPlatformResourceEdge(
|
|
@@ -7677,9 +7939,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7677
7939
|
nodesAdded += result.nodesAdded;
|
|
7678
7940
|
edgesAdded += result.edgesAdded;
|
|
7679
7941
|
};
|
|
7680
|
-
add(
|
|
7681
|
-
add(
|
|
7682
|
-
add(
|
|
7942
|
+
add(import_types29.EdgeType.RUNS_ON, "railway", "railway");
|
|
7943
|
+
add(import_types29.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
7944
|
+
add(import_types29.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
7683
7945
|
}
|
|
7684
7946
|
return { nodesAdded, edgesAdded };
|
|
7685
7947
|
}
|
|
@@ -7687,12 +7949,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7687
7949
|
// src/extract/infra/supabase.ts
|
|
7688
7950
|
init_cjs_shims();
|
|
7689
7951
|
var import_node_fs22 = require("fs");
|
|
7690
|
-
var
|
|
7952
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7691
7953
|
var import_smol_toml4 = require("smol-toml");
|
|
7692
|
-
var
|
|
7954
|
+
var import_types30 = require("@neat.is/types");
|
|
7693
7955
|
async function readSupabaseConfig(dir) {
|
|
7694
|
-
const relFile =
|
|
7695
|
-
const abs =
|
|
7956
|
+
const relFile = import_node_path40.default.join("supabase", "config.toml");
|
|
7957
|
+
const abs = import_node_path40.default.join(dir, relFile);
|
|
7696
7958
|
if (!await exists(abs)) return null;
|
|
7697
7959
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
7698
7960
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -7706,7 +7968,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7706
7968
|
try {
|
|
7707
7969
|
read = await readSupabaseConfig(service.dir);
|
|
7708
7970
|
} catch (err) {
|
|
7709
|
-
recordExtractionError("infra supabase",
|
|
7971
|
+
recordExtractionError("infra supabase", import_node_path40.default.relative(scanPath, service.dir), err);
|
|
7710
7972
|
continue;
|
|
7711
7973
|
}
|
|
7712
7974
|
if (!read) continue;
|
|
@@ -7721,7 +7983,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7721
7983
|
});
|
|
7722
7984
|
}
|
|
7723
7985
|
const anchorId = service.node.id;
|
|
7724
|
-
const evidenceFile = toPosix2(
|
|
7986
|
+
const evidenceFile = toPosix2(import_node_path40.default.relative(scanPath, import_node_path40.default.join(service.dir, relFile)));
|
|
7725
7987
|
const add = (edgeType, kind, name) => {
|
|
7726
7988
|
if (!name) return;
|
|
7727
7989
|
const result = emitPlatformResourceEdge(
|
|
@@ -7737,10 +7999,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7737
7999
|
nodesAdded += result.nodesAdded;
|
|
7738
8000
|
edgesAdded += result.edgesAdded;
|
|
7739
8001
|
};
|
|
7740
|
-
add(
|
|
7741
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
7742
|
-
if (config.storage) add(
|
|
7743
|
-
if (config.auth) add(
|
|
8002
|
+
add(import_types30.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
8003
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types30.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
8004
|
+
if (config.storage) add(import_types30.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
8005
|
+
if (config.auth) add(import_types30.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
7744
8006
|
}
|
|
7745
8007
|
return { nodesAdded, edgesAdded };
|
|
7746
8008
|
}
|
|
@@ -7762,17 +8024,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
7762
8024
|
}
|
|
7763
8025
|
|
|
7764
8026
|
// src/extract/index.ts
|
|
7765
|
-
var
|
|
8027
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
7766
8028
|
|
|
7767
8029
|
// src/extract/retire.ts
|
|
7768
8030
|
init_cjs_shims();
|
|
7769
8031
|
var import_node_fs23 = require("fs");
|
|
7770
|
-
var
|
|
7771
|
-
var
|
|
8032
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
8033
|
+
var import_types31 = require("@neat.is/types");
|
|
7772
8034
|
function dropOrphanedFileNodes(graph) {
|
|
7773
8035
|
const orphans = [];
|
|
7774
8036
|
graph.forEachNode((id, attrs) => {
|
|
7775
|
-
if (attrs.type !==
|
|
8037
|
+
if (attrs.type !== import_types31.NodeType.FileNode) return;
|
|
7776
8038
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
7777
8039
|
orphans.push(id);
|
|
7778
8040
|
}
|
|
@@ -7785,14 +8047,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
7785
8047
|
const bases = [scanPath, ...serviceDirs];
|
|
7786
8048
|
graph.forEachEdge((id, attrs) => {
|
|
7787
8049
|
const edge = attrs;
|
|
7788
|
-
if (edge.provenance !==
|
|
8050
|
+
if (edge.provenance !== import_types31.Provenance.EXTRACTED) return;
|
|
7789
8051
|
const evidenceFile = edge.evidence?.file;
|
|
7790
8052
|
if (!evidenceFile) return;
|
|
7791
|
-
if (
|
|
8053
|
+
if (import_node_path41.default.isAbsolute(evidenceFile)) {
|
|
7792
8054
|
if (!(0, import_node_fs23.existsSync)(evidenceFile)) toDrop.push(id);
|
|
7793
8055
|
return;
|
|
7794
8056
|
}
|
|
7795
|
-
const found = bases.some((base) => (0, import_node_fs23.existsSync)(
|
|
8057
|
+
const found = bases.some((base) => (0, import_node_fs23.existsSync)(import_node_path41.default.join(base, evidenceFile)));
|
|
7796
8058
|
if (!found) toDrop.push(id);
|
|
7797
8059
|
});
|
|
7798
8060
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -7834,7 +8096,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7834
8096
|
}
|
|
7835
8097
|
const droppedEntries = drainDroppedExtracted();
|
|
7836
8098
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
7837
|
-
const rejectedPath =
|
|
8099
|
+
const rejectedPath = import_node_path42.default.join(import_node_path42.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
7838
8100
|
try {
|
|
7839
8101
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
7840
8102
|
} catch (err) {
|
|
@@ -7869,8 +8131,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7869
8131
|
// src/persist.ts
|
|
7870
8132
|
init_cjs_shims();
|
|
7871
8133
|
var import_node_fs24 = require("fs");
|
|
7872
|
-
var
|
|
7873
|
-
var
|
|
8134
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
8135
|
+
var import_types32 = require("@neat.is/types");
|
|
7874
8136
|
var SCHEMA_VERSION = 4;
|
|
7875
8137
|
function migrateV1ToV2(payload) {
|
|
7876
8138
|
const nodes = payload.graph.nodes;
|
|
@@ -7892,12 +8154,12 @@ function migrateV2ToV3(payload) {
|
|
|
7892
8154
|
for (const edge of edges) {
|
|
7893
8155
|
const attrs = edge.attributes;
|
|
7894
8156
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
7895
|
-
attrs.provenance =
|
|
8157
|
+
attrs.provenance = import_types32.Provenance.OBSERVED;
|
|
7896
8158
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
7897
8159
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
7898
8160
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
7899
8161
|
if (type && source && target) {
|
|
7900
|
-
const newId = (0,
|
|
8162
|
+
const newId = (0, import_types32.observedEdgeId)(source, target, type);
|
|
7901
8163
|
attrs.id = newId;
|
|
7902
8164
|
if (edge.key) edge.key = newId;
|
|
7903
8165
|
}
|
|
@@ -7906,7 +8168,7 @@ function migrateV2ToV3(payload) {
|
|
|
7906
8168
|
return { ...payload, schemaVersion: 3 };
|
|
7907
8169
|
}
|
|
7908
8170
|
async function ensureDir(filePath) {
|
|
7909
|
-
await import_node_fs24.promises.mkdir(
|
|
8171
|
+
await import_node_fs24.promises.mkdir(import_node_path43.default.dirname(filePath), { recursive: true });
|
|
7910
8172
|
}
|
|
7911
8173
|
async function saveGraphToDisk(graph, outPath) {
|
|
7912
8174
|
await ensureDir(outPath);
|
|
@@ -7989,19 +8251,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
7989
8251
|
init_cjs_shims();
|
|
7990
8252
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
7991
8253
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
7992
|
-
var
|
|
8254
|
+
var import_types35 = require("@neat.is/types");
|
|
7993
8255
|
|
|
7994
8256
|
// src/extend/index.ts
|
|
7995
8257
|
init_cjs_shims();
|
|
7996
8258
|
var import_node_fs26 = require("fs");
|
|
7997
|
-
var
|
|
8259
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
7998
8260
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
7999
8261
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
8000
8262
|
|
|
8001
8263
|
// src/installers/package-manager.ts
|
|
8002
8264
|
init_cjs_shims();
|
|
8003
8265
|
var import_node_fs25 = require("fs");
|
|
8004
|
-
var
|
|
8266
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8005
8267
|
var import_node_child_process = require("child_process");
|
|
8006
8268
|
var LOCKFILE_PRIORITY = [
|
|
8007
8269
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -8023,22 +8285,22 @@ async function exists2(p) {
|
|
|
8023
8285
|
}
|
|
8024
8286
|
}
|
|
8025
8287
|
async function detectPackageManager(serviceDir) {
|
|
8026
|
-
let dir =
|
|
8288
|
+
let dir = import_node_path44.default.resolve(serviceDir);
|
|
8027
8289
|
const stops = /* @__PURE__ */ new Set();
|
|
8028
8290
|
for (let i = 0; i < 64; i++) {
|
|
8029
8291
|
if (stops.has(dir)) break;
|
|
8030
8292
|
stops.add(dir);
|
|
8031
8293
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
8032
|
-
const lockPath =
|
|
8294
|
+
const lockPath = import_node_path44.default.join(dir, candidate.lockfile);
|
|
8033
8295
|
if (await exists2(lockPath)) {
|
|
8034
8296
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
8035
8297
|
}
|
|
8036
8298
|
}
|
|
8037
|
-
const parent =
|
|
8299
|
+
const parent = import_node_path44.default.dirname(dir);
|
|
8038
8300
|
if (parent === dir) break;
|
|
8039
8301
|
dir = parent;
|
|
8040
8302
|
}
|
|
8041
|
-
return { pm: "npm", cwd:
|
|
8303
|
+
return { pm: "npm", cwd: import_node_path44.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
8042
8304
|
}
|
|
8043
8305
|
async function runPackageManagerInstall(cmd) {
|
|
8044
8306
|
return new Promise((resolve) => {
|
|
@@ -8087,7 +8349,7 @@ async function fileExists2(p) {
|
|
|
8087
8349
|
}
|
|
8088
8350
|
}
|
|
8089
8351
|
async function readPackageJson(scanPath) {
|
|
8090
|
-
const pkgPath =
|
|
8352
|
+
const pkgPath = import_node_path45.default.join(scanPath, "package.json");
|
|
8091
8353
|
const raw = await import_node_fs26.promises.readFile(pkgPath, "utf8");
|
|
8092
8354
|
return JSON.parse(raw);
|
|
8093
8355
|
}
|
|
@@ -8101,27 +8363,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
8101
8363
|
]);
|
|
8102
8364
|
async function findHookFiles(scanPath) {
|
|
8103
8365
|
const found = [];
|
|
8104
|
-
const
|
|
8366
|
+
const walk4 = async (dir) => {
|
|
8105
8367
|
const entries = await import_node_fs26.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
8106
8368
|
for (const entry of entries) {
|
|
8107
8369
|
if (entry.isDirectory()) {
|
|
8108
8370
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
8109
|
-
await
|
|
8371
|
+
await walk4(import_node_path45.default.join(dir, entry.name));
|
|
8110
8372
|
} else if (entry.isFile()) {
|
|
8111
8373
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
8112
|
-
const rel =
|
|
8113
|
-
found.push(rel.split(
|
|
8374
|
+
const rel = import_node_path45.default.relative(scanPath, import_node_path45.default.join(dir, entry.name));
|
|
8375
|
+
found.push(rel.split(import_node_path45.default.sep).join("/"));
|
|
8114
8376
|
}
|
|
8115
8377
|
}
|
|
8116
8378
|
}
|
|
8117
8379
|
};
|
|
8118
|
-
await
|
|
8380
|
+
await walk4(scanPath);
|
|
8119
8381
|
return found.sort();
|
|
8120
8382
|
}
|
|
8121
8383
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
8122
8384
|
let fallback = null;
|
|
8123
8385
|
for (const file of hookFiles) {
|
|
8124
|
-
const content = await import_node_fs26.promises.readFile(
|
|
8386
|
+
const content = await import_node_fs26.promises.readFile(import_node_path45.default.join(scanPath, file), "utf8");
|
|
8125
8387
|
const patched = splicedContent(content, snippet2);
|
|
8126
8388
|
if (patched !== null) return { file, content, patched };
|
|
8127
8389
|
if (fallback === null) fallback = { file, content };
|
|
@@ -8129,11 +8391,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
8129
8391
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
8130
8392
|
}
|
|
8131
8393
|
function extendLogPath() {
|
|
8132
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
8394
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path45.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
8133
8395
|
}
|
|
8134
8396
|
async function appendExtendLog(entry) {
|
|
8135
8397
|
const logPath = extendLogPath();
|
|
8136
|
-
await import_node_fs26.promises.mkdir(
|
|
8398
|
+
await import_node_fs26.promises.mkdir(import_node_path45.default.dirname(logPath), { recursive: true });
|
|
8137
8399
|
await import_node_fs26.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
8138
8400
|
}
|
|
8139
8401
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -8192,7 +8454,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
8192
8454
|
}
|
|
8193
8455
|
async function describeProjectInstrumentation(ctx) {
|
|
8194
8456
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
8195
|
-
const envNeat = await fileExists2(
|
|
8457
|
+
const envNeat = await fileExists2(import_node_path45.default.join(ctx.scanPath, ".env.neat"));
|
|
8196
8458
|
const registryInstrPackages = new Set(
|
|
8197
8459
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
8198
8460
|
);
|
|
@@ -8214,7 +8476,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
8214
8476
|
);
|
|
8215
8477
|
}
|
|
8216
8478
|
for (const file of hookFiles) {
|
|
8217
|
-
const content = await import_node_fs26.promises.readFile(
|
|
8479
|
+
const content = await import_node_fs26.promises.readFile(import_node_path45.default.join(ctx.scanPath, file), "utf8");
|
|
8218
8480
|
if (content.includes(args.registration_snippet)) {
|
|
8219
8481
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
8220
8482
|
}
|
|
@@ -8226,10 +8488,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
8226
8488
|
);
|
|
8227
8489
|
}
|
|
8228
8490
|
const primaryFile = primary.file;
|
|
8229
|
-
const primaryPath =
|
|
8491
|
+
const primaryPath = import_node_path45.default.join(ctx.scanPath, primaryFile);
|
|
8230
8492
|
const filesTouched = [];
|
|
8231
8493
|
const depsAdded = [];
|
|
8232
|
-
const pkgPath =
|
|
8494
|
+
const pkgPath = import_node_path45.default.join(ctx.scanPath, "package.json");
|
|
8233
8495
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
8234
8496
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
8235
8497
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -8268,7 +8530,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
8268
8530
|
};
|
|
8269
8531
|
}
|
|
8270
8532
|
for (const file of hookFiles) {
|
|
8271
|
-
const content = await import_node_fs26.promises.readFile(
|
|
8533
|
+
const content = await import_node_fs26.promises.readFile(import_node_path45.default.join(ctx.scanPath, file), "utf8");
|
|
8272
8534
|
if (content.includes(args.registration_snippet)) {
|
|
8273
8535
|
return {
|
|
8274
8536
|
library: args.library,
|
|
@@ -8309,7 +8571,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
8309
8571
|
if (!match) {
|
|
8310
8572
|
return { undone: false, message: "no apply found for library" };
|
|
8311
8573
|
}
|
|
8312
|
-
const pkgPath =
|
|
8574
|
+
const pkgPath = import_node_path45.default.join(ctx.scanPath, "package.json");
|
|
8313
8575
|
if (await fileExists2(pkgPath)) {
|
|
8314
8576
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
8315
8577
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -8320,7 +8582,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
8320
8582
|
}
|
|
8321
8583
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
8322
8584
|
for (const file of hookFiles) {
|
|
8323
|
-
const filePath =
|
|
8585
|
+
const filePath = import_node_path45.default.join(ctx.scanPath, file);
|
|
8324
8586
|
const content = await import_node_fs26.promises.readFile(filePath, "utf8");
|
|
8325
8587
|
if (content.includes(match.registration_snippet)) {
|
|
8326
8588
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -8336,39 +8598,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
8336
8598
|
|
|
8337
8599
|
// src/divergences.ts
|
|
8338
8600
|
init_cjs_shims();
|
|
8339
|
-
var
|
|
8601
|
+
var import_types33 = require("@neat.is/types");
|
|
8340
8602
|
function bucketKey(source, target, type) {
|
|
8341
8603
|
return `${type}|${source}|${target}`;
|
|
8342
8604
|
}
|
|
8343
8605
|
function bucketSourceFor(graph, edge) {
|
|
8344
|
-
if (edge.type !==
|
|
8345
|
-
const parsed = (0,
|
|
8606
|
+
if (edge.type !== import_types33.EdgeType.CONNECTS_TO) return edge.source;
|
|
8607
|
+
const parsed = (0, import_types33.parseFileId)(edge.source);
|
|
8346
8608
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
8347
8609
|
const target = graph.getNodeAttributes(edge.target);
|
|
8348
|
-
if (target.type !==
|
|
8349
|
-
return (0,
|
|
8610
|
+
if (target.type !== import_types33.NodeType.DatabaseNode) return edge.source;
|
|
8611
|
+
return (0, import_types33.serviceId)(parsed.service);
|
|
8350
8612
|
}
|
|
8351
8613
|
function bucketEdges(graph) {
|
|
8352
8614
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
8353
8615
|
graph.forEachEdge((id, attrs) => {
|
|
8354
8616
|
const e = attrs;
|
|
8355
|
-
const parsed = (0,
|
|
8617
|
+
const parsed = (0, import_types33.parseEdgeId)(id);
|
|
8356
8618
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
8357
8619
|
const source = bucketSourceFor(graph, e);
|
|
8358
8620
|
const key = bucketKey(source, e.target, e.type);
|
|
8359
8621
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
8360
8622
|
switch (provenance) {
|
|
8361
|
-
case
|
|
8623
|
+
case import_types33.Provenance.EXTRACTED:
|
|
8362
8624
|
cur.extracted = e;
|
|
8363
8625
|
break;
|
|
8364
|
-
case
|
|
8626
|
+
case import_types33.Provenance.OBSERVED:
|
|
8365
8627
|
cur.observed = e;
|
|
8366
8628
|
break;
|
|
8367
|
-
case
|
|
8629
|
+
case import_types33.Provenance.INFERRED:
|
|
8368
8630
|
cur.inferred = e;
|
|
8369
8631
|
break;
|
|
8370
8632
|
default:
|
|
8371
|
-
if (e.provenance ===
|
|
8633
|
+
if (e.provenance === import_types33.Provenance.STALE) cur.stale = e;
|
|
8372
8634
|
}
|
|
8373
8635
|
buckets2.set(key, cur);
|
|
8374
8636
|
});
|
|
@@ -8377,12 +8639,12 @@ function bucketEdges(graph) {
|
|
|
8377
8639
|
function nodeIsFrontier(graph, nodeId) {
|
|
8378
8640
|
if (!graph.hasNode(nodeId)) return false;
|
|
8379
8641
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
8380
|
-
return attrs.type ===
|
|
8642
|
+
return attrs.type === import_types33.NodeType.FrontierNode;
|
|
8381
8643
|
}
|
|
8382
8644
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
8383
8645
|
if (!graph.hasNode(nodeId)) return false;
|
|
8384
8646
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
8385
|
-
return attrs.type ===
|
|
8647
|
+
return attrs.type === import_types33.NodeType.WebSocketChannelNode;
|
|
8386
8648
|
}
|
|
8387
8649
|
function clampConfidence(n) {
|
|
8388
8650
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -8402,14 +8664,14 @@ function gradedConfidence(edge) {
|
|
|
8402
8664
|
return clampConfidence(confidenceForEdge(edge));
|
|
8403
8665
|
}
|
|
8404
8666
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8667
|
+
import_types33.EdgeType.CALLS,
|
|
8668
|
+
import_types33.EdgeType.CONNECTS_TO,
|
|
8669
|
+
import_types33.EdgeType.PUBLISHES_TO,
|
|
8670
|
+
import_types33.EdgeType.CONSUMES_FROM
|
|
8409
8671
|
]);
|
|
8410
8672
|
function detectMissingDivergences(graph, bucket) {
|
|
8411
8673
|
const out = [];
|
|
8412
|
-
if (bucket.type ===
|
|
8674
|
+
if (bucket.type === import_types33.EdgeType.CONTAINS) return out;
|
|
8413
8675
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
8414
8676
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
8415
8677
|
out.push({
|
|
@@ -8450,7 +8712,7 @@ function declaredHostFor(svc) {
|
|
|
8450
8712
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
8451
8713
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8452
8714
|
const e = graph.getEdgeAttributes(edgeId);
|
|
8453
|
-
if (e.type ===
|
|
8715
|
+
if (e.type === import_types33.EdgeType.CONFIGURED_BY && e.provenance === import_types33.Provenance.EXTRACTED) {
|
|
8454
8716
|
return true;
|
|
8455
8717
|
}
|
|
8456
8718
|
}
|
|
@@ -8463,10 +8725,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
8463
8725
|
const out = [];
|
|
8464
8726
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8465
8727
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
8466
|
-
if (edge.type !==
|
|
8467
|
-
if (edge.provenance !==
|
|
8728
|
+
if (edge.type !== import_types33.EdgeType.CONNECTS_TO) continue;
|
|
8729
|
+
if (edge.provenance !== import_types33.Provenance.OBSERVED) continue;
|
|
8468
8730
|
const target = graph.getNodeAttributes(edge.target);
|
|
8469
|
-
if (target.type !==
|
|
8731
|
+
if (target.type !== import_types33.NodeType.DatabaseNode) continue;
|
|
8470
8732
|
const observedHost = target.host?.trim();
|
|
8471
8733
|
if (!observedHost) continue;
|
|
8472
8734
|
if (observedHost === declaredHost) continue;
|
|
@@ -8488,10 +8750,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
8488
8750
|
const deps = svc.dependencies ?? {};
|
|
8489
8751
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8490
8752
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
8491
|
-
if (edge.type !==
|
|
8492
|
-
if (edge.provenance !==
|
|
8753
|
+
if (edge.type !== import_types33.EdgeType.CONNECTS_TO) continue;
|
|
8754
|
+
if (edge.provenance !== import_types33.Provenance.OBSERVED) continue;
|
|
8493
8755
|
const target = graph.getNodeAttributes(edge.target);
|
|
8494
|
-
if (target.type !==
|
|
8756
|
+
if (target.type !== import_types33.NodeType.DatabaseNode) continue;
|
|
8495
8757
|
for (const pair of compatPairs()) {
|
|
8496
8758
|
if (pair.engine !== target.engine) continue;
|
|
8497
8759
|
const declared = deps[pair.driver];
|
|
@@ -8550,7 +8812,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
8550
8812
|
for (const d of all) {
|
|
8551
8813
|
if (d.type !== "host-mismatch") continue;
|
|
8552
8814
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
8553
|
-
declaredHalf.add((0,
|
|
8815
|
+
declaredHalf.add((0, import_types33.databaseId)(d.extractedHost));
|
|
8554
8816
|
}
|
|
8555
8817
|
if (observedHalf.size === 0) return all;
|
|
8556
8818
|
return all.filter((d) => {
|
|
@@ -8569,7 +8831,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8569
8831
|
}
|
|
8570
8832
|
graph.forEachNode((nodeId, attrs) => {
|
|
8571
8833
|
const n = attrs;
|
|
8572
|
-
if (n.type !==
|
|
8834
|
+
if (n.type !== import_types33.NodeType.ServiceNode) return;
|
|
8573
8835
|
const svc = n;
|
|
8574
8836
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
8575
8837
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -8603,7 +8865,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8603
8865
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
8604
8866
|
return a.target.localeCompare(b.target);
|
|
8605
8867
|
});
|
|
8606
|
-
return
|
|
8868
|
+
return import_types33.DivergenceResultSchema.parse({
|
|
8607
8869
|
divergences: filtered,
|
|
8608
8870
|
totalAffected: filtered.length,
|
|
8609
8871
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -8734,23 +8996,23 @@ function canonicalJson(value) {
|
|
|
8734
8996
|
|
|
8735
8997
|
// src/projects.ts
|
|
8736
8998
|
init_cjs_shims();
|
|
8737
|
-
var
|
|
8999
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8738
9000
|
function pathsForProject(project, baseDir) {
|
|
8739
9001
|
if (project === DEFAULT_PROJECT) {
|
|
8740
9002
|
return {
|
|
8741
|
-
snapshotPath:
|
|
8742
|
-
errorsPath:
|
|
8743
|
-
staleEventsPath:
|
|
8744
|
-
embeddingsCachePath:
|
|
8745
|
-
policyViolationsPath:
|
|
9003
|
+
snapshotPath: import_node_path46.default.join(baseDir, "graph.json"),
|
|
9004
|
+
errorsPath: import_node_path46.default.join(baseDir, "errors.ndjson"),
|
|
9005
|
+
staleEventsPath: import_node_path46.default.join(baseDir, "stale-events.ndjson"),
|
|
9006
|
+
embeddingsCachePath: import_node_path46.default.join(baseDir, "embeddings.json"),
|
|
9007
|
+
policyViolationsPath: import_node_path46.default.join(baseDir, "policy-violations.ndjson")
|
|
8746
9008
|
};
|
|
8747
9009
|
}
|
|
8748
9010
|
return {
|
|
8749
|
-
snapshotPath:
|
|
8750
|
-
errorsPath:
|
|
8751
|
-
staleEventsPath:
|
|
8752
|
-
embeddingsCachePath:
|
|
8753
|
-
policyViolationsPath:
|
|
9011
|
+
snapshotPath: import_node_path46.default.join(baseDir, `${project}.json`),
|
|
9012
|
+
errorsPath: import_node_path46.default.join(baseDir, `errors.${project}.ndjson`),
|
|
9013
|
+
staleEventsPath: import_node_path46.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
9014
|
+
embeddingsCachePath: import_node_path46.default.join(baseDir, `embeddings.${project}.json`),
|
|
9015
|
+
policyViolationsPath: import_node_path46.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
8754
9016
|
};
|
|
8755
9017
|
}
|
|
8756
9018
|
var Projects = class {
|
|
@@ -8788,23 +9050,23 @@ var Projects = class {
|
|
|
8788
9050
|
init_cjs_shims();
|
|
8789
9051
|
var import_node_fs28 = require("fs");
|
|
8790
9052
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
8791
|
-
var
|
|
8792
|
-
var
|
|
9053
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9054
|
+
var import_types34 = require("@neat.is/types");
|
|
8793
9055
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
8794
9056
|
var LOCK_RETRY_MS = 50;
|
|
8795
9057
|
function neatHome() {
|
|
8796
9058
|
const override = process.env.NEAT_HOME;
|
|
8797
|
-
if (override && override.length > 0) return
|
|
8798
|
-
return
|
|
9059
|
+
if (override && override.length > 0) return import_node_path47.default.resolve(override);
|
|
9060
|
+
return import_node_path47.default.join(import_node_os3.default.homedir(), ".neat");
|
|
8799
9061
|
}
|
|
8800
9062
|
function registryPath() {
|
|
8801
|
-
return
|
|
9063
|
+
return import_node_path47.default.join(neatHome(), "projects.json");
|
|
8802
9064
|
}
|
|
8803
9065
|
function registryLockPath() {
|
|
8804
|
-
return
|
|
9066
|
+
return import_node_path47.default.join(neatHome(), "projects.json.lock");
|
|
8805
9067
|
}
|
|
8806
9068
|
function daemonPidPath() {
|
|
8807
|
-
return
|
|
9069
|
+
return import_node_path47.default.join(neatHome(), "neatd.pid");
|
|
8808
9070
|
}
|
|
8809
9071
|
function isPidAliveDefault(pid) {
|
|
8810
9072
|
try {
|
|
@@ -8864,7 +9126,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
8864
9126
|
}
|
|
8865
9127
|
}
|
|
8866
9128
|
async function normalizeProjectPath(input) {
|
|
8867
|
-
const resolved =
|
|
9129
|
+
const resolved = import_node_path47.default.resolve(input);
|
|
8868
9130
|
try {
|
|
8869
9131
|
return await import_node_fs28.promises.realpath(resolved);
|
|
8870
9132
|
} catch {
|
|
@@ -8872,7 +9134,7 @@ async function normalizeProjectPath(input) {
|
|
|
8872
9134
|
}
|
|
8873
9135
|
}
|
|
8874
9136
|
async function writeAtomically(target, contents) {
|
|
8875
|
-
await import_node_fs28.promises.mkdir(
|
|
9137
|
+
await import_node_fs28.promises.mkdir(import_node_path47.default.dirname(target), { recursive: true });
|
|
8876
9138
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
8877
9139
|
const fd = await import_node_fs28.promises.open(tmp, "w");
|
|
8878
9140
|
try {
|
|
@@ -8885,7 +9147,7 @@ async function writeAtomically(target, contents) {
|
|
|
8885
9147
|
}
|
|
8886
9148
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
8887
9149
|
const deadline = Date.now() + timeoutMs;
|
|
8888
|
-
await import_node_fs28.promises.mkdir(
|
|
9150
|
+
await import_node_fs28.promises.mkdir(import_node_path47.default.dirname(lockPath), { recursive: true });
|
|
8889
9151
|
let probedHolder = false;
|
|
8890
9152
|
while (true) {
|
|
8891
9153
|
try {
|
|
@@ -8938,10 +9200,10 @@ async function readRegistry() {
|
|
|
8938
9200
|
throw err;
|
|
8939
9201
|
}
|
|
8940
9202
|
const parsed = JSON.parse(raw);
|
|
8941
|
-
return
|
|
9203
|
+
return import_types34.RegistryFileSchema.parse(parsed);
|
|
8942
9204
|
}
|
|
8943
9205
|
async function writeRegistry(reg) {
|
|
8944
|
-
const validated =
|
|
9206
|
+
const validated = import_types34.RegistryFileSchema.parse(reg);
|
|
8945
9207
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
8946
9208
|
}
|
|
8947
9209
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -9136,7 +9398,7 @@ init_auth();
|
|
|
9136
9398
|
// src/connectors-config.ts
|
|
9137
9399
|
init_cjs_shims();
|
|
9138
9400
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
9139
|
-
var
|
|
9401
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
9140
9402
|
var import_node_fs29 = require("fs");
|
|
9141
9403
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
9142
9404
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -9151,11 +9413,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
9151
9413
|
};
|
|
9152
9414
|
function neatHome2() {
|
|
9153
9415
|
const override = process.env.NEAT_HOME;
|
|
9154
|
-
if (override && override.length > 0) return
|
|
9155
|
-
return
|
|
9416
|
+
if (override && override.length > 0) return import_node_path48.default.resolve(override);
|
|
9417
|
+
return import_node_path48.default.join(import_node_os4.default.homedir(), ".neat");
|
|
9156
9418
|
}
|
|
9157
9419
|
function connectorsConfigPath(home = neatHome2()) {
|
|
9158
|
-
return
|
|
9420
|
+
return import_node_path48.default.join(home, "connectors.json");
|
|
9159
9421
|
}
|
|
9160
9422
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
9161
9423
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -9491,11 +9753,11 @@ function registerRoutes(scope, ctx) {
|
|
|
9491
9753
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
9492
9754
|
const parsed = [];
|
|
9493
9755
|
for (const c of candidates) {
|
|
9494
|
-
const r =
|
|
9756
|
+
const r = import_types35.DivergenceTypeSchema.safeParse(c);
|
|
9495
9757
|
if (!r.success) {
|
|
9496
9758
|
return reply.code(400).send({
|
|
9497
9759
|
error: `unknown divergence type "${c}"`,
|
|
9498
|
-
allowed:
|
|
9760
|
+
allowed: import_types35.DivergenceTypeSchema.options
|
|
9499
9761
|
});
|
|
9500
9762
|
}
|
|
9501
9763
|
parsed.push(r.data);
|
|
@@ -9766,7 +10028,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9766
10028
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
9767
10029
|
let violations = await log.readAll();
|
|
9768
10030
|
if (req.query.severity) {
|
|
9769
|
-
const sev =
|
|
10031
|
+
const sev = import_types35.PolicySeveritySchema.safeParse(req.query.severity);
|
|
9770
10032
|
if (!sev.success) {
|
|
9771
10033
|
return reply.code(400).send({
|
|
9772
10034
|
error: "invalid severity",
|
|
@@ -9805,7 +10067,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9805
10067
|
scope.post("/policies/check", async (req, reply) => {
|
|
9806
10068
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
9807
10069
|
if (!proj) return;
|
|
9808
|
-
const parsed =
|
|
10070
|
+
const parsed = import_types35.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
9809
10071
|
if (!parsed.success) {
|
|
9810
10072
|
return reply.code(400).send({
|
|
9811
10073
|
error: "invalid /policies/check body",
|
|
@@ -10107,21 +10369,21 @@ init_otel_grpc();
|
|
|
10107
10369
|
// src/daemon.ts
|
|
10108
10370
|
init_cjs_shims();
|
|
10109
10371
|
var import_node_fs31 = require("fs");
|
|
10110
|
-
var
|
|
10372
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
10111
10373
|
var import_node_module = require("module");
|
|
10112
10374
|
init_otel();
|
|
10113
10375
|
|
|
10114
10376
|
// src/connectors/index.ts
|
|
10115
10377
|
init_cjs_shims();
|
|
10116
|
-
var
|
|
10378
|
+
var import_types36 = require("@neat.is/types");
|
|
10117
10379
|
var NO_ENV = "unknown";
|
|
10118
10380
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
10119
10381
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
10120
10382
|
const sites = [];
|
|
10121
10383
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
10122
10384
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
10123
|
-
if (edge.provenance !==
|
|
10124
|
-
const parsed = (0,
|
|
10385
|
+
if (edge.provenance !== import_types36.Provenance.EXTRACTED) continue;
|
|
10386
|
+
const parsed = (0, import_types36.parseFileId)(edge.source);
|
|
10125
10387
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
10126
10388
|
const site = { relPath: edge.evidence.file };
|
|
10127
10389
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -10132,7 +10394,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
10132
10394
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
10133
10395
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
10134
10396
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
10135
|
-
if (attrs.type !==
|
|
10397
|
+
if (attrs.type !== import_types36.NodeType.RouteNode || !attrs.path) return void 0;
|
|
10136
10398
|
const site = { relPath: attrs.path };
|
|
10137
10399
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
10138
10400
|
return site;
|
|
@@ -10603,10 +10865,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
10603
10865
|
// src/connectors/supabase/map.ts
|
|
10604
10866
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
10605
10867
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
10606
|
-
function targetFromRestPath(
|
|
10607
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
10868
|
+
function targetFromRestPath(path53) {
|
|
10869
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path53);
|
|
10608
10870
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
10609
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
10871
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path53);
|
|
10610
10872
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
10611
10873
|
return null;
|
|
10612
10874
|
}
|
|
@@ -10715,23 +10977,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
10715
10977
|
|
|
10716
10978
|
// src/connectors/supabase/resolve.ts
|
|
10717
10979
|
init_cjs_shims();
|
|
10718
|
-
var
|
|
10980
|
+
var import_types38 = require("@neat.is/types");
|
|
10719
10981
|
function createSupabaseResolveTarget(graph, config) {
|
|
10720
10982
|
return (signal, _ctx) => {
|
|
10721
10983
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
10722
10984
|
return null;
|
|
10723
10985
|
}
|
|
10724
|
-
const subResourceId = (0,
|
|
10986
|
+
const subResourceId = (0, import_types38.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
10725
10987
|
if (graph.hasNode(subResourceId)) {
|
|
10726
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
10988
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types38.EdgeType.CALLS };
|
|
10727
10989
|
}
|
|
10728
|
-
const bareResourceId = (0,
|
|
10990
|
+
const bareResourceId = (0, import_types38.infraId)(signal.targetKind, signal.targetName);
|
|
10729
10991
|
if (graph.hasNode(bareResourceId)) {
|
|
10730
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
10992
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types38.EdgeType.CALLS };
|
|
10731
10993
|
}
|
|
10732
|
-
const projectLevelId = (0,
|
|
10994
|
+
const projectLevelId = (0, import_types38.infraId)("supabase", config.nodeRef);
|
|
10733
10995
|
if (graph.hasNode(projectLevelId)) {
|
|
10734
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
10996
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types38.EdgeType.CALLS };
|
|
10735
10997
|
}
|
|
10736
10998
|
return null;
|
|
10737
10999
|
};
|
|
@@ -10824,7 +11086,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
10824
11086
|
|
|
10825
11087
|
// src/connectors/railway/index.ts
|
|
10826
11088
|
init_cjs_shims();
|
|
10827
|
-
var
|
|
11089
|
+
var import_types42 = require("@neat.is/types");
|
|
10828
11090
|
|
|
10829
11091
|
// src/connectors/railway/client.ts
|
|
10830
11092
|
init_cjs_shims();
|
|
@@ -10950,7 +11212,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
10950
11212
|
const out = [];
|
|
10951
11213
|
graph.forEachNode((_id, attrs) => {
|
|
10952
11214
|
const node = attrs;
|
|
10953
|
-
if (node.type !==
|
|
11215
|
+
if (node.type !== import_types42.NodeType.RouteNode) return;
|
|
10954
11216
|
const route = attrs;
|
|
10955
11217
|
if (route.service !== serviceName) return;
|
|
10956
11218
|
out.push({
|
|
@@ -11054,12 +11316,12 @@ function createRailwayResolveTarget(config) {
|
|
|
11054
11316
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
11055
11317
|
if (!serviceName) return null;
|
|
11056
11318
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
11057
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
11319
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types42.EdgeType.CALLS };
|
|
11058
11320
|
}
|
|
11059
11321
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
11060
11322
|
const peerName = config.serviceNameById[signal.targetName];
|
|
11061
11323
|
if (!peerName) return null;
|
|
11062
|
-
return { targetNodeId: (0,
|
|
11324
|
+
return { targetNodeId: (0, import_types42.serviceId)(peerName), serviceName, edgeType: import_types42.EdgeType.CONNECTS_TO };
|
|
11063
11325
|
}
|
|
11064
11326
|
return null;
|
|
11065
11327
|
};
|
|
@@ -11183,9 +11445,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
11183
11445
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
11184
11446
|
if (secondSep === -1) return null;
|
|
11185
11447
|
const method = rest.slice(0, secondSep);
|
|
11186
|
-
const
|
|
11187
|
-
if (!resourceName || !method || !
|
|
11188
|
-
return { resourceName, method, path:
|
|
11448
|
+
const path53 = rest.slice(secondSep + 1);
|
|
11449
|
+
if (!resourceName || !method || !path53) return null;
|
|
11450
|
+
return { resourceName, method, path: path53 };
|
|
11189
11451
|
}
|
|
11190
11452
|
function resourceNameFor(type, labels) {
|
|
11191
11453
|
if (!labels) return null;
|
|
@@ -11223,14 +11485,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
11223
11485
|
if (!req) return null;
|
|
11224
11486
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
11225
11487
|
const method = req.requestMethod.toUpperCase();
|
|
11226
|
-
const
|
|
11227
|
-
if (
|
|
11488
|
+
const path53 = pathFromRequestUrl(req.requestUrl);
|
|
11489
|
+
if (path53 === null) return null;
|
|
11228
11490
|
const timestamp = entry.timestamp;
|
|
11229
11491
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
11230
11492
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
11231
11493
|
return {
|
|
11232
11494
|
targetKind: resourceType,
|
|
11233
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
11495
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path53 }),
|
|
11234
11496
|
callCount: 1,
|
|
11235
11497
|
errorCount: isError ? 1 : 0,
|
|
11236
11498
|
lastObservedIso: timestamp
|
|
@@ -11247,7 +11509,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
11247
11509
|
|
|
11248
11510
|
// src/connectors/firebase/resolve.ts
|
|
11249
11511
|
init_cjs_shims();
|
|
11250
|
-
var
|
|
11512
|
+
var import_types43 = require("@neat.is/types");
|
|
11251
11513
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
11252
11514
|
switch (resourceType) {
|
|
11253
11515
|
case "cloud_function":
|
|
@@ -11262,7 +11524,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
11262
11524
|
const entries = [];
|
|
11263
11525
|
graph.forEachNode((_id, attrs) => {
|
|
11264
11526
|
const node = attrs;
|
|
11265
|
-
if (node.type !==
|
|
11527
|
+
if (node.type !== import_types43.NodeType.RouteNode) return;
|
|
11266
11528
|
const route = attrs;
|
|
11267
11529
|
if (route.service !== serviceName) return;
|
|
11268
11530
|
entries.push({
|
|
@@ -11294,7 +11556,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
11294
11556
|
return {
|
|
11295
11557
|
targetNodeId: match.routeNodeId,
|
|
11296
11558
|
serviceName,
|
|
11297
|
-
edgeType:
|
|
11559
|
+
edgeType: import_types43.EdgeType.CALLS
|
|
11298
11560
|
};
|
|
11299
11561
|
};
|
|
11300
11562
|
}
|
|
@@ -11321,7 +11583,7 @@ init_cjs_shims();
|
|
|
11321
11583
|
|
|
11322
11584
|
// src/connectors/cloudflare/connector.ts
|
|
11323
11585
|
init_cjs_shims();
|
|
11324
|
-
var
|
|
11586
|
+
var import_types45 = require("@neat.is/types");
|
|
11325
11587
|
|
|
11326
11588
|
// src/connectors/cloudflare/client.ts
|
|
11327
11589
|
init_cjs_shims();
|
|
@@ -11437,7 +11699,7 @@ function mapEventToSignal(event) {
|
|
|
11437
11699
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
11438
11700
|
const statusCode = metadata?.statusCode;
|
|
11439
11701
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
11440
|
-
const
|
|
11702
|
+
const path53 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
11441
11703
|
return {
|
|
11442
11704
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
11443
11705
|
targetName: scriptName,
|
|
@@ -11445,7 +11707,7 @@ function mapEventToSignal(event) {
|
|
|
11445
11707
|
errorCount: isError ? 1 : 0,
|
|
11446
11708
|
lastObservedIso: observedAt.toISOString(),
|
|
11447
11709
|
method,
|
|
11448
|
-
...
|
|
11710
|
+
...path53 ? { path: path53 } : {},
|
|
11449
11711
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
11450
11712
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
11451
11713
|
};
|
|
@@ -11485,19 +11747,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
11485
11747
|
graph.forEachNode((id, attrs) => {
|
|
11486
11748
|
if (found) return;
|
|
11487
11749
|
const a = attrs;
|
|
11488
|
-
if (a.type ===
|
|
11750
|
+
if (a.type === import_types45.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
11489
11751
|
found = id;
|
|
11490
11752
|
}
|
|
11491
11753
|
});
|
|
11492
11754
|
return found;
|
|
11493
11755
|
}
|
|
11494
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
11495
|
-
const normalizedPath = normalizePathTemplate(
|
|
11756
|
+
function findMatchingRouteNode(graph, serviceName, method, path53) {
|
|
11757
|
+
const normalizedPath = normalizePathTemplate(path53);
|
|
11496
11758
|
let found = null;
|
|
11497
11759
|
graph.forEachNode((id, attrs) => {
|
|
11498
11760
|
if (found) return;
|
|
11499
11761
|
const a = attrs;
|
|
11500
|
-
if (a.type !==
|
|
11762
|
+
if (a.type !== import_types45.NodeType.RouteNode || a.service !== serviceName) return;
|
|
11501
11763
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
11502
11764
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
11503
11765
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -11509,18 +11771,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
11509
11771
|
return (signal) => {
|
|
11510
11772
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
11511
11773
|
const scriptName = signal.targetName;
|
|
11512
|
-
const { method, path:
|
|
11774
|
+
const { method, path: path53 } = signal;
|
|
11513
11775
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
11514
|
-
if (!method || !
|
|
11515
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
11776
|
+
if (!method || !path53) return wholeFileId;
|
|
11777
|
+
return findMatchingRouteNode(graph, serviceName, method, path53) ?? wholeFileId;
|
|
11516
11778
|
};
|
|
11517
11779
|
const mapping = config.workers?.[scriptName];
|
|
11518
11780
|
if (mapping) {
|
|
11519
|
-
const wholeFileId = (0,
|
|
11781
|
+
const wholeFileId = (0, import_types45.fileId)(mapping.service, mapping.entryFile);
|
|
11520
11782
|
return {
|
|
11521
11783
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
11522
11784
|
serviceName: mapping.service,
|
|
11523
|
-
edgeType:
|
|
11785
|
+
edgeType: import_types45.EdgeType.CALLS
|
|
11524
11786
|
};
|
|
11525
11787
|
}
|
|
11526
11788
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -11529,13 +11791,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
11529
11791
|
return {
|
|
11530
11792
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
11531
11793
|
serviceName: fileNode.service,
|
|
11532
|
-
edgeType:
|
|
11794
|
+
edgeType: import_types45.EdgeType.CALLS
|
|
11533
11795
|
};
|
|
11534
11796
|
}
|
|
11535
11797
|
return {
|
|
11536
|
-
targetNodeId: (0,
|
|
11798
|
+
targetNodeId: (0, import_types45.infraId)("cloudflare-worker", scriptName),
|
|
11537
11799
|
serviceName: scriptName,
|
|
11538
|
-
edgeType:
|
|
11800
|
+
edgeType: import_types45.EdgeType.CALLS,
|
|
11539
11801
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
11540
11802
|
};
|
|
11541
11803
|
};
|
|
@@ -11979,7 +12241,7 @@ init_auth();
|
|
|
11979
12241
|
// src/unrouted.ts
|
|
11980
12242
|
init_cjs_shims();
|
|
11981
12243
|
var import_node_fs30 = require("fs");
|
|
11982
|
-
var
|
|
12244
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
11983
12245
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
11984
12246
|
return {
|
|
11985
12247
|
timestamp: now.toISOString(),
|
|
@@ -11989,34 +12251,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
11989
12251
|
};
|
|
11990
12252
|
}
|
|
11991
12253
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
11992
|
-
const target =
|
|
12254
|
+
const target = import_node_path51.default.join(neatHome3, "errors.ndjson");
|
|
11993
12255
|
await import_node_fs30.promises.mkdir(neatHome3, { recursive: true });
|
|
11994
12256
|
await import_node_fs30.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
11995
12257
|
}
|
|
11996
12258
|
function unroutedErrorsPath(neatHome3) {
|
|
11997
|
-
return
|
|
12259
|
+
return import_node_path51.default.join(neatHome3, "errors.ndjson");
|
|
11998
12260
|
}
|
|
11999
12261
|
|
|
12000
12262
|
// src/daemon.ts
|
|
12001
|
-
var
|
|
12263
|
+
var import_types48 = require("@neat.is/types");
|
|
12002
12264
|
function daemonJsonPath(scanPath) {
|
|
12003
|
-
return
|
|
12265
|
+
return import_node_path52.default.join(scanPath, "neat-out", "daemon.json");
|
|
12004
12266
|
}
|
|
12005
12267
|
function daemonsDiscoveryDir(home) {
|
|
12006
12268
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
12007
|
-
return
|
|
12269
|
+
return import_node_path52.default.join(base, "daemons");
|
|
12008
12270
|
}
|
|
12009
12271
|
function daemonDiscoveryPath(project, home) {
|
|
12010
|
-
return
|
|
12272
|
+
return import_node_path52.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
12011
12273
|
}
|
|
12012
12274
|
function sanitizeDiscoveryName(project) {
|
|
12013
12275
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
12014
12276
|
}
|
|
12015
12277
|
function neatHomeFromEnv() {
|
|
12016
12278
|
const env = process.env.NEAT_HOME;
|
|
12017
|
-
if (env && env.length > 0) return
|
|
12279
|
+
if (env && env.length > 0) return import_node_path52.default.resolve(env);
|
|
12018
12280
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
12019
|
-
return
|
|
12281
|
+
return import_node_path52.default.join(home, ".neat");
|
|
12020
12282
|
}
|
|
12021
12283
|
function resolveNeatVersion() {
|
|
12022
12284
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -12071,11 +12333,11 @@ function teardownSlot(slot) {
|
|
|
12071
12333
|
}
|
|
12072
12334
|
}
|
|
12073
12335
|
function neatHomeFor(opts) {
|
|
12074
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
12336
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path52.default.resolve(opts.neatHome);
|
|
12075
12337
|
const env = process.env.NEAT_HOME;
|
|
12076
|
-
if (env && env.length > 0) return
|
|
12338
|
+
if (env && env.length > 0) return import_node_path52.default.resolve(env);
|
|
12077
12339
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
12078
|
-
return
|
|
12340
|
+
return import_node_path52.default.join(home, ".neat");
|
|
12079
12341
|
}
|
|
12080
12342
|
function routeSpanToProject(serviceName, projects) {
|
|
12081
12343
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -12119,11 +12381,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
12119
12381
|
if (!serviceName) return true;
|
|
12120
12382
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
12121
12383
|
return graph.someNode(
|
|
12122
|
-
(_id, attrs) => attrs.type ===
|
|
12384
|
+
(_id, attrs) => attrs.type === import_types48.NodeType.ServiceNode && attrs.name === serviceName
|
|
12123
12385
|
);
|
|
12124
12386
|
}
|
|
12125
12387
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
12126
|
-
const paths = pathsForProject(entry.name,
|
|
12388
|
+
const paths = pathsForProject(entry.name, import_node_path52.default.join(entry.path, "neat-out"));
|
|
12127
12389
|
try {
|
|
12128
12390
|
const stat = await import_node_fs31.promises.stat(entry.path);
|
|
12129
12391
|
if (!stat.isDirectory()) {
|
|
@@ -12254,7 +12516,7 @@ async function startDaemon(opts = {}) {
|
|
|
12254
12516
|
const projectArg = typeof opts.project === "string" && opts.project.length > 0 ? opts.project : process.env.NEAT_PROJECT && process.env.NEAT_PROJECT.length > 0 ? process.env.NEAT_PROJECT : null;
|
|
12255
12517
|
const projectPathArg = opts.projectPath && opts.projectPath.length > 0 ? opts.projectPath : process.env.NEAT_PROJECT_PATH && process.env.NEAT_PROJECT_PATH.length > 0 ? process.env.NEAT_PROJECT_PATH : null;
|
|
12256
12518
|
const singleProject = projectArg;
|
|
12257
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
12519
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path52.default.resolve(projectPathArg) : null;
|
|
12258
12520
|
if (singleProject && !singleProjectPath) {
|
|
12259
12521
|
throw new Error(
|
|
12260
12522
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -12269,7 +12531,7 @@ async function startDaemon(opts = {}) {
|
|
|
12269
12531
|
);
|
|
12270
12532
|
}
|
|
12271
12533
|
}
|
|
12272
|
-
const pidPath =
|
|
12534
|
+
const pidPath = import_node_path52.default.join(home, "neatd.pid");
|
|
12273
12535
|
await writeAtomically(pidPath, `${process.pid}
|
|
12274
12536
|
`);
|
|
12275
12537
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -12676,8 +12938,8 @@ async function startDaemon(opts = {}) {
|
|
|
12676
12938
|
let registryWatcher = null;
|
|
12677
12939
|
let reloadTimer = null;
|
|
12678
12940
|
if (!singleProject) try {
|
|
12679
|
-
const regDir =
|
|
12680
|
-
const regBase =
|
|
12941
|
+
const regDir = import_node_path52.default.dirname(regPath);
|
|
12942
|
+
const regBase = import_node_path52.default.basename(regPath);
|
|
12681
12943
|
registryWatcher = (0, import_node_fs31.watch)(regDir, (_eventType, filename) => {
|
|
12682
12944
|
if (filename !== null && filename !== regBase) return;
|
|
12683
12945
|
if (reloadTimer) clearTimeout(reloadTimer);
|