@neat.is/core 0.7.1 → 0.7.3
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-MDBE23Y3.js → chunk-3SBEY67S.js} +2 -2
- package/dist/{chunk-RR4LWQQB.js → chunk-BY6ZP5WA.js} +267 -139
- package/dist/chunk-BY6ZP5WA.js.map +1 -0
- package/dist/cli.cjs +945 -466
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +2 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +356 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +425 -296
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +434 -305
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +357 -228
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-RR4LWQQB.js.map +0 -1
- /package/dist/{chunk-MDBE23Y3.js.map → chunk-3SBEY67S.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 path60 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
64
|
+
if (exactUnauthPaths.has(path60) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path60)) {
|
|
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_path39.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
197
|
+
return import_node_path39.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_path39, 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_path39 = __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);
|
|
@@ -414,8 +414,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
414
414
|
const v = attrs[key];
|
|
415
415
|
if (typeof v === "string" && v.length > 0) {
|
|
416
416
|
const q = v.indexOf("?");
|
|
417
|
-
const
|
|
418
|
-
if (
|
|
417
|
+
const path60 = q === -1 ? v : v.slice(0, q);
|
|
418
|
+
if (path60.length > 0) return path60;
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
return void 0;
|
|
@@ -474,10 +474,10 @@ function parseOtlpRequest(body) {
|
|
|
474
474
|
return out;
|
|
475
475
|
}
|
|
476
476
|
function loadProtoRoot() {
|
|
477
|
-
const here =
|
|
478
|
-
const protoRoot =
|
|
477
|
+
const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
478
|
+
const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
|
|
479
479
|
const root = new import_protobufjs.default.Root();
|
|
480
|
-
root.resolvePath = (_origin, target) =>
|
|
480
|
+
root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
|
|
481
481
|
root.loadSync(
|
|
482
482
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
483
483
|
{ keepCase: true }
|
|
@@ -716,12 +716,12 @@ function logSpanHandler(span) {
|
|
|
716
716
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
717
717
|
);
|
|
718
718
|
}
|
|
719
|
-
var
|
|
719
|
+
var import_node_path40, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
720
720
|
var init_otel = __esm({
|
|
721
721
|
"src/otel.ts"() {
|
|
722
722
|
"use strict";
|
|
723
723
|
init_cjs_shims();
|
|
724
|
-
|
|
724
|
+
import_node_path40 = __toESM(require("path"), 1);
|
|
725
725
|
import_node_url2 = require("url");
|
|
726
726
|
import_fastify = __toESM(require("fastify"), 1);
|
|
727
727
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -1314,19 +1314,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1314
1314
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1315
1315
|
let best = { path: [start], edges: [] };
|
|
1316
1316
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1317
|
-
function step(node,
|
|
1318
|
-
if (
|
|
1319
|
-
best = { path: [...
|
|
1317
|
+
function step(node, path60, edges) {
|
|
1318
|
+
if (path60.length > best.path.length) {
|
|
1319
|
+
best = { path: [...path60], edges: [...edges] };
|
|
1320
1320
|
}
|
|
1321
|
-
if (
|
|
1321
|
+
if (path60.length - 1 >= maxDepth) return;
|
|
1322
1322
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1323
1323
|
for (const [srcId, edge] of incoming) {
|
|
1324
1324
|
if (visited.has(srcId)) continue;
|
|
1325
1325
|
visited.add(srcId);
|
|
1326
|
-
|
|
1326
|
+
path60.push(srcId);
|
|
1327
1327
|
edges.push(edge);
|
|
1328
|
-
step(srcId,
|
|
1329
|
-
|
|
1328
|
+
step(srcId, path60, edges);
|
|
1329
|
+
path60.pop();
|
|
1330
1330
|
edges.pop();
|
|
1331
1331
|
visited.delete(srcId);
|
|
1332
1332
|
}
|
|
@@ -1533,26 +1533,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
|
|
|
1533
1533
|
return best;
|
|
1534
1534
|
}
|
|
1535
1535
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1536
|
-
const
|
|
1536
|
+
const path60 = [originServiceId];
|
|
1537
1537
|
const edges = [];
|
|
1538
1538
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1539
1539
|
let current = originServiceId;
|
|
1540
1540
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1541
1541
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1542
1542
|
if (!hop) break;
|
|
1543
|
-
|
|
1543
|
+
path60.push(hop.nextService);
|
|
1544
1544
|
edges.push(hop.edge);
|
|
1545
1545
|
visited.add(hop.nextService);
|
|
1546
1546
|
current = hop.nextService;
|
|
1547
1547
|
}
|
|
1548
1548
|
if (edges.length === 0) return null;
|
|
1549
|
-
return { path:
|
|
1549
|
+
return { path: path60, edges, culprit: current };
|
|
1550
1550
|
}
|
|
1551
1551
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1552
1552
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1553
1553
|
if (!chain) return null;
|
|
1554
1554
|
const culprit = chain.culprit;
|
|
1555
|
-
const
|
|
1555
|
+
const path60 = [...chain.path];
|
|
1556
1556
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1557
1557
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1558
1558
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1560,14 +1560,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1560
1560
|
if (loc) {
|
|
1561
1561
|
let rootCauseNode = culprit;
|
|
1562
1562
|
if (loc.fileNode) {
|
|
1563
|
-
|
|
1563
|
+
path60.push(loc.fileNode);
|
|
1564
1564
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1565
1565
|
rootCauseNode = loc.fileNode;
|
|
1566
1566
|
}
|
|
1567
1567
|
return import_types.RootCauseResultSchema.parse({
|
|
1568
1568
|
rootCauseNode,
|
|
1569
1569
|
rootCauseReason: loc.rootCauseReason,
|
|
1570
|
-
traversalPath:
|
|
1570
|
+
traversalPath: path60,
|
|
1571
1571
|
edgeProvenances,
|
|
1572
1572
|
confidence,
|
|
1573
1573
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1579,7 +1579,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1579
1579
|
return import_types.RootCauseResultSchema.parse({
|
|
1580
1580
|
rootCauseNode: culprit,
|
|
1581
1581
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1582
|
-
traversalPath:
|
|
1582
|
+
traversalPath: path60,
|
|
1583
1583
|
edgeProvenances,
|
|
1584
1584
|
confidence,
|
|
1585
1585
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -6949,7 +6949,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
6949
6949
|
|
|
6950
6950
|
// src/extract/calls/index.ts
|
|
6951
6951
|
init_cjs_shims();
|
|
6952
|
-
var
|
|
6952
|
+
var import_types30 = require("@neat.is/types");
|
|
6953
6953
|
|
|
6954
6954
|
// src/extract/calls/http.ts
|
|
6955
6955
|
init_cjs_shims();
|
|
@@ -8405,12 +8405,140 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
8405
8405
|
return out;
|
|
8406
8406
|
}
|
|
8407
8407
|
|
|
8408
|
+
// src/extract/calls/prisma.ts
|
|
8409
|
+
init_cjs_shims();
|
|
8410
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
8411
|
+
var import_types28 = require("@neat.is/types");
|
|
8412
|
+
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
8413
|
+
"Int",
|
|
8414
|
+
"String",
|
|
8415
|
+
"Boolean",
|
|
8416
|
+
"DateTime",
|
|
8417
|
+
"Float",
|
|
8418
|
+
"Decimal",
|
|
8419
|
+
"BigInt",
|
|
8420
|
+
"Bytes",
|
|
8421
|
+
"Json"
|
|
8422
|
+
]);
|
|
8423
|
+
function stripLineComment(line) {
|
|
8424
|
+
let inStr = false;
|
|
8425
|
+
for (let i = 0; i < line.length; i++) {
|
|
8426
|
+
const ch = line[i];
|
|
8427
|
+
if (ch === '"' && line[i - 1] !== "\\") inStr = !inStr;
|
|
8428
|
+
else if (!inStr && ch === "/" && line[i + 1] === "/") return line.slice(0, i);
|
|
8429
|
+
}
|
|
8430
|
+
return line;
|
|
8431
|
+
}
|
|
8432
|
+
function netBraces(line) {
|
|
8433
|
+
const s = stripLineComment(line).replace(/"(\\.|[^"\\])*"/g, "");
|
|
8434
|
+
let n = 0;
|
|
8435
|
+
for (const ch of s) {
|
|
8436
|
+
if (ch === "{") n++;
|
|
8437
|
+
else if (ch === "}") n--;
|
|
8438
|
+
}
|
|
8439
|
+
return n;
|
|
8440
|
+
}
|
|
8441
|
+
function prismaColumnsFromSchema(file, serviceDir) {
|
|
8442
|
+
const content = file.content;
|
|
8443
|
+
if (!/\bmodel\s+[A-Za-z_]\w*\s*\{/.test(content)) return [];
|
|
8444
|
+
const lines = content.split("\n");
|
|
8445
|
+
const modelNames = /* @__PURE__ */ new Set();
|
|
8446
|
+
const enumNames = /* @__PURE__ */ new Set();
|
|
8447
|
+
for (const line of lines) {
|
|
8448
|
+
const m = line.match(/^\s*model\s+([A-Za-z_]\w*)\s*\{/);
|
|
8449
|
+
if (m) modelNames.add(m[1]);
|
|
8450
|
+
const e = line.match(/^\s*enum\s+([A-Za-z_]\w*)\s*\{/);
|
|
8451
|
+
if (e) enumNames.add(e[1]);
|
|
8452
|
+
}
|
|
8453
|
+
const out = [];
|
|
8454
|
+
const seenTable = /* @__PURE__ */ new Set();
|
|
8455
|
+
const finalize = (b) => {
|
|
8456
|
+
if (seenTable.has(b.tableName)) return;
|
|
8457
|
+
seenTable.add(b.tableName);
|
|
8458
|
+
out.push({
|
|
8459
|
+
infraId: (0, import_types28.infraId)("sql-table", b.tableName),
|
|
8460
|
+
name: b.tableName,
|
|
8461
|
+
kind: "sql-table",
|
|
8462
|
+
edgeType: "CALLS",
|
|
8463
|
+
confidenceKind: "structural",
|
|
8464
|
+
columns: b.columns,
|
|
8465
|
+
evidence: {
|
|
8466
|
+
file: import_node_path38.default.relative(serviceDir, file.path),
|
|
8467
|
+
line: b.startLine,
|
|
8468
|
+
snippet: snippet(content, b.startLine)
|
|
8469
|
+
}
|
|
8470
|
+
});
|
|
8471
|
+
};
|
|
8472
|
+
let current = null;
|
|
8473
|
+
let depth = 0;
|
|
8474
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8475
|
+
const raw = lines[i];
|
|
8476
|
+
const lineNo = i + 1;
|
|
8477
|
+
if (current === null) {
|
|
8478
|
+
const header = raw.match(/^\s*(model|enum|datasource|generator|type)\s+([A-Za-z_]\w*)\b/);
|
|
8479
|
+
if (header && raw.includes("{")) {
|
|
8480
|
+
current = {
|
|
8481
|
+
kind: header[1],
|
|
8482
|
+
tableName: header[2],
|
|
8483
|
+
startLine: lineNo,
|
|
8484
|
+
columns: [],
|
|
8485
|
+
seenCol: /* @__PURE__ */ new Set()
|
|
8486
|
+
};
|
|
8487
|
+
depth = netBraces(raw);
|
|
8488
|
+
if (depth <= 0) {
|
|
8489
|
+
if (current.kind === "model") finalize(current);
|
|
8490
|
+
current = null;
|
|
8491
|
+
}
|
|
8492
|
+
}
|
|
8493
|
+
continue;
|
|
8494
|
+
}
|
|
8495
|
+
depth += netBraces(raw);
|
|
8496
|
+
if (depth <= 0) {
|
|
8497
|
+
if (current.kind === "model") finalize(current);
|
|
8498
|
+
current = null;
|
|
8499
|
+
continue;
|
|
8500
|
+
}
|
|
8501
|
+
if (current.kind !== "model") continue;
|
|
8502
|
+
const trimmed = stripLineComment(raw).trim();
|
|
8503
|
+
if (!trimmed) continue;
|
|
8504
|
+
if (trimmed.startsWith("@@")) {
|
|
8505
|
+
const map = trimmed.match(/@@map\(\s*"([^"]+)"\s*\)/);
|
|
8506
|
+
if (map) current.tableName = map[1];
|
|
8507
|
+
continue;
|
|
8508
|
+
}
|
|
8509
|
+
const fm = trimmed.match(/^([A-Za-z_]\w*)\s+([A-Za-z_]\w*)/);
|
|
8510
|
+
if (!fm) continue;
|
|
8511
|
+
const fieldName = fm[1];
|
|
8512
|
+
const baseType = fm[2];
|
|
8513
|
+
if (/@relation\b/.test(trimmed) || modelNames.has(baseType)) continue;
|
|
8514
|
+
if (!enumNames.has(baseType) && !SCALAR_TYPES.has(baseType)) continue;
|
|
8515
|
+
const mapM = trimmed.match(/(?<!@)@map\(\s*"([^"]+)"\s*\)/);
|
|
8516
|
+
const columnName = mapM ? mapM[1] : fieldName;
|
|
8517
|
+
if (!current.seenCol.has(columnName)) {
|
|
8518
|
+
current.seenCol.add(columnName);
|
|
8519
|
+
current.columns.push(columnName);
|
|
8520
|
+
}
|
|
8521
|
+
}
|
|
8522
|
+
if (current && current.kind === "model") finalize(current);
|
|
8523
|
+
return out;
|
|
8524
|
+
}
|
|
8525
|
+
async function prismaColumnEndpoints(serviceDir) {
|
|
8526
|
+
const schemaPath = await findFirst(serviceDir, [
|
|
8527
|
+
import_node_path38.default.join("prisma", "schema.prisma"),
|
|
8528
|
+
"schema.prisma"
|
|
8529
|
+
]);
|
|
8530
|
+
if (!schemaPath) return [];
|
|
8531
|
+
const content = await readIfExists(schemaPath);
|
|
8532
|
+
if (!content) return [];
|
|
8533
|
+
return prismaColumnsFromSchema({ path: schemaPath, content }, serviceDir);
|
|
8534
|
+
}
|
|
8535
|
+
|
|
8408
8536
|
// src/extract/calls/go.ts
|
|
8409
8537
|
init_cjs_shims();
|
|
8410
|
-
var
|
|
8538
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
8411
8539
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
8412
8540
|
var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
|
|
8413
|
-
var
|
|
8541
|
+
var import_types29 = require("@neat.is/types");
|
|
8414
8542
|
init_otel();
|
|
8415
8543
|
var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
|
|
8416
8544
|
var PARSE_CHUNK8 = 16384;
|
|
@@ -8422,7 +8550,7 @@ function walk5(node, visit) {
|
|
|
8422
8550
|
}
|
|
8423
8551
|
}
|
|
8424
8552
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
8425
|
-
if (
|
|
8553
|
+
if (import_node_path41.default.extname(file.path) !== ".go") return [];
|
|
8426
8554
|
const parser = new import_tree_sitter10.default();
|
|
8427
8555
|
parser.setLanguage(import_tree_sitter_go3.default);
|
|
8428
8556
|
const tree = parser.parse(
|
|
@@ -8442,12 +8570,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8442
8570
|
if (!table) return;
|
|
8443
8571
|
const line = node.startPosition.row + 1;
|
|
8444
8572
|
out.push({
|
|
8445
|
-
infraId: (0,
|
|
8573
|
+
infraId: (0, import_types29.infraId)("sql-table", table),
|
|
8446
8574
|
name: table,
|
|
8447
8575
|
kind: "sql-table",
|
|
8448
8576
|
edgeType: "CALLS",
|
|
8449
8577
|
confidenceKind: "verified-call-site",
|
|
8450
|
-
evidence: { file: toPosix(
|
|
8578
|
+
evidence: { file: toPosix(import_node_path41.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
|
|
8451
8579
|
});
|
|
8452
8580
|
});
|
|
8453
8581
|
return out;
|
|
@@ -8457,11 +8585,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8457
8585
|
function edgeTypeFromEndpoint(ep) {
|
|
8458
8586
|
switch (ep.edgeType) {
|
|
8459
8587
|
case "PUBLISHES_TO":
|
|
8460
|
-
return
|
|
8588
|
+
return import_types30.EdgeType.PUBLISHES_TO;
|
|
8461
8589
|
case "CONSUMES_FROM":
|
|
8462
|
-
return
|
|
8590
|
+
return import_types30.EdgeType.CONSUMES_FROM;
|
|
8463
8591
|
default:
|
|
8464
|
-
return
|
|
8592
|
+
return import_types30.EdgeType.CALLS;
|
|
8465
8593
|
}
|
|
8466
8594
|
}
|
|
8467
8595
|
function isAwsKind(kind) {
|
|
@@ -8496,13 +8624,14 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8496
8624
|
}
|
|
8497
8625
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
8498
8626
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
8627
|
+
endpoints.push(...await prismaColumnEndpoints(service.dir));
|
|
8499
8628
|
if (endpoints.length === 0) continue;
|
|
8500
8629
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
8501
8630
|
for (const ep of endpoints) {
|
|
8502
8631
|
if (!graph.hasNode(ep.infraId)) {
|
|
8503
8632
|
const node = {
|
|
8504
8633
|
id: ep.infraId,
|
|
8505
|
-
type:
|
|
8634
|
+
type: import_types30.NodeType.InfraNode,
|
|
8506
8635
|
name: ep.name,
|
|
8507
8636
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
8508
8637
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -8515,20 +8644,20 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8515
8644
|
}
|
|
8516
8645
|
if (ep.columns && ep.columns.length > 0) {
|
|
8517
8646
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
8518
|
-
if (node.type ===
|
|
8647
|
+
if (node.type === import_types30.NodeType.InfraNode) {
|
|
8519
8648
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
8520
8649
|
...node,
|
|
8521
8650
|
columns: foldColumns(
|
|
8522
8651
|
node.columns,
|
|
8523
8652
|
ep.columns,
|
|
8524
|
-
|
|
8525
|
-
(0,
|
|
8653
|
+
import_types30.Provenance.EXTRACTED,
|
|
8654
|
+
(0, import_types30.confidenceForExtracted)(ep.confidenceKind)
|
|
8526
8655
|
)
|
|
8527
8656
|
});
|
|
8528
8657
|
}
|
|
8529
8658
|
}
|
|
8530
8659
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
8531
|
-
const confidence = (0,
|
|
8660
|
+
const confidence = (0, import_types30.confidenceForExtracted)(ep.confidenceKind);
|
|
8532
8661
|
const relFile = toPosix(ep.evidence.file);
|
|
8533
8662
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
8534
8663
|
graph,
|
|
@@ -8538,7 +8667,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8538
8667
|
);
|
|
8539
8668
|
nodesAdded += n;
|
|
8540
8669
|
edgesAdded += e;
|
|
8541
|
-
if (!(0,
|
|
8670
|
+
if (!(0, import_types30.passesExtractedFloor)(confidence)) {
|
|
8542
8671
|
noteExtractedDropped({
|
|
8543
8672
|
source: fileNodeId,
|
|
8544
8673
|
target: ep.infraId,
|
|
@@ -8558,7 +8687,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8558
8687
|
source: fileNodeId,
|
|
8559
8688
|
target: ep.infraId,
|
|
8560
8689
|
type: edgeType,
|
|
8561
|
-
provenance:
|
|
8690
|
+
provenance: import_types30.Provenance.EXTRACTED,
|
|
8562
8691
|
confidence,
|
|
8563
8692
|
evidence: ep.evidence
|
|
8564
8693
|
};
|
|
@@ -8584,16 +8713,16 @@ init_cjs_shims();
|
|
|
8584
8713
|
|
|
8585
8714
|
// src/extract/infra/docker-compose.ts
|
|
8586
8715
|
init_cjs_shims();
|
|
8587
|
-
var
|
|
8588
|
-
var
|
|
8716
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8717
|
+
var import_types32 = require("@neat.is/types");
|
|
8589
8718
|
|
|
8590
8719
|
// src/extract/infra/shared.ts
|
|
8591
8720
|
init_cjs_shims();
|
|
8592
|
-
var
|
|
8721
|
+
var import_types31 = require("@neat.is/types");
|
|
8593
8722
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
8594
8723
|
return {
|
|
8595
|
-
id: (0,
|
|
8596
|
-
type:
|
|
8724
|
+
id: (0, import_types31.infraId)(kind, name),
|
|
8725
|
+
type: import_types31.NodeType.InfraNode,
|
|
8597
8726
|
name,
|
|
8598
8727
|
provider,
|
|
8599
8728
|
kind,
|
|
@@ -8637,8 +8766,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
8637
8766
|
source: anchorId,
|
|
8638
8767
|
target: node.id,
|
|
8639
8768
|
type: edgeType,
|
|
8640
|
-
provenance:
|
|
8641
|
-
confidence: (0,
|
|
8769
|
+
provenance: import_types31.Provenance.EXTRACTED,
|
|
8770
|
+
confidence: (0, import_types31.confidenceForExtracted)("structural"),
|
|
8642
8771
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
8643
8772
|
};
|
|
8644
8773
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8655,7 +8784,7 @@ function dependsOnList(value) {
|
|
|
8655
8784
|
}
|
|
8656
8785
|
function serviceNameToServiceNode(name, services) {
|
|
8657
8786
|
for (const s of services) {
|
|
8658
|
-
if (s.node.name === name ||
|
|
8787
|
+
if (s.node.name === name || import_node_path42.default.basename(s.dir) === name) return s.node.id;
|
|
8659
8788
|
}
|
|
8660
8789
|
return null;
|
|
8661
8790
|
}
|
|
@@ -8664,7 +8793,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8664
8793
|
let edgesAdded = 0;
|
|
8665
8794
|
let composePath = null;
|
|
8666
8795
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
8667
|
-
const abs =
|
|
8796
|
+
const abs = import_node_path42.default.join(scanPath, name);
|
|
8668
8797
|
if (await exists(abs)) {
|
|
8669
8798
|
composePath = abs;
|
|
8670
8799
|
break;
|
|
@@ -8677,13 +8806,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8677
8806
|
} catch (err) {
|
|
8678
8807
|
recordExtractionError(
|
|
8679
8808
|
"infra docker-compose",
|
|
8680
|
-
|
|
8809
|
+
import_node_path42.default.relative(scanPath, composePath),
|
|
8681
8810
|
err
|
|
8682
8811
|
);
|
|
8683
8812
|
return { nodesAdded, edgesAdded };
|
|
8684
8813
|
}
|
|
8685
8814
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
8686
|
-
const evidenceFile =
|
|
8815
|
+
const evidenceFile = import_node_path42.default.relative(scanPath, composePath).split(import_node_path42.default.sep).join("/");
|
|
8687
8816
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
8688
8817
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
8689
8818
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -8705,15 +8834,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8705
8834
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
8706
8835
|
const targetId = composeNameToNodeId.get(dep);
|
|
8707
8836
|
if (!targetId) continue;
|
|
8708
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
8837
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types32.EdgeType.DEPENDS_ON);
|
|
8709
8838
|
if (graph.hasEdge(edgeId)) continue;
|
|
8710
8839
|
const edge = {
|
|
8711
8840
|
id: edgeId,
|
|
8712
8841
|
source: sourceId,
|
|
8713
8842
|
target: targetId,
|
|
8714
|
-
type:
|
|
8715
|
-
provenance:
|
|
8716
|
-
confidence: (0,
|
|
8843
|
+
type: import_types32.EdgeType.DEPENDS_ON,
|
|
8844
|
+
provenance: import_types32.Provenance.EXTRACTED,
|
|
8845
|
+
confidence: (0, import_types32.confidenceForExtracted)("structural"),
|
|
8717
8846
|
evidence: { file: evidenceFile }
|
|
8718
8847
|
};
|
|
8719
8848
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8725,9 +8854,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8725
8854
|
|
|
8726
8855
|
// src/extract/infra/dockerfile.ts
|
|
8727
8856
|
init_cjs_shims();
|
|
8728
|
-
var
|
|
8857
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
8729
8858
|
var import_node_fs17 = require("fs");
|
|
8730
|
-
var
|
|
8859
|
+
var import_types33 = require("@neat.is/types");
|
|
8731
8860
|
function readDockerfile(content) {
|
|
8732
8861
|
let image = null;
|
|
8733
8862
|
const ports = [];
|
|
@@ -8756,7 +8885,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8756
8885
|
let nodesAdded = 0;
|
|
8757
8886
|
let edgesAdded = 0;
|
|
8758
8887
|
for (const service of services) {
|
|
8759
|
-
const dockerfilePath =
|
|
8888
|
+
const dockerfilePath = import_node_path43.default.join(service.dir, "Dockerfile");
|
|
8760
8889
|
if (!await exists(dockerfilePath)) continue;
|
|
8761
8890
|
let content;
|
|
8762
8891
|
try {
|
|
@@ -8764,7 +8893,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8764
8893
|
} catch (err) {
|
|
8765
8894
|
recordExtractionError(
|
|
8766
8895
|
"infra dockerfile",
|
|
8767
|
-
|
|
8896
|
+
import_node_path43.default.relative(scanPath, dockerfilePath),
|
|
8768
8897
|
err
|
|
8769
8898
|
);
|
|
8770
8899
|
continue;
|
|
@@ -8776,8 +8905,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8776
8905
|
graph.addNode(node.id, node);
|
|
8777
8906
|
nodesAdded++;
|
|
8778
8907
|
}
|
|
8779
|
-
const relDockerfile = toPosix(
|
|
8780
|
-
const evidenceFile = toPosix(
|
|
8908
|
+
const relDockerfile = toPosix(import_node_path43.default.relative(service.dir, dockerfilePath));
|
|
8909
|
+
const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, dockerfilePath));
|
|
8781
8910
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
8782
8911
|
graph,
|
|
8783
8912
|
service.pkg.name,
|
|
@@ -8786,15 +8915,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8786
8915
|
);
|
|
8787
8916
|
nodesAdded += fn;
|
|
8788
8917
|
edgesAdded += fe;
|
|
8789
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
8918
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types33.EdgeType.RUNS_ON);
|
|
8790
8919
|
if (!graph.hasEdge(edgeId)) {
|
|
8791
8920
|
const edge = {
|
|
8792
8921
|
id: edgeId,
|
|
8793
8922
|
source: fileNodeId,
|
|
8794
8923
|
target: node.id,
|
|
8795
|
-
type:
|
|
8796
|
-
provenance:
|
|
8797
|
-
confidence: (0,
|
|
8924
|
+
type: import_types33.EdgeType.RUNS_ON,
|
|
8925
|
+
provenance: import_types33.Provenance.EXTRACTED,
|
|
8926
|
+
confidence: (0, import_types33.confidenceForExtracted)("structural"),
|
|
8798
8927
|
evidence: {
|
|
8799
8928
|
file: evidenceFile,
|
|
8800
8929
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -8809,15 +8938,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8809
8938
|
graph.addNode(portNode.id, portNode);
|
|
8810
8939
|
nodesAdded++;
|
|
8811
8940
|
}
|
|
8812
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
8941
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types33.EdgeType.CONNECTS_TO);
|
|
8813
8942
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
8814
8943
|
const portEdge = {
|
|
8815
8944
|
id: portEdgeId,
|
|
8816
8945
|
source: fileNodeId,
|
|
8817
8946
|
target: portNode.id,
|
|
8818
|
-
type:
|
|
8819
|
-
provenance:
|
|
8820
|
-
confidence: (0,
|
|
8947
|
+
type: import_types33.EdgeType.CONNECTS_TO,
|
|
8948
|
+
provenance: import_types33.Provenance.EXTRACTED,
|
|
8949
|
+
confidence: (0, import_types33.confidenceForExtracted)("structural"),
|
|
8821
8950
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
8822
8951
|
};
|
|
8823
8952
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -8830,8 +8959,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8830
8959
|
// src/extract/infra/terraform.ts
|
|
8831
8960
|
init_cjs_shims();
|
|
8832
8961
|
var import_node_fs18 = require("fs");
|
|
8833
|
-
var
|
|
8834
|
-
var
|
|
8962
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8963
|
+
var import_types34 = require("@neat.is/types");
|
|
8835
8964
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
8836
8965
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
8837
8966
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -8841,11 +8970,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
8841
8970
|
for (const entry of entries) {
|
|
8842
8971
|
if (entry.isDirectory()) {
|
|
8843
8972
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
8844
|
-
const child =
|
|
8973
|
+
const child = import_node_path44.default.join(start, entry.name);
|
|
8845
8974
|
if (await isPythonVenvDir(child)) continue;
|
|
8846
8975
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
8847
8976
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
8848
|
-
out.push(
|
|
8977
|
+
out.push(import_node_path44.default.join(start, entry.name));
|
|
8849
8978
|
}
|
|
8850
8979
|
}
|
|
8851
8980
|
return out;
|
|
@@ -8877,7 +9006,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8877
9006
|
const files = await walkTfFiles(scanPath);
|
|
8878
9007
|
for (const file of files) {
|
|
8879
9008
|
const content = await import_node_fs18.promises.readFile(file, "utf8");
|
|
8880
|
-
const evidenceFile = toPosix(
|
|
9009
|
+
const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, file));
|
|
8881
9010
|
const resources = [];
|
|
8882
9011
|
const byKey = /* @__PURE__ */ new Map();
|
|
8883
9012
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -8912,16 +9041,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8912
9041
|
if (!target) continue;
|
|
8913
9042
|
if (seen.has(target.nodeId)) continue;
|
|
8914
9043
|
seen.add(target.nodeId);
|
|
8915
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
9044
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types34.EdgeType.DEPENDS_ON);
|
|
8916
9045
|
if (graph.hasEdge(edgeId)) continue;
|
|
8917
9046
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
8918
9047
|
const edge = {
|
|
8919
9048
|
id: edgeId,
|
|
8920
9049
|
source: resource.nodeId,
|
|
8921
9050
|
target: target.nodeId,
|
|
8922
|
-
type:
|
|
8923
|
-
provenance:
|
|
8924
|
-
confidence: (0,
|
|
9051
|
+
type: import_types34.EdgeType.DEPENDS_ON,
|
|
9052
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9053
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8925
9054
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
8926
9055
|
};
|
|
8927
9056
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8935,7 +9064,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8935
9064
|
// src/extract/infra/k8s.ts
|
|
8936
9065
|
init_cjs_shims();
|
|
8937
9066
|
var import_node_fs19 = require("fs");
|
|
8938
|
-
var
|
|
9067
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8939
9068
|
var import_yaml3 = require("yaml");
|
|
8940
9069
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
8941
9070
|
Service: "k8s-service",
|
|
@@ -8953,11 +9082,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
8953
9082
|
for (const entry of entries) {
|
|
8954
9083
|
if (entry.isDirectory()) {
|
|
8955
9084
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
8956
|
-
const child =
|
|
9085
|
+
const child = import_node_path45.default.join(start, entry.name);
|
|
8957
9086
|
if (await isPythonVenvDir(child)) continue;
|
|
8958
9087
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
8959
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
8960
|
-
out.push(
|
|
9088
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path45.default.extname(entry.name))) {
|
|
9089
|
+
out.push(import_node_path45.default.join(start, entry.name));
|
|
8961
9090
|
}
|
|
8962
9091
|
}
|
|
8963
9092
|
return out;
|
|
@@ -8991,13 +9120,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
8991
9120
|
// src/extract/infra/cloudflare.ts
|
|
8992
9121
|
init_cjs_shims();
|
|
8993
9122
|
var import_node_fs20 = require("fs");
|
|
8994
|
-
var
|
|
9123
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8995
9124
|
var import_smol_toml2 = require("smol-toml");
|
|
8996
|
-
var
|
|
9125
|
+
var import_types35 = require("@neat.is/types");
|
|
8997
9126
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
8998
9127
|
async function readWranglerConfig(dir) {
|
|
8999
9128
|
for (const filename of WRANGLER_FILENAMES) {
|
|
9000
|
-
const abs =
|
|
9129
|
+
const abs = import_node_path46.default.join(dir, filename);
|
|
9001
9130
|
if (!await exists(abs)) continue;
|
|
9002
9131
|
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
9003
9132
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9041,8 +9170,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
9041
9170
|
source: anchorId,
|
|
9042
9171
|
target: node.id,
|
|
9043
9172
|
type: edgeType,
|
|
9044
|
-
provenance:
|
|
9045
|
-
confidence: (0,
|
|
9173
|
+
provenance: import_types35.Provenance.EXTRACTED,
|
|
9174
|
+
confidence: (0, import_types35.confidenceForExtracted)("structural"),
|
|
9046
9175
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
9047
9176
|
};
|
|
9048
9177
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -9060,11 +9189,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9060
9189
|
try {
|
|
9061
9190
|
read = await readWranglerConfig(service.dir);
|
|
9062
9191
|
} catch (err) {
|
|
9063
|
-
recordExtractionError("infra cloudflare",
|
|
9192
|
+
recordExtractionError("infra cloudflare", import_node_path46.default.relative(scanPath, service.dir), err);
|
|
9064
9193
|
continue;
|
|
9065
9194
|
}
|
|
9066
9195
|
if (!read || !read.config.name) continue;
|
|
9067
|
-
const evidenceFile = toPosix(
|
|
9196
|
+
const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, read.relFile)));
|
|
9068
9197
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
9069
9198
|
}
|
|
9070
9199
|
for (const worker of discovered) {
|
|
@@ -9076,7 +9205,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9076
9205
|
}
|
|
9077
9206
|
let anchorId = service.node.id;
|
|
9078
9207
|
if (config.main) {
|
|
9079
|
-
const entryRelPath = toPosix(
|
|
9208
|
+
const entryRelPath = toPosix(import_node_path46.default.normalize(config.main));
|
|
9080
9209
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
9081
9210
|
graph,
|
|
9082
9211
|
service.pkg.name,
|
|
@@ -9103,15 +9232,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9103
9232
|
nodesAdded++;
|
|
9104
9233
|
}
|
|
9105
9234
|
if (runtimeNode.id !== anchorId) {
|
|
9106
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
9235
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types35.EdgeType.RUNS_ON);
|
|
9107
9236
|
if (!graph.hasEdge(runsOnId)) {
|
|
9108
9237
|
const edge = {
|
|
9109
9238
|
id: runsOnId,
|
|
9110
9239
|
source: anchorId,
|
|
9111
9240
|
target: runtimeNode.id,
|
|
9112
|
-
type:
|
|
9113
|
-
provenance:
|
|
9114
|
-
confidence: (0,
|
|
9241
|
+
type: import_types35.EdgeType.RUNS_ON,
|
|
9242
|
+
provenance: import_types35.Provenance.EXTRACTED,
|
|
9243
|
+
confidence: (0, import_types35.confidenceForExtracted)("structural"),
|
|
9115
9244
|
evidence: {
|
|
9116
9245
|
file: evidenceFile,
|
|
9117
9246
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -9125,7 +9254,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9125
9254
|
const result = addResourceEdge(
|
|
9126
9255
|
graph,
|
|
9127
9256
|
anchorId,
|
|
9128
|
-
|
|
9257
|
+
import_types35.EdgeType.CONNECTS_TO,
|
|
9129
9258
|
"cloudflare-route",
|
|
9130
9259
|
route,
|
|
9131
9260
|
evidenceFile,
|
|
@@ -9149,7 +9278,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9149
9278
|
const result = addResourceEdge(
|
|
9150
9279
|
graph,
|
|
9151
9280
|
anchorId,
|
|
9152
|
-
|
|
9281
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9153
9282
|
group.kind,
|
|
9154
9283
|
name,
|
|
9155
9284
|
evidenceFile,
|
|
@@ -9163,7 +9292,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9163
9292
|
const result = addResourceEdge(
|
|
9164
9293
|
graph,
|
|
9165
9294
|
anchorId,
|
|
9166
|
-
|
|
9295
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9167
9296
|
"cloudflare-cron",
|
|
9168
9297
|
cron,
|
|
9169
9298
|
evidenceFile,
|
|
@@ -9176,7 +9305,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9176
9305
|
const result = addResourceEdge(
|
|
9177
9306
|
graph,
|
|
9178
9307
|
anchorId,
|
|
9179
|
-
|
|
9308
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9180
9309
|
"cloudflare-env-var",
|
|
9181
9310
|
varName,
|
|
9182
9311
|
evidenceFile,
|
|
@@ -9189,15 +9318,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9189
9318
|
if (!svc.service) continue;
|
|
9190
9319
|
const target = workerIndex.get(svc.service);
|
|
9191
9320
|
if (target && target.anchorId !== anchorId) {
|
|
9192
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
9321
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types35.EdgeType.CALLS);
|
|
9193
9322
|
if (!graph.hasEdge(edgeId)) {
|
|
9194
9323
|
const edge = {
|
|
9195
9324
|
id: edgeId,
|
|
9196
9325
|
source: anchorId,
|
|
9197
9326
|
target: target.anchorId,
|
|
9198
|
-
type:
|
|
9199
|
-
provenance:
|
|
9200
|
-
confidence: (0,
|
|
9327
|
+
type: import_types35.EdgeType.CALLS,
|
|
9328
|
+
provenance: import_types35.Provenance.EXTRACTED,
|
|
9329
|
+
confidence: (0, import_types35.confidenceForExtracted)("structural"),
|
|
9201
9330
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
9202
9331
|
};
|
|
9203
9332
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -9208,7 +9337,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9208
9337
|
const result = addResourceEdge(
|
|
9209
9338
|
graph,
|
|
9210
9339
|
anchorId,
|
|
9211
|
-
|
|
9340
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9212
9341
|
"cloudflare-service-binding",
|
|
9213
9342
|
svc.service,
|
|
9214
9343
|
evidenceFile,
|
|
@@ -9224,12 +9353,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9224
9353
|
// src/extract/infra/vercel.ts
|
|
9225
9354
|
init_cjs_shims();
|
|
9226
9355
|
var import_node_fs21 = require("fs");
|
|
9227
|
-
var
|
|
9228
|
-
var
|
|
9356
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9357
|
+
var import_types36 = require("@neat.is/types");
|
|
9229
9358
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
9230
9359
|
async function readVercelConfig(dir) {
|
|
9231
9360
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
9232
|
-
const abs =
|
|
9361
|
+
const abs = import_node_path47.default.join(dir, filename);
|
|
9233
9362
|
if (!await exists(abs)) continue;
|
|
9234
9363
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
9235
9364
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9238,7 +9367,7 @@ async function readVercelConfig(dir) {
|
|
|
9238
9367
|
return null;
|
|
9239
9368
|
}
|
|
9240
9369
|
async function readLinkedProjectName(dir) {
|
|
9241
|
-
const abs =
|
|
9370
|
+
const abs = import_node_path47.default.join(dir, ".vercel", "project.json");
|
|
9242
9371
|
if (!await exists(abs)) return void 0;
|
|
9243
9372
|
const parsed = JSON.parse(await import_node_fs21.promises.readFile(abs, "utf8"));
|
|
9244
9373
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -9256,7 +9385,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9256
9385
|
read = await readVercelConfig(service.dir);
|
|
9257
9386
|
projectName = await readLinkedProjectName(service.dir);
|
|
9258
9387
|
} catch (err) {
|
|
9259
|
-
recordExtractionError("infra vercel",
|
|
9388
|
+
recordExtractionError("infra vercel", import_node_path47.default.relative(scanPath, service.dir), err);
|
|
9260
9389
|
continue;
|
|
9261
9390
|
}
|
|
9262
9391
|
if (!read && !projectName) continue;
|
|
@@ -9272,7 +9401,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9272
9401
|
const anchorId = service.node.id;
|
|
9273
9402
|
if (!read) continue;
|
|
9274
9403
|
const { config, relFile, raw } = read;
|
|
9275
|
-
const evidenceFile = toPosix(
|
|
9404
|
+
const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
|
|
9276
9405
|
const add = (edgeType, kind, name) => {
|
|
9277
9406
|
if (!name) return;
|
|
9278
9407
|
const result = emitPlatformResourceEdge(
|
|
@@ -9288,12 +9417,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9288
9417
|
nodesAdded += result.nodesAdded;
|
|
9289
9418
|
edgesAdded += result.edgesAdded;
|
|
9290
9419
|
};
|
|
9291
|
-
add(
|
|
9292
|
-
for (const cron of config.crons ?? []) add(
|
|
9293
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
9294
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
9420
|
+
add(import_types36.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
9421
|
+
for (const cron of config.crons ?? []) add(import_types36.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
9422
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9423
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9295
9424
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
9296
|
-
add(
|
|
9425
|
+
add(import_types36.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
9297
9426
|
}
|
|
9298
9427
|
}
|
|
9299
9428
|
return { nodesAdded, edgesAdded };
|
|
@@ -9302,13 +9431,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9302
9431
|
// src/extract/infra/railway.ts
|
|
9303
9432
|
init_cjs_shims();
|
|
9304
9433
|
var import_node_fs22 = require("fs");
|
|
9305
|
-
var
|
|
9434
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
9306
9435
|
var import_smol_toml3 = require("smol-toml");
|
|
9307
|
-
var
|
|
9436
|
+
var import_types37 = require("@neat.is/types");
|
|
9308
9437
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
9309
9438
|
async function readRailwayConfig(dir) {
|
|
9310
9439
|
for (const filename of RAILWAY_FILENAMES) {
|
|
9311
|
-
const abs =
|
|
9440
|
+
const abs = import_node_path48.default.join(dir, filename);
|
|
9312
9441
|
if (!await exists(abs)) continue;
|
|
9313
9442
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
9314
9443
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9324,7 +9453,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9324
9453
|
try {
|
|
9325
9454
|
read = await readRailwayConfig(service.dir);
|
|
9326
9455
|
} catch (err) {
|
|
9327
|
-
recordExtractionError("infra railway",
|
|
9456
|
+
recordExtractionError("infra railway", import_node_path48.default.relative(scanPath, service.dir), err);
|
|
9328
9457
|
continue;
|
|
9329
9458
|
}
|
|
9330
9459
|
if (!read) continue;
|
|
@@ -9334,7 +9463,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9334
9463
|
}
|
|
9335
9464
|
const anchorId = service.node.id;
|
|
9336
9465
|
const { config, relFile, raw } = read;
|
|
9337
|
-
const evidenceFile = toPosix(
|
|
9466
|
+
const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
|
|
9338
9467
|
const add = (edgeType, kind, name) => {
|
|
9339
9468
|
if (!name) return;
|
|
9340
9469
|
const result = emitPlatformResourceEdge(
|
|
@@ -9350,9 +9479,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9350
9479
|
nodesAdded += result.nodesAdded;
|
|
9351
9480
|
edgesAdded += result.edgesAdded;
|
|
9352
9481
|
};
|
|
9353
|
-
add(
|
|
9354
|
-
add(
|
|
9355
|
-
add(
|
|
9482
|
+
add(import_types37.EdgeType.RUNS_ON, "railway", "railway");
|
|
9483
|
+
add(import_types37.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
9484
|
+
add(import_types37.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
9356
9485
|
}
|
|
9357
9486
|
return { nodesAdded, edgesAdded };
|
|
9358
9487
|
}
|
|
@@ -9360,12 +9489,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9360
9489
|
// src/extract/infra/supabase.ts
|
|
9361
9490
|
init_cjs_shims();
|
|
9362
9491
|
var import_node_fs23 = require("fs");
|
|
9363
|
-
var
|
|
9492
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9364
9493
|
var import_smol_toml4 = require("smol-toml");
|
|
9365
|
-
var
|
|
9494
|
+
var import_types38 = require("@neat.is/types");
|
|
9366
9495
|
async function readSupabaseConfig(dir) {
|
|
9367
|
-
const relFile =
|
|
9368
|
-
const abs =
|
|
9496
|
+
const relFile = import_node_path49.default.join("supabase", "config.toml");
|
|
9497
|
+
const abs = import_node_path49.default.join(dir, relFile);
|
|
9369
9498
|
if (!await exists(abs)) return null;
|
|
9370
9499
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
9371
9500
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -9379,7 +9508,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9379
9508
|
try {
|
|
9380
9509
|
read = await readSupabaseConfig(service.dir);
|
|
9381
9510
|
} catch (err) {
|
|
9382
|
-
recordExtractionError("infra supabase",
|
|
9511
|
+
recordExtractionError("infra supabase", import_node_path49.default.relative(scanPath, service.dir), err);
|
|
9383
9512
|
continue;
|
|
9384
9513
|
}
|
|
9385
9514
|
if (!read) continue;
|
|
@@ -9394,7 +9523,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9394
9523
|
});
|
|
9395
9524
|
}
|
|
9396
9525
|
const anchorId = service.node.id;
|
|
9397
|
-
const evidenceFile = toPosix(
|
|
9526
|
+
const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
|
|
9398
9527
|
const add = (edgeType, kind, name) => {
|
|
9399
9528
|
if (!name) return;
|
|
9400
9529
|
const result = emitPlatformResourceEdge(
|
|
@@ -9410,10 +9539,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9410
9539
|
nodesAdded += result.nodesAdded;
|
|
9411
9540
|
edgesAdded += result.edgesAdded;
|
|
9412
9541
|
};
|
|
9413
|
-
add(
|
|
9414
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
9415
|
-
if (config.storage) add(
|
|
9416
|
-
if (config.auth) add(
|
|
9542
|
+
add(import_types38.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
9543
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types38.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
9544
|
+
if (config.storage) add(import_types38.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
9545
|
+
if (config.auth) add(import_types38.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
9417
9546
|
}
|
|
9418
9547
|
return { nodesAdded, edgesAdded };
|
|
9419
9548
|
}
|
|
@@ -9435,17 +9564,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
9435
9564
|
}
|
|
9436
9565
|
|
|
9437
9566
|
// src/extract/index.ts
|
|
9438
|
-
var
|
|
9567
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
9439
9568
|
|
|
9440
9569
|
// src/extract/retire.ts
|
|
9441
9570
|
init_cjs_shims();
|
|
9442
9571
|
var import_node_fs24 = require("fs");
|
|
9443
|
-
var
|
|
9444
|
-
var
|
|
9572
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9573
|
+
var import_types39 = require("@neat.is/types");
|
|
9445
9574
|
function dropOrphanedFileNodes(graph) {
|
|
9446
9575
|
const orphans = [];
|
|
9447
9576
|
graph.forEachNode((id, attrs) => {
|
|
9448
|
-
if (attrs.type !==
|
|
9577
|
+
if (attrs.type !== import_types39.NodeType.FileNode) return;
|
|
9449
9578
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
9450
9579
|
orphans.push(id);
|
|
9451
9580
|
}
|
|
@@ -9458,14 +9587,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
9458
9587
|
const bases = [scanPath, ...serviceDirs];
|
|
9459
9588
|
graph.forEachEdge((id, attrs) => {
|
|
9460
9589
|
const edge = attrs;
|
|
9461
|
-
if (edge.provenance !==
|
|
9590
|
+
if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
|
|
9462
9591
|
const evidenceFile = edge.evidence?.file;
|
|
9463
9592
|
if (!evidenceFile) return;
|
|
9464
|
-
if (
|
|
9593
|
+
if (import_node_path50.default.isAbsolute(evidenceFile)) {
|
|
9465
9594
|
if (!(0, import_node_fs24.existsSync)(evidenceFile)) toDrop.push(id);
|
|
9466
9595
|
return;
|
|
9467
9596
|
}
|
|
9468
|
-
const found = bases.some((base) => (0, import_node_fs24.existsSync)(
|
|
9597
|
+
const found = bases.some((base) => (0, import_node_fs24.existsSync)(import_node_path50.default.join(base, evidenceFile)));
|
|
9469
9598
|
if (!found) toDrop.push(id);
|
|
9470
9599
|
});
|
|
9471
9600
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -9518,7 +9647,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9518
9647
|
}
|
|
9519
9648
|
const droppedEntries = drainDroppedExtracted();
|
|
9520
9649
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
9521
|
-
const rejectedPath =
|
|
9650
|
+
const rejectedPath = import_node_path51.default.join(import_node_path51.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
9522
9651
|
try {
|
|
9523
9652
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
9524
9653
|
} catch (err) {
|
|
@@ -9553,8 +9682,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9553
9682
|
// src/persist.ts
|
|
9554
9683
|
init_cjs_shims();
|
|
9555
9684
|
var import_node_fs25 = require("fs");
|
|
9556
|
-
var
|
|
9557
|
-
var
|
|
9685
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
9686
|
+
var import_types40 = require("@neat.is/types");
|
|
9558
9687
|
var SCHEMA_VERSION = 6;
|
|
9559
9688
|
function migrateV1ToV2(payload) {
|
|
9560
9689
|
const nodes = payload.graph.nodes;
|
|
@@ -9578,7 +9707,7 @@ function migrateV5ToV6(payload) {
|
|
|
9578
9707
|
if (Array.isArray(nodes)) {
|
|
9579
9708
|
for (const node of nodes) {
|
|
9580
9709
|
const attrs = node.attributes;
|
|
9581
|
-
if (!attrs || attrs.type !==
|
|
9710
|
+
if (!attrs || attrs.type !== import_types40.NodeType.InfraNode) continue;
|
|
9582
9711
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
9583
9712
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
9584
9713
|
}
|
|
@@ -9591,12 +9720,12 @@ function migrateV2ToV3(payload) {
|
|
|
9591
9720
|
for (const edge of edges) {
|
|
9592
9721
|
const attrs = edge.attributes;
|
|
9593
9722
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
9594
|
-
attrs.provenance =
|
|
9723
|
+
attrs.provenance = import_types40.Provenance.OBSERVED;
|
|
9595
9724
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
9596
9725
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
9597
9726
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
9598
9727
|
if (type && source && target) {
|
|
9599
|
-
const newId = (0,
|
|
9728
|
+
const newId = (0, import_types40.observedEdgeId)(source, target, type);
|
|
9600
9729
|
attrs.id = newId;
|
|
9601
9730
|
if (edge.key) edge.key = newId;
|
|
9602
9731
|
}
|
|
@@ -9605,7 +9734,7 @@ function migrateV2ToV3(payload) {
|
|
|
9605
9734
|
return { ...payload, schemaVersion: 3 };
|
|
9606
9735
|
}
|
|
9607
9736
|
async function ensureDir(filePath) {
|
|
9608
|
-
await import_node_fs25.promises.mkdir(
|
|
9737
|
+
await import_node_fs25.promises.mkdir(import_node_path52.default.dirname(filePath), { recursive: true });
|
|
9609
9738
|
}
|
|
9610
9739
|
async function saveGraphToDisk(graph, outPath) {
|
|
9611
9740
|
await ensureDir(outPath);
|
|
@@ -9694,19 +9823,19 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
9694
9823
|
init_cjs_shims();
|
|
9695
9824
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
9696
9825
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
9697
|
-
var
|
|
9826
|
+
var import_types59 = require("@neat.is/types");
|
|
9698
9827
|
|
|
9699
9828
|
// src/extend/index.ts
|
|
9700
9829
|
init_cjs_shims();
|
|
9701
9830
|
var import_node_fs27 = require("fs");
|
|
9702
|
-
var
|
|
9831
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
9703
9832
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
9704
9833
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
9705
9834
|
|
|
9706
9835
|
// src/installers/package-manager.ts
|
|
9707
9836
|
init_cjs_shims();
|
|
9708
9837
|
var import_node_fs26 = require("fs");
|
|
9709
|
-
var
|
|
9838
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
9710
9839
|
var import_node_child_process = require("child_process");
|
|
9711
9840
|
var LOCKFILE_PRIORITY = [
|
|
9712
9841
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -9728,22 +9857,22 @@ async function exists2(p) {
|
|
|
9728
9857
|
}
|
|
9729
9858
|
}
|
|
9730
9859
|
async function detectPackageManager(serviceDir) {
|
|
9731
|
-
let dir =
|
|
9860
|
+
let dir = import_node_path53.default.resolve(serviceDir);
|
|
9732
9861
|
const stops = /* @__PURE__ */ new Set();
|
|
9733
9862
|
for (let i = 0; i < 64; i++) {
|
|
9734
9863
|
if (stops.has(dir)) break;
|
|
9735
9864
|
stops.add(dir);
|
|
9736
9865
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
9737
|
-
const lockPath =
|
|
9866
|
+
const lockPath = import_node_path53.default.join(dir, candidate.lockfile);
|
|
9738
9867
|
if (await exists2(lockPath)) {
|
|
9739
9868
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
9740
9869
|
}
|
|
9741
9870
|
}
|
|
9742
|
-
const parent =
|
|
9871
|
+
const parent = import_node_path53.default.dirname(dir);
|
|
9743
9872
|
if (parent === dir) break;
|
|
9744
9873
|
dir = parent;
|
|
9745
9874
|
}
|
|
9746
|
-
return { pm: "npm", cwd:
|
|
9875
|
+
return { pm: "npm", cwd: import_node_path53.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
9747
9876
|
}
|
|
9748
9877
|
async function runPackageManagerInstall(cmd) {
|
|
9749
9878
|
return new Promise((resolve) => {
|
|
@@ -9792,7 +9921,7 @@ async function fileExists2(p) {
|
|
|
9792
9921
|
}
|
|
9793
9922
|
}
|
|
9794
9923
|
async function readPackageJson(scanPath) {
|
|
9795
|
-
const pkgPath =
|
|
9924
|
+
const pkgPath = import_node_path54.default.join(scanPath, "package.json");
|
|
9796
9925
|
const raw = await import_node_fs27.promises.readFile(pkgPath, "utf8");
|
|
9797
9926
|
return JSON.parse(raw);
|
|
9798
9927
|
}
|
|
@@ -9811,11 +9940,11 @@ async function findHookFiles(scanPath) {
|
|
|
9811
9940
|
for (const entry of entries) {
|
|
9812
9941
|
if (entry.isDirectory()) {
|
|
9813
9942
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
9814
|
-
await walk6(
|
|
9943
|
+
await walk6(import_node_path54.default.join(dir, entry.name));
|
|
9815
9944
|
} else if (entry.isFile()) {
|
|
9816
9945
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
9817
|
-
const rel =
|
|
9818
|
-
found.push(rel.split(
|
|
9946
|
+
const rel = import_node_path54.default.relative(scanPath, import_node_path54.default.join(dir, entry.name));
|
|
9947
|
+
found.push(rel.split(import_node_path54.default.sep).join("/"));
|
|
9819
9948
|
}
|
|
9820
9949
|
}
|
|
9821
9950
|
}
|
|
@@ -9826,7 +9955,7 @@ async function findHookFiles(scanPath) {
|
|
|
9826
9955
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
9827
9956
|
let fallback = null;
|
|
9828
9957
|
for (const file of hookFiles) {
|
|
9829
|
-
const content = await import_node_fs27.promises.readFile(
|
|
9958
|
+
const content = await import_node_fs27.promises.readFile(import_node_path54.default.join(scanPath, file), "utf8");
|
|
9830
9959
|
const patched = splicedContent(content, snippet2);
|
|
9831
9960
|
if (patched !== null) return { file, content, patched };
|
|
9832
9961
|
if (fallback === null) fallback = { file, content };
|
|
@@ -9834,11 +9963,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
9834
9963
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
9835
9964
|
}
|
|
9836
9965
|
function extendLogPath() {
|
|
9837
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
9966
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path54.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
9838
9967
|
}
|
|
9839
9968
|
async function appendExtendLog(entry) {
|
|
9840
9969
|
const logPath = extendLogPath();
|
|
9841
|
-
await import_node_fs27.promises.mkdir(
|
|
9970
|
+
await import_node_fs27.promises.mkdir(import_node_path54.default.dirname(logPath), { recursive: true });
|
|
9842
9971
|
await import_node_fs27.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
9843
9972
|
}
|
|
9844
9973
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -9897,7 +10026,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
9897
10026
|
}
|
|
9898
10027
|
async function describeProjectInstrumentation(ctx) {
|
|
9899
10028
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
9900
|
-
const envNeat = await fileExists2(
|
|
10029
|
+
const envNeat = await fileExists2(import_node_path54.default.join(ctx.scanPath, ".env.neat"));
|
|
9901
10030
|
const registryInstrPackages = new Set(
|
|
9902
10031
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
9903
10032
|
);
|
|
@@ -9919,7 +10048,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
9919
10048
|
);
|
|
9920
10049
|
}
|
|
9921
10050
|
for (const file of hookFiles) {
|
|
9922
|
-
const content = await import_node_fs27.promises.readFile(
|
|
10051
|
+
const content = await import_node_fs27.promises.readFile(import_node_path54.default.join(ctx.scanPath, file), "utf8");
|
|
9923
10052
|
if (content.includes(args.registration_snippet)) {
|
|
9924
10053
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
9925
10054
|
}
|
|
@@ -9931,10 +10060,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
9931
10060
|
);
|
|
9932
10061
|
}
|
|
9933
10062
|
const primaryFile = primary.file;
|
|
9934
|
-
const primaryPath =
|
|
10063
|
+
const primaryPath = import_node_path54.default.join(ctx.scanPath, primaryFile);
|
|
9935
10064
|
const filesTouched = [];
|
|
9936
10065
|
const depsAdded = [];
|
|
9937
|
-
const pkgPath =
|
|
10066
|
+
const pkgPath = import_node_path54.default.join(ctx.scanPath, "package.json");
|
|
9938
10067
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
9939
10068
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
9940
10069
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -9973,7 +10102,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
9973
10102
|
};
|
|
9974
10103
|
}
|
|
9975
10104
|
for (const file of hookFiles) {
|
|
9976
|
-
const content = await import_node_fs27.promises.readFile(
|
|
10105
|
+
const content = await import_node_fs27.promises.readFile(import_node_path54.default.join(ctx.scanPath, file), "utf8");
|
|
9977
10106
|
if (content.includes(args.registration_snippet)) {
|
|
9978
10107
|
return {
|
|
9979
10108
|
library: args.library,
|
|
@@ -10014,7 +10143,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
10014
10143
|
if (!match) {
|
|
10015
10144
|
return { undone: false, message: "no apply found for library" };
|
|
10016
10145
|
}
|
|
10017
|
-
const pkgPath =
|
|
10146
|
+
const pkgPath = import_node_path54.default.join(ctx.scanPath, "package.json");
|
|
10018
10147
|
if (await fileExists2(pkgPath)) {
|
|
10019
10148
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
10020
10149
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -10025,7 +10154,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
10025
10154
|
}
|
|
10026
10155
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
10027
10156
|
for (const file of hookFiles) {
|
|
10028
|
-
const filePath =
|
|
10157
|
+
const filePath = import_node_path54.default.join(ctx.scanPath, file);
|
|
10029
10158
|
const content = await import_node_fs27.promises.readFile(filePath, "utf8");
|
|
10030
10159
|
if (content.includes(match.registration_snippet)) {
|
|
10031
10160
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -10041,39 +10170,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
10041
10170
|
|
|
10042
10171
|
// src/divergences.ts
|
|
10043
10172
|
init_cjs_shims();
|
|
10044
|
-
var
|
|
10173
|
+
var import_types41 = require("@neat.is/types");
|
|
10045
10174
|
function bucketKey(source, target, type) {
|
|
10046
10175
|
return `${type}|${source}|${target}`;
|
|
10047
10176
|
}
|
|
10048
10177
|
function bucketSourceFor(graph, edge) {
|
|
10049
|
-
if (edge.type !==
|
|
10050
|
-
const parsed = (0,
|
|
10178
|
+
if (edge.type !== import_types41.EdgeType.CONNECTS_TO) return edge.source;
|
|
10179
|
+
const parsed = (0, import_types41.parseFileId)(edge.source);
|
|
10051
10180
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
10052
10181
|
const target = graph.getNodeAttributes(edge.target);
|
|
10053
|
-
if (target.type !==
|
|
10054
|
-
return (0,
|
|
10182
|
+
if (target.type !== import_types41.NodeType.DatabaseNode) return edge.source;
|
|
10183
|
+
return (0, import_types41.serviceId)(parsed.service);
|
|
10055
10184
|
}
|
|
10056
10185
|
function bucketEdges(graph) {
|
|
10057
10186
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
10058
10187
|
graph.forEachEdge((id, attrs) => {
|
|
10059
10188
|
const e = attrs;
|
|
10060
|
-
const parsed = (0,
|
|
10189
|
+
const parsed = (0, import_types41.parseEdgeId)(id);
|
|
10061
10190
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
10062
10191
|
const source = bucketSourceFor(graph, e);
|
|
10063
10192
|
const key = bucketKey(source, e.target, e.type);
|
|
10064
10193
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
10065
10194
|
switch (provenance) {
|
|
10066
|
-
case
|
|
10195
|
+
case import_types41.Provenance.EXTRACTED:
|
|
10067
10196
|
cur.extracted = e;
|
|
10068
10197
|
break;
|
|
10069
|
-
case
|
|
10198
|
+
case import_types41.Provenance.OBSERVED:
|
|
10070
10199
|
cur.observed = e;
|
|
10071
10200
|
break;
|
|
10072
|
-
case
|
|
10201
|
+
case import_types41.Provenance.INFERRED:
|
|
10073
10202
|
cur.inferred = e;
|
|
10074
10203
|
break;
|
|
10075
10204
|
default:
|
|
10076
|
-
if (e.provenance ===
|
|
10205
|
+
if (e.provenance === import_types41.Provenance.STALE) cur.stale = e;
|
|
10077
10206
|
}
|
|
10078
10207
|
buckets2.set(key, cur);
|
|
10079
10208
|
});
|
|
@@ -10082,17 +10211,17 @@ function bucketEdges(graph) {
|
|
|
10082
10211
|
function nodeIsFrontier(graph, nodeId) {
|
|
10083
10212
|
if (!graph.hasNode(nodeId)) return false;
|
|
10084
10213
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
10085
|
-
return attrs.type ===
|
|
10214
|
+
return attrs.type === import_types41.NodeType.FrontierNode;
|
|
10086
10215
|
}
|
|
10087
10216
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
10088
10217
|
if (!graph.hasNode(nodeId)) return false;
|
|
10089
10218
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
10090
|
-
return attrs.type ===
|
|
10219
|
+
return attrs.type === import_types41.NodeType.WebSocketChannelNode;
|
|
10091
10220
|
}
|
|
10092
10221
|
function nodeIsSymbol(graph, nodeId) {
|
|
10093
10222
|
if (!graph.hasNode(nodeId)) return false;
|
|
10094
10223
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
10095
|
-
return attrs.type ===
|
|
10224
|
+
return attrs.type === import_types41.NodeType.SymbolNode;
|
|
10096
10225
|
}
|
|
10097
10226
|
function clampConfidence(n) {
|
|
10098
10227
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -10112,14 +10241,14 @@ function gradedConfidence(edge) {
|
|
|
10112
10241
|
return clampConfidence(confidenceForEdge(edge));
|
|
10113
10242
|
}
|
|
10114
10243
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10244
|
+
import_types41.EdgeType.CALLS,
|
|
10245
|
+
import_types41.EdgeType.CONNECTS_TO,
|
|
10246
|
+
import_types41.EdgeType.PUBLISHES_TO,
|
|
10247
|
+
import_types41.EdgeType.CONSUMES_FROM
|
|
10119
10248
|
]);
|
|
10120
10249
|
function detectMissingDivergences(graph, bucket) {
|
|
10121
10250
|
const out = [];
|
|
10122
|
-
if (bucket.type ===
|
|
10251
|
+
if (bucket.type === import_types41.EdgeType.CONTAINS) return out;
|
|
10123
10252
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
10124
10253
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
10125
10254
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
@@ -10161,7 +10290,7 @@ function declaredHostFor(svc) {
|
|
|
10161
10290
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
10162
10291
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
10163
10292
|
const e = graph.getEdgeAttributes(edgeId);
|
|
10164
|
-
if (e.type ===
|
|
10293
|
+
if (e.type === import_types41.EdgeType.CONFIGURED_BY && e.provenance === import_types41.Provenance.EXTRACTED) {
|
|
10165
10294
|
return true;
|
|
10166
10295
|
}
|
|
10167
10296
|
}
|
|
@@ -10174,10 +10303,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
10174
10303
|
const out = [];
|
|
10175
10304
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
10176
10305
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
10177
|
-
if (edge.type !==
|
|
10178
|
-
if (edge.provenance !==
|
|
10306
|
+
if (edge.type !== import_types41.EdgeType.CONNECTS_TO) continue;
|
|
10307
|
+
if (edge.provenance !== import_types41.Provenance.OBSERVED) continue;
|
|
10179
10308
|
const target = graph.getNodeAttributes(edge.target);
|
|
10180
|
-
if (target.type !==
|
|
10309
|
+
if (target.type !== import_types41.NodeType.DatabaseNode) continue;
|
|
10181
10310
|
const observedHost = target.host?.trim();
|
|
10182
10311
|
if (!observedHost) continue;
|
|
10183
10312
|
if (observedHost === declaredHost) continue;
|
|
@@ -10199,10 +10328,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
10199
10328
|
const deps = svc.dependencies ?? {};
|
|
10200
10329
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
10201
10330
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
10202
|
-
if (edge.type !==
|
|
10203
|
-
if (edge.provenance !==
|
|
10331
|
+
if (edge.type !== import_types41.EdgeType.CONNECTS_TO) continue;
|
|
10332
|
+
if (edge.provenance !== import_types41.Provenance.OBSERVED) continue;
|
|
10204
10333
|
const target = graph.getNodeAttributes(edge.target);
|
|
10205
|
-
if (target.type !==
|
|
10334
|
+
if (target.type !== import_types41.NodeType.DatabaseNode) continue;
|
|
10206
10335
|
for (const pair of compatPairs()) {
|
|
10207
10336
|
if (pair.engine !== target.engine) continue;
|
|
10208
10337
|
const declared = deps[pair.driver];
|
|
@@ -10299,7 +10428,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
10299
10428
|
for (const d of all) {
|
|
10300
10429
|
if (d.type !== "host-mismatch") continue;
|
|
10301
10430
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
10302
|
-
declaredHalf.add((0,
|
|
10431
|
+
declaredHalf.add((0, import_types41.databaseId)(d.extractedHost));
|
|
10303
10432
|
}
|
|
10304
10433
|
if (observedHalf.size === 0) return all;
|
|
10305
10434
|
return all.filter((d) => {
|
|
@@ -10318,13 +10447,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
10318
10447
|
}
|
|
10319
10448
|
graph.forEachNode((nodeId, attrs) => {
|
|
10320
10449
|
const n = attrs;
|
|
10321
|
-
if (n.type ===
|
|
10450
|
+
if (n.type === import_types41.NodeType.ServiceNode) {
|
|
10322
10451
|
const svc = n;
|
|
10323
10452
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
10324
10453
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
10325
10454
|
return;
|
|
10326
10455
|
}
|
|
10327
|
-
if (n.type ===
|
|
10456
|
+
if (n.type === import_types41.NodeType.InfraNode && n.kind === "sql-table") {
|
|
10328
10457
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
10329
10458
|
}
|
|
10330
10459
|
});
|
|
@@ -10360,7 +10489,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
10360
10489
|
const bc = "column" in b && b.column ? b.column : "";
|
|
10361
10490
|
return ac.localeCompare(bc);
|
|
10362
10491
|
});
|
|
10363
|
-
return
|
|
10492
|
+
return import_types41.DivergenceResultSchema.parse({
|
|
10364
10493
|
divergences: filtered,
|
|
10365
10494
|
totalAffected: filtered.length,
|
|
10366
10495
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -10491,23 +10620,23 @@ function canonicalJson(value) {
|
|
|
10491
10620
|
|
|
10492
10621
|
// src/projects.ts
|
|
10493
10622
|
init_cjs_shims();
|
|
10494
|
-
var
|
|
10623
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
10495
10624
|
function pathsForProject(project, baseDir) {
|
|
10496
10625
|
if (project === DEFAULT_PROJECT) {
|
|
10497
10626
|
return {
|
|
10498
|
-
snapshotPath:
|
|
10499
|
-
errorsPath:
|
|
10500
|
-
staleEventsPath:
|
|
10501
|
-
embeddingsCachePath:
|
|
10502
|
-
policyViolationsPath:
|
|
10627
|
+
snapshotPath: import_node_path55.default.join(baseDir, "graph.json"),
|
|
10628
|
+
errorsPath: import_node_path55.default.join(baseDir, "errors.ndjson"),
|
|
10629
|
+
staleEventsPath: import_node_path55.default.join(baseDir, "stale-events.ndjson"),
|
|
10630
|
+
embeddingsCachePath: import_node_path55.default.join(baseDir, "embeddings.json"),
|
|
10631
|
+
policyViolationsPath: import_node_path55.default.join(baseDir, "policy-violations.ndjson")
|
|
10503
10632
|
};
|
|
10504
10633
|
}
|
|
10505
10634
|
return {
|
|
10506
|
-
snapshotPath:
|
|
10507
|
-
errorsPath:
|
|
10508
|
-
staleEventsPath:
|
|
10509
|
-
embeddingsCachePath:
|
|
10510
|
-
policyViolationsPath:
|
|
10635
|
+
snapshotPath: import_node_path55.default.join(baseDir, `${project}.json`),
|
|
10636
|
+
errorsPath: import_node_path55.default.join(baseDir, `errors.${project}.ndjson`),
|
|
10637
|
+
staleEventsPath: import_node_path55.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
10638
|
+
embeddingsCachePath: import_node_path55.default.join(baseDir, `embeddings.${project}.json`),
|
|
10639
|
+
policyViolationsPath: import_node_path55.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
10511
10640
|
};
|
|
10512
10641
|
}
|
|
10513
10642
|
var Projects = class {
|
|
@@ -10545,26 +10674,26 @@ var Projects = class {
|
|
|
10545
10674
|
init_cjs_shims();
|
|
10546
10675
|
var import_node_fs29 = require("fs");
|
|
10547
10676
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
10548
|
-
var
|
|
10549
|
-
var
|
|
10677
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
10678
|
+
var import_types42 = require("@neat.is/types");
|
|
10550
10679
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
10551
10680
|
var LOCK_RETRY_MS = 50;
|
|
10552
10681
|
function neatHome() {
|
|
10553
10682
|
const override = process.env.NEAT_HOME;
|
|
10554
|
-
if (override && override.length > 0) return
|
|
10555
|
-
return
|
|
10683
|
+
if (override && override.length > 0) return import_node_path56.default.resolve(override);
|
|
10684
|
+
return import_node_path56.default.join(import_node_os3.default.homedir(), ".neat");
|
|
10556
10685
|
}
|
|
10557
10686
|
function registryPath() {
|
|
10558
|
-
return
|
|
10687
|
+
return import_node_path56.default.join(neatHome(), "projects.json");
|
|
10559
10688
|
}
|
|
10560
10689
|
function registryLockPath() {
|
|
10561
|
-
return
|
|
10690
|
+
return import_node_path56.default.join(neatHome(), "projects.json.lock");
|
|
10562
10691
|
}
|
|
10563
10692
|
function daemonPidPath() {
|
|
10564
|
-
return
|
|
10693
|
+
return import_node_path56.default.join(neatHome(), "neatd.pid");
|
|
10565
10694
|
}
|
|
10566
10695
|
function daemonsDir() {
|
|
10567
|
-
return
|
|
10696
|
+
return import_node_path56.default.join(neatHome(), "daemons");
|
|
10568
10697
|
}
|
|
10569
10698
|
function isFiniteInt(v) {
|
|
10570
10699
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -10605,7 +10734,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
10605
10734
|
const out = [];
|
|
10606
10735
|
for (const name of names) {
|
|
10607
10736
|
if (!name.endsWith(".json")) continue;
|
|
10608
|
-
const file =
|
|
10737
|
+
const file = import_node_path56.default.join(dir, name);
|
|
10609
10738
|
let raw;
|
|
10610
10739
|
try {
|
|
10611
10740
|
raw = await import_node_fs29.promises.readFile(file, "utf8");
|
|
@@ -10682,7 +10811,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
10682
10811
|
}
|
|
10683
10812
|
}
|
|
10684
10813
|
async function normalizeProjectPath(input) {
|
|
10685
|
-
const resolved =
|
|
10814
|
+
const resolved = import_node_path56.default.resolve(input);
|
|
10686
10815
|
try {
|
|
10687
10816
|
return await import_node_fs29.promises.realpath(resolved);
|
|
10688
10817
|
} catch {
|
|
@@ -10690,7 +10819,7 @@ async function normalizeProjectPath(input) {
|
|
|
10690
10819
|
}
|
|
10691
10820
|
}
|
|
10692
10821
|
async function writeAtomically(target, contents) {
|
|
10693
|
-
await import_node_fs29.promises.mkdir(
|
|
10822
|
+
await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(target), { recursive: true });
|
|
10694
10823
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
10695
10824
|
const fd = await import_node_fs29.promises.open(tmp, "w");
|
|
10696
10825
|
try {
|
|
@@ -10703,7 +10832,7 @@ async function writeAtomically(target, contents) {
|
|
|
10703
10832
|
}
|
|
10704
10833
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
10705
10834
|
const deadline = Date.now() + timeoutMs;
|
|
10706
|
-
await import_node_fs29.promises.mkdir(
|
|
10835
|
+
await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(lockPath), { recursive: true });
|
|
10707
10836
|
let probedHolder = false;
|
|
10708
10837
|
while (true) {
|
|
10709
10838
|
try {
|
|
@@ -10756,10 +10885,10 @@ async function readRegistry() {
|
|
|
10756
10885
|
throw err;
|
|
10757
10886
|
}
|
|
10758
10887
|
const parsed = JSON.parse(raw);
|
|
10759
|
-
return
|
|
10888
|
+
return import_types42.RegistryFileSchema.parse(parsed);
|
|
10760
10889
|
}
|
|
10761
10890
|
async function writeRegistry(reg) {
|
|
10762
|
-
const validated =
|
|
10891
|
+
const validated = import_types42.RegistryFileSchema.parse(reg);
|
|
10763
10892
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
10764
10893
|
}
|
|
10765
10894
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -10954,7 +11083,7 @@ init_auth();
|
|
|
10954
11083
|
// src/connectors-config.ts
|
|
10955
11084
|
init_cjs_shims();
|
|
10956
11085
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10957
|
-
var
|
|
11086
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
10958
11087
|
var import_node_fs30 = require("fs");
|
|
10959
11088
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10960
11089
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -10969,11 +11098,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10969
11098
|
};
|
|
10970
11099
|
function neatHome2() {
|
|
10971
11100
|
const override = process.env.NEAT_HOME;
|
|
10972
|
-
if (override && override.length > 0) return
|
|
10973
|
-
return
|
|
11101
|
+
if (override && override.length > 0) return import_node_path57.default.resolve(override);
|
|
11102
|
+
return import_node_path57.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10974
11103
|
}
|
|
10975
11104
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10976
|
-
return
|
|
11105
|
+
return import_node_path57.default.join(home, "connectors.json");
|
|
10977
11106
|
}
|
|
10978
11107
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10979
11108
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -11160,15 +11289,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
11160
11289
|
|
|
11161
11290
|
// src/connectors/index.ts
|
|
11162
11291
|
init_cjs_shims();
|
|
11163
|
-
var
|
|
11292
|
+
var import_types43 = require("@neat.is/types");
|
|
11164
11293
|
var NO_ENV = "unknown";
|
|
11165
11294
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
11166
11295
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
11167
11296
|
const sites = [];
|
|
11168
11297
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
11169
11298
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
11170
|
-
if (edge.provenance !==
|
|
11171
|
-
const parsed = (0,
|
|
11299
|
+
if (edge.provenance !== import_types43.Provenance.EXTRACTED) continue;
|
|
11300
|
+
const parsed = (0, import_types43.parseFileId)(edge.source);
|
|
11172
11301
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
11173
11302
|
const site = { relPath: edge.evidence.file };
|
|
11174
11303
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -11179,7 +11308,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
11179
11308
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
11180
11309
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
11181
11310
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
11182
|
-
if (attrs.type !==
|
|
11311
|
+
if (attrs.type !== import_types43.NodeType.RouteNode || !attrs.path) return void 0;
|
|
11183
11312
|
const site = { relPath: attrs.path };
|
|
11184
11313
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
11185
11314
|
return site;
|
|
@@ -11656,10 +11785,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
11656
11785
|
// src/connectors/supabase/map.ts
|
|
11657
11786
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
11658
11787
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
11659
|
-
function targetFromRestPath(
|
|
11660
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
11788
|
+
function targetFromRestPath(path60) {
|
|
11789
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path60);
|
|
11661
11790
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
11662
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
11791
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path60);
|
|
11663
11792
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
11664
11793
|
return null;
|
|
11665
11794
|
}
|
|
@@ -11770,23 +11899,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
11770
11899
|
|
|
11771
11900
|
// src/connectors/supabase/resolve.ts
|
|
11772
11901
|
init_cjs_shims();
|
|
11773
|
-
var
|
|
11902
|
+
var import_types45 = require("@neat.is/types");
|
|
11774
11903
|
function createSupabaseResolveTarget(graph, config) {
|
|
11775
11904
|
return (signal, _ctx) => {
|
|
11776
11905
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
11777
11906
|
return null;
|
|
11778
11907
|
}
|
|
11779
|
-
const subResourceId = (0,
|
|
11908
|
+
const subResourceId = (0, import_types45.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
11780
11909
|
if (graph.hasNode(subResourceId)) {
|
|
11781
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
11910
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11782
11911
|
}
|
|
11783
|
-
const bareResourceId = (0,
|
|
11912
|
+
const bareResourceId = (0, import_types45.infraId)(signal.targetKind, signal.targetName);
|
|
11784
11913
|
if (graph.hasNode(bareResourceId)) {
|
|
11785
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
11914
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11786
11915
|
}
|
|
11787
|
-
const projectLevelId = (0,
|
|
11916
|
+
const projectLevelId = (0, import_types45.infraId)("supabase", config.nodeRef);
|
|
11788
11917
|
if (graph.hasNode(projectLevelId)) {
|
|
11789
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
11918
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11790
11919
|
}
|
|
11791
11920
|
return null;
|
|
11792
11921
|
};
|
|
@@ -11879,7 +12008,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
11879
12008
|
|
|
11880
12009
|
// src/connectors/railway/index.ts
|
|
11881
12010
|
init_cjs_shims();
|
|
11882
|
-
var
|
|
12011
|
+
var import_types49 = require("@neat.is/types");
|
|
11883
12012
|
|
|
11884
12013
|
// src/connectors/railway/client.ts
|
|
11885
12014
|
init_cjs_shims();
|
|
@@ -12030,7 +12159,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
12030
12159
|
const out = [];
|
|
12031
12160
|
graph.forEachNode((_id, attrs) => {
|
|
12032
12161
|
const node = attrs;
|
|
12033
|
-
if (node.type !==
|
|
12162
|
+
if (node.type !== import_types49.NodeType.RouteNode) return;
|
|
12034
12163
|
const route = attrs;
|
|
12035
12164
|
if (route.service !== serviceName) return;
|
|
12036
12165
|
out.push({
|
|
@@ -12134,12 +12263,12 @@ function createRailwayResolveTarget(config) {
|
|
|
12134
12263
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
12135
12264
|
if (!serviceName) return null;
|
|
12136
12265
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
12137
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
12266
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types49.EdgeType.CALLS };
|
|
12138
12267
|
}
|
|
12139
12268
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
12140
12269
|
const peerName = config.serviceNameById[signal.targetName];
|
|
12141
12270
|
if (!peerName) return null;
|
|
12142
|
-
return { targetNodeId: (0,
|
|
12271
|
+
return { targetNodeId: (0, import_types49.serviceId)(peerName), serviceName, edgeType: import_types49.EdgeType.CONNECTS_TO };
|
|
12143
12272
|
}
|
|
12144
12273
|
return null;
|
|
12145
12274
|
};
|
|
@@ -12263,9 +12392,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
12263
12392
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
12264
12393
|
if (secondSep === -1) return null;
|
|
12265
12394
|
const method = rest.slice(0, secondSep);
|
|
12266
|
-
const
|
|
12267
|
-
if (!resourceName || !method || !
|
|
12268
|
-
return { resourceName, method, path:
|
|
12395
|
+
const path60 = rest.slice(secondSep + 1);
|
|
12396
|
+
if (!resourceName || !method || !path60) return null;
|
|
12397
|
+
return { resourceName, method, path: path60 };
|
|
12269
12398
|
}
|
|
12270
12399
|
function resourceNameFor(type, labels) {
|
|
12271
12400
|
if (!labels) return null;
|
|
@@ -12303,14 +12432,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
12303
12432
|
if (!req) return null;
|
|
12304
12433
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
12305
12434
|
const method = req.requestMethod.toUpperCase();
|
|
12306
|
-
const
|
|
12307
|
-
if (
|
|
12435
|
+
const path60 = pathFromRequestUrl(req.requestUrl);
|
|
12436
|
+
if (path60 === null) return null;
|
|
12308
12437
|
const timestamp = entry.timestamp;
|
|
12309
12438
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
12310
12439
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
12311
12440
|
return {
|
|
12312
12441
|
targetKind: resourceType,
|
|
12313
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
12442
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path60 }),
|
|
12314
12443
|
callCount: 1,
|
|
12315
12444
|
errorCount: isError ? 1 : 0,
|
|
12316
12445
|
lastObservedIso: timestamp
|
|
@@ -12327,7 +12456,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
12327
12456
|
|
|
12328
12457
|
// src/connectors/firebase/resolve.ts
|
|
12329
12458
|
init_cjs_shims();
|
|
12330
|
-
var
|
|
12459
|
+
var import_types50 = require("@neat.is/types");
|
|
12331
12460
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
12332
12461
|
switch (resourceType) {
|
|
12333
12462
|
case "cloud_function":
|
|
@@ -12342,7 +12471,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
12342
12471
|
const entries = [];
|
|
12343
12472
|
graph.forEachNode((_id, attrs) => {
|
|
12344
12473
|
const node = attrs;
|
|
12345
|
-
if (node.type !==
|
|
12474
|
+
if (node.type !== import_types50.NodeType.RouteNode) return;
|
|
12346
12475
|
const route = attrs;
|
|
12347
12476
|
if (route.service !== serviceName) return;
|
|
12348
12477
|
entries.push({
|
|
@@ -12374,7 +12503,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
12374
12503
|
return {
|
|
12375
12504
|
targetNodeId: match.routeNodeId,
|
|
12376
12505
|
serviceName,
|
|
12377
|
-
edgeType:
|
|
12506
|
+
edgeType: import_types50.EdgeType.CALLS
|
|
12378
12507
|
};
|
|
12379
12508
|
};
|
|
12380
12509
|
}
|
|
@@ -12401,7 +12530,7 @@ init_cjs_shims();
|
|
|
12401
12530
|
|
|
12402
12531
|
// src/connectors/cloudflare/connector.ts
|
|
12403
12532
|
init_cjs_shims();
|
|
12404
|
-
var
|
|
12533
|
+
var import_types52 = require("@neat.is/types");
|
|
12405
12534
|
|
|
12406
12535
|
// src/connectors/cloudflare/client.ts
|
|
12407
12536
|
init_cjs_shims();
|
|
@@ -12517,7 +12646,7 @@ function mapEventToSignal(event) {
|
|
|
12517
12646
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
12518
12647
|
const statusCode = metadata?.statusCode;
|
|
12519
12648
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
12520
|
-
const
|
|
12649
|
+
const path60 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
12521
12650
|
return {
|
|
12522
12651
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
12523
12652
|
targetName: scriptName,
|
|
@@ -12525,7 +12654,7 @@ function mapEventToSignal(event) {
|
|
|
12525
12654
|
errorCount: isError ? 1 : 0,
|
|
12526
12655
|
lastObservedIso: observedAt.toISOString(),
|
|
12527
12656
|
method,
|
|
12528
|
-
...
|
|
12657
|
+
...path60 ? { path: path60 } : {},
|
|
12529
12658
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
12530
12659
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
12531
12660
|
};
|
|
@@ -12565,19 +12694,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
12565
12694
|
graph.forEachNode((id, attrs) => {
|
|
12566
12695
|
if (found) return;
|
|
12567
12696
|
const a = attrs;
|
|
12568
|
-
if (a.type ===
|
|
12697
|
+
if (a.type === import_types52.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
12569
12698
|
found = id;
|
|
12570
12699
|
}
|
|
12571
12700
|
});
|
|
12572
12701
|
return found;
|
|
12573
12702
|
}
|
|
12574
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
12575
|
-
const normalizedPath = normalizePathTemplate(
|
|
12703
|
+
function findMatchingRouteNode(graph, serviceName, method, path60) {
|
|
12704
|
+
const normalizedPath = normalizePathTemplate(path60);
|
|
12576
12705
|
let found = null;
|
|
12577
12706
|
graph.forEachNode((id, attrs) => {
|
|
12578
12707
|
if (found) return;
|
|
12579
12708
|
const a = attrs;
|
|
12580
|
-
if (a.type !==
|
|
12709
|
+
if (a.type !== import_types52.NodeType.RouteNode || a.service !== serviceName) return;
|
|
12581
12710
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
12582
12711
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
12583
12712
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -12589,18 +12718,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12589
12718
|
return (signal) => {
|
|
12590
12719
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
12591
12720
|
const scriptName = signal.targetName;
|
|
12592
|
-
const { method, path:
|
|
12721
|
+
const { method, path: path60 } = signal;
|
|
12593
12722
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
12594
|
-
if (!method || !
|
|
12595
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
12723
|
+
if (!method || !path60) return wholeFileId;
|
|
12724
|
+
return findMatchingRouteNode(graph, serviceName, method, path60) ?? wholeFileId;
|
|
12596
12725
|
};
|
|
12597
12726
|
const mapping = config.workers?.[scriptName];
|
|
12598
12727
|
if (mapping) {
|
|
12599
|
-
const wholeFileId = (0,
|
|
12728
|
+
const wholeFileId = (0, import_types52.fileId)(mapping.service, mapping.entryFile);
|
|
12600
12729
|
return {
|
|
12601
12730
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
12602
12731
|
serviceName: mapping.service,
|
|
12603
|
-
edgeType:
|
|
12732
|
+
edgeType: import_types52.EdgeType.CALLS
|
|
12604
12733
|
};
|
|
12605
12734
|
}
|
|
12606
12735
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -12609,13 +12738,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12609
12738
|
return {
|
|
12610
12739
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
12611
12740
|
serviceName: fileNode.service,
|
|
12612
|
-
edgeType:
|
|
12741
|
+
edgeType: import_types52.EdgeType.CALLS
|
|
12613
12742
|
};
|
|
12614
12743
|
}
|
|
12615
12744
|
return {
|
|
12616
|
-
targetNodeId: (0,
|
|
12745
|
+
targetNodeId: (0, import_types52.infraId)("cloudflare-worker", scriptName),
|
|
12617
12746
|
serviceName: scriptName,
|
|
12618
|
-
edgeType:
|
|
12747
|
+
edgeType: import_types52.EdgeType.CALLS,
|
|
12619
12748
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
12620
12749
|
};
|
|
12621
12750
|
};
|
|
@@ -12811,14 +12940,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
12811
12940
|
|
|
12812
12941
|
// src/connectors/neon/resolve.ts
|
|
12813
12942
|
init_cjs_shims();
|
|
12814
|
-
var
|
|
12943
|
+
var import_types56 = require("@neat.is/types");
|
|
12815
12944
|
function createNeonResolveTarget(config) {
|
|
12816
12945
|
return (signal) => {
|
|
12817
12946
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
12818
12947
|
return {
|
|
12819
|
-
targetNodeId: (0,
|
|
12948
|
+
targetNodeId: (0, import_types56.infraId)("sql-table", signal.targetName),
|
|
12820
12949
|
serviceName: config.serviceName,
|
|
12821
|
-
edgeType:
|
|
12950
|
+
edgeType: import_types56.EdgeType.CALLS,
|
|
12822
12951
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
12823
12952
|
};
|
|
12824
12953
|
};
|
|
@@ -13382,11 +13511,11 @@ function registerRoutes(scope, ctx) {
|
|
|
13382
13511
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
13383
13512
|
const parsed = [];
|
|
13384
13513
|
for (const c of candidates) {
|
|
13385
|
-
const r =
|
|
13514
|
+
const r = import_types59.DivergenceTypeSchema.safeParse(c);
|
|
13386
13515
|
if (!r.success) {
|
|
13387
13516
|
return reply.code(400).send({
|
|
13388
13517
|
error: `unknown divergence type "${c}"`,
|
|
13389
|
-
allowed:
|
|
13518
|
+
allowed: import_types59.DivergenceTypeSchema.options
|
|
13390
13519
|
});
|
|
13391
13520
|
}
|
|
13392
13521
|
parsed.push(r.data);
|
|
@@ -13695,7 +13824,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13695
13824
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
13696
13825
|
let violations = await log.readAll();
|
|
13697
13826
|
if (req.query.severity) {
|
|
13698
|
-
const sev =
|
|
13827
|
+
const sev = import_types59.PolicySeveritySchema.safeParse(req.query.severity);
|
|
13699
13828
|
if (!sev.success) {
|
|
13700
13829
|
return reply.code(400).send({
|
|
13701
13830
|
error: "invalid severity",
|
|
@@ -13734,7 +13863,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13734
13863
|
scope.post("/policies/check", async (req, reply) => {
|
|
13735
13864
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
13736
13865
|
if (!proj) return;
|
|
13737
|
-
const parsed =
|
|
13866
|
+
const parsed = import_types59.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
13738
13867
|
if (!parsed.success) {
|
|
13739
13868
|
return reply.code(400).send({
|
|
13740
13869
|
error: "invalid /policies/check body",
|
|
@@ -14056,7 +14185,7 @@ init_otel_grpc();
|
|
|
14056
14185
|
// src/daemon.ts
|
|
14057
14186
|
init_cjs_shims();
|
|
14058
14187
|
var import_node_fs32 = require("fs");
|
|
14059
|
-
var
|
|
14188
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14060
14189
|
var import_node_module = require("module");
|
|
14061
14190
|
init_otel();
|
|
14062
14191
|
init_auth();
|
|
@@ -14064,7 +14193,7 @@ init_auth();
|
|
|
14064
14193
|
// src/unrouted.ts
|
|
14065
14194
|
init_cjs_shims();
|
|
14066
14195
|
var import_node_fs31 = require("fs");
|
|
14067
|
-
var
|
|
14196
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
14068
14197
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
14069
14198
|
return {
|
|
14070
14199
|
timestamp: now.toISOString(),
|
|
@@ -14074,34 +14203,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
14074
14203
|
};
|
|
14075
14204
|
}
|
|
14076
14205
|
async function appendUnroutedSpan(neatHome3, record) {
|
|
14077
|
-
const target =
|
|
14206
|
+
const target = import_node_path58.default.join(neatHome3, "errors.ndjson");
|
|
14078
14207
|
await import_node_fs31.promises.mkdir(neatHome3, { recursive: true });
|
|
14079
14208
|
await import_node_fs31.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
14080
14209
|
}
|
|
14081
14210
|
function unroutedErrorsPath(neatHome3) {
|
|
14082
|
-
return
|
|
14211
|
+
return import_node_path58.default.join(neatHome3, "errors.ndjson");
|
|
14083
14212
|
}
|
|
14084
14213
|
|
|
14085
14214
|
// src/daemon.ts
|
|
14086
|
-
var
|
|
14215
|
+
var import_types60 = require("@neat.is/types");
|
|
14087
14216
|
function daemonJsonPath(scanPath) {
|
|
14088
|
-
return
|
|
14217
|
+
return import_node_path59.default.join(scanPath, "neat-out", "daemon.json");
|
|
14089
14218
|
}
|
|
14090
14219
|
function daemonsDiscoveryDir(home) {
|
|
14091
14220
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
14092
|
-
return
|
|
14221
|
+
return import_node_path59.default.join(base, "daemons");
|
|
14093
14222
|
}
|
|
14094
14223
|
function daemonDiscoveryPath(project, home) {
|
|
14095
|
-
return
|
|
14224
|
+
return import_node_path59.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
14096
14225
|
}
|
|
14097
14226
|
function sanitizeDiscoveryName(project) {
|
|
14098
14227
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
14099
14228
|
}
|
|
14100
14229
|
function neatHomeFromEnv() {
|
|
14101
14230
|
const env = process.env.NEAT_HOME;
|
|
14102
|
-
if (env && env.length > 0) return
|
|
14231
|
+
if (env && env.length > 0) return import_node_path59.default.resolve(env);
|
|
14103
14232
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
14104
|
-
return
|
|
14233
|
+
return import_node_path59.default.join(home, ".neat");
|
|
14105
14234
|
}
|
|
14106
14235
|
function resolveNeatVersion() {
|
|
14107
14236
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -14156,11 +14285,11 @@ function teardownSlot(slot) {
|
|
|
14156
14285
|
}
|
|
14157
14286
|
}
|
|
14158
14287
|
function neatHomeFor(opts) {
|
|
14159
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
14288
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path59.default.resolve(opts.neatHome);
|
|
14160
14289
|
const env = process.env.NEAT_HOME;
|
|
14161
|
-
if (env && env.length > 0) return
|
|
14290
|
+
if (env && env.length > 0) return import_node_path59.default.resolve(env);
|
|
14162
14291
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
14163
|
-
return
|
|
14292
|
+
return import_node_path59.default.join(home, ".neat");
|
|
14164
14293
|
}
|
|
14165
14294
|
function routeSpanToProject(serviceName, projects) {
|
|
14166
14295
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -14208,11 +14337,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
14208
14337
|
if (!serviceName) return true;
|
|
14209
14338
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
14210
14339
|
return graph.someNode(
|
|
14211
|
-
(_id, attrs) => attrs.type ===
|
|
14340
|
+
(_id, attrs) => attrs.type === import_types60.NodeType.ServiceNode && attrs.name === serviceName
|
|
14212
14341
|
);
|
|
14213
14342
|
}
|
|
14214
14343
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
14215
|
-
const paths = pathsForProject(entry.name,
|
|
14344
|
+
const paths = pathsForProject(entry.name, import_node_path59.default.join(entry.path, "neat-out"));
|
|
14216
14345
|
try {
|
|
14217
14346
|
const stat = await import_node_fs32.promises.stat(entry.path);
|
|
14218
14347
|
if (!stat.isDirectory()) {
|
|
@@ -14328,7 +14457,7 @@ async function startDaemon(opts = {}) {
|
|
|
14328
14457
|
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;
|
|
14329
14458
|
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;
|
|
14330
14459
|
const singleProject = projectArg;
|
|
14331
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
14460
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path59.default.resolve(projectPathArg) : null;
|
|
14332
14461
|
if (singleProject && !singleProjectPath) {
|
|
14333
14462
|
throw new Error(
|
|
14334
14463
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -14343,7 +14472,7 @@ async function startDaemon(opts = {}) {
|
|
|
14343
14472
|
);
|
|
14344
14473
|
}
|
|
14345
14474
|
}
|
|
14346
|
-
const pidPath =
|
|
14475
|
+
const pidPath = import_node_path59.default.join(home, "neatd.pid");
|
|
14347
14476
|
await writeAtomically(pidPath, `${process.pid}
|
|
14348
14477
|
`);
|
|
14349
14478
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -14755,8 +14884,8 @@ async function startDaemon(opts = {}) {
|
|
|
14755
14884
|
let registryWatcher = null;
|
|
14756
14885
|
let reloadTimer = null;
|
|
14757
14886
|
if (!singleProject) try {
|
|
14758
|
-
const regDir =
|
|
14759
|
-
const regBase =
|
|
14887
|
+
const regDir = import_node_path59.default.dirname(regPath);
|
|
14888
|
+
const regBase = import_node_path59.default.basename(regPath);
|
|
14760
14889
|
registryWatcher = (0, import_node_fs32.watch)(regDir, (_eventType, filename) => {
|
|
14761
14890
|
if (filename !== null && filename !== regBase) return;
|
|
14762
14891
|
if (reloadTimer) clearTimeout(reloadTimer);
|