@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/neatd.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req2, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path62 = (req2.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path62) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path62)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -194,8 +194,8 @@ function reshapeGrpcRequest(req2) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
function resolveProtoRoot() {
|
|
197
|
-
const here =
|
|
198
|
-
return
|
|
197
|
+
const here = import_node_path39.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path39.default.resolve(here, "..", "proto");
|
|
199
199
|
}
|
|
200
200
|
function loadTraceService() {
|
|
201
201
|
const protoRoot = resolveProtoRoot();
|
|
@@ -263,13 +263,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
263
263
|
})
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
|
-
var import_node_url,
|
|
266
|
+
var import_node_url, import_node_path39, import_node_crypto2, grpc, protoLoader;
|
|
267
267
|
var init_otel_grpc = __esm({
|
|
268
268
|
"src/otel-grpc.ts"() {
|
|
269
269
|
"use strict";
|
|
270
270
|
init_cjs_shims();
|
|
271
271
|
import_node_url = require("url");
|
|
272
|
-
|
|
272
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
273
273
|
import_node_crypto2 = require("crypto");
|
|
274
274
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
275
275
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -415,8 +415,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
415
415
|
const v = attrs[key];
|
|
416
416
|
if (typeof v === "string" && v.length > 0) {
|
|
417
417
|
const q = v.indexOf("?");
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
418
|
+
const path62 = q === -1 ? v : v.slice(0, q);
|
|
419
|
+
if (path62.length > 0) return path62;
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
return void 0;
|
|
@@ -475,10 +475,10 @@ function parseOtlpRequest(body) {
|
|
|
475
475
|
return out;
|
|
476
476
|
}
|
|
477
477
|
function loadProtoRoot() {
|
|
478
|
-
const here =
|
|
479
|
-
const protoRoot =
|
|
478
|
+
const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
479
|
+
const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
|
|
480
480
|
const root = new import_protobufjs.default.Root();
|
|
481
|
-
root.resolvePath = (_origin, target) =>
|
|
481
|
+
root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
|
|
482
482
|
root.loadSync(
|
|
483
483
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
484
484
|
{ keepCase: true }
|
|
@@ -709,12 +709,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
711
|
}
|
|
712
|
-
var
|
|
712
|
+
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;
|
|
713
713
|
var init_otel = __esm({
|
|
714
714
|
"src/otel.ts"() {
|
|
715
715
|
"use strict";
|
|
716
716
|
init_cjs_shims();
|
|
717
|
-
|
|
717
|
+
import_node_path40 = __toESM(require("path"), 1);
|
|
718
718
|
import_node_url2 = require("url");
|
|
719
719
|
import_fastify = __toESM(require("fastify"), 1);
|
|
720
720
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -738,13 +738,13 @@ __export(neatd_exports, {
|
|
|
738
738
|
module.exports = __toCommonJS(neatd_exports);
|
|
739
739
|
init_cjs_shims();
|
|
740
740
|
var import_node_fs34 = require("fs");
|
|
741
|
-
var
|
|
741
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
742
742
|
var import_node_module2 = require("module");
|
|
743
743
|
|
|
744
744
|
// src/daemon.ts
|
|
745
745
|
init_cjs_shims();
|
|
746
746
|
var import_node_fs32 = require("fs");
|
|
747
|
-
var
|
|
747
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
748
748
|
var import_node_module = require("module");
|
|
749
749
|
|
|
750
750
|
// src/graph.ts
|
|
@@ -1277,19 +1277,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1277
1277
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1278
1278
|
let best = { path: [start], edges: [] };
|
|
1279
1279
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1280
|
-
function step(node,
|
|
1281
|
-
if (
|
|
1282
|
-
best = { path: [...
|
|
1280
|
+
function step(node, path62, edges) {
|
|
1281
|
+
if (path62.length > best.path.length) {
|
|
1282
|
+
best = { path: [...path62], edges: [...edges] };
|
|
1283
1283
|
}
|
|
1284
|
-
if (
|
|
1284
|
+
if (path62.length - 1 >= maxDepth) return;
|
|
1285
1285
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1286
1286
|
for (const [srcId, edge] of incoming) {
|
|
1287
1287
|
if (visited.has(srcId)) continue;
|
|
1288
1288
|
visited.add(srcId);
|
|
1289
|
-
|
|
1289
|
+
path62.push(srcId);
|
|
1290
1290
|
edges.push(edge);
|
|
1291
|
-
step(srcId,
|
|
1292
|
-
|
|
1291
|
+
step(srcId, path62, edges);
|
|
1292
|
+
path62.pop();
|
|
1293
1293
|
edges.pop();
|
|
1294
1294
|
visited.delete(srcId);
|
|
1295
1295
|
}
|
|
@@ -1496,26 +1496,26 @@ function dominantFailingCall(graph, serviceId7, visited) {
|
|
|
1496
1496
|
return best;
|
|
1497
1497
|
}
|
|
1498
1498
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1499
|
-
const
|
|
1499
|
+
const path62 = [originServiceId];
|
|
1500
1500
|
const edges = [];
|
|
1501
1501
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1502
1502
|
let current = originServiceId;
|
|
1503
1503
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1504
1504
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1505
1505
|
if (!hop) break;
|
|
1506
|
-
|
|
1506
|
+
path62.push(hop.nextService);
|
|
1507
1507
|
edges.push(hop.edge);
|
|
1508
1508
|
visited.add(hop.nextService);
|
|
1509
1509
|
current = hop.nextService;
|
|
1510
1510
|
}
|
|
1511
1511
|
if (edges.length === 0) return null;
|
|
1512
|
-
return { path:
|
|
1512
|
+
return { path: path62, edges, culprit: current };
|
|
1513
1513
|
}
|
|
1514
1514
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1515
1515
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1516
1516
|
if (!chain) return null;
|
|
1517
1517
|
const culprit = chain.culprit;
|
|
1518
|
-
const
|
|
1518
|
+
const path62 = [...chain.path];
|
|
1519
1519
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1520
1520
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1521
1521
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1523,14 +1523,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1523
1523
|
if (loc) {
|
|
1524
1524
|
let rootCauseNode = culprit;
|
|
1525
1525
|
if (loc.fileNode) {
|
|
1526
|
-
|
|
1526
|
+
path62.push(loc.fileNode);
|
|
1527
1527
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1528
1528
|
rootCauseNode = loc.fileNode;
|
|
1529
1529
|
}
|
|
1530
1530
|
return import_types.RootCauseResultSchema.parse({
|
|
1531
1531
|
rootCauseNode,
|
|
1532
1532
|
rootCauseReason: loc.rootCauseReason,
|
|
1533
|
-
traversalPath:
|
|
1533
|
+
traversalPath: path62,
|
|
1534
1534
|
edgeProvenances,
|
|
1535
1535
|
confidence,
|
|
1536
1536
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1542,7 +1542,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1542
1542
|
return import_types.RootCauseResultSchema.parse({
|
|
1543
1543
|
rootCauseNode: culprit,
|
|
1544
1544
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1545
|
-
traversalPath:
|
|
1545
|
+
traversalPath: path62,
|
|
1546
1546
|
edgeProvenances,
|
|
1547
1547
|
confidence,
|
|
1548
1548
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -6909,7 +6909,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
6909
6909
|
|
|
6910
6910
|
// src/extract/calls/index.ts
|
|
6911
6911
|
init_cjs_shims();
|
|
6912
|
-
var
|
|
6912
|
+
var import_types30 = require("@neat.is/types");
|
|
6913
6913
|
|
|
6914
6914
|
// src/extract/calls/http.ts
|
|
6915
6915
|
init_cjs_shims();
|
|
@@ -8365,12 +8365,140 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
8365
8365
|
return out;
|
|
8366
8366
|
}
|
|
8367
8367
|
|
|
8368
|
+
// src/extract/calls/prisma.ts
|
|
8369
|
+
init_cjs_shims();
|
|
8370
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
8371
|
+
var import_types28 = require("@neat.is/types");
|
|
8372
|
+
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
8373
|
+
"Int",
|
|
8374
|
+
"String",
|
|
8375
|
+
"Boolean",
|
|
8376
|
+
"DateTime",
|
|
8377
|
+
"Float",
|
|
8378
|
+
"Decimal",
|
|
8379
|
+
"BigInt",
|
|
8380
|
+
"Bytes",
|
|
8381
|
+
"Json"
|
|
8382
|
+
]);
|
|
8383
|
+
function stripLineComment(line) {
|
|
8384
|
+
let inStr = false;
|
|
8385
|
+
for (let i = 0; i < line.length; i++) {
|
|
8386
|
+
const ch = line[i];
|
|
8387
|
+
if (ch === '"' && line[i - 1] !== "\\") inStr = !inStr;
|
|
8388
|
+
else if (!inStr && ch === "/" && line[i + 1] === "/") return line.slice(0, i);
|
|
8389
|
+
}
|
|
8390
|
+
return line;
|
|
8391
|
+
}
|
|
8392
|
+
function netBraces(line) {
|
|
8393
|
+
const s = stripLineComment(line).replace(/"(\\.|[^"\\])*"/g, "");
|
|
8394
|
+
let n = 0;
|
|
8395
|
+
for (const ch of s) {
|
|
8396
|
+
if (ch === "{") n++;
|
|
8397
|
+
else if (ch === "}") n--;
|
|
8398
|
+
}
|
|
8399
|
+
return n;
|
|
8400
|
+
}
|
|
8401
|
+
function prismaColumnsFromSchema(file, serviceDir) {
|
|
8402
|
+
const content = file.content;
|
|
8403
|
+
if (!/\bmodel\s+[A-Za-z_]\w*\s*\{/.test(content)) return [];
|
|
8404
|
+
const lines = content.split("\n");
|
|
8405
|
+
const modelNames = /* @__PURE__ */ new Set();
|
|
8406
|
+
const enumNames = /* @__PURE__ */ new Set();
|
|
8407
|
+
for (const line of lines) {
|
|
8408
|
+
const m = line.match(/^\s*model\s+([A-Za-z_]\w*)\s*\{/);
|
|
8409
|
+
if (m) modelNames.add(m[1]);
|
|
8410
|
+
const e = line.match(/^\s*enum\s+([A-Za-z_]\w*)\s*\{/);
|
|
8411
|
+
if (e) enumNames.add(e[1]);
|
|
8412
|
+
}
|
|
8413
|
+
const out = [];
|
|
8414
|
+
const seenTable = /* @__PURE__ */ new Set();
|
|
8415
|
+
const finalize = (b) => {
|
|
8416
|
+
if (seenTable.has(b.tableName)) return;
|
|
8417
|
+
seenTable.add(b.tableName);
|
|
8418
|
+
out.push({
|
|
8419
|
+
infraId: (0, import_types28.infraId)("sql-table", b.tableName),
|
|
8420
|
+
name: b.tableName,
|
|
8421
|
+
kind: "sql-table",
|
|
8422
|
+
edgeType: "CALLS",
|
|
8423
|
+
confidenceKind: "structural",
|
|
8424
|
+
columns: b.columns,
|
|
8425
|
+
evidence: {
|
|
8426
|
+
file: import_node_path38.default.relative(serviceDir, file.path),
|
|
8427
|
+
line: b.startLine,
|
|
8428
|
+
snippet: snippet(content, b.startLine)
|
|
8429
|
+
}
|
|
8430
|
+
});
|
|
8431
|
+
};
|
|
8432
|
+
let current = null;
|
|
8433
|
+
let depth = 0;
|
|
8434
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8435
|
+
const raw = lines[i];
|
|
8436
|
+
const lineNo = i + 1;
|
|
8437
|
+
if (current === null) {
|
|
8438
|
+
const header = raw.match(/^\s*(model|enum|datasource|generator|type)\s+([A-Za-z_]\w*)\b/);
|
|
8439
|
+
if (header && raw.includes("{")) {
|
|
8440
|
+
current = {
|
|
8441
|
+
kind: header[1],
|
|
8442
|
+
tableName: header[2],
|
|
8443
|
+
startLine: lineNo,
|
|
8444
|
+
columns: [],
|
|
8445
|
+
seenCol: /* @__PURE__ */ new Set()
|
|
8446
|
+
};
|
|
8447
|
+
depth = netBraces(raw);
|
|
8448
|
+
if (depth <= 0) {
|
|
8449
|
+
if (current.kind === "model") finalize(current);
|
|
8450
|
+
current = null;
|
|
8451
|
+
}
|
|
8452
|
+
}
|
|
8453
|
+
continue;
|
|
8454
|
+
}
|
|
8455
|
+
depth += netBraces(raw);
|
|
8456
|
+
if (depth <= 0) {
|
|
8457
|
+
if (current.kind === "model") finalize(current);
|
|
8458
|
+
current = null;
|
|
8459
|
+
continue;
|
|
8460
|
+
}
|
|
8461
|
+
if (current.kind !== "model") continue;
|
|
8462
|
+
const trimmed = stripLineComment(raw).trim();
|
|
8463
|
+
if (!trimmed) continue;
|
|
8464
|
+
if (trimmed.startsWith("@@")) {
|
|
8465
|
+
const map = trimmed.match(/@@map\(\s*"([^"]+)"\s*\)/);
|
|
8466
|
+
if (map) current.tableName = map[1];
|
|
8467
|
+
continue;
|
|
8468
|
+
}
|
|
8469
|
+
const fm = trimmed.match(/^([A-Za-z_]\w*)\s+([A-Za-z_]\w*)/);
|
|
8470
|
+
if (!fm) continue;
|
|
8471
|
+
const fieldName = fm[1];
|
|
8472
|
+
const baseType = fm[2];
|
|
8473
|
+
if (/@relation\b/.test(trimmed) || modelNames.has(baseType)) continue;
|
|
8474
|
+
if (!enumNames.has(baseType) && !SCALAR_TYPES.has(baseType)) continue;
|
|
8475
|
+
const mapM = trimmed.match(/(?<!@)@map\(\s*"([^"]+)"\s*\)/);
|
|
8476
|
+
const columnName = mapM ? mapM[1] : fieldName;
|
|
8477
|
+
if (!current.seenCol.has(columnName)) {
|
|
8478
|
+
current.seenCol.add(columnName);
|
|
8479
|
+
current.columns.push(columnName);
|
|
8480
|
+
}
|
|
8481
|
+
}
|
|
8482
|
+
if (current && current.kind === "model") finalize(current);
|
|
8483
|
+
return out;
|
|
8484
|
+
}
|
|
8485
|
+
async function prismaColumnEndpoints(serviceDir) {
|
|
8486
|
+
const schemaPath = await findFirst(serviceDir, [
|
|
8487
|
+
import_node_path38.default.join("prisma", "schema.prisma"),
|
|
8488
|
+
"schema.prisma"
|
|
8489
|
+
]);
|
|
8490
|
+
if (!schemaPath) return [];
|
|
8491
|
+
const content = await readIfExists(schemaPath);
|
|
8492
|
+
if (!content) return [];
|
|
8493
|
+
return prismaColumnsFromSchema({ path: schemaPath, content }, serviceDir);
|
|
8494
|
+
}
|
|
8495
|
+
|
|
8368
8496
|
// src/extract/calls/go.ts
|
|
8369
8497
|
init_cjs_shims();
|
|
8370
|
-
var
|
|
8498
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
8371
8499
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
8372
8500
|
var import_tree_sitter_go3 = __toESM(require("tree-sitter-go"), 1);
|
|
8373
|
-
var
|
|
8501
|
+
var import_types29 = require("@neat.is/types");
|
|
8374
8502
|
init_otel();
|
|
8375
8503
|
var SQL_METHODS = /* @__PURE__ */ new Set(["Exec", "ExecContext", "Query", "QueryContext", "QueryRow", "QueryRowContext"]);
|
|
8376
8504
|
var PARSE_CHUNK8 = 16384;
|
|
@@ -8382,7 +8510,7 @@ function walk5(node, visit) {
|
|
|
8382
8510
|
}
|
|
8383
8511
|
}
|
|
8384
8512
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
8385
|
-
if (
|
|
8513
|
+
if (import_node_path41.default.extname(file.path) !== ".go") return [];
|
|
8386
8514
|
const parser = new import_tree_sitter10.default();
|
|
8387
8515
|
parser.setLanguage(import_tree_sitter_go3.default);
|
|
8388
8516
|
const tree = parser.parse(
|
|
@@ -8402,12 +8530,12 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8402
8530
|
if (!table) return;
|
|
8403
8531
|
const line = node.startPosition.row + 1;
|
|
8404
8532
|
out.push({
|
|
8405
|
-
infraId: (0,
|
|
8533
|
+
infraId: (0, import_types29.infraId)("sql-table", table),
|
|
8406
8534
|
name: table,
|
|
8407
8535
|
kind: "sql-table",
|
|
8408
8536
|
edgeType: "CALLS",
|
|
8409
8537
|
confidenceKind: "verified-call-site",
|
|
8410
|
-
evidence: { file: toPosix(
|
|
8538
|
+
evidence: { file: toPosix(import_node_path41.default.relative(serviceDir, file.path)), line, snippet: snippet(file.content, line) }
|
|
8411
8539
|
});
|
|
8412
8540
|
});
|
|
8413
8541
|
return out;
|
|
@@ -8417,11 +8545,11 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
8417
8545
|
function edgeTypeFromEndpoint(ep) {
|
|
8418
8546
|
switch (ep.edgeType) {
|
|
8419
8547
|
case "PUBLISHES_TO":
|
|
8420
|
-
return
|
|
8548
|
+
return import_types30.EdgeType.PUBLISHES_TO;
|
|
8421
8549
|
case "CONSUMES_FROM":
|
|
8422
|
-
return
|
|
8550
|
+
return import_types30.EdgeType.CONSUMES_FROM;
|
|
8423
8551
|
default:
|
|
8424
|
-
return
|
|
8552
|
+
return import_types30.EdgeType.CALLS;
|
|
8425
8553
|
}
|
|
8426
8554
|
}
|
|
8427
8555
|
function isAwsKind(kind) {
|
|
@@ -8456,13 +8584,14 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8456
8584
|
}
|
|
8457
8585
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
8458
8586
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
8587
|
+
endpoints.push(...await prismaColumnEndpoints(service.dir));
|
|
8459
8588
|
if (endpoints.length === 0) continue;
|
|
8460
8589
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
8461
8590
|
for (const ep of endpoints) {
|
|
8462
8591
|
if (!graph.hasNode(ep.infraId)) {
|
|
8463
8592
|
const node = {
|
|
8464
8593
|
id: ep.infraId,
|
|
8465
|
-
type:
|
|
8594
|
+
type: import_types30.NodeType.InfraNode,
|
|
8466
8595
|
name: ep.name,
|
|
8467
8596
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
8468
8597
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -8475,20 +8604,20 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8475
8604
|
}
|
|
8476
8605
|
if (ep.columns && ep.columns.length > 0) {
|
|
8477
8606
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
8478
|
-
if (node.type ===
|
|
8607
|
+
if (node.type === import_types30.NodeType.InfraNode) {
|
|
8479
8608
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
8480
8609
|
...node,
|
|
8481
8610
|
columns: foldColumns(
|
|
8482
8611
|
node.columns,
|
|
8483
8612
|
ep.columns,
|
|
8484
|
-
|
|
8485
|
-
(0,
|
|
8613
|
+
import_types30.Provenance.EXTRACTED,
|
|
8614
|
+
(0, import_types30.confidenceForExtracted)(ep.confidenceKind)
|
|
8486
8615
|
)
|
|
8487
8616
|
});
|
|
8488
8617
|
}
|
|
8489
8618
|
}
|
|
8490
8619
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
8491
|
-
const confidence = (0,
|
|
8620
|
+
const confidence = (0, import_types30.confidenceForExtracted)(ep.confidenceKind);
|
|
8492
8621
|
const relFile = toPosix(ep.evidence.file);
|
|
8493
8622
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
8494
8623
|
graph,
|
|
@@ -8498,7 +8627,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8498
8627
|
);
|
|
8499
8628
|
nodesAdded += n;
|
|
8500
8629
|
edgesAdded += e;
|
|
8501
|
-
if (!(0,
|
|
8630
|
+
if (!(0, import_types30.passesExtractedFloor)(confidence)) {
|
|
8502
8631
|
noteExtractedDropped({
|
|
8503
8632
|
source: fileNodeId,
|
|
8504
8633
|
target: ep.infraId,
|
|
@@ -8518,7 +8647,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
8518
8647
|
source: fileNodeId,
|
|
8519
8648
|
target: ep.infraId,
|
|
8520
8649
|
type: edgeType,
|
|
8521
|
-
provenance:
|
|
8650
|
+
provenance: import_types30.Provenance.EXTRACTED,
|
|
8522
8651
|
confidence,
|
|
8523
8652
|
evidence: ep.evidence
|
|
8524
8653
|
};
|
|
@@ -8544,16 +8673,16 @@ init_cjs_shims();
|
|
|
8544
8673
|
|
|
8545
8674
|
// src/extract/infra/docker-compose.ts
|
|
8546
8675
|
init_cjs_shims();
|
|
8547
|
-
var
|
|
8548
|
-
var
|
|
8676
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8677
|
+
var import_types32 = require("@neat.is/types");
|
|
8549
8678
|
|
|
8550
8679
|
// src/extract/infra/shared.ts
|
|
8551
8680
|
init_cjs_shims();
|
|
8552
|
-
var
|
|
8681
|
+
var import_types31 = require("@neat.is/types");
|
|
8553
8682
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
8554
8683
|
return {
|
|
8555
|
-
id: (0,
|
|
8556
|
-
type:
|
|
8684
|
+
id: (0, import_types31.infraId)(kind, name),
|
|
8685
|
+
type: import_types31.NodeType.InfraNode,
|
|
8557
8686
|
name,
|
|
8558
8687
|
provider,
|
|
8559
8688
|
kind,
|
|
@@ -8597,8 +8726,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
8597
8726
|
source: anchorId,
|
|
8598
8727
|
target: node.id,
|
|
8599
8728
|
type: edgeType,
|
|
8600
|
-
provenance:
|
|
8601
|
-
confidence: (0,
|
|
8729
|
+
provenance: import_types31.Provenance.EXTRACTED,
|
|
8730
|
+
confidence: (0, import_types31.confidenceForExtracted)("structural"),
|
|
8602
8731
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
8603
8732
|
};
|
|
8604
8733
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8615,7 +8744,7 @@ function dependsOnList(value) {
|
|
|
8615
8744
|
}
|
|
8616
8745
|
function serviceNameToServiceNode(name, services) {
|
|
8617
8746
|
for (const s of services) {
|
|
8618
|
-
if (s.node.name === name ||
|
|
8747
|
+
if (s.node.name === name || import_node_path42.default.basename(s.dir) === name) return s.node.id;
|
|
8619
8748
|
}
|
|
8620
8749
|
return null;
|
|
8621
8750
|
}
|
|
@@ -8624,7 +8753,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8624
8753
|
let edgesAdded = 0;
|
|
8625
8754
|
let composePath = null;
|
|
8626
8755
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
8627
|
-
const abs =
|
|
8756
|
+
const abs = import_node_path42.default.join(scanPath, name);
|
|
8628
8757
|
if (await exists(abs)) {
|
|
8629
8758
|
composePath = abs;
|
|
8630
8759
|
break;
|
|
@@ -8637,13 +8766,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8637
8766
|
} catch (err) {
|
|
8638
8767
|
recordExtractionError(
|
|
8639
8768
|
"infra docker-compose",
|
|
8640
|
-
|
|
8769
|
+
import_node_path42.default.relative(scanPath, composePath),
|
|
8641
8770
|
err
|
|
8642
8771
|
);
|
|
8643
8772
|
return { nodesAdded, edgesAdded };
|
|
8644
8773
|
}
|
|
8645
8774
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
8646
|
-
const evidenceFile =
|
|
8775
|
+
const evidenceFile = import_node_path42.default.relative(scanPath, composePath).split(import_node_path42.default.sep).join("/");
|
|
8647
8776
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
8648
8777
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
8649
8778
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -8665,15 +8794,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8665
8794
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
8666
8795
|
const targetId = composeNameToNodeId.get(dep);
|
|
8667
8796
|
if (!targetId) continue;
|
|
8668
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
8797
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types32.EdgeType.DEPENDS_ON);
|
|
8669
8798
|
if (graph.hasEdge(edgeId)) continue;
|
|
8670
8799
|
const edge = {
|
|
8671
8800
|
id: edgeId,
|
|
8672
8801
|
source: sourceId,
|
|
8673
8802
|
target: targetId,
|
|
8674
|
-
type:
|
|
8675
|
-
provenance:
|
|
8676
|
-
confidence: (0,
|
|
8803
|
+
type: import_types32.EdgeType.DEPENDS_ON,
|
|
8804
|
+
provenance: import_types32.Provenance.EXTRACTED,
|
|
8805
|
+
confidence: (0, import_types32.confidenceForExtracted)("structural"),
|
|
8677
8806
|
evidence: { file: evidenceFile }
|
|
8678
8807
|
};
|
|
8679
8808
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8685,9 +8814,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
8685
8814
|
|
|
8686
8815
|
// src/extract/infra/dockerfile.ts
|
|
8687
8816
|
init_cjs_shims();
|
|
8688
|
-
var
|
|
8817
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
8689
8818
|
var import_node_fs17 = require("fs");
|
|
8690
|
-
var
|
|
8819
|
+
var import_types33 = require("@neat.is/types");
|
|
8691
8820
|
function readDockerfile(content) {
|
|
8692
8821
|
let image = null;
|
|
8693
8822
|
const ports = [];
|
|
@@ -8716,7 +8845,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8716
8845
|
let nodesAdded = 0;
|
|
8717
8846
|
let edgesAdded = 0;
|
|
8718
8847
|
for (const service of services) {
|
|
8719
|
-
const dockerfilePath =
|
|
8848
|
+
const dockerfilePath = import_node_path43.default.join(service.dir, "Dockerfile");
|
|
8720
8849
|
if (!await exists(dockerfilePath)) continue;
|
|
8721
8850
|
let content;
|
|
8722
8851
|
try {
|
|
@@ -8724,7 +8853,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8724
8853
|
} catch (err) {
|
|
8725
8854
|
recordExtractionError(
|
|
8726
8855
|
"infra dockerfile",
|
|
8727
|
-
|
|
8856
|
+
import_node_path43.default.relative(scanPath, dockerfilePath),
|
|
8728
8857
|
err
|
|
8729
8858
|
);
|
|
8730
8859
|
continue;
|
|
@@ -8736,8 +8865,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8736
8865
|
graph.addNode(node.id, node);
|
|
8737
8866
|
nodesAdded++;
|
|
8738
8867
|
}
|
|
8739
|
-
const relDockerfile = toPosix(
|
|
8740
|
-
const evidenceFile = toPosix(
|
|
8868
|
+
const relDockerfile = toPosix(import_node_path43.default.relative(service.dir, dockerfilePath));
|
|
8869
|
+
const evidenceFile = toPosix(import_node_path43.default.relative(scanPath, dockerfilePath));
|
|
8741
8870
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
8742
8871
|
graph,
|
|
8743
8872
|
service.pkg.name,
|
|
@@ -8746,15 +8875,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8746
8875
|
);
|
|
8747
8876
|
nodesAdded += fn;
|
|
8748
8877
|
edgesAdded += fe;
|
|
8749
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
8878
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types33.EdgeType.RUNS_ON);
|
|
8750
8879
|
if (!graph.hasEdge(edgeId)) {
|
|
8751
8880
|
const edge = {
|
|
8752
8881
|
id: edgeId,
|
|
8753
8882
|
source: fileNodeId,
|
|
8754
8883
|
target: node.id,
|
|
8755
|
-
type:
|
|
8756
|
-
provenance:
|
|
8757
|
-
confidence: (0,
|
|
8884
|
+
type: import_types33.EdgeType.RUNS_ON,
|
|
8885
|
+
provenance: import_types33.Provenance.EXTRACTED,
|
|
8886
|
+
confidence: (0, import_types33.confidenceForExtracted)("structural"),
|
|
8758
8887
|
evidence: {
|
|
8759
8888
|
file: evidenceFile,
|
|
8760
8889
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -8769,15 +8898,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8769
8898
|
graph.addNode(portNode.id, portNode);
|
|
8770
8899
|
nodesAdded++;
|
|
8771
8900
|
}
|
|
8772
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
8901
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types33.EdgeType.CONNECTS_TO);
|
|
8773
8902
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
8774
8903
|
const portEdge = {
|
|
8775
8904
|
id: portEdgeId,
|
|
8776
8905
|
source: fileNodeId,
|
|
8777
8906
|
target: portNode.id,
|
|
8778
|
-
type:
|
|
8779
|
-
provenance:
|
|
8780
|
-
confidence: (0,
|
|
8907
|
+
type: import_types33.EdgeType.CONNECTS_TO,
|
|
8908
|
+
provenance: import_types33.Provenance.EXTRACTED,
|
|
8909
|
+
confidence: (0, import_types33.confidenceForExtracted)("structural"),
|
|
8781
8910
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
8782
8911
|
};
|
|
8783
8912
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -8790,8 +8919,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
8790
8919
|
// src/extract/infra/terraform.ts
|
|
8791
8920
|
init_cjs_shims();
|
|
8792
8921
|
var import_node_fs18 = require("fs");
|
|
8793
|
-
var
|
|
8794
|
-
var
|
|
8922
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8923
|
+
var import_types34 = require("@neat.is/types");
|
|
8795
8924
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
8796
8925
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
8797
8926
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -8801,11 +8930,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
8801
8930
|
for (const entry2 of entries) {
|
|
8802
8931
|
if (entry2.isDirectory()) {
|
|
8803
8932
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
8804
|
-
const child =
|
|
8933
|
+
const child = import_node_path44.default.join(start, entry2.name);
|
|
8805
8934
|
if (await isPythonVenvDir(child)) continue;
|
|
8806
8935
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
8807
8936
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
8808
|
-
out.push(
|
|
8937
|
+
out.push(import_node_path44.default.join(start, entry2.name));
|
|
8809
8938
|
}
|
|
8810
8939
|
}
|
|
8811
8940
|
return out;
|
|
@@ -8837,7 +8966,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8837
8966
|
const files = await walkTfFiles(scanPath);
|
|
8838
8967
|
for (const file of files) {
|
|
8839
8968
|
const content = await import_node_fs18.promises.readFile(file, "utf8");
|
|
8840
|
-
const evidenceFile = toPosix(
|
|
8969
|
+
const evidenceFile = toPosix(import_node_path44.default.relative(scanPath, file));
|
|
8841
8970
|
const resources = [];
|
|
8842
8971
|
const byKey = /* @__PURE__ */ new Map();
|
|
8843
8972
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -8872,16 +9001,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8872
9001
|
if (!target) continue;
|
|
8873
9002
|
if (seen.has(target.nodeId)) continue;
|
|
8874
9003
|
seen.add(target.nodeId);
|
|
8875
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
9004
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types34.EdgeType.DEPENDS_ON);
|
|
8876
9005
|
if (graph.hasEdge(edgeId)) continue;
|
|
8877
9006
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
8878
9007
|
const edge = {
|
|
8879
9008
|
id: edgeId,
|
|
8880
9009
|
source: resource.nodeId,
|
|
8881
9010
|
target: target.nodeId,
|
|
8882
|
-
type:
|
|
8883
|
-
provenance:
|
|
8884
|
-
confidence: (0,
|
|
9011
|
+
type: import_types34.EdgeType.DEPENDS_ON,
|
|
9012
|
+
provenance: import_types34.Provenance.EXTRACTED,
|
|
9013
|
+
confidence: (0, import_types34.confidenceForExtracted)("structural"),
|
|
8885
9014
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
8886
9015
|
};
|
|
8887
9016
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -8895,7 +9024,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
8895
9024
|
// src/extract/infra/k8s.ts
|
|
8896
9025
|
init_cjs_shims();
|
|
8897
9026
|
var import_node_fs19 = require("fs");
|
|
8898
|
-
var
|
|
9027
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8899
9028
|
var import_yaml3 = require("yaml");
|
|
8900
9029
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
8901
9030
|
Service: "k8s-service",
|
|
@@ -8913,11 +9042,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
8913
9042
|
for (const entry2 of entries) {
|
|
8914
9043
|
if (entry2.isDirectory()) {
|
|
8915
9044
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
8916
|
-
const child =
|
|
9045
|
+
const child = import_node_path45.default.join(start, entry2.name);
|
|
8917
9046
|
if (await isPythonVenvDir(child)) continue;
|
|
8918
9047
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
8919
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
8920
|
-
out.push(
|
|
9048
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path45.default.extname(entry2.name))) {
|
|
9049
|
+
out.push(import_node_path45.default.join(start, entry2.name));
|
|
8921
9050
|
}
|
|
8922
9051
|
}
|
|
8923
9052
|
return out;
|
|
@@ -8951,13 +9080,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
8951
9080
|
// src/extract/infra/cloudflare.ts
|
|
8952
9081
|
init_cjs_shims();
|
|
8953
9082
|
var import_node_fs20 = require("fs");
|
|
8954
|
-
var
|
|
9083
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8955
9084
|
var import_smol_toml2 = require("smol-toml");
|
|
8956
|
-
var
|
|
9085
|
+
var import_types35 = require("@neat.is/types");
|
|
8957
9086
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
8958
9087
|
async function readWranglerConfig(dir) {
|
|
8959
9088
|
for (const filename of WRANGLER_FILENAMES) {
|
|
8960
|
-
const abs =
|
|
9089
|
+
const abs = import_node_path46.default.join(dir, filename);
|
|
8961
9090
|
if (!await exists(abs)) continue;
|
|
8962
9091
|
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
8963
9092
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9001,8 +9130,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
9001
9130
|
source: anchorId,
|
|
9002
9131
|
target: node.id,
|
|
9003
9132
|
type: edgeType,
|
|
9004
|
-
provenance:
|
|
9005
|
-
confidence: (0,
|
|
9133
|
+
provenance: import_types35.Provenance.EXTRACTED,
|
|
9134
|
+
confidence: (0, import_types35.confidenceForExtracted)("structural"),
|
|
9006
9135
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
9007
9136
|
};
|
|
9008
9137
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -9020,11 +9149,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9020
9149
|
try {
|
|
9021
9150
|
read = await readWranglerConfig(service.dir);
|
|
9022
9151
|
} catch (err) {
|
|
9023
|
-
recordExtractionError("infra cloudflare",
|
|
9152
|
+
recordExtractionError("infra cloudflare", import_node_path46.default.relative(scanPath, service.dir), err);
|
|
9024
9153
|
continue;
|
|
9025
9154
|
}
|
|
9026
9155
|
if (!read || !read.config.name) continue;
|
|
9027
|
-
const evidenceFile = toPosix(
|
|
9156
|
+
const evidenceFile = toPosix(import_node_path46.default.relative(scanPath, import_node_path46.default.join(service.dir, read.relFile)));
|
|
9028
9157
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
9029
9158
|
}
|
|
9030
9159
|
for (const worker of discovered) {
|
|
@@ -9036,7 +9165,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9036
9165
|
}
|
|
9037
9166
|
let anchorId = service.node.id;
|
|
9038
9167
|
if (config.main) {
|
|
9039
|
-
const entryRelPath = toPosix(
|
|
9168
|
+
const entryRelPath = toPosix(import_node_path46.default.normalize(config.main));
|
|
9040
9169
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
9041
9170
|
graph,
|
|
9042
9171
|
service.pkg.name,
|
|
@@ -9063,15 +9192,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9063
9192
|
nodesAdded++;
|
|
9064
9193
|
}
|
|
9065
9194
|
if (runtimeNode.id !== anchorId) {
|
|
9066
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
9195
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types35.EdgeType.RUNS_ON);
|
|
9067
9196
|
if (!graph.hasEdge(runsOnId)) {
|
|
9068
9197
|
const edge = {
|
|
9069
9198
|
id: runsOnId,
|
|
9070
9199
|
source: anchorId,
|
|
9071
9200
|
target: runtimeNode.id,
|
|
9072
|
-
type:
|
|
9073
|
-
provenance:
|
|
9074
|
-
confidence: (0,
|
|
9201
|
+
type: import_types35.EdgeType.RUNS_ON,
|
|
9202
|
+
provenance: import_types35.Provenance.EXTRACTED,
|
|
9203
|
+
confidence: (0, import_types35.confidenceForExtracted)("structural"),
|
|
9075
9204
|
evidence: {
|
|
9076
9205
|
file: evidenceFile,
|
|
9077
9206
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -9085,7 +9214,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9085
9214
|
const result = addResourceEdge(
|
|
9086
9215
|
graph,
|
|
9087
9216
|
anchorId,
|
|
9088
|
-
|
|
9217
|
+
import_types35.EdgeType.CONNECTS_TO,
|
|
9089
9218
|
"cloudflare-route",
|
|
9090
9219
|
route,
|
|
9091
9220
|
evidenceFile,
|
|
@@ -9109,7 +9238,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9109
9238
|
const result = addResourceEdge(
|
|
9110
9239
|
graph,
|
|
9111
9240
|
anchorId,
|
|
9112
|
-
|
|
9241
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9113
9242
|
group.kind,
|
|
9114
9243
|
name,
|
|
9115
9244
|
evidenceFile,
|
|
@@ -9123,7 +9252,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9123
9252
|
const result = addResourceEdge(
|
|
9124
9253
|
graph,
|
|
9125
9254
|
anchorId,
|
|
9126
|
-
|
|
9255
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9127
9256
|
"cloudflare-cron",
|
|
9128
9257
|
cron,
|
|
9129
9258
|
evidenceFile,
|
|
@@ -9136,7 +9265,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9136
9265
|
const result = addResourceEdge(
|
|
9137
9266
|
graph,
|
|
9138
9267
|
anchorId,
|
|
9139
|
-
|
|
9268
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9140
9269
|
"cloudflare-env-var",
|
|
9141
9270
|
varName,
|
|
9142
9271
|
evidenceFile,
|
|
@@ -9149,15 +9278,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9149
9278
|
if (!svc.service) continue;
|
|
9150
9279
|
const target = workerIndex.get(svc.service);
|
|
9151
9280
|
if (target && target.anchorId !== anchorId) {
|
|
9152
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
9281
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types35.EdgeType.CALLS);
|
|
9153
9282
|
if (!graph.hasEdge(edgeId)) {
|
|
9154
9283
|
const edge = {
|
|
9155
9284
|
id: edgeId,
|
|
9156
9285
|
source: anchorId,
|
|
9157
9286
|
target: target.anchorId,
|
|
9158
|
-
type:
|
|
9159
|
-
provenance:
|
|
9160
|
-
confidence: (0,
|
|
9287
|
+
type: import_types35.EdgeType.CALLS,
|
|
9288
|
+
provenance: import_types35.Provenance.EXTRACTED,
|
|
9289
|
+
confidence: (0, import_types35.confidenceForExtracted)("structural"),
|
|
9161
9290
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
9162
9291
|
};
|
|
9163
9292
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -9168,7 +9297,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9168
9297
|
const result = addResourceEdge(
|
|
9169
9298
|
graph,
|
|
9170
9299
|
anchorId,
|
|
9171
|
-
|
|
9300
|
+
import_types35.EdgeType.DEPENDS_ON,
|
|
9172
9301
|
"cloudflare-service-binding",
|
|
9173
9302
|
svc.service,
|
|
9174
9303
|
evidenceFile,
|
|
@@ -9184,12 +9313,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
9184
9313
|
// src/extract/infra/vercel.ts
|
|
9185
9314
|
init_cjs_shims();
|
|
9186
9315
|
var import_node_fs21 = require("fs");
|
|
9187
|
-
var
|
|
9188
|
-
var
|
|
9316
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
9317
|
+
var import_types36 = require("@neat.is/types");
|
|
9189
9318
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
9190
9319
|
async function readVercelConfig(dir) {
|
|
9191
9320
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
9192
|
-
const abs =
|
|
9321
|
+
const abs = import_node_path47.default.join(dir, filename);
|
|
9193
9322
|
if (!await exists(abs)) continue;
|
|
9194
9323
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
9195
9324
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9198,7 +9327,7 @@ async function readVercelConfig(dir) {
|
|
|
9198
9327
|
return null;
|
|
9199
9328
|
}
|
|
9200
9329
|
async function readLinkedProjectName(dir) {
|
|
9201
|
-
const abs =
|
|
9330
|
+
const abs = import_node_path47.default.join(dir, ".vercel", "project.json");
|
|
9202
9331
|
if (!await exists(abs)) return void 0;
|
|
9203
9332
|
const parsed = JSON.parse(await import_node_fs21.promises.readFile(abs, "utf8"));
|
|
9204
9333
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -9216,7 +9345,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9216
9345
|
read = await readVercelConfig(service.dir);
|
|
9217
9346
|
projectName = await readLinkedProjectName(service.dir);
|
|
9218
9347
|
} catch (err) {
|
|
9219
|
-
recordExtractionError("infra vercel",
|
|
9348
|
+
recordExtractionError("infra vercel", import_node_path47.default.relative(scanPath, service.dir), err);
|
|
9220
9349
|
continue;
|
|
9221
9350
|
}
|
|
9222
9351
|
if (!read && !projectName) continue;
|
|
@@ -9232,7 +9361,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9232
9361
|
const anchorId = service.node.id;
|
|
9233
9362
|
if (!read) continue;
|
|
9234
9363
|
const { config, relFile, raw } = read;
|
|
9235
|
-
const evidenceFile = toPosix(
|
|
9364
|
+
const evidenceFile = toPosix(import_node_path47.default.relative(scanPath, import_node_path47.default.join(service.dir, relFile)));
|
|
9236
9365
|
const add = (edgeType, kind, name) => {
|
|
9237
9366
|
if (!name) return;
|
|
9238
9367
|
const result = emitPlatformResourceEdge(
|
|
@@ -9248,12 +9377,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9248
9377
|
nodesAdded += result.nodesAdded;
|
|
9249
9378
|
edgesAdded += result.edgesAdded;
|
|
9250
9379
|
};
|
|
9251
|
-
add(
|
|
9252
|
-
for (const cron of config.crons ?? []) add(
|
|
9253
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
9254
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
9380
|
+
add(import_types36.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
9381
|
+
for (const cron of config.crons ?? []) add(import_types36.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
9382
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9383
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types36.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
9255
9384
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
9256
|
-
add(
|
|
9385
|
+
add(import_types36.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
9257
9386
|
}
|
|
9258
9387
|
}
|
|
9259
9388
|
return { nodesAdded, edgesAdded };
|
|
@@ -9262,13 +9391,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
9262
9391
|
// src/extract/infra/railway.ts
|
|
9263
9392
|
init_cjs_shims();
|
|
9264
9393
|
var import_node_fs22 = require("fs");
|
|
9265
|
-
var
|
|
9394
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
9266
9395
|
var import_smol_toml3 = require("smol-toml");
|
|
9267
|
-
var
|
|
9396
|
+
var import_types37 = require("@neat.is/types");
|
|
9268
9397
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
9269
9398
|
async function readRailwayConfig(dir) {
|
|
9270
9399
|
for (const filename of RAILWAY_FILENAMES) {
|
|
9271
|
-
const abs =
|
|
9400
|
+
const abs = import_node_path48.default.join(dir, filename);
|
|
9272
9401
|
if (!await exists(abs)) continue;
|
|
9273
9402
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
9274
9403
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -9284,7 +9413,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9284
9413
|
try {
|
|
9285
9414
|
read = await readRailwayConfig(service.dir);
|
|
9286
9415
|
} catch (err) {
|
|
9287
|
-
recordExtractionError("infra railway",
|
|
9416
|
+
recordExtractionError("infra railway", import_node_path48.default.relative(scanPath, service.dir), err);
|
|
9288
9417
|
continue;
|
|
9289
9418
|
}
|
|
9290
9419
|
if (!read) continue;
|
|
@@ -9294,7 +9423,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9294
9423
|
}
|
|
9295
9424
|
const anchorId = service.node.id;
|
|
9296
9425
|
const { config, relFile, raw } = read;
|
|
9297
|
-
const evidenceFile = toPosix(
|
|
9426
|
+
const evidenceFile = toPosix(import_node_path48.default.relative(scanPath, import_node_path48.default.join(service.dir, relFile)));
|
|
9298
9427
|
const add = (edgeType, kind, name) => {
|
|
9299
9428
|
if (!name) return;
|
|
9300
9429
|
const result = emitPlatformResourceEdge(
|
|
@@ -9310,9 +9439,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9310
9439
|
nodesAdded += result.nodesAdded;
|
|
9311
9440
|
edgesAdded += result.edgesAdded;
|
|
9312
9441
|
};
|
|
9313
|
-
add(
|
|
9314
|
-
add(
|
|
9315
|
-
add(
|
|
9442
|
+
add(import_types37.EdgeType.RUNS_ON, "railway", "railway");
|
|
9443
|
+
add(import_types37.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
9444
|
+
add(import_types37.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
9316
9445
|
}
|
|
9317
9446
|
return { nodesAdded, edgesAdded };
|
|
9318
9447
|
}
|
|
@@ -9320,12 +9449,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
9320
9449
|
// src/extract/infra/supabase.ts
|
|
9321
9450
|
init_cjs_shims();
|
|
9322
9451
|
var import_node_fs23 = require("fs");
|
|
9323
|
-
var
|
|
9452
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9324
9453
|
var import_smol_toml4 = require("smol-toml");
|
|
9325
|
-
var
|
|
9454
|
+
var import_types38 = require("@neat.is/types");
|
|
9326
9455
|
async function readSupabaseConfig(dir) {
|
|
9327
|
-
const relFile =
|
|
9328
|
-
const abs =
|
|
9456
|
+
const relFile = import_node_path49.default.join("supabase", "config.toml");
|
|
9457
|
+
const abs = import_node_path49.default.join(dir, relFile);
|
|
9329
9458
|
if (!await exists(abs)) return null;
|
|
9330
9459
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
9331
9460
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -9339,7 +9468,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9339
9468
|
try {
|
|
9340
9469
|
read = await readSupabaseConfig(service.dir);
|
|
9341
9470
|
} catch (err) {
|
|
9342
|
-
recordExtractionError("infra supabase",
|
|
9471
|
+
recordExtractionError("infra supabase", import_node_path49.default.relative(scanPath, service.dir), err);
|
|
9343
9472
|
continue;
|
|
9344
9473
|
}
|
|
9345
9474
|
if (!read) continue;
|
|
@@ -9354,7 +9483,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9354
9483
|
});
|
|
9355
9484
|
}
|
|
9356
9485
|
const anchorId = service.node.id;
|
|
9357
|
-
const evidenceFile = toPosix(
|
|
9486
|
+
const evidenceFile = toPosix(import_node_path49.default.relative(scanPath, import_node_path49.default.join(service.dir, relFile)));
|
|
9358
9487
|
const add = (edgeType, kind, name) => {
|
|
9359
9488
|
if (!name) return;
|
|
9360
9489
|
const result = emitPlatformResourceEdge(
|
|
@@ -9370,10 +9499,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
9370
9499
|
nodesAdded += result.nodesAdded;
|
|
9371
9500
|
edgesAdded += result.edgesAdded;
|
|
9372
9501
|
};
|
|
9373
|
-
add(
|
|
9374
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
9375
|
-
if (config.storage) add(
|
|
9376
|
-
if (config.auth) add(
|
|
9502
|
+
add(import_types38.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
9503
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types38.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
9504
|
+
if (config.storage) add(import_types38.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
9505
|
+
if (config.auth) add(import_types38.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
9377
9506
|
}
|
|
9378
9507
|
return { nodesAdded, edgesAdded };
|
|
9379
9508
|
}
|
|
@@ -9395,17 +9524,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
9395
9524
|
}
|
|
9396
9525
|
|
|
9397
9526
|
// src/extract/index.ts
|
|
9398
|
-
var
|
|
9527
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
9399
9528
|
|
|
9400
9529
|
// src/extract/retire.ts
|
|
9401
9530
|
init_cjs_shims();
|
|
9402
9531
|
var import_node_fs24 = require("fs");
|
|
9403
|
-
var
|
|
9404
|
-
var
|
|
9532
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9533
|
+
var import_types39 = require("@neat.is/types");
|
|
9405
9534
|
function dropOrphanedFileNodes(graph) {
|
|
9406
9535
|
const orphans = [];
|
|
9407
9536
|
graph.forEachNode((id, attrs) => {
|
|
9408
|
-
if (attrs.type !==
|
|
9537
|
+
if (attrs.type !== import_types39.NodeType.FileNode) return;
|
|
9409
9538
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
9410
9539
|
orphans.push(id);
|
|
9411
9540
|
}
|
|
@@ -9418,14 +9547,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
9418
9547
|
const bases = [scanPath, ...serviceDirs];
|
|
9419
9548
|
graph.forEachEdge((id, attrs) => {
|
|
9420
9549
|
const edge = attrs;
|
|
9421
|
-
if (edge.provenance !==
|
|
9550
|
+
if (edge.provenance !== import_types39.Provenance.EXTRACTED) return;
|
|
9422
9551
|
const evidenceFile = edge.evidence?.file;
|
|
9423
9552
|
if (!evidenceFile) return;
|
|
9424
|
-
if (
|
|
9553
|
+
if (import_node_path50.default.isAbsolute(evidenceFile)) {
|
|
9425
9554
|
if (!(0, import_node_fs24.existsSync)(evidenceFile)) toDrop.push(id);
|
|
9426
9555
|
return;
|
|
9427
9556
|
}
|
|
9428
|
-
const found = bases.some((base) => (0, import_node_fs24.existsSync)(
|
|
9557
|
+
const found = bases.some((base) => (0, import_node_fs24.existsSync)(import_node_path50.default.join(base, evidenceFile)));
|
|
9429
9558
|
if (!found) toDrop.push(id);
|
|
9430
9559
|
});
|
|
9431
9560
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -9478,7 +9607,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9478
9607
|
}
|
|
9479
9608
|
const droppedEntries = drainDroppedExtracted();
|
|
9480
9609
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
9481
|
-
const rejectedPath =
|
|
9610
|
+
const rejectedPath = import_node_path51.default.join(import_node_path51.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
9482
9611
|
try {
|
|
9483
9612
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
9484
9613
|
} catch (err) {
|
|
@@ -9513,8 +9642,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
9513
9642
|
// src/persist.ts
|
|
9514
9643
|
init_cjs_shims();
|
|
9515
9644
|
var import_node_fs25 = require("fs");
|
|
9516
|
-
var
|
|
9517
|
-
var
|
|
9645
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
9646
|
+
var import_types40 = require("@neat.is/types");
|
|
9518
9647
|
var SCHEMA_VERSION = 6;
|
|
9519
9648
|
function migrateV1ToV2(payload) {
|
|
9520
9649
|
const nodes = payload.graph.nodes;
|
|
@@ -9538,7 +9667,7 @@ function migrateV5ToV6(payload) {
|
|
|
9538
9667
|
if (Array.isArray(nodes)) {
|
|
9539
9668
|
for (const node of nodes) {
|
|
9540
9669
|
const attrs = node.attributes;
|
|
9541
|
-
if (!attrs || attrs.type !==
|
|
9670
|
+
if (!attrs || attrs.type !== import_types40.NodeType.InfraNode) continue;
|
|
9542
9671
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
9543
9672
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
9544
9673
|
}
|
|
@@ -9551,12 +9680,12 @@ function migrateV2ToV3(payload) {
|
|
|
9551
9680
|
for (const edge of edges) {
|
|
9552
9681
|
const attrs = edge.attributes;
|
|
9553
9682
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
9554
|
-
attrs.provenance =
|
|
9683
|
+
attrs.provenance = import_types40.Provenance.OBSERVED;
|
|
9555
9684
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
9556
9685
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
9557
9686
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
9558
9687
|
if (type && source && target) {
|
|
9559
|
-
const newId = (0,
|
|
9688
|
+
const newId = (0, import_types40.observedEdgeId)(source, target, type);
|
|
9560
9689
|
attrs.id = newId;
|
|
9561
9690
|
if (edge.key) edge.key = newId;
|
|
9562
9691
|
}
|
|
@@ -9565,7 +9694,7 @@ function migrateV2ToV3(payload) {
|
|
|
9565
9694
|
return { ...payload, schemaVersion: 3 };
|
|
9566
9695
|
}
|
|
9567
9696
|
async function ensureDir(filePath) {
|
|
9568
|
-
await import_node_fs25.promises.mkdir(
|
|
9697
|
+
await import_node_fs25.promises.mkdir(import_node_path52.default.dirname(filePath), { recursive: true });
|
|
9569
9698
|
}
|
|
9570
9699
|
async function saveGraphToDisk(graph, outPath) {
|
|
9571
9700
|
await ensureDir(outPath);
|
|
@@ -9652,23 +9781,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
9652
9781
|
|
|
9653
9782
|
// src/projects.ts
|
|
9654
9783
|
init_cjs_shims();
|
|
9655
|
-
var
|
|
9784
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
9656
9785
|
function pathsForProject(project, baseDir) {
|
|
9657
9786
|
if (project === DEFAULT_PROJECT) {
|
|
9658
9787
|
return {
|
|
9659
|
-
snapshotPath:
|
|
9660
|
-
errorsPath:
|
|
9661
|
-
staleEventsPath:
|
|
9662
|
-
embeddingsCachePath:
|
|
9663
|
-
policyViolationsPath:
|
|
9788
|
+
snapshotPath: import_node_path53.default.join(baseDir, "graph.json"),
|
|
9789
|
+
errorsPath: import_node_path53.default.join(baseDir, "errors.ndjson"),
|
|
9790
|
+
staleEventsPath: import_node_path53.default.join(baseDir, "stale-events.ndjson"),
|
|
9791
|
+
embeddingsCachePath: import_node_path53.default.join(baseDir, "embeddings.json"),
|
|
9792
|
+
policyViolationsPath: import_node_path53.default.join(baseDir, "policy-violations.ndjson")
|
|
9664
9793
|
};
|
|
9665
9794
|
}
|
|
9666
9795
|
return {
|
|
9667
|
-
snapshotPath:
|
|
9668
|
-
errorsPath:
|
|
9669
|
-
staleEventsPath:
|
|
9670
|
-
embeddingsCachePath:
|
|
9671
|
-
policyViolationsPath:
|
|
9796
|
+
snapshotPath: import_node_path53.default.join(baseDir, `${project}.json`),
|
|
9797
|
+
errorsPath: import_node_path53.default.join(baseDir, `errors.${project}.ndjson`),
|
|
9798
|
+
staleEventsPath: import_node_path53.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
9799
|
+
embeddingsCachePath: import_node_path53.default.join(baseDir, `embeddings.${project}.json`),
|
|
9800
|
+
policyViolationsPath: import_node_path53.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
9672
9801
|
};
|
|
9673
9802
|
}
|
|
9674
9803
|
var Projects = class {
|
|
@@ -9706,19 +9835,19 @@ var Projects = class {
|
|
|
9706
9835
|
init_cjs_shims();
|
|
9707
9836
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
9708
9837
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
9709
|
-
var
|
|
9838
|
+
var import_types59 = require("@neat.is/types");
|
|
9710
9839
|
|
|
9711
9840
|
// src/extend/index.ts
|
|
9712
9841
|
init_cjs_shims();
|
|
9713
9842
|
var import_node_fs27 = require("fs");
|
|
9714
|
-
var
|
|
9843
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
9715
9844
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
9716
9845
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
9717
9846
|
|
|
9718
9847
|
// src/installers/package-manager.ts
|
|
9719
9848
|
init_cjs_shims();
|
|
9720
9849
|
var import_node_fs26 = require("fs");
|
|
9721
|
-
var
|
|
9850
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
9722
9851
|
var import_node_child_process = require("child_process");
|
|
9723
9852
|
var LOCKFILE_PRIORITY = [
|
|
9724
9853
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -9740,22 +9869,22 @@ async function exists2(p) {
|
|
|
9740
9869
|
}
|
|
9741
9870
|
}
|
|
9742
9871
|
async function detectPackageManager(serviceDir) {
|
|
9743
|
-
let dir =
|
|
9872
|
+
let dir = import_node_path54.default.resolve(serviceDir);
|
|
9744
9873
|
const stops = /* @__PURE__ */ new Set();
|
|
9745
9874
|
for (let i = 0; i < 64; i++) {
|
|
9746
9875
|
if (stops.has(dir)) break;
|
|
9747
9876
|
stops.add(dir);
|
|
9748
9877
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
9749
|
-
const lockPath =
|
|
9878
|
+
const lockPath = import_node_path54.default.join(dir, candidate.lockfile);
|
|
9750
9879
|
if (await exists2(lockPath)) {
|
|
9751
9880
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
9752
9881
|
}
|
|
9753
9882
|
}
|
|
9754
|
-
const parent =
|
|
9883
|
+
const parent = import_node_path54.default.dirname(dir);
|
|
9755
9884
|
if (parent === dir) break;
|
|
9756
9885
|
dir = parent;
|
|
9757
9886
|
}
|
|
9758
|
-
return { pm: "npm", cwd:
|
|
9887
|
+
return { pm: "npm", cwd: import_node_path54.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
9759
9888
|
}
|
|
9760
9889
|
async function runPackageManagerInstall(cmd) {
|
|
9761
9890
|
return new Promise((resolve) => {
|
|
@@ -9804,7 +9933,7 @@ async function fileExists2(p) {
|
|
|
9804
9933
|
}
|
|
9805
9934
|
}
|
|
9806
9935
|
async function readPackageJson(scanPath) {
|
|
9807
|
-
const pkgPath =
|
|
9936
|
+
const pkgPath = import_node_path55.default.join(scanPath, "package.json");
|
|
9808
9937
|
const raw = await import_node_fs27.promises.readFile(pkgPath, "utf8");
|
|
9809
9938
|
return JSON.parse(raw);
|
|
9810
9939
|
}
|
|
@@ -9823,11 +9952,11 @@ async function findHookFiles(scanPath) {
|
|
|
9823
9952
|
for (const entry2 of entries) {
|
|
9824
9953
|
if (entry2.isDirectory()) {
|
|
9825
9954
|
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
9826
|
-
await walk6(
|
|
9955
|
+
await walk6(import_node_path55.default.join(dir, entry2.name));
|
|
9827
9956
|
} else if (entry2.isFile()) {
|
|
9828
9957
|
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
9829
|
-
const rel =
|
|
9830
|
-
found.push(rel.split(
|
|
9958
|
+
const rel = import_node_path55.default.relative(scanPath, import_node_path55.default.join(dir, entry2.name));
|
|
9959
|
+
found.push(rel.split(import_node_path55.default.sep).join("/"));
|
|
9831
9960
|
}
|
|
9832
9961
|
}
|
|
9833
9962
|
}
|
|
@@ -9838,7 +9967,7 @@ async function findHookFiles(scanPath) {
|
|
|
9838
9967
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
9839
9968
|
let fallback = null;
|
|
9840
9969
|
for (const file of hookFiles) {
|
|
9841
|
-
const content = await import_node_fs27.promises.readFile(
|
|
9970
|
+
const content = await import_node_fs27.promises.readFile(import_node_path55.default.join(scanPath, file), "utf8");
|
|
9842
9971
|
const patched = splicedContent(content, snippet2);
|
|
9843
9972
|
if (patched !== null) return { file, content, patched };
|
|
9844
9973
|
if (fallback === null) fallback = { file, content };
|
|
@@ -9846,11 +9975,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
9846
9975
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
9847
9976
|
}
|
|
9848
9977
|
function extendLogPath() {
|
|
9849
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
9978
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path55.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
9850
9979
|
}
|
|
9851
9980
|
async function appendExtendLog(entry2) {
|
|
9852
9981
|
const logPath = extendLogPath();
|
|
9853
|
-
await import_node_fs27.promises.mkdir(
|
|
9982
|
+
await import_node_fs27.promises.mkdir(import_node_path55.default.dirname(logPath), { recursive: true });
|
|
9854
9983
|
await import_node_fs27.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
9855
9984
|
}
|
|
9856
9985
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -9909,7 +10038,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
9909
10038
|
}
|
|
9910
10039
|
async function describeProjectInstrumentation(ctx) {
|
|
9911
10040
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
9912
|
-
const envNeat = await fileExists2(
|
|
10041
|
+
const envNeat = await fileExists2(import_node_path55.default.join(ctx.scanPath, ".env.neat"));
|
|
9913
10042
|
const registryInstrPackages = new Set(
|
|
9914
10043
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
9915
10044
|
);
|
|
@@ -9931,7 +10060,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
9931
10060
|
);
|
|
9932
10061
|
}
|
|
9933
10062
|
for (const file of hookFiles) {
|
|
9934
|
-
const content = await import_node_fs27.promises.readFile(
|
|
10063
|
+
const content = await import_node_fs27.promises.readFile(import_node_path55.default.join(ctx.scanPath, file), "utf8");
|
|
9935
10064
|
if (content.includes(args.registration_snippet)) {
|
|
9936
10065
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
9937
10066
|
}
|
|
@@ -9943,10 +10072,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
9943
10072
|
);
|
|
9944
10073
|
}
|
|
9945
10074
|
const primaryFile = primary.file;
|
|
9946
|
-
const primaryPath =
|
|
10075
|
+
const primaryPath = import_node_path55.default.join(ctx.scanPath, primaryFile);
|
|
9947
10076
|
const filesTouched = [];
|
|
9948
10077
|
const depsAdded = [];
|
|
9949
|
-
const pkgPath =
|
|
10078
|
+
const pkgPath = import_node_path55.default.join(ctx.scanPath, "package.json");
|
|
9950
10079
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
9951
10080
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
9952
10081
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -9985,7 +10114,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
9985
10114
|
};
|
|
9986
10115
|
}
|
|
9987
10116
|
for (const file of hookFiles) {
|
|
9988
|
-
const content = await import_node_fs27.promises.readFile(
|
|
10117
|
+
const content = await import_node_fs27.promises.readFile(import_node_path55.default.join(ctx.scanPath, file), "utf8");
|
|
9989
10118
|
if (content.includes(args.registration_snippet)) {
|
|
9990
10119
|
return {
|
|
9991
10120
|
library: args.library,
|
|
@@ -10026,7 +10155,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
10026
10155
|
if (!match) {
|
|
10027
10156
|
return { undone: false, message: "no apply found for library" };
|
|
10028
10157
|
}
|
|
10029
|
-
const pkgPath =
|
|
10158
|
+
const pkgPath = import_node_path55.default.join(ctx.scanPath, "package.json");
|
|
10030
10159
|
if (await fileExists2(pkgPath)) {
|
|
10031
10160
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
10032
10161
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -10037,7 +10166,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
10037
10166
|
}
|
|
10038
10167
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
10039
10168
|
for (const file of hookFiles) {
|
|
10040
|
-
const filePath =
|
|
10169
|
+
const filePath = import_node_path55.default.join(ctx.scanPath, file);
|
|
10041
10170
|
const content = await import_node_fs27.promises.readFile(filePath, "utf8");
|
|
10042
10171
|
if (content.includes(match.registration_snippet)) {
|
|
10043
10172
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -10053,39 +10182,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
10053
10182
|
|
|
10054
10183
|
// src/divergences.ts
|
|
10055
10184
|
init_cjs_shims();
|
|
10056
|
-
var
|
|
10185
|
+
var import_types41 = require("@neat.is/types");
|
|
10057
10186
|
function bucketKey(source, target, type) {
|
|
10058
10187
|
return `${type}|${source}|${target}`;
|
|
10059
10188
|
}
|
|
10060
10189
|
function bucketSourceFor(graph, edge) {
|
|
10061
|
-
if (edge.type !==
|
|
10062
|
-
const parsed = (0,
|
|
10190
|
+
if (edge.type !== import_types41.EdgeType.CONNECTS_TO) return edge.source;
|
|
10191
|
+
const parsed = (0, import_types41.parseFileId)(edge.source);
|
|
10063
10192
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
10064
10193
|
const target = graph.getNodeAttributes(edge.target);
|
|
10065
|
-
if (target.type !==
|
|
10066
|
-
return (0,
|
|
10194
|
+
if (target.type !== import_types41.NodeType.DatabaseNode) return edge.source;
|
|
10195
|
+
return (0, import_types41.serviceId)(parsed.service);
|
|
10067
10196
|
}
|
|
10068
10197
|
function bucketEdges(graph) {
|
|
10069
10198
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
10070
10199
|
graph.forEachEdge((id, attrs) => {
|
|
10071
10200
|
const e = attrs;
|
|
10072
|
-
const parsed = (0,
|
|
10201
|
+
const parsed = (0, import_types41.parseEdgeId)(id);
|
|
10073
10202
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
10074
10203
|
const source = bucketSourceFor(graph, e);
|
|
10075
10204
|
const key = bucketKey(source, e.target, e.type);
|
|
10076
10205
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
10077
10206
|
switch (provenance) {
|
|
10078
|
-
case
|
|
10207
|
+
case import_types41.Provenance.EXTRACTED:
|
|
10079
10208
|
cur.extracted = e;
|
|
10080
10209
|
break;
|
|
10081
|
-
case
|
|
10210
|
+
case import_types41.Provenance.OBSERVED:
|
|
10082
10211
|
cur.observed = e;
|
|
10083
10212
|
break;
|
|
10084
|
-
case
|
|
10213
|
+
case import_types41.Provenance.INFERRED:
|
|
10085
10214
|
cur.inferred = e;
|
|
10086
10215
|
break;
|
|
10087
10216
|
default:
|
|
10088
|
-
if (e.provenance ===
|
|
10217
|
+
if (e.provenance === import_types41.Provenance.STALE) cur.stale = e;
|
|
10089
10218
|
}
|
|
10090
10219
|
buckets2.set(key, cur);
|
|
10091
10220
|
});
|
|
@@ -10094,17 +10223,17 @@ function bucketEdges(graph) {
|
|
|
10094
10223
|
function nodeIsFrontier(graph, nodeId) {
|
|
10095
10224
|
if (!graph.hasNode(nodeId)) return false;
|
|
10096
10225
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
10097
|
-
return attrs.type ===
|
|
10226
|
+
return attrs.type === import_types41.NodeType.FrontierNode;
|
|
10098
10227
|
}
|
|
10099
10228
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
10100
10229
|
if (!graph.hasNode(nodeId)) return false;
|
|
10101
10230
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
10102
|
-
return attrs.type ===
|
|
10231
|
+
return attrs.type === import_types41.NodeType.WebSocketChannelNode;
|
|
10103
10232
|
}
|
|
10104
10233
|
function nodeIsSymbol(graph, nodeId) {
|
|
10105
10234
|
if (!graph.hasNode(nodeId)) return false;
|
|
10106
10235
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
10107
|
-
return attrs.type ===
|
|
10236
|
+
return attrs.type === import_types41.NodeType.SymbolNode;
|
|
10108
10237
|
}
|
|
10109
10238
|
function clampConfidence(n) {
|
|
10110
10239
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -10124,14 +10253,14 @@ function gradedConfidence(edge) {
|
|
|
10124
10253
|
return clampConfidence(confidenceForEdge(edge));
|
|
10125
10254
|
}
|
|
10126
10255
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10256
|
+
import_types41.EdgeType.CALLS,
|
|
10257
|
+
import_types41.EdgeType.CONNECTS_TO,
|
|
10258
|
+
import_types41.EdgeType.PUBLISHES_TO,
|
|
10259
|
+
import_types41.EdgeType.CONSUMES_FROM
|
|
10131
10260
|
]);
|
|
10132
10261
|
function detectMissingDivergences(graph, bucket) {
|
|
10133
10262
|
const out = [];
|
|
10134
|
-
if (bucket.type ===
|
|
10263
|
+
if (bucket.type === import_types41.EdgeType.CONTAINS) return out;
|
|
10135
10264
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
10136
10265
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
10137
10266
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
@@ -10173,7 +10302,7 @@ function declaredHostFor(svc) {
|
|
|
10173
10302
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
10174
10303
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
10175
10304
|
const e = graph.getEdgeAttributes(edgeId);
|
|
10176
|
-
if (e.type ===
|
|
10305
|
+
if (e.type === import_types41.EdgeType.CONFIGURED_BY && e.provenance === import_types41.Provenance.EXTRACTED) {
|
|
10177
10306
|
return true;
|
|
10178
10307
|
}
|
|
10179
10308
|
}
|
|
@@ -10186,10 +10315,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
10186
10315
|
const out = [];
|
|
10187
10316
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
10188
10317
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
10189
|
-
if (edge.type !==
|
|
10190
|
-
if (edge.provenance !==
|
|
10318
|
+
if (edge.type !== import_types41.EdgeType.CONNECTS_TO) continue;
|
|
10319
|
+
if (edge.provenance !== import_types41.Provenance.OBSERVED) continue;
|
|
10191
10320
|
const target = graph.getNodeAttributes(edge.target);
|
|
10192
|
-
if (target.type !==
|
|
10321
|
+
if (target.type !== import_types41.NodeType.DatabaseNode) continue;
|
|
10193
10322
|
const observedHost = target.host?.trim();
|
|
10194
10323
|
if (!observedHost) continue;
|
|
10195
10324
|
if (observedHost === declaredHost) continue;
|
|
@@ -10211,10 +10340,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
10211
10340
|
const deps = svc.dependencies ?? {};
|
|
10212
10341
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
10213
10342
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
10214
|
-
if (edge.type !==
|
|
10215
|
-
if (edge.provenance !==
|
|
10343
|
+
if (edge.type !== import_types41.EdgeType.CONNECTS_TO) continue;
|
|
10344
|
+
if (edge.provenance !== import_types41.Provenance.OBSERVED) continue;
|
|
10216
10345
|
const target = graph.getNodeAttributes(edge.target);
|
|
10217
|
-
if (target.type !==
|
|
10346
|
+
if (target.type !== import_types41.NodeType.DatabaseNode) continue;
|
|
10218
10347
|
for (const pair of compatPairs()) {
|
|
10219
10348
|
if (pair.engine !== target.engine) continue;
|
|
10220
10349
|
const declared = deps[pair.driver];
|
|
@@ -10311,7 +10440,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
10311
10440
|
for (const d of all) {
|
|
10312
10441
|
if (d.type !== "host-mismatch") continue;
|
|
10313
10442
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
10314
|
-
declaredHalf.add((0,
|
|
10443
|
+
declaredHalf.add((0, import_types41.databaseId)(d.extractedHost));
|
|
10315
10444
|
}
|
|
10316
10445
|
if (observedHalf.size === 0) return all;
|
|
10317
10446
|
return all.filter((d) => {
|
|
@@ -10330,13 +10459,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
10330
10459
|
}
|
|
10331
10460
|
graph.forEachNode((nodeId, attrs) => {
|
|
10332
10461
|
const n = attrs;
|
|
10333
|
-
if (n.type ===
|
|
10462
|
+
if (n.type === import_types41.NodeType.ServiceNode) {
|
|
10334
10463
|
const svc = n;
|
|
10335
10464
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
10336
10465
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
10337
10466
|
return;
|
|
10338
10467
|
}
|
|
10339
|
-
if (n.type ===
|
|
10468
|
+
if (n.type === import_types41.NodeType.InfraNode && n.kind === "sql-table") {
|
|
10340
10469
|
for (const d of detectColumnDrift(n)) all.push(d);
|
|
10341
10470
|
}
|
|
10342
10471
|
});
|
|
@@ -10372,7 +10501,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
10372
10501
|
const bc = "column" in b && b.column ? b.column : "";
|
|
10373
10502
|
return ac.localeCompare(bc);
|
|
10374
10503
|
});
|
|
10375
|
-
return
|
|
10504
|
+
return import_types41.DivergenceResultSchema.parse({
|
|
10376
10505
|
divergences: filtered,
|
|
10377
10506
|
totalAffected: filtered.length,
|
|
10378
10507
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -10505,26 +10634,26 @@ function canonicalJson(value) {
|
|
|
10505
10634
|
init_cjs_shims();
|
|
10506
10635
|
var import_node_fs29 = require("fs");
|
|
10507
10636
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
10508
|
-
var
|
|
10509
|
-
var
|
|
10637
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
10638
|
+
var import_types42 = require("@neat.is/types");
|
|
10510
10639
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
10511
10640
|
var LOCK_RETRY_MS = 50;
|
|
10512
10641
|
function neatHome() {
|
|
10513
10642
|
const override = process.env.NEAT_HOME;
|
|
10514
|
-
if (override && override.length > 0) return
|
|
10515
|
-
return
|
|
10643
|
+
if (override && override.length > 0) return import_node_path56.default.resolve(override);
|
|
10644
|
+
return import_node_path56.default.join(import_node_os3.default.homedir(), ".neat");
|
|
10516
10645
|
}
|
|
10517
10646
|
function registryPath() {
|
|
10518
|
-
return
|
|
10647
|
+
return import_node_path56.default.join(neatHome(), "projects.json");
|
|
10519
10648
|
}
|
|
10520
10649
|
function registryLockPath() {
|
|
10521
|
-
return
|
|
10650
|
+
return import_node_path56.default.join(neatHome(), "projects.json.lock");
|
|
10522
10651
|
}
|
|
10523
10652
|
function daemonPidPath() {
|
|
10524
|
-
return
|
|
10653
|
+
return import_node_path56.default.join(neatHome(), "neatd.pid");
|
|
10525
10654
|
}
|
|
10526
10655
|
function daemonsDir() {
|
|
10527
|
-
return
|
|
10656
|
+
return import_node_path56.default.join(neatHome(), "daemons");
|
|
10528
10657
|
}
|
|
10529
10658
|
function isFiniteInt(v) {
|
|
10530
10659
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -10565,7 +10694,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
10565
10694
|
const out = [];
|
|
10566
10695
|
for (const name of names) {
|
|
10567
10696
|
if (!name.endsWith(".json")) continue;
|
|
10568
|
-
const file =
|
|
10697
|
+
const file = import_node_path56.default.join(dir, name);
|
|
10569
10698
|
let raw;
|
|
10570
10699
|
try {
|
|
10571
10700
|
raw = await import_node_fs29.promises.readFile(file, "utf8");
|
|
@@ -10642,7 +10771,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
10642
10771
|
}
|
|
10643
10772
|
}
|
|
10644
10773
|
async function writeAtomically(target, contents) {
|
|
10645
|
-
await import_node_fs29.promises.mkdir(
|
|
10774
|
+
await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(target), { recursive: true });
|
|
10646
10775
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
10647
10776
|
const fd = await import_node_fs29.promises.open(tmp, "w");
|
|
10648
10777
|
try {
|
|
@@ -10655,7 +10784,7 @@ async function writeAtomically(target, contents) {
|
|
|
10655
10784
|
}
|
|
10656
10785
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
10657
10786
|
const deadline = Date.now() + timeoutMs;
|
|
10658
|
-
await import_node_fs29.promises.mkdir(
|
|
10787
|
+
await import_node_fs29.promises.mkdir(import_node_path56.default.dirname(lockPath), { recursive: true });
|
|
10659
10788
|
let probedHolder = false;
|
|
10660
10789
|
while (true) {
|
|
10661
10790
|
try {
|
|
@@ -10708,10 +10837,10 @@ async function readRegistry() {
|
|
|
10708
10837
|
throw err;
|
|
10709
10838
|
}
|
|
10710
10839
|
const parsed = JSON.parse(raw);
|
|
10711
|
-
return
|
|
10840
|
+
return import_types42.RegistryFileSchema.parse(parsed);
|
|
10712
10841
|
}
|
|
10713
10842
|
async function writeRegistry(reg) {
|
|
10714
|
-
const validated =
|
|
10843
|
+
const validated = import_types42.RegistryFileSchema.parse(reg);
|
|
10715
10844
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
10716
10845
|
}
|
|
10717
10846
|
async function getProject(name) {
|
|
@@ -10856,7 +10985,7 @@ init_auth();
|
|
|
10856
10985
|
// src/connectors-config.ts
|
|
10857
10986
|
init_cjs_shims();
|
|
10858
10987
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10859
|
-
var
|
|
10988
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
10860
10989
|
var import_node_fs30 = require("fs");
|
|
10861
10990
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10862
10991
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -10871,11 +11000,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10871
11000
|
};
|
|
10872
11001
|
function neatHome2() {
|
|
10873
11002
|
const override = process.env.NEAT_HOME;
|
|
10874
|
-
if (override && override.length > 0) return
|
|
10875
|
-
return
|
|
11003
|
+
if (override && override.length > 0) return import_node_path57.default.resolve(override);
|
|
11004
|
+
return import_node_path57.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10876
11005
|
}
|
|
10877
11006
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10878
|
-
return
|
|
11007
|
+
return import_node_path57.default.join(home, "connectors.json");
|
|
10879
11008
|
}
|
|
10880
11009
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10881
11010
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -11062,15 +11191,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
11062
11191
|
|
|
11063
11192
|
// src/connectors/index.ts
|
|
11064
11193
|
init_cjs_shims();
|
|
11065
|
-
var
|
|
11194
|
+
var import_types43 = require("@neat.is/types");
|
|
11066
11195
|
var NO_ENV = "unknown";
|
|
11067
11196
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
11068
11197
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
11069
11198
|
const sites = [];
|
|
11070
11199
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
11071
11200
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
11072
|
-
if (edge.provenance !==
|
|
11073
|
-
const parsed = (0,
|
|
11201
|
+
if (edge.provenance !== import_types43.Provenance.EXTRACTED) continue;
|
|
11202
|
+
const parsed = (0, import_types43.parseFileId)(edge.source);
|
|
11074
11203
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
11075
11204
|
const site = { relPath: edge.evidence.file };
|
|
11076
11205
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -11081,7 +11210,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
11081
11210
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
11082
11211
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
11083
11212
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
11084
|
-
if (attrs.type !==
|
|
11213
|
+
if (attrs.type !== import_types43.NodeType.RouteNode || !attrs.path) return void 0;
|
|
11085
11214
|
const site = { relPath: attrs.path };
|
|
11086
11215
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
11087
11216
|
return site;
|
|
@@ -11558,10 +11687,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
11558
11687
|
// src/connectors/supabase/map.ts
|
|
11559
11688
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
11560
11689
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
11561
|
-
function targetFromRestPath(
|
|
11562
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
11690
|
+
function targetFromRestPath(path62) {
|
|
11691
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path62);
|
|
11563
11692
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
11564
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
11693
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path62);
|
|
11565
11694
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
11566
11695
|
return null;
|
|
11567
11696
|
}
|
|
@@ -11672,23 +11801,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
11672
11801
|
|
|
11673
11802
|
// src/connectors/supabase/resolve.ts
|
|
11674
11803
|
init_cjs_shims();
|
|
11675
|
-
var
|
|
11804
|
+
var import_types45 = require("@neat.is/types");
|
|
11676
11805
|
function createSupabaseResolveTarget(graph, config) {
|
|
11677
11806
|
return (signal, _ctx) => {
|
|
11678
11807
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
11679
11808
|
return null;
|
|
11680
11809
|
}
|
|
11681
|
-
const subResourceId = (0,
|
|
11810
|
+
const subResourceId = (0, import_types45.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
11682
11811
|
if (graph.hasNode(subResourceId)) {
|
|
11683
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
11812
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11684
11813
|
}
|
|
11685
|
-
const bareResourceId = (0,
|
|
11814
|
+
const bareResourceId = (0, import_types45.infraId)(signal.targetKind, signal.targetName);
|
|
11686
11815
|
if (graph.hasNode(bareResourceId)) {
|
|
11687
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
11816
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11688
11817
|
}
|
|
11689
|
-
const projectLevelId = (0,
|
|
11818
|
+
const projectLevelId = (0, import_types45.infraId)("supabase", config.nodeRef);
|
|
11690
11819
|
if (graph.hasNode(projectLevelId)) {
|
|
11691
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
11820
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types45.EdgeType.CALLS };
|
|
11692
11821
|
}
|
|
11693
11822
|
return null;
|
|
11694
11823
|
};
|
|
@@ -11781,7 +11910,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
11781
11910
|
|
|
11782
11911
|
// src/connectors/railway/index.ts
|
|
11783
11912
|
init_cjs_shims();
|
|
11784
|
-
var
|
|
11913
|
+
var import_types49 = require("@neat.is/types");
|
|
11785
11914
|
|
|
11786
11915
|
// src/connectors/railway/client.ts
|
|
11787
11916
|
init_cjs_shims();
|
|
@@ -11932,7 +12061,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
11932
12061
|
const out = [];
|
|
11933
12062
|
graph.forEachNode((_id, attrs) => {
|
|
11934
12063
|
const node = attrs;
|
|
11935
|
-
if (node.type !==
|
|
12064
|
+
if (node.type !== import_types49.NodeType.RouteNode) return;
|
|
11936
12065
|
const route = attrs;
|
|
11937
12066
|
if (route.service !== serviceName) return;
|
|
11938
12067
|
out.push({
|
|
@@ -12036,12 +12165,12 @@ function createRailwayResolveTarget(config) {
|
|
|
12036
12165
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
12037
12166
|
if (!serviceName) return null;
|
|
12038
12167
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
12039
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
12168
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types49.EdgeType.CALLS };
|
|
12040
12169
|
}
|
|
12041
12170
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
12042
12171
|
const peerName = config.serviceNameById[signal.targetName];
|
|
12043
12172
|
if (!peerName) return null;
|
|
12044
|
-
return { targetNodeId: (0,
|
|
12173
|
+
return { targetNodeId: (0, import_types49.serviceId)(peerName), serviceName, edgeType: import_types49.EdgeType.CONNECTS_TO };
|
|
12045
12174
|
}
|
|
12046
12175
|
return null;
|
|
12047
12176
|
};
|
|
@@ -12165,9 +12294,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
12165
12294
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
12166
12295
|
if (secondSep === -1) return null;
|
|
12167
12296
|
const method = rest.slice(0, secondSep);
|
|
12168
|
-
const
|
|
12169
|
-
if (!resourceName || !method || !
|
|
12170
|
-
return { resourceName, method, path:
|
|
12297
|
+
const path62 = rest.slice(secondSep + 1);
|
|
12298
|
+
if (!resourceName || !method || !path62) return null;
|
|
12299
|
+
return { resourceName, method, path: path62 };
|
|
12171
12300
|
}
|
|
12172
12301
|
function resourceNameFor(type, labels) {
|
|
12173
12302
|
if (!labels) return null;
|
|
@@ -12205,14 +12334,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
12205
12334
|
if (!req2) return null;
|
|
12206
12335
|
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
12207
12336
|
const method = req2.requestMethod.toUpperCase();
|
|
12208
|
-
const
|
|
12209
|
-
if (
|
|
12337
|
+
const path62 = pathFromRequestUrl(req2.requestUrl);
|
|
12338
|
+
if (path62 === null) return null;
|
|
12210
12339
|
const timestamp = entry2.timestamp;
|
|
12211
12340
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
12212
12341
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD2;
|
|
12213
12342
|
return {
|
|
12214
12343
|
targetKind: resourceType,
|
|
12215
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
12344
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path62 }),
|
|
12216
12345
|
callCount: 1,
|
|
12217
12346
|
errorCount: isError ? 1 : 0,
|
|
12218
12347
|
lastObservedIso: timestamp
|
|
@@ -12229,7 +12358,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
12229
12358
|
|
|
12230
12359
|
// src/connectors/firebase/resolve.ts
|
|
12231
12360
|
init_cjs_shims();
|
|
12232
|
-
var
|
|
12361
|
+
var import_types50 = require("@neat.is/types");
|
|
12233
12362
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
12234
12363
|
switch (resourceType) {
|
|
12235
12364
|
case "cloud_function":
|
|
@@ -12244,7 +12373,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
12244
12373
|
const entries = [];
|
|
12245
12374
|
graph.forEachNode((_id, attrs) => {
|
|
12246
12375
|
const node = attrs;
|
|
12247
|
-
if (node.type !==
|
|
12376
|
+
if (node.type !== import_types50.NodeType.RouteNode) return;
|
|
12248
12377
|
const route = attrs;
|
|
12249
12378
|
if (route.service !== serviceName) return;
|
|
12250
12379
|
entries.push({
|
|
@@ -12276,7 +12405,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
12276
12405
|
return {
|
|
12277
12406
|
targetNodeId: match.routeNodeId,
|
|
12278
12407
|
serviceName,
|
|
12279
|
-
edgeType:
|
|
12408
|
+
edgeType: import_types50.EdgeType.CALLS
|
|
12280
12409
|
};
|
|
12281
12410
|
};
|
|
12282
12411
|
}
|
|
@@ -12303,7 +12432,7 @@ init_cjs_shims();
|
|
|
12303
12432
|
|
|
12304
12433
|
// src/connectors/cloudflare/connector.ts
|
|
12305
12434
|
init_cjs_shims();
|
|
12306
|
-
var
|
|
12435
|
+
var import_types52 = require("@neat.is/types");
|
|
12307
12436
|
|
|
12308
12437
|
// src/connectors/cloudflare/client.ts
|
|
12309
12438
|
init_cjs_shims();
|
|
@@ -12419,7 +12548,7 @@ function mapEventToSignal(event) {
|
|
|
12419
12548
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
12420
12549
|
const statusCode = metadata?.statusCode;
|
|
12421
12550
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
12422
|
-
const
|
|
12551
|
+
const path62 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
12423
12552
|
return {
|
|
12424
12553
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
12425
12554
|
targetName: scriptName,
|
|
@@ -12427,7 +12556,7 @@ function mapEventToSignal(event) {
|
|
|
12427
12556
|
errorCount: isError ? 1 : 0,
|
|
12428
12557
|
lastObservedIso: observedAt.toISOString(),
|
|
12429
12558
|
method,
|
|
12430
|
-
...
|
|
12559
|
+
...path62 ? { path: path62 } : {},
|
|
12431
12560
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
12432
12561
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
12433
12562
|
};
|
|
@@ -12467,19 +12596,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
12467
12596
|
graph.forEachNode((id, attrs) => {
|
|
12468
12597
|
if (found) return;
|
|
12469
12598
|
const a = attrs;
|
|
12470
|
-
if (a.type ===
|
|
12599
|
+
if (a.type === import_types52.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
12471
12600
|
found = id;
|
|
12472
12601
|
}
|
|
12473
12602
|
});
|
|
12474
12603
|
return found;
|
|
12475
12604
|
}
|
|
12476
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
12477
|
-
const normalizedPath = normalizePathTemplate(
|
|
12605
|
+
function findMatchingRouteNode(graph, serviceName, method, path62) {
|
|
12606
|
+
const normalizedPath = normalizePathTemplate(path62);
|
|
12478
12607
|
let found = null;
|
|
12479
12608
|
graph.forEachNode((id, attrs) => {
|
|
12480
12609
|
if (found) return;
|
|
12481
12610
|
const a = attrs;
|
|
12482
|
-
if (a.type !==
|
|
12611
|
+
if (a.type !== import_types52.NodeType.RouteNode || a.service !== serviceName) return;
|
|
12483
12612
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
12484
12613
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
12485
12614
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -12491,18 +12620,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12491
12620
|
return (signal) => {
|
|
12492
12621
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
12493
12622
|
const scriptName = signal.targetName;
|
|
12494
|
-
const { method, path:
|
|
12623
|
+
const { method, path: path62 } = signal;
|
|
12495
12624
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
12496
|
-
if (!method || !
|
|
12497
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
12625
|
+
if (!method || !path62) return wholeFileId;
|
|
12626
|
+
return findMatchingRouteNode(graph, serviceName, method, path62) ?? wholeFileId;
|
|
12498
12627
|
};
|
|
12499
12628
|
const mapping = config.workers?.[scriptName];
|
|
12500
12629
|
if (mapping) {
|
|
12501
|
-
const wholeFileId = (0,
|
|
12630
|
+
const wholeFileId = (0, import_types52.fileId)(mapping.service, mapping.entryFile);
|
|
12502
12631
|
return {
|
|
12503
12632
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
12504
12633
|
serviceName: mapping.service,
|
|
12505
|
-
edgeType:
|
|
12634
|
+
edgeType: import_types52.EdgeType.CALLS
|
|
12506
12635
|
};
|
|
12507
12636
|
}
|
|
12508
12637
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -12511,13 +12640,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
12511
12640
|
return {
|
|
12512
12641
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
12513
12642
|
serviceName: fileNode.service,
|
|
12514
|
-
edgeType:
|
|
12643
|
+
edgeType: import_types52.EdgeType.CALLS
|
|
12515
12644
|
};
|
|
12516
12645
|
}
|
|
12517
12646
|
return {
|
|
12518
|
-
targetNodeId: (0,
|
|
12647
|
+
targetNodeId: (0, import_types52.infraId)("cloudflare-worker", scriptName),
|
|
12519
12648
|
serviceName: scriptName,
|
|
12520
|
-
edgeType:
|
|
12649
|
+
edgeType: import_types52.EdgeType.CALLS,
|
|
12521
12650
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
12522
12651
|
};
|
|
12523
12652
|
};
|
|
@@ -12713,14 +12842,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
12713
12842
|
|
|
12714
12843
|
// src/connectors/neon/resolve.ts
|
|
12715
12844
|
init_cjs_shims();
|
|
12716
|
-
var
|
|
12845
|
+
var import_types56 = require("@neat.is/types");
|
|
12717
12846
|
function createNeonResolveTarget(config) {
|
|
12718
12847
|
return (signal) => {
|
|
12719
12848
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
12720
12849
|
return {
|
|
12721
|
-
targetNodeId: (0,
|
|
12850
|
+
targetNodeId: (0, import_types56.infraId)("sql-table", signal.targetName),
|
|
12722
12851
|
serviceName: config.serviceName,
|
|
12723
|
-
edgeType:
|
|
12852
|
+
edgeType: import_types56.EdgeType.CALLS,
|
|
12724
12853
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
12725
12854
|
};
|
|
12726
12855
|
};
|
|
@@ -13284,11 +13413,11 @@ function registerRoutes(scope, ctx) {
|
|
|
13284
13413
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
13285
13414
|
const parsed = [];
|
|
13286
13415
|
for (const c of candidates) {
|
|
13287
|
-
const r =
|
|
13416
|
+
const r = import_types59.DivergenceTypeSchema.safeParse(c);
|
|
13288
13417
|
if (!r.success) {
|
|
13289
13418
|
return reply.code(400).send({
|
|
13290
13419
|
error: `unknown divergence type "${c}"`,
|
|
13291
|
-
allowed:
|
|
13420
|
+
allowed: import_types59.DivergenceTypeSchema.options
|
|
13292
13421
|
});
|
|
13293
13422
|
}
|
|
13294
13423
|
parsed.push(r.data);
|
|
@@ -13597,7 +13726,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13597
13726
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
13598
13727
|
let violations = await log.readAll();
|
|
13599
13728
|
if (req2.query.severity) {
|
|
13600
|
-
const sev =
|
|
13729
|
+
const sev = import_types59.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
13601
13730
|
if (!sev.success) {
|
|
13602
13731
|
return reply.code(400).send({
|
|
13603
13732
|
error: "invalid severity",
|
|
@@ -13636,7 +13765,7 @@ function registerRoutes(scope, ctx) {
|
|
|
13636
13765
|
scope.post("/policies/check", async (req2, reply) => {
|
|
13637
13766
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
13638
13767
|
if (!proj) return;
|
|
13639
|
-
const parsed =
|
|
13768
|
+
const parsed = import_types59.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
13640
13769
|
if (!parsed.success) {
|
|
13641
13770
|
return reply.code(400).send({
|
|
13642
13771
|
error: "invalid /policies/check body",
|
|
@@ -13958,7 +14087,7 @@ init_auth();
|
|
|
13958
14087
|
// src/unrouted.ts
|
|
13959
14088
|
init_cjs_shims();
|
|
13960
14089
|
var import_node_fs31 = require("fs");
|
|
13961
|
-
var
|
|
14090
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
13962
14091
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
13963
14092
|
return {
|
|
13964
14093
|
timestamp: now.toISOString(),
|
|
@@ -13968,34 +14097,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
13968
14097
|
};
|
|
13969
14098
|
}
|
|
13970
14099
|
async function appendUnroutedSpan(neatHome4, record) {
|
|
13971
|
-
const target =
|
|
14100
|
+
const target = import_node_path58.default.join(neatHome4, "errors.ndjson");
|
|
13972
14101
|
await import_node_fs31.promises.mkdir(neatHome4, { recursive: true });
|
|
13973
14102
|
await import_node_fs31.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
13974
14103
|
}
|
|
13975
14104
|
function unroutedErrorsPath(neatHome4) {
|
|
13976
|
-
return
|
|
14105
|
+
return import_node_path58.default.join(neatHome4, "errors.ndjson");
|
|
13977
14106
|
}
|
|
13978
14107
|
|
|
13979
14108
|
// src/daemon.ts
|
|
13980
|
-
var
|
|
14109
|
+
var import_types60 = require("@neat.is/types");
|
|
13981
14110
|
function daemonJsonPath(scanPath) {
|
|
13982
|
-
return
|
|
14111
|
+
return import_node_path59.default.join(scanPath, "neat-out", "daemon.json");
|
|
13983
14112
|
}
|
|
13984
14113
|
function daemonsDiscoveryDir(home) {
|
|
13985
14114
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
13986
|
-
return
|
|
14115
|
+
return import_node_path59.default.join(base, "daemons");
|
|
13987
14116
|
}
|
|
13988
14117
|
function daemonDiscoveryPath(project, home) {
|
|
13989
|
-
return
|
|
14118
|
+
return import_node_path59.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
13990
14119
|
}
|
|
13991
14120
|
function sanitizeDiscoveryName(project) {
|
|
13992
14121
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
13993
14122
|
}
|
|
13994
14123
|
function neatHomeFromEnv() {
|
|
13995
14124
|
const env = process.env.NEAT_HOME;
|
|
13996
|
-
if (env && env.length > 0) return
|
|
14125
|
+
if (env && env.length > 0) return import_node_path59.default.resolve(env);
|
|
13997
14126
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
13998
|
-
return
|
|
14127
|
+
return import_node_path59.default.join(home, ".neat");
|
|
13999
14128
|
}
|
|
14000
14129
|
function resolveNeatVersion() {
|
|
14001
14130
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -14064,11 +14193,11 @@ function teardownSlot(slot) {
|
|
|
14064
14193
|
}
|
|
14065
14194
|
}
|
|
14066
14195
|
function neatHomeFor(opts) {
|
|
14067
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
14196
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path59.default.resolve(opts.neatHome);
|
|
14068
14197
|
const env = process.env.NEAT_HOME;
|
|
14069
|
-
if (env && env.length > 0) return
|
|
14198
|
+
if (env && env.length > 0) return import_node_path59.default.resolve(env);
|
|
14070
14199
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
14071
|
-
return
|
|
14200
|
+
return import_node_path59.default.join(home, ".neat");
|
|
14072
14201
|
}
|
|
14073
14202
|
function routeSpanToProject(serviceName, projects) {
|
|
14074
14203
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -14116,11 +14245,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
14116
14245
|
if (!serviceName) return true;
|
|
14117
14246
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
14118
14247
|
return graph.someNode(
|
|
14119
|
-
(_id, attrs) => attrs.type ===
|
|
14248
|
+
(_id, attrs) => attrs.type === import_types60.NodeType.ServiceNode && attrs.name === serviceName
|
|
14120
14249
|
);
|
|
14121
14250
|
}
|
|
14122
14251
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
14123
|
-
const paths = pathsForProject(entry2.name,
|
|
14252
|
+
const paths = pathsForProject(entry2.name, import_node_path59.default.join(entry2.path, "neat-out"));
|
|
14124
14253
|
try {
|
|
14125
14254
|
const stat = await import_node_fs32.promises.stat(entry2.path);
|
|
14126
14255
|
if (!stat.isDirectory()) {
|
|
@@ -14236,7 +14365,7 @@ async function startDaemon(opts = {}) {
|
|
|
14236
14365
|
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;
|
|
14237
14366
|
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;
|
|
14238
14367
|
const singleProject = projectArg;
|
|
14239
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
14368
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path59.default.resolve(projectPathArg) : null;
|
|
14240
14369
|
if (singleProject && !singleProjectPath) {
|
|
14241
14370
|
throw new Error(
|
|
14242
14371
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -14251,7 +14380,7 @@ async function startDaemon(opts = {}) {
|
|
|
14251
14380
|
);
|
|
14252
14381
|
}
|
|
14253
14382
|
}
|
|
14254
|
-
const pidPath =
|
|
14383
|
+
const pidPath = import_node_path59.default.join(home, "neatd.pid");
|
|
14255
14384
|
await writeAtomically(pidPath, `${process.pid}
|
|
14256
14385
|
`);
|
|
14257
14386
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -14663,8 +14792,8 @@ async function startDaemon(opts = {}) {
|
|
|
14663
14792
|
let registryWatcher = null;
|
|
14664
14793
|
let reloadTimer = null;
|
|
14665
14794
|
if (!singleProject) try {
|
|
14666
|
-
const regDir =
|
|
14667
|
-
const regBase =
|
|
14795
|
+
const regDir = import_node_path59.default.dirname(regPath);
|
|
14796
|
+
const regBase = import_node_path59.default.basename(regPath);
|
|
14668
14797
|
registryWatcher = (0, import_node_fs32.watch)(regDir, (_eventType, filename) => {
|
|
14669
14798
|
if (filename !== null && filename !== regBase) return;
|
|
14670
14799
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
@@ -14739,7 +14868,7 @@ init_cjs_shims();
|
|
|
14739
14868
|
var import_node_child_process2 = require("child_process");
|
|
14740
14869
|
var import_node_fs33 = require("fs");
|
|
14741
14870
|
var import_node_net = __toESM(require("net"), 1);
|
|
14742
|
-
var
|
|
14871
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
14743
14872
|
var DEFAULT_WEB_PORT = 6328;
|
|
14744
14873
|
var DEFAULT_REST_PORT = 8080;
|
|
14745
14874
|
function asValidPort(value) {
|
|
@@ -14748,11 +14877,11 @@ function asValidPort(value) {
|
|
|
14748
14877
|
}
|
|
14749
14878
|
function projectRoot() {
|
|
14750
14879
|
const fromEnv = process.env.NEAT_SCAN_PATH;
|
|
14751
|
-
return
|
|
14880
|
+
return import_node_path60.default.resolve(fromEnv && fromEnv.length > 0 ? fromEnv : process.cwd());
|
|
14752
14881
|
}
|
|
14753
14882
|
async function readDaemonPorts(root) {
|
|
14754
14883
|
try {
|
|
14755
|
-
const raw = await import_node_fs33.promises.readFile(
|
|
14884
|
+
const raw = await import_node_fs33.promises.readFile(import_node_path60.default.join(root, "neat-out", "daemon.json"), "utf8");
|
|
14756
14885
|
const parsed = JSON.parse(raw);
|
|
14757
14886
|
const ports = parsed?.ports ?? {};
|
|
14758
14887
|
return { web: asValidPort(ports.web), rest: asValidPort(ports.rest) };
|
|
@@ -14797,10 +14926,10 @@ function resolveWebPackageDir() {
|
|
|
14797
14926
|
eval("require")
|
|
14798
14927
|
);
|
|
14799
14928
|
const pkgJsonPath = req.resolve("@neat.is/web/package.json");
|
|
14800
|
-
return
|
|
14929
|
+
return import_node_path60.default.dirname(pkgJsonPath);
|
|
14801
14930
|
}
|
|
14802
14931
|
function resolveStandaloneServerEntry(webDir) {
|
|
14803
|
-
return
|
|
14932
|
+
return import_node_path60.default.join(webDir, ".next/standalone/packages/web/server.js");
|
|
14804
14933
|
}
|
|
14805
14934
|
async function pickInternalPort() {
|
|
14806
14935
|
return new Promise((resolve, reject) => {
|
|
@@ -14853,7 +14982,7 @@ async function spawnWebUI(restPort, opts = {}) {
|
|
|
14853
14982
|
NEAT_API_URL: apiUrl
|
|
14854
14983
|
};
|
|
14855
14984
|
child = (0, import_node_child_process2.spawn)(process.execPath, [serverEntry], {
|
|
14856
|
-
cwd:
|
|
14985
|
+
cwd: import_node_path60.default.dirname(serverEntry),
|
|
14857
14986
|
env,
|
|
14858
14987
|
stdio: ["ignore", "inherit", "inherit"],
|
|
14859
14988
|
detached: false
|
|
@@ -15029,14 +15158,14 @@ function localVersion() {
|
|
|
15029
15158
|
}
|
|
15030
15159
|
function neatHome3() {
|
|
15031
15160
|
if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {
|
|
15032
|
-
return
|
|
15161
|
+
return import_node_path61.default.resolve(process.env.NEAT_HOME);
|
|
15033
15162
|
}
|
|
15034
15163
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
15035
|
-
return
|
|
15164
|
+
return import_node_path61.default.join(home, ".neat");
|
|
15036
15165
|
}
|
|
15037
15166
|
async function readPid() {
|
|
15038
15167
|
try {
|
|
15039
|
-
const raw = await import_node_fs34.promises.readFile(
|
|
15168
|
+
const raw = await import_node_fs34.promises.readFile(import_node_path61.default.join(neatHome3(), "neatd.pid"), "utf8");
|
|
15040
15169
|
const n = Number.parseInt(raw.trim(), 10);
|
|
15041
15170
|
return Number.isFinite(n) ? n : null;
|
|
15042
15171
|
} catch {
|