@neat.is/core 0.4.12 → 0.4.14
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-HVF4S7J3.js → chunk-6CO7C4IU.js} +6 -3
- package/dist/{chunk-HVF4S7J3.js.map → chunk-6CO7C4IU.js.map} +1 -1
- package/dist/{chunk-3QCRUEQD.js → chunk-GHPHVXYM.js} +5 -3
- package/dist/chunk-GHPHVXYM.js.map +1 -0
- package/dist/{chunk-7JY6F7BY.js → chunk-QZRDQ7WX.js} +3 -3
- package/dist/{chunk-WDG4QEFO.js → chunk-XS4CGNRO.js} +558 -233
- package/dist/chunk-XS4CGNRO.js.map +1 -0
- package/dist/cli.cjs +801 -458
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +21 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +613 -286
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +620 -293
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-VSPMP3OS.js → otel-grpc-QAISVAY5.js} +3 -3
- package/dist/server.cjs +538 -211
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +6 -2
- package/dist/chunk-3QCRUEQD.js.map +0 -1
- package/dist/chunk-WDG4QEFO.js.map +0 -1
- /package/dist/{chunk-7JY6F7BY.js.map → chunk-QZRDQ7WX.js.map} +0 -0
- /package/dist/{otel-grpc-VSPMP3OS.js.map → otel-grpc-QAISVAY5.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -57,9 +57,9 @@ function mountBearerAuth(app, opts) {
|
|
|
57
57
|
const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...opts.extraUnauthenticatedSuffixes ?? []];
|
|
58
58
|
const publicRead = opts.publicRead === true;
|
|
59
59
|
app.addHook("preHandler", (req, reply, done) => {
|
|
60
|
-
const
|
|
60
|
+
const path42 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
61
61
|
for (const suffix of suffixes) {
|
|
62
|
-
if (
|
|
62
|
+
if (path42 === suffix || path42.endsWith(suffix)) {
|
|
63
63
|
done();
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
@@ -133,7 +133,9 @@ __export(otel_grpc_exports, {
|
|
|
133
133
|
});
|
|
134
134
|
function bytesToHex(buf) {
|
|
135
135
|
if (!buf) return "";
|
|
136
|
-
|
|
136
|
+
if (Buffer.isBuffer(buf)) return buf.toString("hex");
|
|
137
|
+
if (buf instanceof Uint8Array) return Buffer.from(buf).toString("hex");
|
|
138
|
+
return "";
|
|
137
139
|
}
|
|
138
140
|
function nanosToString(n) {
|
|
139
141
|
if (n === void 0 || n === null) return "0";
|
|
@@ -185,8 +187,8 @@ function reshapeGrpcRequest(req) {
|
|
|
185
187
|
};
|
|
186
188
|
}
|
|
187
189
|
function resolveProtoRoot() {
|
|
188
|
-
const here =
|
|
189
|
-
return
|
|
190
|
+
const here = import_node_path38.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
191
|
+
return import_node_path38.default.resolve(here, "..", "proto");
|
|
190
192
|
}
|
|
191
193
|
function loadTraceService() {
|
|
192
194
|
const protoRoot = resolveProtoRoot();
|
|
@@ -254,13 +256,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
254
256
|
})
|
|
255
257
|
};
|
|
256
258
|
}
|
|
257
|
-
var import_node_url,
|
|
259
|
+
var import_node_url, import_node_path38, import_node_crypto2, grpc, protoLoader;
|
|
258
260
|
var init_otel_grpc = __esm({
|
|
259
261
|
"src/otel-grpc.ts"() {
|
|
260
262
|
"use strict";
|
|
261
263
|
init_cjs_shims();
|
|
262
264
|
import_node_url = require("url");
|
|
263
|
-
|
|
265
|
+
import_node_path38 = __toESM(require("path"), 1);
|
|
264
266
|
import_node_crypto2 = require("crypto");
|
|
265
267
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
266
268
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -370,10 +372,10 @@ function parseOtlpRequest(body) {
|
|
|
370
372
|
return out;
|
|
371
373
|
}
|
|
372
374
|
function loadProtoRoot() {
|
|
373
|
-
const here =
|
|
374
|
-
const protoRoot =
|
|
375
|
+
const here = import_node_path39.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
376
|
+
const protoRoot = import_node_path39.default.resolve(here, "..", "proto");
|
|
375
377
|
const root = new import_protobufjs.default.Root();
|
|
376
|
-
root.resolvePath = (_origin, target) =>
|
|
378
|
+
root.resolvePath = (_origin, target) => import_node_path39.default.resolve(protoRoot, target);
|
|
377
379
|
root.loadSync(
|
|
378
380
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
379
381
|
{ keepCase: true }
|
|
@@ -406,7 +408,10 @@ function encodeProtobufResponseBody() {
|
|
|
406
408
|
}
|
|
407
409
|
async function decodeProtobufBody(buf) {
|
|
408
410
|
const Type = loadProtobufDecoder();
|
|
409
|
-
const decoded = Type.decode(buf)
|
|
411
|
+
const decoded = Type.toObject(Type.decode(buf), {
|
|
412
|
+
longs: String,
|
|
413
|
+
enums: Number
|
|
414
|
+
});
|
|
410
415
|
const { reshapeGrpcRequest: reshapeGrpcRequest2 } = await Promise.resolve().then(() => (init_otel_grpc(), otel_grpc_exports));
|
|
411
416
|
return reshapeGrpcRequest2(decoded);
|
|
412
417
|
}
|
|
@@ -574,12 +579,12 @@ function logSpanHandler(span) {
|
|
|
574
579
|
`otel: ${span.service} ${span.name} parent=${parent} status=${status2}${db}`
|
|
575
580
|
);
|
|
576
581
|
}
|
|
577
|
-
var
|
|
582
|
+
var import_node_path39, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
578
583
|
var init_otel = __esm({
|
|
579
584
|
"src/otel.ts"() {
|
|
580
585
|
"use strict";
|
|
581
586
|
init_cjs_shims();
|
|
582
|
-
|
|
587
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
583
588
|
import_node_url2 = require("url");
|
|
584
589
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
585
590
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -1117,19 +1122,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1117
1122
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1118
1123
|
let best = { path: [start], edges: [] };
|
|
1119
1124
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1120
|
-
function step(node,
|
|
1121
|
-
if (
|
|
1122
|
-
best = { path: [...
|
|
1125
|
+
function step(node, path42, edges) {
|
|
1126
|
+
if (path42.length > best.path.length) {
|
|
1127
|
+
best = { path: [...path42], edges: [...edges] };
|
|
1123
1128
|
}
|
|
1124
|
-
if (
|
|
1129
|
+
if (path42.length - 1 >= maxDepth) return;
|
|
1125
1130
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1126
1131
|
for (const [srcId, edge] of incoming) {
|
|
1127
1132
|
if (visited.has(srcId)) continue;
|
|
1128
1133
|
visited.add(srcId);
|
|
1129
|
-
|
|
1134
|
+
path42.push(srcId);
|
|
1130
1135
|
edges.push(edge);
|
|
1131
|
-
step(srcId,
|
|
1132
|
-
|
|
1136
|
+
step(srcId, path42, edges);
|
|
1137
|
+
path42.pop();
|
|
1133
1138
|
edges.pop();
|
|
1134
1139
|
visited.delete(srcId);
|
|
1135
1140
|
}
|
|
@@ -3089,10 +3094,8 @@ async function addServiceAliases(graph, scanPath, services) {
|
|
|
3089
3094
|
await collectK8sAliases(graph, scanPath, byName);
|
|
3090
3095
|
}
|
|
3091
3096
|
|
|
3092
|
-
// src/extract/
|
|
3097
|
+
// src/extract/files.ts
|
|
3093
3098
|
init_cjs_shims();
|
|
3094
|
-
var import_node_path18 = __toESM(require("path"), 1);
|
|
3095
|
-
var import_types8 = require("@neat.is/types");
|
|
3096
3099
|
|
|
3097
3100
|
// src/extract/calls/shared.ts
|
|
3098
3101
|
init_cjs_shims();
|
|
@@ -3191,11 +3194,333 @@ function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
|
|
|
3191
3194
|
return { fileNodeId, nodesAdded, edgesAdded };
|
|
3192
3195
|
}
|
|
3193
3196
|
|
|
3197
|
+
// src/extract/files.ts
|
|
3198
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
3199
|
+
async function addFiles(graph, services) {
|
|
3200
|
+
let nodesAdded = 0;
|
|
3201
|
+
let edgesAdded = 0;
|
|
3202
|
+
for (const service of services) {
|
|
3203
|
+
const filePaths = await walkSourceFiles(service.dir);
|
|
3204
|
+
for (const filePath of filePaths) {
|
|
3205
|
+
const relPath = toPosix2(import_node_path11.default.relative(service.dir, filePath));
|
|
3206
|
+
const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
3207
|
+
graph,
|
|
3208
|
+
service.pkg.name,
|
|
3209
|
+
service.node.id,
|
|
3210
|
+
relPath
|
|
3211
|
+
);
|
|
3212
|
+
nodesAdded += n;
|
|
3213
|
+
edgesAdded += e;
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
return { nodesAdded, edgesAdded };
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
// src/extract/imports.ts
|
|
3220
|
+
init_cjs_shims();
|
|
3221
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
3222
|
+
var import_node_fs11 = require("fs");
|
|
3223
|
+
var import_tree_sitter = __toESM(require("tree-sitter"), 1);
|
|
3224
|
+
var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
|
|
3225
|
+
var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
|
|
3226
|
+
var import_types8 = require("@neat.is/types");
|
|
3227
|
+
var PARSE_CHUNK = 16384;
|
|
3228
|
+
function parseSource(parser, source) {
|
|
3229
|
+
return parser.parse(
|
|
3230
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK)
|
|
3231
|
+
);
|
|
3232
|
+
}
|
|
3233
|
+
function makeJsParser() {
|
|
3234
|
+
const p = new import_tree_sitter.default();
|
|
3235
|
+
p.setLanguage(import_tree_sitter_javascript.default);
|
|
3236
|
+
return p;
|
|
3237
|
+
}
|
|
3238
|
+
function makePyParser() {
|
|
3239
|
+
const p = new import_tree_sitter.default();
|
|
3240
|
+
p.setLanguage(import_tree_sitter_python.default);
|
|
3241
|
+
return p;
|
|
3242
|
+
}
|
|
3243
|
+
function stringLiteralText(node) {
|
|
3244
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
3245
|
+
const child = node.child(i);
|
|
3246
|
+
if (child?.type === "string_fragment") return child.text;
|
|
3247
|
+
}
|
|
3248
|
+
const raw = node.text;
|
|
3249
|
+
if (raw.length >= 2) return raw.slice(1, -1);
|
|
3250
|
+
return raw.length === 0 ? null : "";
|
|
3251
|
+
}
|
|
3252
|
+
function clipSnippet(text) {
|
|
3253
|
+
const oneLine = text.split("\n")[0] ?? text;
|
|
3254
|
+
return oneLine.length > 120 ? oneLine.slice(0, 120) : oneLine;
|
|
3255
|
+
}
|
|
3256
|
+
function collectJsImports(node, out) {
|
|
3257
|
+
if (node.type === "import_statement") {
|
|
3258
|
+
const source = node.childForFieldName("source");
|
|
3259
|
+
if (source) {
|
|
3260
|
+
const specifier = stringLiteralText(source);
|
|
3261
|
+
if (specifier) {
|
|
3262
|
+
out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3267
|
+
if (node.type === "call_expression") {
|
|
3268
|
+
const fn = node.childForFieldName("function");
|
|
3269
|
+
if (fn?.type === "identifier" && fn.text === "require") {
|
|
3270
|
+
const args = node.childForFieldName("arguments");
|
|
3271
|
+
const firstArg = args?.namedChild(0);
|
|
3272
|
+
if (firstArg?.type === "string") {
|
|
3273
|
+
const specifier = stringLiteralText(firstArg);
|
|
3274
|
+
if (specifier) {
|
|
3275
|
+
out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3281
|
+
const child = node.namedChild(i);
|
|
3282
|
+
if (child) collectJsImports(child, out);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
function collectPyImports(node, out) {
|
|
3286
|
+
if (node.type === "import_from_statement") {
|
|
3287
|
+
let level = 0;
|
|
3288
|
+
let modulePath = "";
|
|
3289
|
+
let pastFrom = false;
|
|
3290
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
3291
|
+
const child = node.child(i);
|
|
3292
|
+
if (!child) continue;
|
|
3293
|
+
if (!pastFrom) {
|
|
3294
|
+
if (child.type === "from") pastFrom = true;
|
|
3295
|
+
continue;
|
|
3296
|
+
}
|
|
3297
|
+
if (child.type === "import") break;
|
|
3298
|
+
if (child.type === "relative_import") {
|
|
3299
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
3300
|
+
const rc = child.child(j);
|
|
3301
|
+
if (!rc) continue;
|
|
3302
|
+
if (rc.type === "import_prefix") {
|
|
3303
|
+
for (let k = 0; k < rc.childCount; k++) {
|
|
3304
|
+
if (rc.child(k)?.type === ".") level++;
|
|
3305
|
+
}
|
|
3306
|
+
} else if (rc.type === "dotted_name") modulePath = rc.text;
|
|
3307
|
+
}
|
|
3308
|
+
break;
|
|
3309
|
+
}
|
|
3310
|
+
if (child.type === "dotted_name") {
|
|
3311
|
+
modulePath = child.text;
|
|
3312
|
+
break;
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
if (level > 0 || modulePath) {
|
|
3316
|
+
out.push({ modulePath, level, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3320
|
+
const child = node.namedChild(i);
|
|
3321
|
+
if (child) collectPyImports(child, out);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
async function fileExists(p) {
|
|
3325
|
+
try {
|
|
3326
|
+
await import_node_fs11.promises.access(p);
|
|
3327
|
+
return true;
|
|
3328
|
+
} catch {
|
|
3329
|
+
return false;
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
function isWithinServiceDir(candidate, serviceDir) {
|
|
3333
|
+
const rel = import_node_path12.default.relative(serviceDir, candidate);
|
|
3334
|
+
return rel !== "" && !rel.startsWith("..") && !import_node_path12.default.isAbsolute(rel);
|
|
3335
|
+
}
|
|
3336
|
+
var JS_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
3337
|
+
var JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`);
|
|
3338
|
+
async function firstExistingCandidate(base, serviceDir) {
|
|
3339
|
+
for (const ext of JS_EXTENSIONS) {
|
|
3340
|
+
const candidate = base + ext;
|
|
3341
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3342
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, candidate));
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
for (const indexFile of JS_INDEX_FILES) {
|
|
3346
|
+
const candidate = import_node_path12.default.join(base, indexFile);
|
|
3347
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3348
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, candidate));
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
return null;
|
|
3352
|
+
}
|
|
3353
|
+
async function loadTsPathConfig(serviceDir) {
|
|
3354
|
+
const tsconfigPath = import_node_path12.default.join(serviceDir, "tsconfig.json");
|
|
3355
|
+
let raw;
|
|
3356
|
+
try {
|
|
3357
|
+
raw = await import_node_fs11.promises.readFile(tsconfigPath, "utf8");
|
|
3358
|
+
} catch {
|
|
3359
|
+
return null;
|
|
3360
|
+
}
|
|
3361
|
+
try {
|
|
3362
|
+
const parsed = JSON.parse(raw);
|
|
3363
|
+
const paths = parsed.compilerOptions?.paths;
|
|
3364
|
+
if (!paths || Object.keys(paths).length === 0) return null;
|
|
3365
|
+
const baseUrl = parsed.compilerOptions?.baseUrl;
|
|
3366
|
+
return { paths, baseDir: baseUrl ? import_node_path12.default.resolve(serviceDir, baseUrl) : serviceDir };
|
|
3367
|
+
} catch (err) {
|
|
3368
|
+
recordExtractionError("import alias resolution", tsconfigPath, err);
|
|
3369
|
+
return null;
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
async function resolveTsAlias(specifier, config, serviceDir) {
|
|
3373
|
+
for (const [pattern, targets] of Object.entries(config.paths)) {
|
|
3374
|
+
let suffix = null;
|
|
3375
|
+
if (pattern === specifier) {
|
|
3376
|
+
suffix = "";
|
|
3377
|
+
} else if (pattern.endsWith("/*")) {
|
|
3378
|
+
const prefix = pattern.slice(0, -1);
|
|
3379
|
+
if (specifier.startsWith(prefix)) suffix = specifier.slice(prefix.length);
|
|
3380
|
+
}
|
|
3381
|
+
if (suffix === null) continue;
|
|
3382
|
+
for (const target of targets) {
|
|
3383
|
+
const targetBase = target.endsWith("/*") ? target.slice(0, -2) : target.replace(/\*$/, "");
|
|
3384
|
+
const resolvedBase = import_node_path12.default.resolve(config.baseDir, targetBase, suffix);
|
|
3385
|
+
const hit = await firstExistingCandidate(resolvedBase, serviceDir);
|
|
3386
|
+
if (hit) return hit;
|
|
3387
|
+
if (isWithinServiceDir(resolvedBase, serviceDir) && await fileExists(resolvedBase)) {
|
|
3388
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, resolvedBase));
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
return null;
|
|
3393
|
+
}
|
|
3394
|
+
async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
|
|
3395
|
+
if (!specifier) return null;
|
|
3396
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
3397
|
+
const base = import_node_path12.default.resolve(importerDir, specifier);
|
|
3398
|
+
const ext = import_node_path12.default.extname(specifier);
|
|
3399
|
+
if (ext) {
|
|
3400
|
+
if (ext === ".js" || ext === ".jsx") {
|
|
3401
|
+
const tsExt = ext === ".jsx" ? ".tsx" : ".ts";
|
|
3402
|
+
const tsSibling = base.slice(0, -ext.length) + tsExt;
|
|
3403
|
+
if (isWithinServiceDir(tsSibling, serviceDir) && await fileExists(tsSibling)) {
|
|
3404
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, tsSibling));
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
if (isWithinServiceDir(base, serviceDir) && await fileExists(base)) {
|
|
3408
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, base));
|
|
3409
|
+
}
|
|
3410
|
+
return null;
|
|
3411
|
+
}
|
|
3412
|
+
return firstExistingCandidate(base, serviceDir);
|
|
3413
|
+
}
|
|
3414
|
+
if (tsPaths) return resolveTsAlias(specifier, tsPaths, serviceDir);
|
|
3415
|
+
return null;
|
|
3416
|
+
}
|
|
3417
|
+
async function resolvePyImport(imp, importerPath, serviceDir) {
|
|
3418
|
+
if (!imp.modulePath) return null;
|
|
3419
|
+
const relPath = imp.modulePath.split(".").join("/");
|
|
3420
|
+
let baseDir;
|
|
3421
|
+
if (imp.level > 0) {
|
|
3422
|
+
baseDir = import_node_path12.default.dirname(importerPath);
|
|
3423
|
+
for (let i = 1; i < imp.level; i++) baseDir = import_node_path12.default.dirname(baseDir);
|
|
3424
|
+
} else {
|
|
3425
|
+
baseDir = serviceDir;
|
|
3426
|
+
}
|
|
3427
|
+
const candidates = [import_node_path12.default.join(baseDir, `${relPath}.py`), import_node_path12.default.join(baseDir, relPath, "__init__.py")];
|
|
3428
|
+
for (const candidate of candidates) {
|
|
3429
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists(candidate)) {
|
|
3430
|
+
return toPosix2(import_node_path12.default.relative(serviceDir, candidate));
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
return null;
|
|
3434
|
+
}
|
|
3435
|
+
function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
|
|
3436
|
+
const importeeFileId = (0, import_types8.fileId)(serviceName, importeeRelPath);
|
|
3437
|
+
if (!graph.hasNode(importeeFileId)) return 0;
|
|
3438
|
+
const edgeId = (0, import_types8.extractedEdgeId)(importerFileId, importeeFileId, import_types8.EdgeType.IMPORTS);
|
|
3439
|
+
if (graph.hasEdge(edgeId)) return 0;
|
|
3440
|
+
const edge = {
|
|
3441
|
+
id: edgeId,
|
|
3442
|
+
source: importerFileId,
|
|
3443
|
+
target: importeeFileId,
|
|
3444
|
+
type: import_types8.EdgeType.IMPORTS,
|
|
3445
|
+
provenance: import_types8.Provenance.EXTRACTED,
|
|
3446
|
+
confidence: (0, import_types8.confidenceForExtracted)("structural"),
|
|
3447
|
+
evidence: { file: importerRelPath, line, snippet: snippet2 }
|
|
3448
|
+
};
|
|
3449
|
+
graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge);
|
|
3450
|
+
return 1;
|
|
3451
|
+
}
|
|
3452
|
+
async function addImports(graph, services) {
|
|
3453
|
+
const jsParser = makeJsParser();
|
|
3454
|
+
const pyParser = makePyParser();
|
|
3455
|
+
let edgesAdded = 0;
|
|
3456
|
+
for (const service of services) {
|
|
3457
|
+
const tsPaths = await loadTsPathConfig(service.dir);
|
|
3458
|
+
const files = await loadSourceFiles(service.dir);
|
|
3459
|
+
for (const file of files) {
|
|
3460
|
+
if (isTestPath(file.path)) continue;
|
|
3461
|
+
const relFile = toPosix2(import_node_path12.default.relative(service.dir, file.path));
|
|
3462
|
+
const importerFileId = (0, import_types8.fileId)(service.pkg.name, relFile);
|
|
3463
|
+
const isPython = import_node_path12.default.extname(file.path) === ".py";
|
|
3464
|
+
if (isPython) {
|
|
3465
|
+
let pyImports = [];
|
|
3466
|
+
try {
|
|
3467
|
+
const tree = parseSource(pyParser, file.content);
|
|
3468
|
+
collectPyImports(tree.rootNode, pyImports);
|
|
3469
|
+
} catch (err) {
|
|
3470
|
+
recordExtractionError("import extraction", file.path, err);
|
|
3471
|
+
continue;
|
|
3472
|
+
}
|
|
3473
|
+
for (const imp of pyImports) {
|
|
3474
|
+
const resolved = await resolvePyImport(imp, file.path, service.dir);
|
|
3475
|
+
if (!resolved) continue;
|
|
3476
|
+
edgesAdded += emitImportEdge(
|
|
3477
|
+
graph,
|
|
3478
|
+
service.pkg.name,
|
|
3479
|
+
importerFileId,
|
|
3480
|
+
relFile,
|
|
3481
|
+
resolved,
|
|
3482
|
+
imp.line,
|
|
3483
|
+
imp.snippet
|
|
3484
|
+
);
|
|
3485
|
+
}
|
|
3486
|
+
continue;
|
|
3487
|
+
}
|
|
3488
|
+
let jsImports = [];
|
|
3489
|
+
try {
|
|
3490
|
+
const tree = parseSource(jsParser, file.content);
|
|
3491
|
+
collectJsImports(tree.rootNode, jsImports);
|
|
3492
|
+
} catch (err) {
|
|
3493
|
+
recordExtractionError("import extraction", file.path, err);
|
|
3494
|
+
continue;
|
|
3495
|
+
}
|
|
3496
|
+
for (const imp of jsImports) {
|
|
3497
|
+
const resolved = await resolveJsImport(imp.specifier, import_node_path12.default.dirname(file.path), service.dir, tsPaths);
|
|
3498
|
+
if (!resolved) continue;
|
|
3499
|
+
edgesAdded += emitImportEdge(
|
|
3500
|
+
graph,
|
|
3501
|
+
service.pkg.name,
|
|
3502
|
+
importerFileId,
|
|
3503
|
+
relFile,
|
|
3504
|
+
resolved,
|
|
3505
|
+
imp.line,
|
|
3506
|
+
imp.snippet
|
|
3507
|
+
);
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
return { nodesAdded: 0, edgesAdded };
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
// src/extract/databases/index.ts
|
|
3515
|
+
init_cjs_shims();
|
|
3516
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
3517
|
+
var import_types9 = require("@neat.is/types");
|
|
3518
|
+
|
|
3194
3519
|
// src/extract/databases/db-config-yaml.ts
|
|
3195
3520
|
init_cjs_shims();
|
|
3196
|
-
var
|
|
3521
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
3197
3522
|
async function parse(serviceDir) {
|
|
3198
|
-
const yamlPath =
|
|
3523
|
+
const yamlPath = import_node_path13.default.join(serviceDir, "db-config.yaml");
|
|
3199
3524
|
if (!await exists(yamlPath)) return [];
|
|
3200
3525
|
const raw = await readYaml(yamlPath);
|
|
3201
3526
|
return [
|
|
@@ -3213,13 +3538,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
|
|
|
3213
3538
|
|
|
3214
3539
|
// src/extract/databases/dotenv.ts
|
|
3215
3540
|
init_cjs_shims();
|
|
3216
|
-
var
|
|
3217
|
-
var
|
|
3541
|
+
var import_node_fs13 = require("fs");
|
|
3542
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
3218
3543
|
|
|
3219
3544
|
// src/extract/databases/shared.ts
|
|
3220
3545
|
init_cjs_shims();
|
|
3221
|
-
var
|
|
3222
|
-
var
|
|
3546
|
+
var import_node_fs12 = require("fs");
|
|
3547
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
3223
3548
|
function schemeToEngine(scheme) {
|
|
3224
3549
|
const s = scheme.toLowerCase().split("+")[0];
|
|
3225
3550
|
switch (s) {
|
|
@@ -3258,14 +3583,14 @@ function parseConnectionString(url) {
|
|
|
3258
3583
|
}
|
|
3259
3584
|
async function readIfExists(filePath) {
|
|
3260
3585
|
try {
|
|
3261
|
-
return await
|
|
3586
|
+
return await import_node_fs12.promises.readFile(filePath, "utf8");
|
|
3262
3587
|
} catch {
|
|
3263
3588
|
return null;
|
|
3264
3589
|
}
|
|
3265
3590
|
}
|
|
3266
3591
|
async function findFirst(serviceDir, candidates) {
|
|
3267
3592
|
for (const rel of candidates) {
|
|
3268
|
-
const abs =
|
|
3593
|
+
const abs = import_node_path14.default.join(serviceDir, rel);
|
|
3269
3594
|
const content = await readIfExists(abs);
|
|
3270
3595
|
if (content !== null) return abs;
|
|
3271
3596
|
}
|
|
@@ -3316,15 +3641,15 @@ function parseDotenvLine(line) {
|
|
|
3316
3641
|
return { key, value };
|
|
3317
3642
|
}
|
|
3318
3643
|
async function parse2(serviceDir) {
|
|
3319
|
-
const entries = await
|
|
3644
|
+
const entries = await import_node_fs13.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
|
|
3320
3645
|
const configs = [];
|
|
3321
3646
|
const seen = /* @__PURE__ */ new Set();
|
|
3322
3647
|
for (const entry of entries) {
|
|
3323
3648
|
if (!entry.isFile()) continue;
|
|
3324
3649
|
const match = isConfigFile(entry.name);
|
|
3325
3650
|
if (!match.match || match.fileType !== "env") continue;
|
|
3326
|
-
const filePath =
|
|
3327
|
-
const content = await
|
|
3651
|
+
const filePath = import_node_path15.default.join(serviceDir, entry.name);
|
|
3652
|
+
const content = await import_node_fs13.promises.readFile(filePath, "utf8");
|
|
3328
3653
|
for (const line of content.split("\n")) {
|
|
3329
3654
|
const parsed = parseDotenvLine(line);
|
|
3330
3655
|
if (!parsed) continue;
|
|
@@ -3343,9 +3668,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
|
|
|
3343
3668
|
|
|
3344
3669
|
// src/extract/databases/prisma.ts
|
|
3345
3670
|
init_cjs_shims();
|
|
3346
|
-
var
|
|
3671
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
3347
3672
|
async function parse3(serviceDir) {
|
|
3348
|
-
const schemaPath =
|
|
3673
|
+
const schemaPath = import_node_path16.default.join(serviceDir, "prisma", "schema.prisma");
|
|
3349
3674
|
const content = await readIfExists(schemaPath);
|
|
3350
3675
|
if (!content) return [];
|
|
3351
3676
|
const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
|
|
@@ -3477,10 +3802,10 @@ var knexParser = { name: "knex", parse: parse5 };
|
|
|
3477
3802
|
|
|
3478
3803
|
// src/extract/databases/ormconfig.ts
|
|
3479
3804
|
init_cjs_shims();
|
|
3480
|
-
var
|
|
3805
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
3481
3806
|
async function parse6(serviceDir) {
|
|
3482
3807
|
for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
|
|
3483
|
-
const abs =
|
|
3808
|
+
const abs = import_node_path17.default.join(serviceDir, candidate);
|
|
3484
3809
|
if (!await exists(abs)) continue;
|
|
3485
3810
|
const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
|
|
3486
3811
|
const entries = Array.isArray(raw) ? raw : [raw];
|
|
@@ -3540,9 +3865,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
|
|
|
3540
3865
|
|
|
3541
3866
|
// src/extract/databases/sequelize.ts
|
|
3542
3867
|
init_cjs_shims();
|
|
3543
|
-
var
|
|
3868
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
3544
3869
|
async function parse8(serviceDir) {
|
|
3545
|
-
const configPath =
|
|
3870
|
+
const configPath = import_node_path18.default.join(serviceDir, "config", "config.json");
|
|
3546
3871
|
if (!await exists(configPath)) return [];
|
|
3547
3872
|
const raw = await readJson(configPath);
|
|
3548
3873
|
const out = [];
|
|
@@ -3569,7 +3894,7 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
|
3569
3894
|
|
|
3570
3895
|
// src/extract/databases/docker-compose.ts
|
|
3571
3896
|
init_cjs_shims();
|
|
3572
|
-
var
|
|
3897
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
3573
3898
|
function portFromService(svc) {
|
|
3574
3899
|
for (const raw of svc.ports ?? []) {
|
|
3575
3900
|
const str = String(raw);
|
|
@@ -3596,7 +3921,7 @@ function databaseFromEnv(svc) {
|
|
|
3596
3921
|
}
|
|
3597
3922
|
async function parse9(serviceDir) {
|
|
3598
3923
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
3599
|
-
const abs =
|
|
3924
|
+
const abs = import_node_path19.default.join(serviceDir, name);
|
|
3600
3925
|
if (!await exists(abs)) continue;
|
|
3601
3926
|
const raw = await readYaml(abs);
|
|
3602
3927
|
if (!raw?.services) return [];
|
|
@@ -3637,8 +3962,8 @@ function compatibleDriversFor(engine) {
|
|
|
3637
3962
|
}
|
|
3638
3963
|
function toDatabaseNode(config) {
|
|
3639
3964
|
return {
|
|
3640
|
-
id: (0,
|
|
3641
|
-
type:
|
|
3965
|
+
id: (0, import_types9.databaseId)(config.host),
|
|
3966
|
+
type: import_types9.NodeType.DatabaseNode,
|
|
3642
3967
|
name: config.database || config.host,
|
|
3643
3968
|
engine: config.engine,
|
|
3644
3969
|
engineVersion: config.engineVersion,
|
|
@@ -3768,7 +4093,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3768
4093
|
discoveredVia: mergedDiscoveredVia
|
|
3769
4094
|
});
|
|
3770
4095
|
}
|
|
3771
|
-
const relConfigFile = toPosix2(
|
|
4096
|
+
const relConfigFile = toPosix2(import_node_path20.default.relative(service.dir, config.sourceFile));
|
|
3772
4097
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
3773
4098
|
graph,
|
|
3774
4099
|
service.pkg.name,
|
|
@@ -3777,14 +4102,14 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3777
4102
|
);
|
|
3778
4103
|
nodesAdded += fn;
|
|
3779
4104
|
edgesAdded += fe;
|
|
3780
|
-
const evidenceFile = toPosix2(
|
|
4105
|
+
const evidenceFile = toPosix2(import_node_path20.default.relative(scanPath, config.sourceFile));
|
|
3781
4106
|
const edge = {
|
|
3782
|
-
id: (0, import_types4.extractedEdgeId)(fileNodeId, dbNode.id,
|
|
4107
|
+
id: (0, import_types4.extractedEdgeId)(fileNodeId, dbNode.id, import_types9.EdgeType.CONNECTS_TO),
|
|
3783
4108
|
source: fileNodeId,
|
|
3784
4109
|
target: dbNode.id,
|
|
3785
|
-
type:
|
|
3786
|
-
provenance:
|
|
3787
|
-
confidence: (0,
|
|
4110
|
+
type: import_types9.EdgeType.CONNECTS_TO,
|
|
4111
|
+
provenance: import_types9.Provenance.EXTRACTED,
|
|
4112
|
+
confidence: (0, import_types9.confidenceForExtracted)("structural"),
|
|
3788
4113
|
evidence: { file: evidenceFile }
|
|
3789
4114
|
};
|
|
3790
4115
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -3811,15 +4136,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
3811
4136
|
|
|
3812
4137
|
// src/extract/configs.ts
|
|
3813
4138
|
init_cjs_shims();
|
|
3814
|
-
var
|
|
3815
|
-
var
|
|
3816
|
-
var
|
|
4139
|
+
var import_node_fs14 = require("fs");
|
|
4140
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
4141
|
+
var import_types10 = require("@neat.is/types");
|
|
3817
4142
|
async function walkConfigFiles(dir) {
|
|
3818
4143
|
const out = [];
|
|
3819
4144
|
async function walk(current) {
|
|
3820
|
-
const entries = await
|
|
4145
|
+
const entries = await import_node_fs14.promises.readdir(current, { withFileTypes: true });
|
|
3821
4146
|
for (const entry of entries) {
|
|
3822
|
-
const full =
|
|
4147
|
+
const full = import_node_path21.default.join(current, entry.name);
|
|
3823
4148
|
if (entry.isDirectory()) {
|
|
3824
4149
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
3825
4150
|
if (await isPythonVenvDir(full)) continue;
|
|
@@ -3838,19 +4163,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3838
4163
|
for (const service of services) {
|
|
3839
4164
|
const configFiles = await walkConfigFiles(service.dir);
|
|
3840
4165
|
for (const file of configFiles) {
|
|
3841
|
-
const relPath =
|
|
4166
|
+
const relPath = import_node_path21.default.relative(scanPath, file);
|
|
3842
4167
|
const node = {
|
|
3843
|
-
id: (0,
|
|
3844
|
-
type:
|
|
3845
|
-
name:
|
|
4168
|
+
id: (0, import_types10.configId)(relPath),
|
|
4169
|
+
type: import_types10.NodeType.ConfigNode,
|
|
4170
|
+
name: import_node_path21.default.basename(file),
|
|
3846
4171
|
path: relPath,
|
|
3847
|
-
fileType: isConfigFile(
|
|
4172
|
+
fileType: isConfigFile(import_node_path21.default.basename(file)).fileType
|
|
3848
4173
|
};
|
|
3849
4174
|
if (!graph.hasNode(node.id)) {
|
|
3850
4175
|
graph.addNode(node.id, node);
|
|
3851
4176
|
nodesAdded++;
|
|
3852
4177
|
}
|
|
3853
|
-
const relToService = toPosix2(
|
|
4178
|
+
const relToService = toPosix2(import_node_path21.default.relative(service.dir, file));
|
|
3854
4179
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
3855
4180
|
graph,
|
|
3856
4181
|
service.pkg.name,
|
|
@@ -3860,13 +4185,13 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3860
4185
|
nodesAdded += fn;
|
|
3861
4186
|
edgesAdded += fe;
|
|
3862
4187
|
const edge = {
|
|
3863
|
-
id: (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
4188
|
+
id: (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types10.EdgeType.CONFIGURED_BY),
|
|
3864
4189
|
source: fileNodeId,
|
|
3865
4190
|
target: node.id,
|
|
3866
|
-
type:
|
|
3867
|
-
provenance:
|
|
3868
|
-
confidence: (0,
|
|
3869
|
-
evidence: { file: relPath.split(
|
|
4191
|
+
type: import_types10.EdgeType.CONFIGURED_BY,
|
|
4192
|
+
provenance: import_types10.Provenance.EXTRACTED,
|
|
4193
|
+
confidence: (0, import_types10.confidenceForExtracted)("structural"),
|
|
4194
|
+
evidence: { file: relPath.split(import_node_path21.default.sep).join("/") }
|
|
3870
4195
|
};
|
|
3871
4196
|
if (!graph.hasEdge(edge.id)) {
|
|
3872
4197
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -3879,15 +4204,15 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
3879
4204
|
|
|
3880
4205
|
// src/extract/calls/index.ts
|
|
3881
4206
|
init_cjs_shims();
|
|
3882
|
-
var
|
|
4207
|
+
var import_types16 = require("@neat.is/types");
|
|
3883
4208
|
|
|
3884
4209
|
// src/extract/calls/http.ts
|
|
3885
4210
|
init_cjs_shims();
|
|
3886
|
-
var
|
|
3887
|
-
var
|
|
3888
|
-
var
|
|
3889
|
-
var
|
|
3890
|
-
var
|
|
4211
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
4212
|
+
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
4213
|
+
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
4214
|
+
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
4215
|
+
var import_types11 = require("@neat.is/types");
|
|
3891
4216
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
3892
4217
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
3893
4218
|
function isInsideJsxExternalLink(node) {
|
|
@@ -3915,14 +4240,14 @@ function collectStringLiterals(node, out) {
|
|
|
3915
4240
|
if (child) collectStringLiterals(child, out);
|
|
3916
4241
|
}
|
|
3917
4242
|
}
|
|
3918
|
-
var
|
|
3919
|
-
function
|
|
4243
|
+
var PARSE_CHUNK2 = 16384;
|
|
4244
|
+
function parseSource2(parser, source) {
|
|
3920
4245
|
return parser.parse(
|
|
3921
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
4246
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK2)
|
|
3922
4247
|
);
|
|
3923
4248
|
}
|
|
3924
4249
|
function callsFromSource(source, parser, knownHosts) {
|
|
3925
|
-
const tree =
|
|
4250
|
+
const tree = parseSource2(parser, source);
|
|
3926
4251
|
const literals = [];
|
|
3927
4252
|
collectStringLiterals(tree.rootNode, literals);
|
|
3928
4253
|
const out = [];
|
|
@@ -3936,25 +4261,25 @@ function callsFromSource(source, parser, knownHosts) {
|
|
|
3936
4261
|
}
|
|
3937
4262
|
return out;
|
|
3938
4263
|
}
|
|
3939
|
-
function
|
|
3940
|
-
const p = new
|
|
3941
|
-
p.setLanguage(
|
|
4264
|
+
function makeJsParser2() {
|
|
4265
|
+
const p = new import_tree_sitter2.default();
|
|
4266
|
+
p.setLanguage(import_tree_sitter_javascript2.default);
|
|
3942
4267
|
return p;
|
|
3943
4268
|
}
|
|
3944
|
-
function
|
|
3945
|
-
const p = new
|
|
3946
|
-
p.setLanguage(
|
|
4269
|
+
function makePyParser2() {
|
|
4270
|
+
const p = new import_tree_sitter2.default();
|
|
4271
|
+
p.setLanguage(import_tree_sitter_python2.default);
|
|
3947
4272
|
return p;
|
|
3948
4273
|
}
|
|
3949
4274
|
async function addHttpCallEdges(graph, services) {
|
|
3950
|
-
const jsParser =
|
|
3951
|
-
const pyParser =
|
|
4275
|
+
const jsParser = makeJsParser2();
|
|
4276
|
+
const pyParser = makePyParser2();
|
|
3952
4277
|
const knownHosts = /* @__PURE__ */ new Set();
|
|
3953
4278
|
const hostToNodeId = /* @__PURE__ */ new Map();
|
|
3954
4279
|
for (const service of services) {
|
|
3955
|
-
knownHosts.add(
|
|
4280
|
+
knownHosts.add(import_node_path22.default.basename(service.dir));
|
|
3956
4281
|
knownHosts.add(service.pkg.name);
|
|
3957
|
-
hostToNodeId.set(
|
|
4282
|
+
hostToNodeId.set(import_node_path22.default.basename(service.dir), service.node.id);
|
|
3958
4283
|
hostToNodeId.set(service.pkg.name, service.node.id);
|
|
3959
4284
|
}
|
|
3960
4285
|
let nodesAdded = 0;
|
|
@@ -3964,7 +4289,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
3964
4289
|
const seen = /* @__PURE__ */ new Set();
|
|
3965
4290
|
for (const file of files) {
|
|
3966
4291
|
if (isTestPath(file.path)) continue;
|
|
3967
|
-
const parser =
|
|
4292
|
+
const parser = import_node_path22.default.extname(file.path) === ".py" ? pyParser : jsParser;
|
|
3968
4293
|
let sites;
|
|
3969
4294
|
try {
|
|
3970
4295
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -3973,14 +4298,14 @@ async function addHttpCallEdges(graph, services) {
|
|
|
3973
4298
|
continue;
|
|
3974
4299
|
}
|
|
3975
4300
|
if (sites.length === 0) continue;
|
|
3976
|
-
const relFile = toPosix2(
|
|
4301
|
+
const relFile = toPosix2(import_node_path22.default.relative(service.dir, file.path));
|
|
3977
4302
|
for (const site of sites) {
|
|
3978
4303
|
const targetId = hostToNodeId.get(site.host);
|
|
3979
4304
|
if (!targetId || targetId === service.node.id) continue;
|
|
3980
4305
|
const dedupKey = `${relFile}|${targetId}`;
|
|
3981
4306
|
if (seen.has(dedupKey)) continue;
|
|
3982
4307
|
seen.add(dedupKey);
|
|
3983
|
-
const confidence = (0,
|
|
4308
|
+
const confidence = (0, import_types11.confidenceForExtracted)("hostname-shape-match");
|
|
3984
4309
|
const ev = {
|
|
3985
4310
|
file: relFile,
|
|
3986
4311
|
line: site.line,
|
|
@@ -3994,25 +4319,25 @@ async function addHttpCallEdges(graph, services) {
|
|
|
3994
4319
|
);
|
|
3995
4320
|
nodesAdded += n;
|
|
3996
4321
|
edgesAdded += e;
|
|
3997
|
-
if (!(0,
|
|
4322
|
+
if (!(0, import_types11.passesExtractedFloor)(confidence)) {
|
|
3998
4323
|
noteExtractedDropped({
|
|
3999
4324
|
source: fileNodeId,
|
|
4000
4325
|
target: targetId,
|
|
4001
|
-
type:
|
|
4326
|
+
type: import_types11.EdgeType.CALLS,
|
|
4002
4327
|
confidence,
|
|
4003
4328
|
confidenceKind: "hostname-shape-match",
|
|
4004
4329
|
evidence: ev
|
|
4005
4330
|
});
|
|
4006
4331
|
continue;
|
|
4007
4332
|
}
|
|
4008
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, targetId,
|
|
4333
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, targetId, import_types11.EdgeType.CALLS);
|
|
4009
4334
|
if (!graph.hasEdge(edgeId)) {
|
|
4010
4335
|
const edge = {
|
|
4011
4336
|
id: edgeId,
|
|
4012
4337
|
source: fileNodeId,
|
|
4013
4338
|
target: targetId,
|
|
4014
|
-
type:
|
|
4015
|
-
provenance:
|
|
4339
|
+
type: import_types11.EdgeType.CALLS,
|
|
4340
|
+
provenance: import_types11.Provenance.EXTRACTED,
|
|
4016
4341
|
confidence,
|
|
4017
4342
|
evidence: ev
|
|
4018
4343
|
};
|
|
@@ -4027,8 +4352,8 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4027
4352
|
|
|
4028
4353
|
// src/extract/calls/kafka.ts
|
|
4029
4354
|
init_cjs_shims();
|
|
4030
|
-
var
|
|
4031
|
-
var
|
|
4355
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
4356
|
+
var import_types12 = require("@neat.is/types");
|
|
4032
4357
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4033
4358
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
4034
4359
|
function findAll(re, text) {
|
|
@@ -4049,7 +4374,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4049
4374
|
seen.add(key);
|
|
4050
4375
|
const line = lineOf(file.content, topic);
|
|
4051
4376
|
out.push({
|
|
4052
|
-
infraId: (0,
|
|
4377
|
+
infraId: (0, import_types12.infraId)("kafka-topic", topic),
|
|
4053
4378
|
name: topic,
|
|
4054
4379
|
kind: "kafka-topic",
|
|
4055
4380
|
edgeType,
|
|
@@ -4058,7 +4383,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4058
4383
|
// tier (ADR-066).
|
|
4059
4384
|
confidenceKind: "verified-call-site",
|
|
4060
4385
|
evidence: {
|
|
4061
|
-
file:
|
|
4386
|
+
file: import_node_path23.default.relative(serviceDir, file.path),
|
|
4062
4387
|
line,
|
|
4063
4388
|
snippet: snippet(file.content, line)
|
|
4064
4389
|
}
|
|
@@ -4071,8 +4396,8 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4071
4396
|
|
|
4072
4397
|
// src/extract/calls/redis.ts
|
|
4073
4398
|
init_cjs_shims();
|
|
4074
|
-
var
|
|
4075
|
-
var
|
|
4399
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
4400
|
+
var import_types13 = require("@neat.is/types");
|
|
4076
4401
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
4077
4402
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
4078
4403
|
const out = [];
|
|
@@ -4085,7 +4410,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4085
4410
|
seen.add(host);
|
|
4086
4411
|
const line = lineOf(file.content, host);
|
|
4087
4412
|
out.push({
|
|
4088
|
-
infraId: (0,
|
|
4413
|
+
infraId: (0, import_types13.infraId)("redis", host),
|
|
4089
4414
|
name: host,
|
|
4090
4415
|
kind: "redis",
|
|
4091
4416
|
edgeType: "CALLS",
|
|
@@ -4094,7 +4419,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4094
4419
|
// support tier (ADR-066).
|
|
4095
4420
|
confidenceKind: "url-with-structural-support",
|
|
4096
4421
|
evidence: {
|
|
4097
|
-
file:
|
|
4422
|
+
file: import_node_path24.default.relative(serviceDir, file.path),
|
|
4098
4423
|
line,
|
|
4099
4424
|
snippet: snippet(file.content, line)
|
|
4100
4425
|
}
|
|
@@ -4105,8 +4430,8 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4105
4430
|
|
|
4106
4431
|
// src/extract/calls/aws.ts
|
|
4107
4432
|
init_cjs_shims();
|
|
4108
|
-
var
|
|
4109
|
-
var
|
|
4433
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
4434
|
+
var import_types14 = require("@neat.is/types");
|
|
4110
4435
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4111
4436
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4112
4437
|
function hasMarker(text, markers) {
|
|
@@ -4130,7 +4455,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4130
4455
|
seen.add(key);
|
|
4131
4456
|
const line = lineOf(file.content, name);
|
|
4132
4457
|
out.push({
|
|
4133
|
-
infraId: (0,
|
|
4458
|
+
infraId: (0, import_types14.infraId)(kind, name),
|
|
4134
4459
|
name,
|
|
4135
4460
|
kind,
|
|
4136
4461
|
edgeType: "CALLS",
|
|
@@ -4139,7 +4464,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4139
4464
|
// (ADR-066).
|
|
4140
4465
|
confidenceKind: "verified-call-site",
|
|
4141
4466
|
evidence: {
|
|
4142
|
-
file:
|
|
4467
|
+
file: import_node_path25.default.relative(serviceDir, file.path),
|
|
4143
4468
|
line,
|
|
4144
4469
|
snippet: snippet(file.content, line)
|
|
4145
4470
|
}
|
|
@@ -4164,8 +4489,8 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4164
4489
|
|
|
4165
4490
|
// src/extract/calls/grpc.ts
|
|
4166
4491
|
init_cjs_shims();
|
|
4167
|
-
var
|
|
4168
|
-
var
|
|
4492
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
4493
|
+
var import_types15 = require("@neat.is/types");
|
|
4169
4494
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
4170
4495
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
4171
4496
|
var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
|
|
@@ -4214,7 +4539,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4214
4539
|
const { kind } = classified;
|
|
4215
4540
|
const line = lineOf(file.content, m[0]);
|
|
4216
4541
|
out.push({
|
|
4217
|
-
infraId: (0,
|
|
4542
|
+
infraId: (0, import_types15.infraId)(kind, name),
|
|
4218
4543
|
name,
|
|
4219
4544
|
kind,
|
|
4220
4545
|
edgeType: "CALLS",
|
|
@@ -4223,7 +4548,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4223
4548
|
// tier (ADR-066).
|
|
4224
4549
|
confidenceKind: "verified-call-site",
|
|
4225
4550
|
evidence: {
|
|
4226
|
-
file:
|
|
4551
|
+
file: import_node_path26.default.relative(serviceDir, file.path),
|
|
4227
4552
|
line,
|
|
4228
4553
|
snippet: snippet(file.content, line)
|
|
4229
4554
|
}
|
|
@@ -4236,11 +4561,11 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4236
4561
|
function edgeTypeFromEndpoint(ep) {
|
|
4237
4562
|
switch (ep.edgeType) {
|
|
4238
4563
|
case "PUBLISHES_TO":
|
|
4239
|
-
return
|
|
4564
|
+
return import_types16.EdgeType.PUBLISHES_TO;
|
|
4240
4565
|
case "CONSUMES_FROM":
|
|
4241
|
-
return
|
|
4566
|
+
return import_types16.EdgeType.CONSUMES_FROM;
|
|
4242
4567
|
default:
|
|
4243
|
-
return
|
|
4568
|
+
return import_types16.EdgeType.CALLS;
|
|
4244
4569
|
}
|
|
4245
4570
|
}
|
|
4246
4571
|
function isAwsKind(kind) {
|
|
@@ -4267,7 +4592,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4267
4592
|
if (!graph.hasNode(ep.infraId)) {
|
|
4268
4593
|
const node = {
|
|
4269
4594
|
id: ep.infraId,
|
|
4270
|
-
type:
|
|
4595
|
+
type: import_types16.NodeType.InfraNode,
|
|
4271
4596
|
name: ep.name,
|
|
4272
4597
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
4273
4598
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -4279,7 +4604,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4279
4604
|
nodesAdded++;
|
|
4280
4605
|
}
|
|
4281
4606
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
4282
|
-
const confidence = (0,
|
|
4607
|
+
const confidence = (0, import_types16.confidenceForExtracted)(ep.confidenceKind);
|
|
4283
4608
|
const relFile = toPosix2(ep.evidence.file);
|
|
4284
4609
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
4285
4610
|
graph,
|
|
@@ -4289,7 +4614,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4289
4614
|
);
|
|
4290
4615
|
nodesAdded += n;
|
|
4291
4616
|
edgesAdded += e;
|
|
4292
|
-
if (!(0,
|
|
4617
|
+
if (!(0, import_types16.passesExtractedFloor)(confidence)) {
|
|
4293
4618
|
noteExtractedDropped({
|
|
4294
4619
|
source: fileNodeId,
|
|
4295
4620
|
target: ep.infraId,
|
|
@@ -4309,7 +4634,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4309
4634
|
source: fileNodeId,
|
|
4310
4635
|
target: ep.infraId,
|
|
4311
4636
|
type: edgeType,
|
|
4312
|
-
provenance:
|
|
4637
|
+
provenance: import_types16.Provenance.EXTRACTED,
|
|
4313
4638
|
confidence,
|
|
4314
4639
|
evidence: ep.evidence
|
|
4315
4640
|
};
|
|
@@ -4334,16 +4659,16 @@ init_cjs_shims();
|
|
|
4334
4659
|
|
|
4335
4660
|
// src/extract/infra/docker-compose.ts
|
|
4336
4661
|
init_cjs_shims();
|
|
4337
|
-
var
|
|
4338
|
-
var
|
|
4662
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
4663
|
+
var import_types18 = require("@neat.is/types");
|
|
4339
4664
|
|
|
4340
4665
|
// src/extract/infra/shared.ts
|
|
4341
4666
|
init_cjs_shims();
|
|
4342
|
-
var
|
|
4667
|
+
var import_types17 = require("@neat.is/types");
|
|
4343
4668
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
4344
4669
|
return {
|
|
4345
|
-
id: (0,
|
|
4346
|
-
type:
|
|
4670
|
+
id: (0, import_types17.infraId)(kind, name),
|
|
4671
|
+
type: import_types17.NodeType.InfraNode,
|
|
4347
4672
|
name,
|
|
4348
4673
|
provider,
|
|
4349
4674
|
kind,
|
|
@@ -4372,7 +4697,7 @@ function dependsOnList(value) {
|
|
|
4372
4697
|
}
|
|
4373
4698
|
function serviceNameToServiceNode(name, services) {
|
|
4374
4699
|
for (const s of services) {
|
|
4375
|
-
if (s.node.name === name ||
|
|
4700
|
+
if (s.node.name === name || import_node_path27.default.basename(s.dir) === name) return s.node.id;
|
|
4376
4701
|
}
|
|
4377
4702
|
return null;
|
|
4378
4703
|
}
|
|
@@ -4381,7 +4706,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4381
4706
|
let edgesAdded = 0;
|
|
4382
4707
|
let composePath = null;
|
|
4383
4708
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
4384
|
-
const abs =
|
|
4709
|
+
const abs = import_node_path27.default.join(scanPath, name);
|
|
4385
4710
|
if (await exists(abs)) {
|
|
4386
4711
|
composePath = abs;
|
|
4387
4712
|
break;
|
|
@@ -4394,13 +4719,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4394
4719
|
} catch (err) {
|
|
4395
4720
|
recordExtractionError(
|
|
4396
4721
|
"infra docker-compose",
|
|
4397
|
-
|
|
4722
|
+
import_node_path27.default.relative(scanPath, composePath),
|
|
4398
4723
|
err
|
|
4399
4724
|
);
|
|
4400
4725
|
return { nodesAdded, edgesAdded };
|
|
4401
4726
|
}
|
|
4402
4727
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
4403
|
-
const evidenceFile =
|
|
4728
|
+
const evidenceFile = import_node_path27.default.relative(scanPath, composePath).split(import_node_path27.default.sep).join("/");
|
|
4404
4729
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
4405
4730
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
4406
4731
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -4422,15 +4747,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4422
4747
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
4423
4748
|
const targetId = composeNameToNodeId.get(dep);
|
|
4424
4749
|
if (!targetId) continue;
|
|
4425
|
-
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId,
|
|
4750
|
+
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId, import_types18.EdgeType.DEPENDS_ON);
|
|
4426
4751
|
if (graph.hasEdge(edgeId)) continue;
|
|
4427
4752
|
const edge = {
|
|
4428
4753
|
id: edgeId,
|
|
4429
4754
|
source: sourceId,
|
|
4430
4755
|
target: targetId,
|
|
4431
|
-
type:
|
|
4432
|
-
provenance:
|
|
4433
|
-
confidence: (0,
|
|
4756
|
+
type: import_types18.EdgeType.DEPENDS_ON,
|
|
4757
|
+
provenance: import_types18.Provenance.EXTRACTED,
|
|
4758
|
+
confidence: (0, import_types18.confidenceForExtracted)("structural"),
|
|
4434
4759
|
evidence: { file: evidenceFile }
|
|
4435
4760
|
};
|
|
4436
4761
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4442,9 +4767,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4442
4767
|
|
|
4443
4768
|
// src/extract/infra/dockerfile.ts
|
|
4444
4769
|
init_cjs_shims();
|
|
4445
|
-
var
|
|
4446
|
-
var
|
|
4447
|
-
var
|
|
4770
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
4771
|
+
var import_node_fs15 = require("fs");
|
|
4772
|
+
var import_types19 = require("@neat.is/types");
|
|
4448
4773
|
function runtimeImage(content) {
|
|
4449
4774
|
const lines = content.split("\n");
|
|
4450
4775
|
let last = null;
|
|
@@ -4463,15 +4788,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4463
4788
|
let nodesAdded = 0;
|
|
4464
4789
|
let edgesAdded = 0;
|
|
4465
4790
|
for (const service of services) {
|
|
4466
|
-
const dockerfilePath =
|
|
4791
|
+
const dockerfilePath = import_node_path28.default.join(service.dir, "Dockerfile");
|
|
4467
4792
|
if (!await exists(dockerfilePath)) continue;
|
|
4468
4793
|
let content;
|
|
4469
4794
|
try {
|
|
4470
|
-
content = await
|
|
4795
|
+
content = await import_node_fs15.promises.readFile(dockerfilePath, "utf8");
|
|
4471
4796
|
} catch (err) {
|
|
4472
4797
|
recordExtractionError(
|
|
4473
4798
|
"infra dockerfile",
|
|
4474
|
-
|
|
4799
|
+
import_node_path28.default.relative(scanPath, dockerfilePath),
|
|
4475
4800
|
err
|
|
4476
4801
|
);
|
|
4477
4802
|
continue;
|
|
@@ -4483,7 +4808,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4483
4808
|
graph.addNode(node.id, node);
|
|
4484
4809
|
nodesAdded++;
|
|
4485
4810
|
}
|
|
4486
|
-
const relDockerfile = toPosix2(
|
|
4811
|
+
const relDockerfile = toPosix2(import_node_path28.default.relative(service.dir, dockerfilePath));
|
|
4487
4812
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4488
4813
|
graph,
|
|
4489
4814
|
service.pkg.name,
|
|
@@ -4492,17 +4817,17 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4492
4817
|
);
|
|
4493
4818
|
nodesAdded += fn;
|
|
4494
4819
|
edgesAdded += fe;
|
|
4495
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
4820
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types19.EdgeType.RUNS_ON);
|
|
4496
4821
|
if (!graph.hasEdge(edgeId)) {
|
|
4497
4822
|
const edge = {
|
|
4498
4823
|
id: edgeId,
|
|
4499
4824
|
source: fileNodeId,
|
|
4500
4825
|
target: node.id,
|
|
4501
|
-
type:
|
|
4502
|
-
provenance:
|
|
4503
|
-
confidence: (0,
|
|
4826
|
+
type: import_types19.EdgeType.RUNS_ON,
|
|
4827
|
+
provenance: import_types19.Provenance.EXTRACTED,
|
|
4828
|
+
confidence: (0, import_types19.confidenceForExtracted)("structural"),
|
|
4504
4829
|
evidence: {
|
|
4505
|
-
file: toPosix2(
|
|
4830
|
+
file: toPosix2(import_node_path28.default.relative(scanPath, dockerfilePath))
|
|
4506
4831
|
}
|
|
4507
4832
|
};
|
|
4508
4833
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4514,21 +4839,21 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4514
4839
|
|
|
4515
4840
|
// src/extract/infra/terraform.ts
|
|
4516
4841
|
init_cjs_shims();
|
|
4517
|
-
var
|
|
4518
|
-
var
|
|
4842
|
+
var import_node_fs16 = require("fs");
|
|
4843
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
4519
4844
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
4520
4845
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
4521
4846
|
if (depth > max) return [];
|
|
4522
4847
|
const out = [];
|
|
4523
|
-
const entries = await
|
|
4848
|
+
const entries = await import_node_fs16.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4524
4849
|
for (const entry of entries) {
|
|
4525
4850
|
if (entry.isDirectory()) {
|
|
4526
4851
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
4527
|
-
const child =
|
|
4852
|
+
const child = import_node_path29.default.join(start, entry.name);
|
|
4528
4853
|
if (await isPythonVenvDir(child)) continue;
|
|
4529
4854
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
4530
4855
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
4531
|
-
out.push(
|
|
4856
|
+
out.push(import_node_path29.default.join(start, entry.name));
|
|
4532
4857
|
}
|
|
4533
4858
|
}
|
|
4534
4859
|
return out;
|
|
@@ -4537,7 +4862,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
4537
4862
|
let nodesAdded = 0;
|
|
4538
4863
|
const files = await walkTfFiles(scanPath);
|
|
4539
4864
|
for (const file of files) {
|
|
4540
|
-
const content = await
|
|
4865
|
+
const content = await import_node_fs16.promises.readFile(file, "utf8");
|
|
4541
4866
|
RESOURCE_RE.lastIndex = 0;
|
|
4542
4867
|
let m;
|
|
4543
4868
|
while ((m = RESOURCE_RE.exec(content)) !== null) {
|
|
@@ -4555,8 +4880,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
4555
4880
|
|
|
4556
4881
|
// src/extract/infra/k8s.ts
|
|
4557
4882
|
init_cjs_shims();
|
|
4558
|
-
var
|
|
4559
|
-
var
|
|
4883
|
+
var import_node_fs17 = require("fs");
|
|
4884
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
4560
4885
|
var import_yaml3 = require("yaml");
|
|
4561
4886
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
4562
4887
|
Service: "k8s-service",
|
|
@@ -4570,15 +4895,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
4570
4895
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
4571
4896
|
if (depth > max) return [];
|
|
4572
4897
|
const out = [];
|
|
4573
|
-
const entries = await
|
|
4898
|
+
const entries = await import_node_fs17.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4574
4899
|
for (const entry of entries) {
|
|
4575
4900
|
if (entry.isDirectory()) {
|
|
4576
4901
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
4577
|
-
const child =
|
|
4902
|
+
const child = import_node_path30.default.join(start, entry.name);
|
|
4578
4903
|
if (await isPythonVenvDir(child)) continue;
|
|
4579
4904
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
4580
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
4581
|
-
out.push(
|
|
4905
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path30.default.extname(entry.name))) {
|
|
4906
|
+
out.push(import_node_path30.default.join(start, entry.name));
|
|
4582
4907
|
}
|
|
4583
4908
|
}
|
|
4584
4909
|
return out;
|
|
@@ -4587,7 +4912,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
4587
4912
|
let nodesAdded = 0;
|
|
4588
4913
|
const files = await walkYamlFiles2(scanPath);
|
|
4589
4914
|
for (const file of files) {
|
|
4590
|
-
const content = await
|
|
4915
|
+
const content = await import_node_fs17.promises.readFile(file, "utf8");
|
|
4591
4916
|
let docs;
|
|
4592
4917
|
try {
|
|
4593
4918
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -4622,17 +4947,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
4622
4947
|
}
|
|
4623
4948
|
|
|
4624
4949
|
// src/extract/index.ts
|
|
4625
|
-
var
|
|
4950
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
4626
4951
|
|
|
4627
4952
|
// src/extract/retire.ts
|
|
4628
4953
|
init_cjs_shims();
|
|
4629
|
-
var
|
|
4630
|
-
var
|
|
4631
|
-
var
|
|
4954
|
+
var import_node_fs18 = require("fs");
|
|
4955
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
4956
|
+
var import_types20 = require("@neat.is/types");
|
|
4632
4957
|
function dropOrphanedFileNodes(graph) {
|
|
4633
4958
|
const orphans = [];
|
|
4634
4959
|
graph.forEachNode((id, attrs) => {
|
|
4635
|
-
if (attrs.type !==
|
|
4960
|
+
if (attrs.type !== import_types20.NodeType.FileNode) return;
|
|
4636
4961
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
4637
4962
|
orphans.push(id);
|
|
4638
4963
|
}
|
|
@@ -4645,14 +4970,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
4645
4970
|
const bases = [scanPath, ...serviceDirs];
|
|
4646
4971
|
graph.forEachEdge((id, attrs) => {
|
|
4647
4972
|
const edge = attrs;
|
|
4648
|
-
if (edge.provenance !==
|
|
4973
|
+
if (edge.provenance !== import_types20.Provenance.EXTRACTED) return;
|
|
4649
4974
|
const evidenceFile = edge.evidence?.file;
|
|
4650
4975
|
if (!evidenceFile) return;
|
|
4651
|
-
if (
|
|
4652
|
-
if (!(0,
|
|
4976
|
+
if (import_node_path31.default.isAbsolute(evidenceFile)) {
|
|
4977
|
+
if (!(0, import_node_fs18.existsSync)(evidenceFile)) toDrop.push(id);
|
|
4653
4978
|
return;
|
|
4654
4979
|
}
|
|
4655
|
-
const found = bases.some((base) => (0,
|
|
4980
|
+
const found = bases.some((base) => (0, import_node_fs18.existsSync)(import_node_path31.default.join(base, evidenceFile)));
|
|
4656
4981
|
if (!found) toDrop.push(id);
|
|
4657
4982
|
});
|
|
4658
4983
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -4667,6 +4992,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4667
4992
|
const services = await discoverServices(scanPath);
|
|
4668
4993
|
const phase1Nodes = addServiceNodes(graph, services);
|
|
4669
4994
|
await addServiceAliases(graph, scanPath, services);
|
|
4995
|
+
const fileEnum = await addFiles(graph, services);
|
|
4996
|
+
const importGraph = await addImports(graph, services);
|
|
4670
4997
|
const phase2 = await addDatabasesAndCompat(graph, services, scanPath);
|
|
4671
4998
|
const phase3 = await addConfigNodes(graph, services, scanPath);
|
|
4672
4999
|
const phase4 = await addCallEdges(graph, services);
|
|
@@ -4690,7 +5017,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4690
5017
|
}
|
|
4691
5018
|
const droppedEntries = drainDroppedExtracted();
|
|
4692
5019
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
4693
|
-
const rejectedPath =
|
|
5020
|
+
const rejectedPath = import_node_path32.default.join(import_node_path32.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
4694
5021
|
try {
|
|
4695
5022
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
4696
5023
|
} catch (err) {
|
|
@@ -4700,8 +5027,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4700
5027
|
}
|
|
4701
5028
|
}
|
|
4702
5029
|
const result = {
|
|
4703
|
-
nodesAdded: phase1Nodes + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
|
|
4704
|
-
edgesAdded: phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
|
|
5030
|
+
nodesAdded: phase1Nodes + fileEnum.nodesAdded + importGraph.nodesAdded + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
|
|
5031
|
+
edgesAdded: fileEnum.edgesAdded + importGraph.edgesAdded + phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
|
|
4705
5032
|
frontiersPromoted,
|
|
4706
5033
|
extractionErrors: errorEntries.length,
|
|
4707
5034
|
errorEntries,
|
|
@@ -4724,9 +5051,9 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4724
5051
|
|
|
4725
5052
|
// src/persist.ts
|
|
4726
5053
|
init_cjs_shims();
|
|
4727
|
-
var
|
|
4728
|
-
var
|
|
4729
|
-
var
|
|
5054
|
+
var import_node_fs19 = require("fs");
|
|
5055
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
5056
|
+
var import_types21 = require("@neat.is/types");
|
|
4730
5057
|
var SCHEMA_VERSION = 4;
|
|
4731
5058
|
function migrateV1ToV2(payload) {
|
|
4732
5059
|
const nodes = payload.graph.nodes;
|
|
@@ -4748,12 +5075,12 @@ function migrateV2ToV3(payload) {
|
|
|
4748
5075
|
for (const edge of edges) {
|
|
4749
5076
|
const attrs = edge.attributes;
|
|
4750
5077
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
4751
|
-
attrs.provenance =
|
|
5078
|
+
attrs.provenance = import_types21.Provenance.OBSERVED;
|
|
4752
5079
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
4753
5080
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
4754
5081
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
4755
5082
|
if (type && source && target) {
|
|
4756
|
-
const newId = (0,
|
|
5083
|
+
const newId = (0, import_types21.observedEdgeId)(source, target, type);
|
|
4757
5084
|
attrs.id = newId;
|
|
4758
5085
|
if (edge.key) edge.key = newId;
|
|
4759
5086
|
}
|
|
@@ -4762,7 +5089,7 @@ function migrateV2ToV3(payload) {
|
|
|
4762
5089
|
return { ...payload, schemaVersion: 3 };
|
|
4763
5090
|
}
|
|
4764
5091
|
async function ensureDir(filePath) {
|
|
4765
|
-
await
|
|
5092
|
+
await import_node_fs19.promises.mkdir(import_node_path33.default.dirname(filePath), { recursive: true });
|
|
4766
5093
|
}
|
|
4767
5094
|
async function saveGraphToDisk(graph, outPath) {
|
|
4768
5095
|
await ensureDir(outPath);
|
|
@@ -4772,13 +5099,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
4772
5099
|
graph: graph.export()
|
|
4773
5100
|
};
|
|
4774
5101
|
const tmp = `${outPath}.tmp`;
|
|
4775
|
-
await
|
|
4776
|
-
await
|
|
5102
|
+
await import_node_fs19.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
5103
|
+
await import_node_fs19.promises.rename(tmp, outPath);
|
|
4777
5104
|
}
|
|
4778
5105
|
async function loadGraphFromDisk(graph, outPath) {
|
|
4779
5106
|
let raw;
|
|
4780
5107
|
try {
|
|
4781
|
-
raw = await
|
|
5108
|
+
raw = await import_node_fs19.promises.readFile(outPath, "utf8");
|
|
4782
5109
|
} catch (err) {
|
|
4783
5110
|
if (err.code === "ENOENT") return;
|
|
4784
5111
|
throw err;
|
|
@@ -4839,19 +5166,19 @@ function startPersistLoop(graph, outPath, intervalMs = 6e4) {
|
|
|
4839
5166
|
init_cjs_shims();
|
|
4840
5167
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
4841
5168
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
4842
|
-
var
|
|
5169
|
+
var import_types24 = require("@neat.is/types");
|
|
4843
5170
|
|
|
4844
5171
|
// src/extend/index.ts
|
|
4845
5172
|
init_cjs_shims();
|
|
4846
|
-
var
|
|
4847
|
-
var
|
|
5173
|
+
var import_node_fs21 = require("fs");
|
|
5174
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
4848
5175
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
4849
5176
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
4850
5177
|
|
|
4851
5178
|
// src/installers/package-manager.ts
|
|
4852
5179
|
init_cjs_shims();
|
|
4853
|
-
var
|
|
4854
|
-
var
|
|
5180
|
+
var import_node_fs20 = require("fs");
|
|
5181
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
4855
5182
|
var import_node_child_process = require("child_process");
|
|
4856
5183
|
var LOCKFILE_PRIORITY = [
|
|
4857
5184
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -4866,29 +5193,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
4866
5193
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
4867
5194
|
async function exists2(p) {
|
|
4868
5195
|
try {
|
|
4869
|
-
await
|
|
5196
|
+
await import_node_fs20.promises.access(p);
|
|
4870
5197
|
return true;
|
|
4871
5198
|
} catch {
|
|
4872
5199
|
return false;
|
|
4873
5200
|
}
|
|
4874
5201
|
}
|
|
4875
5202
|
async function detectPackageManager(serviceDir) {
|
|
4876
|
-
let dir =
|
|
5203
|
+
let dir = import_node_path34.default.resolve(serviceDir);
|
|
4877
5204
|
const stops = /* @__PURE__ */ new Set();
|
|
4878
5205
|
for (let i = 0; i < 64; i++) {
|
|
4879
5206
|
if (stops.has(dir)) break;
|
|
4880
5207
|
stops.add(dir);
|
|
4881
5208
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
4882
|
-
const lockPath =
|
|
5209
|
+
const lockPath = import_node_path34.default.join(dir, candidate.lockfile);
|
|
4883
5210
|
if (await exists2(lockPath)) {
|
|
4884
5211
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
4885
5212
|
}
|
|
4886
5213
|
}
|
|
4887
|
-
const parent =
|
|
5214
|
+
const parent = import_node_path34.default.dirname(dir);
|
|
4888
5215
|
if (parent === dir) break;
|
|
4889
5216
|
dir = parent;
|
|
4890
5217
|
}
|
|
4891
|
-
return { pm: "npm", cwd:
|
|
5218
|
+
return { pm: "npm", cwd: import_node_path34.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
4892
5219
|
}
|
|
4893
5220
|
async function runPackageManagerInstall(cmd) {
|
|
4894
5221
|
return new Promise((resolve) => {
|
|
@@ -4928,32 +5255,32 @@ ${err.message}`
|
|
|
4928
5255
|
}
|
|
4929
5256
|
|
|
4930
5257
|
// src/extend/index.ts
|
|
4931
|
-
async function
|
|
5258
|
+
async function fileExists2(p) {
|
|
4932
5259
|
try {
|
|
4933
|
-
await
|
|
5260
|
+
await import_node_fs21.promises.access(p);
|
|
4934
5261
|
return true;
|
|
4935
5262
|
} catch {
|
|
4936
5263
|
return false;
|
|
4937
5264
|
}
|
|
4938
5265
|
}
|
|
4939
5266
|
async function readPackageJson(scanPath) {
|
|
4940
|
-
const pkgPath =
|
|
4941
|
-
const raw = await
|
|
5267
|
+
const pkgPath = import_node_path35.default.join(scanPath, "package.json");
|
|
5268
|
+
const raw = await import_node_fs21.promises.readFile(pkgPath, "utf8");
|
|
4942
5269
|
return JSON.parse(raw);
|
|
4943
5270
|
}
|
|
4944
5271
|
async function findHookFiles(scanPath) {
|
|
4945
|
-
const entries = await
|
|
5272
|
+
const entries = await import_node_fs21.promises.readdir(scanPath);
|
|
4946
5273
|
return entries.filter(
|
|
4947
5274
|
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
4948
5275
|
).sort();
|
|
4949
5276
|
}
|
|
4950
5277
|
function extendLogPath() {
|
|
4951
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
5278
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path35.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
4952
5279
|
}
|
|
4953
5280
|
async function appendExtendLog(entry) {
|
|
4954
5281
|
const logPath = extendLogPath();
|
|
4955
|
-
await
|
|
4956
|
-
await
|
|
5282
|
+
await import_node_fs21.promises.mkdir(import_node_path35.default.dirname(logPath), { recursive: true });
|
|
5283
|
+
await import_node_fs21.promises.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
4957
5284
|
}
|
|
4958
5285
|
function splicedContent(fileContent, snippet2) {
|
|
4959
5286
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -5011,7 +5338,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
5011
5338
|
}
|
|
5012
5339
|
async function describeProjectInstrumentation(ctx) {
|
|
5013
5340
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5014
|
-
const envNeat = await
|
|
5341
|
+
const envNeat = await fileExists2(import_node_path35.default.join(ctx.scanPath, ".env.neat"));
|
|
5015
5342
|
const registryInstrPackages = new Set(
|
|
5016
5343
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
5017
5344
|
);
|
|
@@ -5033,31 +5360,31 @@ async function applyExtension(ctx, args, options) {
|
|
|
5033
5360
|
);
|
|
5034
5361
|
}
|
|
5035
5362
|
for (const file of hookFiles) {
|
|
5036
|
-
const content = await
|
|
5363
|
+
const content = await import_node_fs21.promises.readFile(import_node_path35.default.join(ctx.scanPath, file), "utf8");
|
|
5037
5364
|
if (content.includes(args.registration_snippet)) {
|
|
5038
5365
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
5039
5366
|
}
|
|
5040
5367
|
}
|
|
5041
5368
|
const primaryFile = hookFiles[0];
|
|
5042
|
-
const primaryPath =
|
|
5369
|
+
const primaryPath = import_node_path35.default.join(ctx.scanPath, primaryFile);
|
|
5043
5370
|
const filesTouched = [];
|
|
5044
5371
|
const depsAdded = [];
|
|
5045
|
-
const pkgPath =
|
|
5372
|
+
const pkgPath = import_node_path35.default.join(ctx.scanPath, "package.json");
|
|
5046
5373
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
5047
5374
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
5048
5375
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
5049
|
-
await
|
|
5376
|
+
await import_node_fs21.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5050
5377
|
filesTouched.push("package.json");
|
|
5051
5378
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
5052
5379
|
}
|
|
5053
|
-
const hookContent = await
|
|
5380
|
+
const hookContent = await import_node_fs21.promises.readFile(primaryPath, "utf8");
|
|
5054
5381
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5055
5382
|
if (!patched) {
|
|
5056
5383
|
throw new Error(
|
|
5057
5384
|
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
5058
5385
|
);
|
|
5059
5386
|
}
|
|
5060
|
-
await
|
|
5387
|
+
await import_node_fs21.promises.writeFile(primaryPath, patched, "utf8");
|
|
5061
5388
|
filesTouched.push(primaryFile);
|
|
5062
5389
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
5063
5390
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -5088,7 +5415,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
5088
5415
|
};
|
|
5089
5416
|
}
|
|
5090
5417
|
for (const file of hookFiles) {
|
|
5091
|
-
const content = await
|
|
5418
|
+
const content = await import_node_fs21.promises.readFile(import_node_path35.default.join(ctx.scanPath, file), "utf8");
|
|
5092
5419
|
if (content.includes(args.registration_snippet)) {
|
|
5093
5420
|
return {
|
|
5094
5421
|
library: args.library,
|
|
@@ -5110,7 +5437,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
5110
5437
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
5111
5438
|
filesTouched.push("package.json");
|
|
5112
5439
|
}
|
|
5113
|
-
const hookContent = await
|
|
5440
|
+
const hookContent = await import_node_fs21.promises.readFile(import_node_path35.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
5114
5441
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
5115
5442
|
if (patched) {
|
|
5116
5443
|
filesTouched.push(primaryFile);
|
|
@@ -5122,31 +5449,31 @@ async function dryRunExtension(ctx, args) {
|
|
|
5122
5449
|
}
|
|
5123
5450
|
async function rollbackExtension(ctx, args) {
|
|
5124
5451
|
const logPath = extendLogPath();
|
|
5125
|
-
if (!await
|
|
5452
|
+
if (!await fileExists2(logPath)) {
|
|
5126
5453
|
return { undone: false, message: "no apply found for library" };
|
|
5127
5454
|
}
|
|
5128
|
-
const raw = await
|
|
5455
|
+
const raw = await import_node_fs21.promises.readFile(logPath, "utf8");
|
|
5129
5456
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
5130
5457
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
5131
5458
|
if (!match) {
|
|
5132
5459
|
return { undone: false, message: "no apply found for library" };
|
|
5133
5460
|
}
|
|
5134
|
-
const pkgPath =
|
|
5135
|
-
if (await
|
|
5461
|
+
const pkgPath = import_node_path35.default.join(ctx.scanPath, "package.json");
|
|
5462
|
+
if (await fileExists2(pkgPath)) {
|
|
5136
5463
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
5137
5464
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
5138
5465
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
5139
5466
|
pkg.dependencies = rest;
|
|
5140
|
-
await
|
|
5467
|
+
await import_node_fs21.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
5141
5468
|
}
|
|
5142
5469
|
}
|
|
5143
5470
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
5144
5471
|
for (const file of hookFiles) {
|
|
5145
|
-
const filePath =
|
|
5146
|
-
const content = await
|
|
5472
|
+
const filePath = import_node_path35.default.join(ctx.scanPath, file);
|
|
5473
|
+
const content = await import_node_fs21.promises.readFile(filePath, "utf8");
|
|
5147
5474
|
if (content.includes(match.registration_snippet)) {
|
|
5148
5475
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
5149
|
-
await
|
|
5476
|
+
await import_node_fs21.promises.writeFile(filePath, filtered, "utf8");
|
|
5150
5477
|
break;
|
|
5151
5478
|
}
|
|
5152
5479
|
}
|
|
@@ -5158,7 +5485,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
5158
5485
|
|
|
5159
5486
|
// src/divergences.ts
|
|
5160
5487
|
init_cjs_shims();
|
|
5161
|
-
var
|
|
5488
|
+
var import_types22 = require("@neat.is/types");
|
|
5162
5489
|
function bucketKey(source, target, type) {
|
|
5163
5490
|
return `${type}|${source}|${target}`;
|
|
5164
5491
|
}
|
|
@@ -5166,22 +5493,22 @@ function bucketEdges(graph) {
|
|
|
5166
5493
|
const buckets = /* @__PURE__ */ new Map();
|
|
5167
5494
|
graph.forEachEdge((id, attrs) => {
|
|
5168
5495
|
const e = attrs;
|
|
5169
|
-
const parsed = (0,
|
|
5496
|
+
const parsed = (0, import_types22.parseEdgeId)(id);
|
|
5170
5497
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
5171
5498
|
const key = bucketKey(e.source, e.target, e.type);
|
|
5172
5499
|
const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
|
|
5173
5500
|
switch (provenance) {
|
|
5174
|
-
case
|
|
5501
|
+
case import_types22.Provenance.EXTRACTED:
|
|
5175
5502
|
cur.extracted = e;
|
|
5176
5503
|
break;
|
|
5177
|
-
case
|
|
5504
|
+
case import_types22.Provenance.OBSERVED:
|
|
5178
5505
|
cur.observed = e;
|
|
5179
5506
|
break;
|
|
5180
|
-
case
|
|
5507
|
+
case import_types22.Provenance.INFERRED:
|
|
5181
5508
|
cur.inferred = e;
|
|
5182
5509
|
break;
|
|
5183
5510
|
default:
|
|
5184
|
-
if (e.provenance ===
|
|
5511
|
+
if (e.provenance === import_types22.Provenance.STALE) cur.stale = e;
|
|
5185
5512
|
}
|
|
5186
5513
|
buckets.set(key, cur);
|
|
5187
5514
|
});
|
|
@@ -5190,7 +5517,7 @@ function bucketEdges(graph) {
|
|
|
5190
5517
|
function nodeIsFrontier(graph, nodeId) {
|
|
5191
5518
|
if (!graph.hasNode(nodeId)) return false;
|
|
5192
5519
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
5193
|
-
return attrs.type ===
|
|
5520
|
+
return attrs.type === import_types22.NodeType.FrontierNode;
|
|
5194
5521
|
}
|
|
5195
5522
|
function clampConfidence(n) {
|
|
5196
5523
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -5211,7 +5538,7 @@ function gradedConfidence(edge) {
|
|
|
5211
5538
|
}
|
|
5212
5539
|
function detectMissingDivergences(graph, bucket) {
|
|
5213
5540
|
const out = [];
|
|
5214
|
-
if (bucket.type ===
|
|
5541
|
+
if (bucket.type === import_types22.EdgeType.CONTAINS) return out;
|
|
5215
5542
|
if (bucket.extracted && !bucket.observed) {
|
|
5216
5543
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
5217
5544
|
out.push({
|
|
@@ -5252,7 +5579,7 @@ function declaredHostFor(svc) {
|
|
|
5252
5579
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
5253
5580
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
5254
5581
|
const e = graph.getEdgeAttributes(edgeId);
|
|
5255
|
-
if (e.type ===
|
|
5582
|
+
if (e.type === import_types22.EdgeType.CONFIGURED_BY && e.provenance === import_types22.Provenance.EXTRACTED) {
|
|
5256
5583
|
return true;
|
|
5257
5584
|
}
|
|
5258
5585
|
}
|
|
@@ -5265,10 +5592,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
5265
5592
|
const out = [];
|
|
5266
5593
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
5267
5594
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
5268
|
-
if (edge.type !==
|
|
5269
|
-
if (edge.provenance !==
|
|
5595
|
+
if (edge.type !== import_types22.EdgeType.CONNECTS_TO) continue;
|
|
5596
|
+
if (edge.provenance !== import_types22.Provenance.OBSERVED) continue;
|
|
5270
5597
|
const target = graph.getNodeAttributes(edge.target);
|
|
5271
|
-
if (target.type !==
|
|
5598
|
+
if (target.type !== import_types22.NodeType.DatabaseNode) continue;
|
|
5272
5599
|
const observedHost = target.host?.trim();
|
|
5273
5600
|
if (!observedHost) continue;
|
|
5274
5601
|
if (observedHost === declaredHost) continue;
|
|
@@ -5290,10 +5617,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
5290
5617
|
const deps = svc.dependencies ?? {};
|
|
5291
5618
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
5292
5619
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
5293
|
-
if (edge.type !==
|
|
5294
|
-
if (edge.provenance !==
|
|
5620
|
+
if (edge.type !== import_types22.EdgeType.CONNECTS_TO) continue;
|
|
5621
|
+
if (edge.provenance !== import_types22.Provenance.OBSERVED) continue;
|
|
5295
5622
|
const target = graph.getNodeAttributes(edge.target);
|
|
5296
|
-
if (target.type !==
|
|
5623
|
+
if (target.type !== import_types22.NodeType.DatabaseNode) continue;
|
|
5297
5624
|
for (const pair of compatPairs()) {
|
|
5298
5625
|
if (pair.engine !== target.engine) continue;
|
|
5299
5626
|
const declared = deps[pair.driver];
|
|
@@ -5354,7 +5681,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
5354
5681
|
}
|
|
5355
5682
|
graph.forEachNode((nodeId, attrs) => {
|
|
5356
5683
|
const n = attrs;
|
|
5357
|
-
if (n.type !==
|
|
5684
|
+
if (n.type !== import_types22.NodeType.ServiceNode) return;
|
|
5358
5685
|
const svc = n;
|
|
5359
5686
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
5360
5687
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -5387,7 +5714,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
5387
5714
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
5388
5715
|
return a.target.localeCompare(b.target);
|
|
5389
5716
|
});
|
|
5390
|
-
return
|
|
5717
|
+
return import_types22.DivergenceResultSchema.parse({
|
|
5391
5718
|
divergences: filtered,
|
|
5392
5719
|
totalAffected: filtered.length,
|
|
5393
5720
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -5396,7 +5723,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
5396
5723
|
|
|
5397
5724
|
// src/diff.ts
|
|
5398
5725
|
init_cjs_shims();
|
|
5399
|
-
var
|
|
5726
|
+
var import_node_fs22 = require("fs");
|
|
5400
5727
|
async function loadSnapshotForDiff(target) {
|
|
5401
5728
|
if (/^https?:\/\//i.test(target)) {
|
|
5402
5729
|
const res = await fetch(target);
|
|
@@ -5405,7 +5732,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
5405
5732
|
}
|
|
5406
5733
|
return await res.json();
|
|
5407
5734
|
}
|
|
5408
|
-
const raw = await
|
|
5735
|
+
const raw = await import_node_fs22.promises.readFile(target, "utf8");
|
|
5409
5736
|
return JSON.parse(raw);
|
|
5410
5737
|
}
|
|
5411
5738
|
function indexEntries(entries) {
|
|
@@ -5473,23 +5800,23 @@ function canonicalJson(value) {
|
|
|
5473
5800
|
|
|
5474
5801
|
// src/projects.ts
|
|
5475
5802
|
init_cjs_shims();
|
|
5476
|
-
var
|
|
5803
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
5477
5804
|
function pathsForProject(project, baseDir) {
|
|
5478
5805
|
if (project === DEFAULT_PROJECT) {
|
|
5479
5806
|
return {
|
|
5480
|
-
snapshotPath:
|
|
5481
|
-
errorsPath:
|
|
5482
|
-
staleEventsPath:
|
|
5483
|
-
embeddingsCachePath:
|
|
5484
|
-
policyViolationsPath:
|
|
5807
|
+
snapshotPath: import_node_path36.default.join(baseDir, "graph.json"),
|
|
5808
|
+
errorsPath: import_node_path36.default.join(baseDir, "errors.ndjson"),
|
|
5809
|
+
staleEventsPath: import_node_path36.default.join(baseDir, "stale-events.ndjson"),
|
|
5810
|
+
embeddingsCachePath: import_node_path36.default.join(baseDir, "embeddings.json"),
|
|
5811
|
+
policyViolationsPath: import_node_path36.default.join(baseDir, "policy-violations.ndjson")
|
|
5485
5812
|
};
|
|
5486
5813
|
}
|
|
5487
5814
|
return {
|
|
5488
|
-
snapshotPath:
|
|
5489
|
-
errorsPath:
|
|
5490
|
-
staleEventsPath:
|
|
5491
|
-
embeddingsCachePath:
|
|
5492
|
-
policyViolationsPath:
|
|
5815
|
+
snapshotPath: import_node_path36.default.join(baseDir, `${project}.json`),
|
|
5816
|
+
errorsPath: import_node_path36.default.join(baseDir, `errors.${project}.ndjson`),
|
|
5817
|
+
staleEventsPath: import_node_path36.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
5818
|
+
embeddingsCachePath: import_node_path36.default.join(baseDir, `embeddings.${project}.json`),
|
|
5819
|
+
policyViolationsPath: import_node_path36.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
5493
5820
|
};
|
|
5494
5821
|
}
|
|
5495
5822
|
var Projects = class {
|
|
@@ -5525,25 +5852,25 @@ var Projects = class {
|
|
|
5525
5852
|
|
|
5526
5853
|
// src/registry.ts
|
|
5527
5854
|
init_cjs_shims();
|
|
5528
|
-
var
|
|
5855
|
+
var import_node_fs23 = require("fs");
|
|
5529
5856
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
5530
|
-
var
|
|
5531
|
-
var
|
|
5857
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
5858
|
+
var import_types23 = require("@neat.is/types");
|
|
5532
5859
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
5533
5860
|
var LOCK_RETRY_MS = 50;
|
|
5534
5861
|
function neatHome() {
|
|
5535
5862
|
const override = process.env.NEAT_HOME;
|
|
5536
|
-
if (override && override.length > 0) return
|
|
5537
|
-
return
|
|
5863
|
+
if (override && override.length > 0) return import_node_path37.default.resolve(override);
|
|
5864
|
+
return import_node_path37.default.join(import_node_os3.default.homedir(), ".neat");
|
|
5538
5865
|
}
|
|
5539
5866
|
function registryPath() {
|
|
5540
|
-
return
|
|
5867
|
+
return import_node_path37.default.join(neatHome(), "projects.json");
|
|
5541
5868
|
}
|
|
5542
5869
|
function registryLockPath() {
|
|
5543
|
-
return
|
|
5870
|
+
return import_node_path37.default.join(neatHome(), "projects.json.lock");
|
|
5544
5871
|
}
|
|
5545
5872
|
function daemonPidPath() {
|
|
5546
|
-
return
|
|
5873
|
+
return import_node_path37.default.join(neatHome(), "neatd.pid");
|
|
5547
5874
|
}
|
|
5548
5875
|
function isPidAliveDefault(pid) {
|
|
5549
5876
|
try {
|
|
@@ -5555,7 +5882,7 @@ function isPidAliveDefault(pid) {
|
|
|
5555
5882
|
}
|
|
5556
5883
|
async function readPidFile(file) {
|
|
5557
5884
|
try {
|
|
5558
|
-
const raw = await
|
|
5885
|
+
const raw = await import_node_fs23.promises.readFile(file, "utf8");
|
|
5559
5886
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
5560
5887
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
5561
5888
|
} catch {
|
|
@@ -5603,32 +5930,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
5603
5930
|
}
|
|
5604
5931
|
}
|
|
5605
5932
|
async function normalizeProjectPath(input) {
|
|
5606
|
-
const resolved =
|
|
5933
|
+
const resolved = import_node_path37.default.resolve(input);
|
|
5607
5934
|
try {
|
|
5608
|
-
return await
|
|
5935
|
+
return await import_node_fs23.promises.realpath(resolved);
|
|
5609
5936
|
} catch {
|
|
5610
5937
|
return resolved;
|
|
5611
5938
|
}
|
|
5612
5939
|
}
|
|
5613
5940
|
async function writeAtomically(target, contents) {
|
|
5614
|
-
await
|
|
5941
|
+
await import_node_fs23.promises.mkdir(import_node_path37.default.dirname(target), { recursive: true });
|
|
5615
5942
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
5616
|
-
const fd = await
|
|
5943
|
+
const fd = await import_node_fs23.promises.open(tmp, "w");
|
|
5617
5944
|
try {
|
|
5618
5945
|
await fd.writeFile(contents, "utf8");
|
|
5619
5946
|
await fd.sync();
|
|
5620
5947
|
} finally {
|
|
5621
5948
|
await fd.close();
|
|
5622
5949
|
}
|
|
5623
|
-
await
|
|
5950
|
+
await import_node_fs23.promises.rename(tmp, target);
|
|
5624
5951
|
}
|
|
5625
5952
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
5626
5953
|
const deadline = Date.now() + timeoutMs;
|
|
5627
|
-
await
|
|
5954
|
+
await import_node_fs23.promises.mkdir(import_node_path37.default.dirname(lockPath), { recursive: true });
|
|
5628
5955
|
let probedHolder = false;
|
|
5629
5956
|
while (true) {
|
|
5630
5957
|
try {
|
|
5631
|
-
const fd = await
|
|
5958
|
+
const fd = await import_node_fs23.promises.open(lockPath, "wx");
|
|
5632
5959
|
try {
|
|
5633
5960
|
await fd.writeFile(`${process.pid}
|
|
5634
5961
|
`, "utf8");
|
|
@@ -5653,7 +5980,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
5653
5980
|
}
|
|
5654
5981
|
}
|
|
5655
5982
|
async function releaseLock(lockPath) {
|
|
5656
|
-
await
|
|
5983
|
+
await import_node_fs23.promises.unlink(lockPath).catch(() => {
|
|
5657
5984
|
});
|
|
5658
5985
|
}
|
|
5659
5986
|
async function withLock(fn) {
|
|
@@ -5669,7 +5996,7 @@ async function readRegistry() {
|
|
|
5669
5996
|
const file = registryPath();
|
|
5670
5997
|
let raw;
|
|
5671
5998
|
try {
|
|
5672
|
-
raw = await
|
|
5999
|
+
raw = await import_node_fs23.promises.readFile(file, "utf8");
|
|
5673
6000
|
} catch (err) {
|
|
5674
6001
|
if (err.code === "ENOENT") {
|
|
5675
6002
|
return { version: 1, projects: [] };
|
|
@@ -5677,10 +6004,10 @@ async function readRegistry() {
|
|
|
5677
6004
|
throw err;
|
|
5678
6005
|
}
|
|
5679
6006
|
const parsed = JSON.parse(raw);
|
|
5680
|
-
return
|
|
6007
|
+
return import_types23.RegistryFileSchema.parse(parsed);
|
|
5681
6008
|
}
|
|
5682
6009
|
async function writeRegistry(reg) {
|
|
5683
|
-
const validated =
|
|
6010
|
+
const validated = import_types23.RegistryFileSchema.parse(reg);
|
|
5684
6011
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
5685
6012
|
}
|
|
5686
6013
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -5952,11 +6279,11 @@ function registerRoutes(scope, ctx) {
|
|
|
5952
6279
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
5953
6280
|
const parsed = [];
|
|
5954
6281
|
for (const c of candidates) {
|
|
5955
|
-
const r =
|
|
6282
|
+
const r = import_types24.DivergenceTypeSchema.safeParse(c);
|
|
5956
6283
|
if (!r.success) {
|
|
5957
6284
|
return reply.code(400).send({
|
|
5958
6285
|
error: `unknown divergence type "${c}"`,
|
|
5959
|
-
allowed:
|
|
6286
|
+
allowed: import_types24.DivergenceTypeSchema.options
|
|
5960
6287
|
});
|
|
5961
6288
|
}
|
|
5962
6289
|
parsed.push(r.data);
|
|
@@ -6169,7 +6496,7 @@ function registerRoutes(scope, ctx) {
|
|
|
6169
6496
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
6170
6497
|
let violations = await log.readAll();
|
|
6171
6498
|
if (req.query.severity) {
|
|
6172
|
-
const sev =
|
|
6499
|
+
const sev = import_types24.PolicySeveritySchema.safeParse(req.query.severity);
|
|
6173
6500
|
if (!sev.success) {
|
|
6174
6501
|
return reply.code(400).send({
|
|
6175
6502
|
error: "invalid severity",
|
|
@@ -6186,7 +6513,7 @@ function registerRoutes(scope, ctx) {
|
|
|
6186
6513
|
scope.post("/policies/check", async (req, reply) => {
|
|
6187
6514
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6188
6515
|
if (!proj) return;
|
|
6189
|
-
const parsed =
|
|
6516
|
+
const parsed = import_types24.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
6190
6517
|
if (!parsed.success) {
|
|
6191
6518
|
return reply.code(400).send({
|
|
6192
6519
|
error: "invalid /policies/check body",
|
|
@@ -6428,15 +6755,15 @@ init_otel_grpc();
|
|
|
6428
6755
|
|
|
6429
6756
|
// src/daemon.ts
|
|
6430
6757
|
init_cjs_shims();
|
|
6431
|
-
var
|
|
6432
|
-
var
|
|
6758
|
+
var import_node_fs25 = require("fs");
|
|
6759
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
6433
6760
|
init_otel();
|
|
6434
6761
|
init_auth();
|
|
6435
6762
|
|
|
6436
6763
|
// src/unrouted.ts
|
|
6437
6764
|
init_cjs_shims();
|
|
6438
|
-
var
|
|
6439
|
-
var
|
|
6765
|
+
var import_node_fs24 = require("fs");
|
|
6766
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
6440
6767
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
6441
6768
|
return {
|
|
6442
6769
|
timestamp: now.toISOString(),
|
|
@@ -6446,21 +6773,21 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
6446
6773
|
};
|
|
6447
6774
|
}
|
|
6448
6775
|
async function appendUnroutedSpan(neatHome2, record) {
|
|
6449
|
-
const target =
|
|
6450
|
-
await
|
|
6451
|
-
await
|
|
6776
|
+
const target = import_node_path40.default.join(neatHome2, "errors.ndjson");
|
|
6777
|
+
await import_node_fs24.promises.mkdir(neatHome2, { recursive: true });
|
|
6778
|
+
await import_node_fs24.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
6452
6779
|
}
|
|
6453
6780
|
function unroutedErrorsPath(neatHome2) {
|
|
6454
|
-
return
|
|
6781
|
+
return import_node_path40.default.join(neatHome2, "errors.ndjson");
|
|
6455
6782
|
}
|
|
6456
6783
|
|
|
6457
6784
|
// src/daemon.ts
|
|
6458
6785
|
function neatHomeFor(opts) {
|
|
6459
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
6786
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path41.default.resolve(opts.neatHome);
|
|
6460
6787
|
const env = process.env.NEAT_HOME;
|
|
6461
|
-
if (env && env.length > 0) return
|
|
6788
|
+
if (env && env.length > 0) return import_node_path41.default.resolve(env);
|
|
6462
6789
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
6463
|
-
return
|
|
6790
|
+
return import_node_path41.default.join(home, ".neat");
|
|
6464
6791
|
}
|
|
6465
6792
|
function routeSpanToProject(serviceName, projects) {
|
|
6466
6793
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -6495,9 +6822,9 @@ function isTokenContained(needle, haystack) {
|
|
|
6495
6822
|
return tokens.includes(needle);
|
|
6496
6823
|
}
|
|
6497
6824
|
async function bootstrapProject(entry) {
|
|
6498
|
-
const paths = pathsForProject(entry.name,
|
|
6825
|
+
const paths = pathsForProject(entry.name, import_node_path41.default.join(entry.path, "neat-out"));
|
|
6499
6826
|
try {
|
|
6500
|
-
const stat = await
|
|
6827
|
+
const stat = await import_node_fs25.promises.stat(entry.path);
|
|
6501
6828
|
if (!stat.isDirectory()) {
|
|
6502
6829
|
throw new Error(`registered path ${entry.path} is not a directory`);
|
|
6503
6830
|
}
|
|
@@ -6563,13 +6890,13 @@ async function startDaemon(opts = {}) {
|
|
|
6563
6890
|
const home = neatHomeFor(opts);
|
|
6564
6891
|
const regPath = registryPath();
|
|
6565
6892
|
try {
|
|
6566
|
-
await
|
|
6893
|
+
await import_node_fs25.promises.access(regPath);
|
|
6567
6894
|
} catch {
|
|
6568
6895
|
throw new Error(
|
|
6569
6896
|
`neatd: registry not found at ${regPath}. Run \`neat init <path>\` to register a project before starting the daemon.`
|
|
6570
6897
|
);
|
|
6571
6898
|
}
|
|
6572
|
-
const pidPath =
|
|
6899
|
+
const pidPath = import_node_path41.default.join(home, "neatd.pid");
|
|
6573
6900
|
await writeAtomically(pidPath, `${process.pid}
|
|
6574
6901
|
`);
|
|
6575
6902
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -6727,7 +7054,7 @@ async function startDaemon(opts = {}) {
|
|
|
6727
7054
|
}
|
|
6728
7055
|
if (restApp) await restApp.close().catch(() => {
|
|
6729
7056
|
});
|
|
6730
|
-
await
|
|
7057
|
+
await import_node_fs25.promises.unlink(pidPath).catch(() => {
|
|
6731
7058
|
});
|
|
6732
7059
|
throw new Error(
|
|
6733
7060
|
`neatd: failed to bind REST on port ${restPort} \u2014 ${err.message}`
|
|
@@ -6833,7 +7160,7 @@ async function startDaemon(opts = {}) {
|
|
|
6833
7160
|
});
|
|
6834
7161
|
if (otlpApp) await otlpApp.close().catch(() => {
|
|
6835
7162
|
});
|
|
6836
|
-
await
|
|
7163
|
+
await import_node_fs25.promises.unlink(pidPath).catch(() => {
|
|
6837
7164
|
});
|
|
6838
7165
|
throw new Error(
|
|
6839
7166
|
`neatd: failed to bind OTLP on port ${otlpPort} \u2014 ${err.message}`
|
|
@@ -6879,9 +7206,9 @@ async function startDaemon(opts = {}) {
|
|
|
6879
7206
|
let registryWatcher = null;
|
|
6880
7207
|
let reloadTimer = null;
|
|
6881
7208
|
try {
|
|
6882
|
-
const regDir =
|
|
6883
|
-
const regBase =
|
|
6884
|
-
registryWatcher = (0,
|
|
7209
|
+
const regDir = import_node_path41.default.dirname(regPath);
|
|
7210
|
+
const regBase = import_node_path41.default.basename(regPath);
|
|
7211
|
+
registryWatcher = (0, import_node_fs25.watch)(regDir, (_eventType, filename) => {
|
|
6885
7212
|
if (filename !== null && filename !== regBase) return;
|
|
6886
7213
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
6887
7214
|
reloadTimer = setTimeout(() => {
|
|
@@ -6924,7 +7251,7 @@ async function startDaemon(opts = {}) {
|
|
|
6924
7251
|
} catch {
|
|
6925
7252
|
}
|
|
6926
7253
|
}
|
|
6927
|
-
await
|
|
7254
|
+
await import_node_fs25.promises.unlink(pidPath).catch(() => {
|
|
6928
7255
|
});
|
|
6929
7256
|
};
|
|
6930
7257
|
return {
|