@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/server.cjs
CHANGED
|
@@ -56,9 +56,9 @@ function mountBearerAuth(app, opts) {
|
|
|
56
56
|
const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...opts.extraUnauthenticatedSuffixes ?? []];
|
|
57
57
|
const publicRead = opts.publicRead === true;
|
|
58
58
|
app.addHook("preHandler", (req, reply, done) => {
|
|
59
|
-
const
|
|
59
|
+
const path42 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
60
60
|
for (const suffix of suffixes) {
|
|
61
|
-
if (
|
|
61
|
+
if (path42 === suffix || path42.endsWith(suffix)) {
|
|
62
62
|
done();
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
@@ -132,7 +132,9 @@ __export(otel_grpc_exports, {
|
|
|
132
132
|
});
|
|
133
133
|
function bytesToHex(buf) {
|
|
134
134
|
if (!buf) return "";
|
|
135
|
-
|
|
135
|
+
if (Buffer.isBuffer(buf)) return buf.toString("hex");
|
|
136
|
+
if (buf instanceof Uint8Array) return Buffer.from(buf).toString("hex");
|
|
137
|
+
return "";
|
|
136
138
|
}
|
|
137
139
|
function nanosToString(n) {
|
|
138
140
|
if (n === void 0 || n === null) return "0";
|
|
@@ -184,8 +186,8 @@ function reshapeGrpcRequest(req) {
|
|
|
184
186
|
};
|
|
185
187
|
}
|
|
186
188
|
function resolveProtoRoot() {
|
|
187
|
-
const here =
|
|
188
|
-
return
|
|
189
|
+
const here = import_node_path38.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
190
|
+
return import_node_path38.default.resolve(here, "..", "proto");
|
|
189
191
|
}
|
|
190
192
|
function loadTraceService() {
|
|
191
193
|
const protoRoot = resolveProtoRoot();
|
|
@@ -253,13 +255,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
253
255
|
})
|
|
254
256
|
};
|
|
255
257
|
}
|
|
256
|
-
var import_node_url,
|
|
258
|
+
var import_node_url, import_node_path38, import_node_crypto2, grpc, protoLoader;
|
|
257
259
|
var init_otel_grpc = __esm({
|
|
258
260
|
"src/otel-grpc.ts"() {
|
|
259
261
|
"use strict";
|
|
260
262
|
init_cjs_shims();
|
|
261
263
|
import_node_url = require("url");
|
|
262
|
-
|
|
264
|
+
import_node_path38 = __toESM(require("path"), 1);
|
|
263
265
|
import_node_crypto2 = require("crypto");
|
|
264
266
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
265
267
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -369,10 +371,10 @@ function parseOtlpRequest(body) {
|
|
|
369
371
|
return out;
|
|
370
372
|
}
|
|
371
373
|
function loadProtoRoot() {
|
|
372
|
-
const here =
|
|
373
|
-
const protoRoot =
|
|
374
|
+
const here = import_node_path39.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
375
|
+
const protoRoot = import_node_path39.default.resolve(here, "..", "proto");
|
|
374
376
|
const root = new import_protobufjs.default.Root();
|
|
375
|
-
root.resolvePath = (_origin, target) =>
|
|
377
|
+
root.resolvePath = (_origin, target) => import_node_path39.default.resolve(protoRoot, target);
|
|
376
378
|
root.loadSync(
|
|
377
379
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
378
380
|
{ keepCase: true }
|
|
@@ -405,7 +407,10 @@ function encodeProtobufResponseBody() {
|
|
|
405
407
|
}
|
|
406
408
|
async function decodeProtobufBody(buf) {
|
|
407
409
|
const Type = loadProtobufDecoder();
|
|
408
|
-
const decoded = Type.decode(buf)
|
|
410
|
+
const decoded = Type.toObject(Type.decode(buf), {
|
|
411
|
+
longs: String,
|
|
412
|
+
enums: Number
|
|
413
|
+
});
|
|
409
414
|
const { reshapeGrpcRequest: reshapeGrpcRequest2 } = await Promise.resolve().then(() => (init_otel_grpc(), otel_grpc_exports));
|
|
410
415
|
return reshapeGrpcRequest2(decoded);
|
|
411
416
|
}
|
|
@@ -565,12 +570,12 @@ async function buildOtelReceiver(opts) {
|
|
|
565
570
|
};
|
|
566
571
|
return decorated;
|
|
567
572
|
}
|
|
568
|
-
var
|
|
573
|
+
var import_node_path39, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
569
574
|
var init_otel = __esm({
|
|
570
575
|
"src/otel.ts"() {
|
|
571
576
|
"use strict";
|
|
572
577
|
init_cjs_shims();
|
|
573
|
-
|
|
578
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
574
579
|
import_node_url2 = require("url");
|
|
575
580
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
576
581
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -586,7 +591,7 @@ var init_otel = __esm({
|
|
|
586
591
|
|
|
587
592
|
// src/server.ts
|
|
588
593
|
init_cjs_shims();
|
|
589
|
-
var
|
|
594
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
590
595
|
|
|
591
596
|
// src/graph.ts
|
|
592
597
|
init_cjs_shims();
|
|
@@ -610,7 +615,7 @@ function getGraph(project = DEFAULT_PROJECT) {
|
|
|
610
615
|
init_cjs_shims();
|
|
611
616
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
612
617
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
613
|
-
var
|
|
618
|
+
var import_types24 = require("@neat.is/types");
|
|
614
619
|
|
|
615
620
|
// src/extend/index.ts
|
|
616
621
|
init_cjs_shims();
|
|
@@ -1353,19 +1358,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1353
1358
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1354
1359
|
let best = { path: [start], edges: [] };
|
|
1355
1360
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1356
|
-
function step(node,
|
|
1357
|
-
if (
|
|
1358
|
-
best = { path: [...
|
|
1361
|
+
function step(node, path42, edges) {
|
|
1362
|
+
if (path42.length > best.path.length) {
|
|
1363
|
+
best = { path: [...path42], edges: [...edges] };
|
|
1359
1364
|
}
|
|
1360
|
-
if (
|
|
1365
|
+
if (path42.length - 1 >= maxDepth) return;
|
|
1361
1366
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1362
1367
|
for (const [srcId, edge] of incoming) {
|
|
1363
1368
|
if (visited.has(srcId)) continue;
|
|
1364
1369
|
visited.add(srcId);
|
|
1365
|
-
|
|
1370
|
+
path42.push(srcId);
|
|
1366
1371
|
edges.push(edge);
|
|
1367
|
-
step(srcId,
|
|
1368
|
-
|
|
1372
|
+
step(srcId, path42, edges);
|
|
1373
|
+
path42.pop();
|
|
1369
1374
|
edges.pop();
|
|
1370
1375
|
visited.delete(srcId);
|
|
1371
1376
|
}
|
|
@@ -3564,10 +3569,8 @@ async function addServiceAliases(graph, scanPath, services) {
|
|
|
3564
3569
|
await collectK8sAliases(graph, scanPath, byName);
|
|
3565
3570
|
}
|
|
3566
3571
|
|
|
3567
|
-
// src/extract/
|
|
3572
|
+
// src/extract/files.ts
|
|
3568
3573
|
init_cjs_shims();
|
|
3569
|
-
var import_node_path20 = __toESM(require("path"), 1);
|
|
3570
|
-
var import_types9 = require("@neat.is/types");
|
|
3571
3574
|
|
|
3572
3575
|
// src/extract/calls/shared.ts
|
|
3573
3576
|
init_cjs_shims();
|
|
@@ -3666,11 +3669,333 @@ function ensureFileNode(graph, serviceName, serviceNodeId, relPath) {
|
|
|
3666
3669
|
return { fileNodeId, nodesAdded, edgesAdded };
|
|
3667
3670
|
}
|
|
3668
3671
|
|
|
3672
|
+
// src/extract/files.ts
|
|
3673
|
+
var import_node_path13 = __toESM(require("path"), 1);
|
|
3674
|
+
async function addFiles(graph, services) {
|
|
3675
|
+
let nodesAdded = 0;
|
|
3676
|
+
let edgesAdded = 0;
|
|
3677
|
+
for (const service of services) {
|
|
3678
|
+
const filePaths = await walkSourceFiles(service.dir);
|
|
3679
|
+
for (const filePath of filePaths) {
|
|
3680
|
+
const relPath = toPosix2(import_node_path13.default.relative(service.dir, filePath));
|
|
3681
|
+
const { nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
3682
|
+
graph,
|
|
3683
|
+
service.pkg.name,
|
|
3684
|
+
service.node.id,
|
|
3685
|
+
relPath
|
|
3686
|
+
);
|
|
3687
|
+
nodesAdded += n;
|
|
3688
|
+
edgesAdded += e;
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
return { nodesAdded, edgesAdded };
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
// src/extract/imports.ts
|
|
3695
|
+
init_cjs_shims();
|
|
3696
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
3697
|
+
var import_node_fs13 = require("fs");
|
|
3698
|
+
var import_tree_sitter = __toESM(require("tree-sitter"), 1);
|
|
3699
|
+
var import_tree_sitter_javascript = __toESM(require("tree-sitter-javascript"), 1);
|
|
3700
|
+
var import_tree_sitter_python = __toESM(require("tree-sitter-python"), 1);
|
|
3701
|
+
var import_types9 = require("@neat.is/types");
|
|
3702
|
+
var PARSE_CHUNK = 16384;
|
|
3703
|
+
function parseSource(parser, source) {
|
|
3704
|
+
return parser.parse(
|
|
3705
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK)
|
|
3706
|
+
);
|
|
3707
|
+
}
|
|
3708
|
+
function makeJsParser() {
|
|
3709
|
+
const p = new import_tree_sitter.default();
|
|
3710
|
+
p.setLanguage(import_tree_sitter_javascript.default);
|
|
3711
|
+
return p;
|
|
3712
|
+
}
|
|
3713
|
+
function makePyParser() {
|
|
3714
|
+
const p = new import_tree_sitter.default();
|
|
3715
|
+
p.setLanguage(import_tree_sitter_python.default);
|
|
3716
|
+
return p;
|
|
3717
|
+
}
|
|
3718
|
+
function stringLiteralText(node) {
|
|
3719
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
3720
|
+
const child = node.child(i);
|
|
3721
|
+
if (child?.type === "string_fragment") return child.text;
|
|
3722
|
+
}
|
|
3723
|
+
const raw = node.text;
|
|
3724
|
+
if (raw.length >= 2) return raw.slice(1, -1);
|
|
3725
|
+
return raw.length === 0 ? null : "";
|
|
3726
|
+
}
|
|
3727
|
+
function clipSnippet(text) {
|
|
3728
|
+
const oneLine = text.split("\n")[0] ?? text;
|
|
3729
|
+
return oneLine.length > 120 ? oneLine.slice(0, 120) : oneLine;
|
|
3730
|
+
}
|
|
3731
|
+
function collectJsImports(node, out) {
|
|
3732
|
+
if (node.type === "import_statement") {
|
|
3733
|
+
const source = node.childForFieldName("source");
|
|
3734
|
+
if (source) {
|
|
3735
|
+
const specifier = stringLiteralText(source);
|
|
3736
|
+
if (specifier) {
|
|
3737
|
+
out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
return;
|
|
3741
|
+
}
|
|
3742
|
+
if (node.type === "call_expression") {
|
|
3743
|
+
const fn = node.childForFieldName("function");
|
|
3744
|
+
if (fn?.type === "identifier" && fn.text === "require") {
|
|
3745
|
+
const args = node.childForFieldName("arguments");
|
|
3746
|
+
const firstArg = args?.namedChild(0);
|
|
3747
|
+
if (firstArg?.type === "string") {
|
|
3748
|
+
const specifier = stringLiteralText(firstArg);
|
|
3749
|
+
if (specifier) {
|
|
3750
|
+
out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3756
|
+
const child = node.namedChild(i);
|
|
3757
|
+
if (child) collectJsImports(child, out);
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
function collectPyImports(node, out) {
|
|
3761
|
+
if (node.type === "import_from_statement") {
|
|
3762
|
+
let level = 0;
|
|
3763
|
+
let modulePath = "";
|
|
3764
|
+
let pastFrom = false;
|
|
3765
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
3766
|
+
const child = node.child(i);
|
|
3767
|
+
if (!child) continue;
|
|
3768
|
+
if (!pastFrom) {
|
|
3769
|
+
if (child.type === "from") pastFrom = true;
|
|
3770
|
+
continue;
|
|
3771
|
+
}
|
|
3772
|
+
if (child.type === "import") break;
|
|
3773
|
+
if (child.type === "relative_import") {
|
|
3774
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
3775
|
+
const rc = child.child(j);
|
|
3776
|
+
if (!rc) continue;
|
|
3777
|
+
if (rc.type === "import_prefix") {
|
|
3778
|
+
for (let k = 0; k < rc.childCount; k++) {
|
|
3779
|
+
if (rc.child(k)?.type === ".") level++;
|
|
3780
|
+
}
|
|
3781
|
+
} else if (rc.type === "dotted_name") modulePath = rc.text;
|
|
3782
|
+
}
|
|
3783
|
+
break;
|
|
3784
|
+
}
|
|
3785
|
+
if (child.type === "dotted_name") {
|
|
3786
|
+
modulePath = child.text;
|
|
3787
|
+
break;
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
if (level > 0 || modulePath) {
|
|
3791
|
+
out.push({ modulePath, level, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) });
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
3795
|
+
const child = node.namedChild(i);
|
|
3796
|
+
if (child) collectPyImports(child, out);
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
async function fileExists2(p) {
|
|
3800
|
+
try {
|
|
3801
|
+
await import_node_fs13.promises.access(p);
|
|
3802
|
+
return true;
|
|
3803
|
+
} catch {
|
|
3804
|
+
return false;
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
function isWithinServiceDir(candidate, serviceDir) {
|
|
3808
|
+
const rel = import_node_path14.default.relative(serviceDir, candidate);
|
|
3809
|
+
return rel !== "" && !rel.startsWith("..") && !import_node_path14.default.isAbsolute(rel);
|
|
3810
|
+
}
|
|
3811
|
+
var JS_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
3812
|
+
var JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`);
|
|
3813
|
+
async function firstExistingCandidate(base, serviceDir) {
|
|
3814
|
+
for (const ext of JS_EXTENSIONS) {
|
|
3815
|
+
const candidate = base + ext;
|
|
3816
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
|
|
3817
|
+
return toPosix2(import_node_path14.default.relative(serviceDir, candidate));
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
for (const indexFile of JS_INDEX_FILES) {
|
|
3821
|
+
const candidate = import_node_path14.default.join(base, indexFile);
|
|
3822
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
|
|
3823
|
+
return toPosix2(import_node_path14.default.relative(serviceDir, candidate));
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
return null;
|
|
3827
|
+
}
|
|
3828
|
+
async function loadTsPathConfig(serviceDir) {
|
|
3829
|
+
const tsconfigPath = import_node_path14.default.join(serviceDir, "tsconfig.json");
|
|
3830
|
+
let raw;
|
|
3831
|
+
try {
|
|
3832
|
+
raw = await import_node_fs13.promises.readFile(tsconfigPath, "utf8");
|
|
3833
|
+
} catch {
|
|
3834
|
+
return null;
|
|
3835
|
+
}
|
|
3836
|
+
try {
|
|
3837
|
+
const parsed = JSON.parse(raw);
|
|
3838
|
+
const paths = parsed.compilerOptions?.paths;
|
|
3839
|
+
if (!paths || Object.keys(paths).length === 0) return null;
|
|
3840
|
+
const baseUrl = parsed.compilerOptions?.baseUrl;
|
|
3841
|
+
return { paths, baseDir: baseUrl ? import_node_path14.default.resolve(serviceDir, baseUrl) : serviceDir };
|
|
3842
|
+
} catch (err) {
|
|
3843
|
+
recordExtractionError("import alias resolution", tsconfigPath, err);
|
|
3844
|
+
return null;
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
async function resolveTsAlias(specifier, config, serviceDir) {
|
|
3848
|
+
for (const [pattern, targets] of Object.entries(config.paths)) {
|
|
3849
|
+
let suffix = null;
|
|
3850
|
+
if (pattern === specifier) {
|
|
3851
|
+
suffix = "";
|
|
3852
|
+
} else if (pattern.endsWith("/*")) {
|
|
3853
|
+
const prefix = pattern.slice(0, -1);
|
|
3854
|
+
if (specifier.startsWith(prefix)) suffix = specifier.slice(prefix.length);
|
|
3855
|
+
}
|
|
3856
|
+
if (suffix === null) continue;
|
|
3857
|
+
for (const target of targets) {
|
|
3858
|
+
const targetBase = target.endsWith("/*") ? target.slice(0, -2) : target.replace(/\*$/, "");
|
|
3859
|
+
const resolvedBase = import_node_path14.default.resolve(config.baseDir, targetBase, suffix);
|
|
3860
|
+
const hit = await firstExistingCandidate(resolvedBase, serviceDir);
|
|
3861
|
+
if (hit) return hit;
|
|
3862
|
+
if (isWithinServiceDir(resolvedBase, serviceDir) && await fileExists2(resolvedBase)) {
|
|
3863
|
+
return toPosix2(import_node_path14.default.relative(serviceDir, resolvedBase));
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
return null;
|
|
3868
|
+
}
|
|
3869
|
+
async function resolveJsImport(specifier, importerDir, serviceDir, tsPaths) {
|
|
3870
|
+
if (!specifier) return null;
|
|
3871
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
3872
|
+
const base = import_node_path14.default.resolve(importerDir, specifier);
|
|
3873
|
+
const ext = import_node_path14.default.extname(specifier);
|
|
3874
|
+
if (ext) {
|
|
3875
|
+
if (ext === ".js" || ext === ".jsx") {
|
|
3876
|
+
const tsExt = ext === ".jsx" ? ".tsx" : ".ts";
|
|
3877
|
+
const tsSibling = base.slice(0, -ext.length) + tsExt;
|
|
3878
|
+
if (isWithinServiceDir(tsSibling, serviceDir) && await fileExists2(tsSibling)) {
|
|
3879
|
+
return toPosix2(import_node_path14.default.relative(serviceDir, tsSibling));
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
if (isWithinServiceDir(base, serviceDir) && await fileExists2(base)) {
|
|
3883
|
+
return toPosix2(import_node_path14.default.relative(serviceDir, base));
|
|
3884
|
+
}
|
|
3885
|
+
return null;
|
|
3886
|
+
}
|
|
3887
|
+
return firstExistingCandidate(base, serviceDir);
|
|
3888
|
+
}
|
|
3889
|
+
if (tsPaths) return resolveTsAlias(specifier, tsPaths, serviceDir);
|
|
3890
|
+
return null;
|
|
3891
|
+
}
|
|
3892
|
+
async function resolvePyImport(imp, importerPath, serviceDir) {
|
|
3893
|
+
if (!imp.modulePath) return null;
|
|
3894
|
+
const relPath = imp.modulePath.split(".").join("/");
|
|
3895
|
+
let baseDir;
|
|
3896
|
+
if (imp.level > 0) {
|
|
3897
|
+
baseDir = import_node_path14.default.dirname(importerPath);
|
|
3898
|
+
for (let i = 1; i < imp.level; i++) baseDir = import_node_path14.default.dirname(baseDir);
|
|
3899
|
+
} else {
|
|
3900
|
+
baseDir = serviceDir;
|
|
3901
|
+
}
|
|
3902
|
+
const candidates = [import_node_path14.default.join(baseDir, `${relPath}.py`), import_node_path14.default.join(baseDir, relPath, "__init__.py")];
|
|
3903
|
+
for (const candidate of candidates) {
|
|
3904
|
+
if (isWithinServiceDir(candidate, serviceDir) && await fileExists2(candidate)) {
|
|
3905
|
+
return toPosix2(import_node_path14.default.relative(serviceDir, candidate));
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
return null;
|
|
3909
|
+
}
|
|
3910
|
+
function emitImportEdge(graph, serviceName, importerFileId, importerRelPath, importeeRelPath, line, snippet2) {
|
|
3911
|
+
const importeeFileId = (0, import_types9.fileId)(serviceName, importeeRelPath);
|
|
3912
|
+
if (!graph.hasNode(importeeFileId)) return 0;
|
|
3913
|
+
const edgeId = (0, import_types9.extractedEdgeId)(importerFileId, importeeFileId, import_types9.EdgeType.IMPORTS);
|
|
3914
|
+
if (graph.hasEdge(edgeId)) return 0;
|
|
3915
|
+
const edge = {
|
|
3916
|
+
id: edgeId,
|
|
3917
|
+
source: importerFileId,
|
|
3918
|
+
target: importeeFileId,
|
|
3919
|
+
type: import_types9.EdgeType.IMPORTS,
|
|
3920
|
+
provenance: import_types9.Provenance.EXTRACTED,
|
|
3921
|
+
confidence: (0, import_types9.confidenceForExtracted)("structural"),
|
|
3922
|
+
evidence: { file: importerRelPath, line, snippet: snippet2 }
|
|
3923
|
+
};
|
|
3924
|
+
graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge);
|
|
3925
|
+
return 1;
|
|
3926
|
+
}
|
|
3927
|
+
async function addImports(graph, services) {
|
|
3928
|
+
const jsParser = makeJsParser();
|
|
3929
|
+
const pyParser = makePyParser();
|
|
3930
|
+
let edgesAdded = 0;
|
|
3931
|
+
for (const service of services) {
|
|
3932
|
+
const tsPaths = await loadTsPathConfig(service.dir);
|
|
3933
|
+
const files = await loadSourceFiles(service.dir);
|
|
3934
|
+
for (const file of files) {
|
|
3935
|
+
if (isTestPath(file.path)) continue;
|
|
3936
|
+
const relFile = toPosix2(import_node_path14.default.relative(service.dir, file.path));
|
|
3937
|
+
const importerFileId = (0, import_types9.fileId)(service.pkg.name, relFile);
|
|
3938
|
+
const isPython = import_node_path14.default.extname(file.path) === ".py";
|
|
3939
|
+
if (isPython) {
|
|
3940
|
+
let pyImports = [];
|
|
3941
|
+
try {
|
|
3942
|
+
const tree = parseSource(pyParser, file.content);
|
|
3943
|
+
collectPyImports(tree.rootNode, pyImports);
|
|
3944
|
+
} catch (err) {
|
|
3945
|
+
recordExtractionError("import extraction", file.path, err);
|
|
3946
|
+
continue;
|
|
3947
|
+
}
|
|
3948
|
+
for (const imp of pyImports) {
|
|
3949
|
+
const resolved = await resolvePyImport(imp, file.path, service.dir);
|
|
3950
|
+
if (!resolved) continue;
|
|
3951
|
+
edgesAdded += emitImportEdge(
|
|
3952
|
+
graph,
|
|
3953
|
+
service.pkg.name,
|
|
3954
|
+
importerFileId,
|
|
3955
|
+
relFile,
|
|
3956
|
+
resolved,
|
|
3957
|
+
imp.line,
|
|
3958
|
+
imp.snippet
|
|
3959
|
+
);
|
|
3960
|
+
}
|
|
3961
|
+
continue;
|
|
3962
|
+
}
|
|
3963
|
+
let jsImports = [];
|
|
3964
|
+
try {
|
|
3965
|
+
const tree = parseSource(jsParser, file.content);
|
|
3966
|
+
collectJsImports(tree.rootNode, jsImports);
|
|
3967
|
+
} catch (err) {
|
|
3968
|
+
recordExtractionError("import extraction", file.path, err);
|
|
3969
|
+
continue;
|
|
3970
|
+
}
|
|
3971
|
+
for (const imp of jsImports) {
|
|
3972
|
+
const resolved = await resolveJsImport(imp.specifier, import_node_path14.default.dirname(file.path), service.dir, tsPaths);
|
|
3973
|
+
if (!resolved) continue;
|
|
3974
|
+
edgesAdded += emitImportEdge(
|
|
3975
|
+
graph,
|
|
3976
|
+
service.pkg.name,
|
|
3977
|
+
importerFileId,
|
|
3978
|
+
relFile,
|
|
3979
|
+
resolved,
|
|
3980
|
+
imp.line,
|
|
3981
|
+
imp.snippet
|
|
3982
|
+
);
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
return { nodesAdded: 0, edgesAdded };
|
|
3987
|
+
}
|
|
3988
|
+
|
|
3989
|
+
// src/extract/databases/index.ts
|
|
3990
|
+
init_cjs_shims();
|
|
3991
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
3992
|
+
var import_types10 = require("@neat.is/types");
|
|
3993
|
+
|
|
3669
3994
|
// src/extract/databases/db-config-yaml.ts
|
|
3670
3995
|
init_cjs_shims();
|
|
3671
|
-
var
|
|
3996
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
3672
3997
|
async function parse(serviceDir) {
|
|
3673
|
-
const yamlPath =
|
|
3998
|
+
const yamlPath = import_node_path15.default.join(serviceDir, "db-config.yaml");
|
|
3674
3999
|
if (!await exists2(yamlPath)) return [];
|
|
3675
4000
|
const raw = await readYaml(yamlPath);
|
|
3676
4001
|
return [
|
|
@@ -3688,13 +4013,13 @@ var dbConfigYamlParser = { name: "db-config.yaml", parse };
|
|
|
3688
4013
|
|
|
3689
4014
|
// src/extract/databases/dotenv.ts
|
|
3690
4015
|
init_cjs_shims();
|
|
3691
|
-
var
|
|
3692
|
-
var
|
|
4016
|
+
var import_node_fs15 = require("fs");
|
|
4017
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
3693
4018
|
|
|
3694
4019
|
// src/extract/databases/shared.ts
|
|
3695
4020
|
init_cjs_shims();
|
|
3696
|
-
var
|
|
3697
|
-
var
|
|
4021
|
+
var import_node_fs14 = require("fs");
|
|
4022
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
3698
4023
|
function schemeToEngine(scheme) {
|
|
3699
4024
|
const s = scheme.toLowerCase().split("+")[0];
|
|
3700
4025
|
switch (s) {
|
|
@@ -3733,14 +4058,14 @@ function parseConnectionString(url) {
|
|
|
3733
4058
|
}
|
|
3734
4059
|
async function readIfExists(filePath) {
|
|
3735
4060
|
try {
|
|
3736
|
-
return await
|
|
4061
|
+
return await import_node_fs14.promises.readFile(filePath, "utf8");
|
|
3737
4062
|
} catch {
|
|
3738
4063
|
return null;
|
|
3739
4064
|
}
|
|
3740
4065
|
}
|
|
3741
4066
|
async function findFirst(serviceDir, candidates) {
|
|
3742
4067
|
for (const rel of candidates) {
|
|
3743
|
-
const abs =
|
|
4068
|
+
const abs = import_node_path16.default.join(serviceDir, rel);
|
|
3744
4069
|
const content = await readIfExists(abs);
|
|
3745
4070
|
if (content !== null) return abs;
|
|
3746
4071
|
}
|
|
@@ -3791,15 +4116,15 @@ function parseDotenvLine(line) {
|
|
|
3791
4116
|
return { key, value };
|
|
3792
4117
|
}
|
|
3793
4118
|
async function parse2(serviceDir) {
|
|
3794
|
-
const entries = await
|
|
4119
|
+
const entries = await import_node_fs15.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
|
|
3795
4120
|
const configs = [];
|
|
3796
4121
|
const seen = /* @__PURE__ */ new Set();
|
|
3797
4122
|
for (const entry of entries) {
|
|
3798
4123
|
if (!entry.isFile()) continue;
|
|
3799
4124
|
const match = isConfigFile(entry.name);
|
|
3800
4125
|
if (!match.match || match.fileType !== "env") continue;
|
|
3801
|
-
const filePath =
|
|
3802
|
-
const content = await
|
|
4126
|
+
const filePath = import_node_path17.default.join(serviceDir, entry.name);
|
|
4127
|
+
const content = await import_node_fs15.promises.readFile(filePath, "utf8");
|
|
3803
4128
|
for (const line of content.split("\n")) {
|
|
3804
4129
|
const parsed = parseDotenvLine(line);
|
|
3805
4130
|
if (!parsed) continue;
|
|
@@ -3818,9 +4143,9 @@ var dotenvParser = { name: ".env", parse: parse2 };
|
|
|
3818
4143
|
|
|
3819
4144
|
// src/extract/databases/prisma.ts
|
|
3820
4145
|
init_cjs_shims();
|
|
3821
|
-
var
|
|
4146
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
3822
4147
|
async function parse3(serviceDir) {
|
|
3823
|
-
const schemaPath =
|
|
4148
|
+
const schemaPath = import_node_path18.default.join(serviceDir, "prisma", "schema.prisma");
|
|
3824
4149
|
const content = await readIfExists(schemaPath);
|
|
3825
4150
|
if (!content) return [];
|
|
3826
4151
|
const block = content.match(/datasource\s+\w+\s*\{([^}]*)\}/s);
|
|
@@ -3952,10 +4277,10 @@ var knexParser = { name: "knex", parse: parse5 };
|
|
|
3952
4277
|
|
|
3953
4278
|
// src/extract/databases/ormconfig.ts
|
|
3954
4279
|
init_cjs_shims();
|
|
3955
|
-
var
|
|
4280
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
3956
4281
|
async function parse6(serviceDir) {
|
|
3957
4282
|
for (const candidate of ["ormconfig.json", "ormconfig.yaml", "ormconfig.yml"]) {
|
|
3958
|
-
const abs =
|
|
4283
|
+
const abs = import_node_path19.default.join(serviceDir, candidate);
|
|
3959
4284
|
if (!await exists2(abs)) continue;
|
|
3960
4285
|
const raw = candidate.endsWith(".json") ? await readJson(abs) : await readYaml(abs);
|
|
3961
4286
|
const entries = Array.isArray(raw) ? raw : [raw];
|
|
@@ -4015,9 +4340,9 @@ var typeormParser = { name: "typeorm", parse: parse7 };
|
|
|
4015
4340
|
|
|
4016
4341
|
// src/extract/databases/sequelize.ts
|
|
4017
4342
|
init_cjs_shims();
|
|
4018
|
-
var
|
|
4343
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
4019
4344
|
async function parse8(serviceDir) {
|
|
4020
|
-
const configPath =
|
|
4345
|
+
const configPath = import_node_path20.default.join(serviceDir, "config", "config.json");
|
|
4021
4346
|
if (!await exists2(configPath)) return [];
|
|
4022
4347
|
const raw = await readJson(configPath);
|
|
4023
4348
|
const out = [];
|
|
@@ -4044,7 +4369,7 @@ var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
|
4044
4369
|
|
|
4045
4370
|
// src/extract/databases/docker-compose.ts
|
|
4046
4371
|
init_cjs_shims();
|
|
4047
|
-
var
|
|
4372
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
4048
4373
|
function portFromService(svc) {
|
|
4049
4374
|
for (const raw of svc.ports ?? []) {
|
|
4050
4375
|
const str = String(raw);
|
|
@@ -4071,7 +4396,7 @@ function databaseFromEnv(svc) {
|
|
|
4071
4396
|
}
|
|
4072
4397
|
async function parse9(serviceDir) {
|
|
4073
4398
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
4074
|
-
const abs =
|
|
4399
|
+
const abs = import_node_path21.default.join(serviceDir, name);
|
|
4075
4400
|
if (!await exists2(abs)) continue;
|
|
4076
4401
|
const raw = await readYaml(abs);
|
|
4077
4402
|
if (!raw?.services) return [];
|
|
@@ -4112,8 +4437,8 @@ function compatibleDriversFor(engine) {
|
|
|
4112
4437
|
}
|
|
4113
4438
|
function toDatabaseNode(config) {
|
|
4114
4439
|
return {
|
|
4115
|
-
id: (0,
|
|
4116
|
-
type:
|
|
4440
|
+
id: (0, import_types10.databaseId)(config.host),
|
|
4441
|
+
type: import_types10.NodeType.DatabaseNode,
|
|
4117
4442
|
name: config.database || config.host,
|
|
4118
4443
|
engine: config.engine,
|
|
4119
4444
|
engineVersion: config.engineVersion,
|
|
@@ -4243,7 +4568,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
4243
4568
|
discoveredVia: mergedDiscoveredVia
|
|
4244
4569
|
});
|
|
4245
4570
|
}
|
|
4246
|
-
const relConfigFile = toPosix2(
|
|
4571
|
+
const relConfigFile = toPosix2(import_node_path22.default.relative(service.dir, config.sourceFile));
|
|
4247
4572
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4248
4573
|
graph,
|
|
4249
4574
|
service.pkg.name,
|
|
@@ -4252,14 +4577,14 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
4252
4577
|
);
|
|
4253
4578
|
nodesAdded += fn;
|
|
4254
4579
|
edgesAdded += fe;
|
|
4255
|
-
const evidenceFile = toPosix2(
|
|
4580
|
+
const evidenceFile = toPosix2(import_node_path22.default.relative(scanPath, config.sourceFile));
|
|
4256
4581
|
const edge = {
|
|
4257
|
-
id: (0, import_types5.extractedEdgeId)(fileNodeId, dbNode.id,
|
|
4582
|
+
id: (0, import_types5.extractedEdgeId)(fileNodeId, dbNode.id, import_types10.EdgeType.CONNECTS_TO),
|
|
4258
4583
|
source: fileNodeId,
|
|
4259
4584
|
target: dbNode.id,
|
|
4260
|
-
type:
|
|
4261
|
-
provenance:
|
|
4262
|
-
confidence: (0,
|
|
4585
|
+
type: import_types10.EdgeType.CONNECTS_TO,
|
|
4586
|
+
provenance: import_types10.Provenance.EXTRACTED,
|
|
4587
|
+
confidence: (0, import_types10.confidenceForExtracted)("structural"),
|
|
4263
4588
|
evidence: { file: evidenceFile }
|
|
4264
4589
|
};
|
|
4265
4590
|
if (!graph.hasEdge(edge.id)) {
|
|
@@ -4286,15 +4611,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
4286
4611
|
|
|
4287
4612
|
// src/extract/configs.ts
|
|
4288
4613
|
init_cjs_shims();
|
|
4289
|
-
var
|
|
4290
|
-
var
|
|
4291
|
-
var
|
|
4614
|
+
var import_node_fs16 = require("fs");
|
|
4615
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
4616
|
+
var import_types11 = require("@neat.is/types");
|
|
4292
4617
|
async function walkConfigFiles(dir) {
|
|
4293
4618
|
const out = [];
|
|
4294
4619
|
async function walk(current) {
|
|
4295
|
-
const entries = await
|
|
4620
|
+
const entries = await import_node_fs16.promises.readdir(current, { withFileTypes: true });
|
|
4296
4621
|
for (const entry of entries) {
|
|
4297
|
-
const full =
|
|
4622
|
+
const full = import_node_path23.default.join(current, entry.name);
|
|
4298
4623
|
if (entry.isDirectory()) {
|
|
4299
4624
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
4300
4625
|
if (await isPythonVenvDir(full)) continue;
|
|
@@ -4313,19 +4638,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
4313
4638
|
for (const service of services) {
|
|
4314
4639
|
const configFiles = await walkConfigFiles(service.dir);
|
|
4315
4640
|
for (const file of configFiles) {
|
|
4316
|
-
const relPath =
|
|
4641
|
+
const relPath = import_node_path23.default.relative(scanPath, file);
|
|
4317
4642
|
const node = {
|
|
4318
|
-
id: (0,
|
|
4319
|
-
type:
|
|
4320
|
-
name:
|
|
4643
|
+
id: (0, import_types11.configId)(relPath),
|
|
4644
|
+
type: import_types11.NodeType.ConfigNode,
|
|
4645
|
+
name: import_node_path23.default.basename(file),
|
|
4321
4646
|
path: relPath,
|
|
4322
|
-
fileType: isConfigFile(
|
|
4647
|
+
fileType: isConfigFile(import_node_path23.default.basename(file)).fileType
|
|
4323
4648
|
};
|
|
4324
4649
|
if (!graph.hasNode(node.id)) {
|
|
4325
4650
|
graph.addNode(node.id, node);
|
|
4326
4651
|
nodesAdded++;
|
|
4327
4652
|
}
|
|
4328
|
-
const relToService = toPosix2(
|
|
4653
|
+
const relToService = toPosix2(import_node_path23.default.relative(service.dir, file));
|
|
4329
4654
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4330
4655
|
graph,
|
|
4331
4656
|
service.pkg.name,
|
|
@@ -4335,13 +4660,13 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
4335
4660
|
nodesAdded += fn;
|
|
4336
4661
|
edgesAdded += fe;
|
|
4337
4662
|
const edge = {
|
|
4338
|
-
id: (0, import_types5.extractedEdgeId)(fileNodeId, node.id,
|
|
4663
|
+
id: (0, import_types5.extractedEdgeId)(fileNodeId, node.id, import_types11.EdgeType.CONFIGURED_BY),
|
|
4339
4664
|
source: fileNodeId,
|
|
4340
4665
|
target: node.id,
|
|
4341
|
-
type:
|
|
4342
|
-
provenance:
|
|
4343
|
-
confidence: (0,
|
|
4344
|
-
evidence: { file: relPath.split(
|
|
4666
|
+
type: import_types11.EdgeType.CONFIGURED_BY,
|
|
4667
|
+
provenance: import_types11.Provenance.EXTRACTED,
|
|
4668
|
+
confidence: (0, import_types11.confidenceForExtracted)("structural"),
|
|
4669
|
+
evidence: { file: relPath.split(import_node_path23.default.sep).join("/") }
|
|
4345
4670
|
};
|
|
4346
4671
|
if (!graph.hasEdge(edge.id)) {
|
|
4347
4672
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -4354,15 +4679,15 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
4354
4679
|
|
|
4355
4680
|
// src/extract/calls/index.ts
|
|
4356
4681
|
init_cjs_shims();
|
|
4357
|
-
var
|
|
4682
|
+
var import_types17 = require("@neat.is/types");
|
|
4358
4683
|
|
|
4359
4684
|
// src/extract/calls/http.ts
|
|
4360
4685
|
init_cjs_shims();
|
|
4361
|
-
var
|
|
4362
|
-
var
|
|
4363
|
-
var
|
|
4364
|
-
var
|
|
4365
|
-
var
|
|
4686
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
4687
|
+
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
4688
|
+
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
4689
|
+
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
4690
|
+
var import_types12 = require("@neat.is/types");
|
|
4366
4691
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
4367
4692
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
4368
4693
|
function isInsideJsxExternalLink(node) {
|
|
@@ -4390,14 +4715,14 @@ function collectStringLiterals(node, out) {
|
|
|
4390
4715
|
if (child) collectStringLiterals(child, out);
|
|
4391
4716
|
}
|
|
4392
4717
|
}
|
|
4393
|
-
var
|
|
4394
|
-
function
|
|
4718
|
+
var PARSE_CHUNK2 = 16384;
|
|
4719
|
+
function parseSource2(parser, source) {
|
|
4395
4720
|
return parser.parse(
|
|
4396
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
4721
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK2)
|
|
4397
4722
|
);
|
|
4398
4723
|
}
|
|
4399
4724
|
function callsFromSource(source, parser, knownHosts) {
|
|
4400
|
-
const tree =
|
|
4725
|
+
const tree = parseSource2(parser, source);
|
|
4401
4726
|
const literals = [];
|
|
4402
4727
|
collectStringLiterals(tree.rootNode, literals);
|
|
4403
4728
|
const out = [];
|
|
@@ -4411,25 +4736,25 @@ function callsFromSource(source, parser, knownHosts) {
|
|
|
4411
4736
|
}
|
|
4412
4737
|
return out;
|
|
4413
4738
|
}
|
|
4414
|
-
function
|
|
4415
|
-
const p = new
|
|
4416
|
-
p.setLanguage(
|
|
4739
|
+
function makeJsParser2() {
|
|
4740
|
+
const p = new import_tree_sitter2.default();
|
|
4741
|
+
p.setLanguage(import_tree_sitter_javascript2.default);
|
|
4417
4742
|
return p;
|
|
4418
4743
|
}
|
|
4419
|
-
function
|
|
4420
|
-
const p = new
|
|
4421
|
-
p.setLanguage(
|
|
4744
|
+
function makePyParser2() {
|
|
4745
|
+
const p = new import_tree_sitter2.default();
|
|
4746
|
+
p.setLanguage(import_tree_sitter_python2.default);
|
|
4422
4747
|
return p;
|
|
4423
4748
|
}
|
|
4424
4749
|
async function addHttpCallEdges(graph, services) {
|
|
4425
|
-
const jsParser =
|
|
4426
|
-
const pyParser =
|
|
4750
|
+
const jsParser = makeJsParser2();
|
|
4751
|
+
const pyParser = makePyParser2();
|
|
4427
4752
|
const knownHosts = /* @__PURE__ */ new Set();
|
|
4428
4753
|
const hostToNodeId = /* @__PURE__ */ new Map();
|
|
4429
4754
|
for (const service of services) {
|
|
4430
|
-
knownHosts.add(
|
|
4755
|
+
knownHosts.add(import_node_path24.default.basename(service.dir));
|
|
4431
4756
|
knownHosts.add(service.pkg.name);
|
|
4432
|
-
hostToNodeId.set(
|
|
4757
|
+
hostToNodeId.set(import_node_path24.default.basename(service.dir), service.node.id);
|
|
4433
4758
|
hostToNodeId.set(service.pkg.name, service.node.id);
|
|
4434
4759
|
}
|
|
4435
4760
|
let nodesAdded = 0;
|
|
@@ -4439,7 +4764,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4439
4764
|
const seen = /* @__PURE__ */ new Set();
|
|
4440
4765
|
for (const file of files) {
|
|
4441
4766
|
if (isTestPath(file.path)) continue;
|
|
4442
|
-
const parser =
|
|
4767
|
+
const parser = import_node_path24.default.extname(file.path) === ".py" ? pyParser : jsParser;
|
|
4443
4768
|
let sites;
|
|
4444
4769
|
try {
|
|
4445
4770
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -4448,14 +4773,14 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4448
4773
|
continue;
|
|
4449
4774
|
}
|
|
4450
4775
|
if (sites.length === 0) continue;
|
|
4451
|
-
const relFile = toPosix2(
|
|
4776
|
+
const relFile = toPosix2(import_node_path24.default.relative(service.dir, file.path));
|
|
4452
4777
|
for (const site of sites) {
|
|
4453
4778
|
const targetId = hostToNodeId.get(site.host);
|
|
4454
4779
|
if (!targetId || targetId === service.node.id) continue;
|
|
4455
4780
|
const dedupKey = `${relFile}|${targetId}`;
|
|
4456
4781
|
if (seen.has(dedupKey)) continue;
|
|
4457
4782
|
seen.add(dedupKey);
|
|
4458
|
-
const confidence = (0,
|
|
4783
|
+
const confidence = (0, import_types12.confidenceForExtracted)("hostname-shape-match");
|
|
4459
4784
|
const ev = {
|
|
4460
4785
|
file: relFile,
|
|
4461
4786
|
line: site.line,
|
|
@@ -4469,25 +4794,25 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4469
4794
|
);
|
|
4470
4795
|
nodesAdded += n;
|
|
4471
4796
|
edgesAdded += e;
|
|
4472
|
-
if (!(0,
|
|
4797
|
+
if (!(0, import_types12.passesExtractedFloor)(confidence)) {
|
|
4473
4798
|
noteExtractedDropped({
|
|
4474
4799
|
source: fileNodeId,
|
|
4475
4800
|
target: targetId,
|
|
4476
|
-
type:
|
|
4801
|
+
type: import_types12.EdgeType.CALLS,
|
|
4477
4802
|
confidence,
|
|
4478
4803
|
confidenceKind: "hostname-shape-match",
|
|
4479
4804
|
evidence: ev
|
|
4480
4805
|
});
|
|
4481
4806
|
continue;
|
|
4482
4807
|
}
|
|
4483
|
-
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, targetId,
|
|
4808
|
+
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, targetId, import_types12.EdgeType.CALLS);
|
|
4484
4809
|
if (!graph.hasEdge(edgeId)) {
|
|
4485
4810
|
const edge = {
|
|
4486
4811
|
id: edgeId,
|
|
4487
4812
|
source: fileNodeId,
|
|
4488
4813
|
target: targetId,
|
|
4489
|
-
type:
|
|
4490
|
-
provenance:
|
|
4814
|
+
type: import_types12.EdgeType.CALLS,
|
|
4815
|
+
provenance: import_types12.Provenance.EXTRACTED,
|
|
4491
4816
|
confidence,
|
|
4492
4817
|
evidence: ev
|
|
4493
4818
|
};
|
|
@@ -4502,8 +4827,8 @@ async function addHttpCallEdges(graph, services) {
|
|
|
4502
4827
|
|
|
4503
4828
|
// src/extract/calls/kafka.ts
|
|
4504
4829
|
init_cjs_shims();
|
|
4505
|
-
var
|
|
4506
|
-
var
|
|
4830
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
4831
|
+
var import_types13 = require("@neat.is/types");
|
|
4507
4832
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4508
4833
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
4509
4834
|
function findAll(re, text) {
|
|
@@ -4524,7 +4849,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4524
4849
|
seen.add(key);
|
|
4525
4850
|
const line = lineOf(file.content, topic);
|
|
4526
4851
|
out.push({
|
|
4527
|
-
infraId: (0,
|
|
4852
|
+
infraId: (0, import_types13.infraId)("kafka-topic", topic),
|
|
4528
4853
|
name: topic,
|
|
4529
4854
|
kind: "kafka-topic",
|
|
4530
4855
|
edgeType,
|
|
@@ -4533,7 +4858,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4533
4858
|
// tier (ADR-066).
|
|
4534
4859
|
confidenceKind: "verified-call-site",
|
|
4535
4860
|
evidence: {
|
|
4536
|
-
file:
|
|
4861
|
+
file: import_node_path25.default.relative(serviceDir, file.path),
|
|
4537
4862
|
line,
|
|
4538
4863
|
snippet: snippet(file.content, line)
|
|
4539
4864
|
}
|
|
@@ -4546,8 +4871,8 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
4546
4871
|
|
|
4547
4872
|
// src/extract/calls/redis.ts
|
|
4548
4873
|
init_cjs_shims();
|
|
4549
|
-
var
|
|
4550
|
-
var
|
|
4874
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
4875
|
+
var import_types14 = require("@neat.is/types");
|
|
4551
4876
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
4552
4877
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
4553
4878
|
const out = [];
|
|
@@ -4560,7 +4885,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4560
4885
|
seen.add(host);
|
|
4561
4886
|
const line = lineOf(file.content, host);
|
|
4562
4887
|
out.push({
|
|
4563
|
-
infraId: (0,
|
|
4888
|
+
infraId: (0, import_types14.infraId)("redis", host),
|
|
4564
4889
|
name: host,
|
|
4565
4890
|
kind: "redis",
|
|
4566
4891
|
edgeType: "CALLS",
|
|
@@ -4569,7 +4894,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4569
4894
|
// support tier (ADR-066).
|
|
4570
4895
|
confidenceKind: "url-with-structural-support",
|
|
4571
4896
|
evidence: {
|
|
4572
|
-
file:
|
|
4897
|
+
file: import_node_path26.default.relative(serviceDir, file.path),
|
|
4573
4898
|
line,
|
|
4574
4899
|
snippet: snippet(file.content, line)
|
|
4575
4900
|
}
|
|
@@ -4580,8 +4905,8 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
4580
4905
|
|
|
4581
4906
|
// src/extract/calls/aws.ts
|
|
4582
4907
|
init_cjs_shims();
|
|
4583
|
-
var
|
|
4584
|
-
var
|
|
4908
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
4909
|
+
var import_types15 = require("@neat.is/types");
|
|
4585
4910
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4586
4911
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
4587
4912
|
function hasMarker(text, markers) {
|
|
@@ -4605,7 +4930,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4605
4930
|
seen.add(key);
|
|
4606
4931
|
const line = lineOf(file.content, name);
|
|
4607
4932
|
out.push({
|
|
4608
|
-
infraId: (0,
|
|
4933
|
+
infraId: (0, import_types15.infraId)(kind, name),
|
|
4609
4934
|
name,
|
|
4610
4935
|
kind,
|
|
4611
4936
|
edgeType: "CALLS",
|
|
@@ -4614,7 +4939,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4614
4939
|
// (ADR-066).
|
|
4615
4940
|
confidenceKind: "verified-call-site",
|
|
4616
4941
|
evidence: {
|
|
4617
|
-
file:
|
|
4942
|
+
file: import_node_path27.default.relative(serviceDir, file.path),
|
|
4618
4943
|
line,
|
|
4619
4944
|
snippet: snippet(file.content, line)
|
|
4620
4945
|
}
|
|
@@ -4639,8 +4964,8 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
4639
4964
|
|
|
4640
4965
|
// src/extract/calls/grpc.ts
|
|
4641
4966
|
init_cjs_shims();
|
|
4642
|
-
var
|
|
4643
|
-
var
|
|
4967
|
+
var import_node_path28 = __toESM(require("path"), 1);
|
|
4968
|
+
var import_types16 = require("@neat.is/types");
|
|
4644
4969
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
4645
4970
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
4646
4971
|
var GRPC_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@grpc\/grpc-js['"`]|_grpc_pb['"`]/;
|
|
@@ -4689,7 +5014,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4689
5014
|
const { kind } = classified;
|
|
4690
5015
|
const line = lineOf(file.content, m[0]);
|
|
4691
5016
|
out.push({
|
|
4692
|
-
infraId: (0,
|
|
5017
|
+
infraId: (0, import_types16.infraId)(kind, name),
|
|
4693
5018
|
name,
|
|
4694
5019
|
kind,
|
|
4695
5020
|
edgeType: "CALLS",
|
|
@@ -4698,7 +5023,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4698
5023
|
// tier (ADR-066).
|
|
4699
5024
|
confidenceKind: "verified-call-site",
|
|
4700
5025
|
evidence: {
|
|
4701
|
-
file:
|
|
5026
|
+
file: import_node_path28.default.relative(serviceDir, file.path),
|
|
4702
5027
|
line,
|
|
4703
5028
|
snippet: snippet(file.content, line)
|
|
4704
5029
|
}
|
|
@@ -4711,11 +5036,11 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
4711
5036
|
function edgeTypeFromEndpoint(ep) {
|
|
4712
5037
|
switch (ep.edgeType) {
|
|
4713
5038
|
case "PUBLISHES_TO":
|
|
4714
|
-
return
|
|
5039
|
+
return import_types17.EdgeType.PUBLISHES_TO;
|
|
4715
5040
|
case "CONSUMES_FROM":
|
|
4716
|
-
return
|
|
5041
|
+
return import_types17.EdgeType.CONSUMES_FROM;
|
|
4717
5042
|
default:
|
|
4718
|
-
return
|
|
5043
|
+
return import_types17.EdgeType.CALLS;
|
|
4719
5044
|
}
|
|
4720
5045
|
}
|
|
4721
5046
|
function isAwsKind(kind) {
|
|
@@ -4742,7 +5067,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4742
5067
|
if (!graph.hasNode(ep.infraId)) {
|
|
4743
5068
|
const node = {
|
|
4744
5069
|
id: ep.infraId,
|
|
4745
|
-
type:
|
|
5070
|
+
type: import_types17.NodeType.InfraNode,
|
|
4746
5071
|
name: ep.name,
|
|
4747
5072
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
4748
5073
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -4754,7 +5079,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4754
5079
|
nodesAdded++;
|
|
4755
5080
|
}
|
|
4756
5081
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
4757
|
-
const confidence = (0,
|
|
5082
|
+
const confidence = (0, import_types17.confidenceForExtracted)(ep.confidenceKind);
|
|
4758
5083
|
const relFile = toPosix2(ep.evidence.file);
|
|
4759
5084
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
4760
5085
|
graph,
|
|
@@ -4764,7 +5089,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4764
5089
|
);
|
|
4765
5090
|
nodesAdded += n;
|
|
4766
5091
|
edgesAdded += e;
|
|
4767
|
-
if (!(0,
|
|
5092
|
+
if (!(0, import_types17.passesExtractedFloor)(confidence)) {
|
|
4768
5093
|
noteExtractedDropped({
|
|
4769
5094
|
source: fileNodeId,
|
|
4770
5095
|
target: ep.infraId,
|
|
@@ -4784,7 +5109,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
4784
5109
|
source: fileNodeId,
|
|
4785
5110
|
target: ep.infraId,
|
|
4786
5111
|
type: edgeType,
|
|
4787
|
-
provenance:
|
|
5112
|
+
provenance: import_types17.Provenance.EXTRACTED,
|
|
4788
5113
|
confidence,
|
|
4789
5114
|
evidence: ep.evidence
|
|
4790
5115
|
};
|
|
@@ -4809,16 +5134,16 @@ init_cjs_shims();
|
|
|
4809
5134
|
|
|
4810
5135
|
// src/extract/infra/docker-compose.ts
|
|
4811
5136
|
init_cjs_shims();
|
|
4812
|
-
var
|
|
4813
|
-
var
|
|
5137
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
5138
|
+
var import_types19 = require("@neat.is/types");
|
|
4814
5139
|
|
|
4815
5140
|
// src/extract/infra/shared.ts
|
|
4816
5141
|
init_cjs_shims();
|
|
4817
|
-
var
|
|
5142
|
+
var import_types18 = require("@neat.is/types");
|
|
4818
5143
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
4819
5144
|
return {
|
|
4820
|
-
id: (0,
|
|
4821
|
-
type:
|
|
5145
|
+
id: (0, import_types18.infraId)(kind, name),
|
|
5146
|
+
type: import_types18.NodeType.InfraNode,
|
|
4822
5147
|
name,
|
|
4823
5148
|
provider,
|
|
4824
5149
|
kind,
|
|
@@ -4847,7 +5172,7 @@ function dependsOnList(value) {
|
|
|
4847
5172
|
}
|
|
4848
5173
|
function serviceNameToServiceNode(name, services) {
|
|
4849
5174
|
for (const s of services) {
|
|
4850
|
-
if (s.node.name === name ||
|
|
5175
|
+
if (s.node.name === name || import_node_path29.default.basename(s.dir) === name) return s.node.id;
|
|
4851
5176
|
}
|
|
4852
5177
|
return null;
|
|
4853
5178
|
}
|
|
@@ -4856,7 +5181,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4856
5181
|
let edgesAdded = 0;
|
|
4857
5182
|
let composePath = null;
|
|
4858
5183
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
4859
|
-
const abs =
|
|
5184
|
+
const abs = import_node_path29.default.join(scanPath, name);
|
|
4860
5185
|
if (await exists2(abs)) {
|
|
4861
5186
|
composePath = abs;
|
|
4862
5187
|
break;
|
|
@@ -4869,13 +5194,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4869
5194
|
} catch (err) {
|
|
4870
5195
|
recordExtractionError(
|
|
4871
5196
|
"infra docker-compose",
|
|
4872
|
-
|
|
5197
|
+
import_node_path29.default.relative(scanPath, composePath),
|
|
4873
5198
|
err
|
|
4874
5199
|
);
|
|
4875
5200
|
return { nodesAdded, edgesAdded };
|
|
4876
5201
|
}
|
|
4877
5202
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
4878
|
-
const evidenceFile =
|
|
5203
|
+
const evidenceFile = import_node_path29.default.relative(scanPath, composePath).split(import_node_path29.default.sep).join("/");
|
|
4879
5204
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
4880
5205
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
4881
5206
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -4897,15 +5222,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4897
5222
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
4898
5223
|
const targetId = composeNameToNodeId.get(dep);
|
|
4899
5224
|
if (!targetId) continue;
|
|
4900
|
-
const edgeId = (0, import_types5.extractedEdgeId)(sourceId, targetId,
|
|
5225
|
+
const edgeId = (0, import_types5.extractedEdgeId)(sourceId, targetId, import_types19.EdgeType.DEPENDS_ON);
|
|
4901
5226
|
if (graph.hasEdge(edgeId)) continue;
|
|
4902
5227
|
const edge = {
|
|
4903
5228
|
id: edgeId,
|
|
4904
5229
|
source: sourceId,
|
|
4905
5230
|
target: targetId,
|
|
4906
|
-
type:
|
|
4907
|
-
provenance:
|
|
4908
|
-
confidence: (0,
|
|
5231
|
+
type: import_types19.EdgeType.DEPENDS_ON,
|
|
5232
|
+
provenance: import_types19.Provenance.EXTRACTED,
|
|
5233
|
+
confidence: (0, import_types19.confidenceForExtracted)("structural"),
|
|
4909
5234
|
evidence: { file: evidenceFile }
|
|
4910
5235
|
};
|
|
4911
5236
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4917,9 +5242,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
4917
5242
|
|
|
4918
5243
|
// src/extract/infra/dockerfile.ts
|
|
4919
5244
|
init_cjs_shims();
|
|
4920
|
-
var
|
|
4921
|
-
var
|
|
4922
|
-
var
|
|
5245
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
5246
|
+
var import_node_fs17 = require("fs");
|
|
5247
|
+
var import_types20 = require("@neat.is/types");
|
|
4923
5248
|
function runtimeImage(content) {
|
|
4924
5249
|
const lines = content.split("\n");
|
|
4925
5250
|
let last = null;
|
|
@@ -4938,15 +5263,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4938
5263
|
let nodesAdded = 0;
|
|
4939
5264
|
let edgesAdded = 0;
|
|
4940
5265
|
for (const service of services) {
|
|
4941
|
-
const dockerfilePath =
|
|
5266
|
+
const dockerfilePath = import_node_path30.default.join(service.dir, "Dockerfile");
|
|
4942
5267
|
if (!await exists2(dockerfilePath)) continue;
|
|
4943
5268
|
let content;
|
|
4944
5269
|
try {
|
|
4945
|
-
content = await
|
|
5270
|
+
content = await import_node_fs17.promises.readFile(dockerfilePath, "utf8");
|
|
4946
5271
|
} catch (err) {
|
|
4947
5272
|
recordExtractionError(
|
|
4948
5273
|
"infra dockerfile",
|
|
4949
|
-
|
|
5274
|
+
import_node_path30.default.relative(scanPath, dockerfilePath),
|
|
4950
5275
|
err
|
|
4951
5276
|
);
|
|
4952
5277
|
continue;
|
|
@@ -4958,7 +5283,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4958
5283
|
graph.addNode(node.id, node);
|
|
4959
5284
|
nodesAdded++;
|
|
4960
5285
|
}
|
|
4961
|
-
const relDockerfile = toPosix2(
|
|
5286
|
+
const relDockerfile = toPosix2(import_node_path30.default.relative(service.dir, dockerfilePath));
|
|
4962
5287
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
4963
5288
|
graph,
|
|
4964
5289
|
service.pkg.name,
|
|
@@ -4967,17 +5292,17 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4967
5292
|
);
|
|
4968
5293
|
nodesAdded += fn;
|
|
4969
5294
|
edgesAdded += fe;
|
|
4970
|
-
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, node.id,
|
|
5295
|
+
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, node.id, import_types20.EdgeType.RUNS_ON);
|
|
4971
5296
|
if (!graph.hasEdge(edgeId)) {
|
|
4972
5297
|
const edge = {
|
|
4973
5298
|
id: edgeId,
|
|
4974
5299
|
source: fileNodeId,
|
|
4975
5300
|
target: node.id,
|
|
4976
|
-
type:
|
|
4977
|
-
provenance:
|
|
4978
|
-
confidence: (0,
|
|
5301
|
+
type: import_types20.EdgeType.RUNS_ON,
|
|
5302
|
+
provenance: import_types20.Provenance.EXTRACTED,
|
|
5303
|
+
confidence: (0, import_types20.confidenceForExtracted)("structural"),
|
|
4979
5304
|
evidence: {
|
|
4980
|
-
file: toPosix2(
|
|
5305
|
+
file: toPosix2(import_node_path30.default.relative(scanPath, dockerfilePath))
|
|
4981
5306
|
}
|
|
4982
5307
|
};
|
|
4983
5308
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -4989,21 +5314,21 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
4989
5314
|
|
|
4990
5315
|
// src/extract/infra/terraform.ts
|
|
4991
5316
|
init_cjs_shims();
|
|
4992
|
-
var
|
|
4993
|
-
var
|
|
5317
|
+
var import_node_fs18 = require("fs");
|
|
5318
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
4994
5319
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
4995
5320
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
4996
5321
|
if (depth > max) return [];
|
|
4997
5322
|
const out = [];
|
|
4998
|
-
const entries = await
|
|
5323
|
+
const entries = await import_node_fs18.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
4999
5324
|
for (const entry of entries) {
|
|
5000
5325
|
if (entry.isDirectory()) {
|
|
5001
5326
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
5002
|
-
const child =
|
|
5327
|
+
const child = import_node_path31.default.join(start, entry.name);
|
|
5003
5328
|
if (await isPythonVenvDir(child)) continue;
|
|
5004
5329
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
5005
5330
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
5006
|
-
out.push(
|
|
5331
|
+
out.push(import_node_path31.default.join(start, entry.name));
|
|
5007
5332
|
}
|
|
5008
5333
|
}
|
|
5009
5334
|
return out;
|
|
@@ -5012,7 +5337,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
5012
5337
|
let nodesAdded = 0;
|
|
5013
5338
|
const files = await walkTfFiles(scanPath);
|
|
5014
5339
|
for (const file of files) {
|
|
5015
|
-
const content = await
|
|
5340
|
+
const content = await import_node_fs18.promises.readFile(file, "utf8");
|
|
5016
5341
|
RESOURCE_RE.lastIndex = 0;
|
|
5017
5342
|
let m;
|
|
5018
5343
|
while ((m = RESOURCE_RE.exec(content)) !== null) {
|
|
@@ -5030,8 +5355,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
5030
5355
|
|
|
5031
5356
|
// src/extract/infra/k8s.ts
|
|
5032
5357
|
init_cjs_shims();
|
|
5033
|
-
var
|
|
5034
|
-
var
|
|
5358
|
+
var import_node_fs19 = require("fs");
|
|
5359
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
5035
5360
|
var import_yaml3 = require("yaml");
|
|
5036
5361
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
5037
5362
|
Service: "k8s-service",
|
|
@@ -5045,15 +5370,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
5045
5370
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
5046
5371
|
if (depth > max) return [];
|
|
5047
5372
|
const out = [];
|
|
5048
|
-
const entries = await
|
|
5373
|
+
const entries = await import_node_fs19.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
5049
5374
|
for (const entry of entries) {
|
|
5050
5375
|
if (entry.isDirectory()) {
|
|
5051
5376
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5052
|
-
const child =
|
|
5377
|
+
const child = import_node_path32.default.join(start, entry.name);
|
|
5053
5378
|
if (await isPythonVenvDir(child)) continue;
|
|
5054
5379
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
5055
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
5056
|
-
out.push(
|
|
5380
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path32.default.extname(entry.name))) {
|
|
5381
|
+
out.push(import_node_path32.default.join(start, entry.name));
|
|
5057
5382
|
}
|
|
5058
5383
|
}
|
|
5059
5384
|
return out;
|
|
@@ -5062,7 +5387,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
5062
5387
|
let nodesAdded = 0;
|
|
5063
5388
|
const files = await walkYamlFiles2(scanPath);
|
|
5064
5389
|
for (const file of files) {
|
|
5065
|
-
const content = await
|
|
5390
|
+
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
5066
5391
|
let docs;
|
|
5067
5392
|
try {
|
|
5068
5393
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -5097,17 +5422,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
5097
5422
|
}
|
|
5098
5423
|
|
|
5099
5424
|
// src/extract/index.ts
|
|
5100
|
-
var
|
|
5425
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
5101
5426
|
|
|
5102
5427
|
// src/extract/retire.ts
|
|
5103
5428
|
init_cjs_shims();
|
|
5104
|
-
var
|
|
5105
|
-
var
|
|
5106
|
-
var
|
|
5429
|
+
var import_node_fs20 = require("fs");
|
|
5430
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
5431
|
+
var import_types21 = require("@neat.is/types");
|
|
5107
5432
|
function dropOrphanedFileNodes(graph) {
|
|
5108
5433
|
const orphans = [];
|
|
5109
5434
|
graph.forEachNode((id, attrs) => {
|
|
5110
|
-
if (attrs.type !==
|
|
5435
|
+
if (attrs.type !== import_types21.NodeType.FileNode) return;
|
|
5111
5436
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
5112
5437
|
orphans.push(id);
|
|
5113
5438
|
}
|
|
@@ -5120,14 +5445,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
5120
5445
|
const bases = [scanPath, ...serviceDirs];
|
|
5121
5446
|
graph.forEachEdge((id, attrs) => {
|
|
5122
5447
|
const edge = attrs;
|
|
5123
|
-
if (edge.provenance !==
|
|
5448
|
+
if (edge.provenance !== import_types21.Provenance.EXTRACTED) return;
|
|
5124
5449
|
const evidenceFile = edge.evidence?.file;
|
|
5125
5450
|
if (!evidenceFile) return;
|
|
5126
|
-
if (
|
|
5127
|
-
if (!(0,
|
|
5451
|
+
if (import_node_path33.default.isAbsolute(evidenceFile)) {
|
|
5452
|
+
if (!(0, import_node_fs20.existsSync)(evidenceFile)) toDrop.push(id);
|
|
5128
5453
|
return;
|
|
5129
5454
|
}
|
|
5130
|
-
const found = bases.some((base) => (0,
|
|
5455
|
+
const found = bases.some((base) => (0, import_node_fs20.existsSync)(import_node_path33.default.join(base, evidenceFile)));
|
|
5131
5456
|
if (!found) toDrop.push(id);
|
|
5132
5457
|
});
|
|
5133
5458
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -5142,6 +5467,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
5142
5467
|
const services = await discoverServices(scanPath);
|
|
5143
5468
|
const phase1Nodes = addServiceNodes(graph, services);
|
|
5144
5469
|
await addServiceAliases(graph, scanPath, services);
|
|
5470
|
+
const fileEnum = await addFiles(graph, services);
|
|
5471
|
+
const importGraph = await addImports(graph, services);
|
|
5145
5472
|
const phase2 = await addDatabasesAndCompat(graph, services, scanPath);
|
|
5146
5473
|
const phase3 = await addConfigNodes(graph, services, scanPath);
|
|
5147
5474
|
const phase4 = await addCallEdges(graph, services);
|
|
@@ -5165,7 +5492,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
5165
5492
|
}
|
|
5166
5493
|
const droppedEntries = drainDroppedExtracted();
|
|
5167
5494
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
5168
|
-
const rejectedPath =
|
|
5495
|
+
const rejectedPath = import_node_path34.default.join(import_node_path34.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
5169
5496
|
try {
|
|
5170
5497
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
5171
5498
|
} catch (err) {
|
|
@@ -5175,8 +5502,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
5175
5502
|
}
|
|
5176
5503
|
}
|
|
5177
5504
|
const result = {
|
|
5178
|
-
nodesAdded: phase1Nodes + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
|
|
5179
|
-
edgesAdded: phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
|
|
5505
|
+
nodesAdded: phase1Nodes + fileEnum.nodesAdded + importGraph.nodesAdded + phase2.nodesAdded + phase3.nodesAdded + phase4.nodesAdded + phase5.nodesAdded,
|
|
5506
|
+
edgesAdded: fileEnum.edgesAdded + importGraph.edgesAdded + phase2.edgesAdded + phase3.edgesAdded + phase4.edgesAdded + phase5.edgesAdded,
|
|
5180
5507
|
frontiersPromoted,
|
|
5181
5508
|
extractionErrors: errorEntries.length,
|
|
5182
5509
|
errorEntries,
|
|
@@ -5199,7 +5526,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
5199
5526
|
|
|
5200
5527
|
// src/diff.ts
|
|
5201
5528
|
init_cjs_shims();
|
|
5202
|
-
var
|
|
5529
|
+
var import_node_fs21 = require("fs");
|
|
5203
5530
|
async function loadSnapshotForDiff(target) {
|
|
5204
5531
|
if (/^https?:\/\//i.test(target)) {
|
|
5205
5532
|
const res = await fetch(target);
|
|
@@ -5208,7 +5535,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
5208
5535
|
}
|
|
5209
5536
|
return await res.json();
|
|
5210
5537
|
}
|
|
5211
|
-
const raw = await
|
|
5538
|
+
const raw = await import_node_fs21.promises.readFile(target, "utf8");
|
|
5212
5539
|
return JSON.parse(raw);
|
|
5213
5540
|
}
|
|
5214
5541
|
function indexEntries(entries) {
|
|
@@ -5276,9 +5603,9 @@ function canonicalJson(value) {
|
|
|
5276
5603
|
|
|
5277
5604
|
// src/persist.ts
|
|
5278
5605
|
init_cjs_shims();
|
|
5279
|
-
var
|
|
5280
|
-
var
|
|
5281
|
-
var
|
|
5606
|
+
var import_node_fs22 = require("fs");
|
|
5607
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
5608
|
+
var import_types22 = require("@neat.is/types");
|
|
5282
5609
|
var SCHEMA_VERSION = 4;
|
|
5283
5610
|
function migrateV1ToV2(payload) {
|
|
5284
5611
|
const nodes = payload.graph.nodes;
|
|
@@ -5300,12 +5627,12 @@ function migrateV2ToV3(payload) {
|
|
|
5300
5627
|
for (const edge of edges) {
|
|
5301
5628
|
const attrs = edge.attributes;
|
|
5302
5629
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
5303
|
-
attrs.provenance =
|
|
5630
|
+
attrs.provenance = import_types22.Provenance.OBSERVED;
|
|
5304
5631
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
5305
5632
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
5306
5633
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
5307
5634
|
if (type && source && target) {
|
|
5308
|
-
const newId = (0,
|
|
5635
|
+
const newId = (0, import_types22.observedEdgeId)(source, target, type);
|
|
5309
5636
|
attrs.id = newId;
|
|
5310
5637
|
if (edge.key) edge.key = newId;
|
|
5311
5638
|
}
|
|
@@ -5314,7 +5641,7 @@ function migrateV2ToV3(payload) {
|
|
|
5314
5641
|
return { ...payload, schemaVersion: 3 };
|
|
5315
5642
|
}
|
|
5316
5643
|
async function ensureDir(filePath) {
|
|
5317
|
-
await
|
|
5644
|
+
await import_node_fs22.promises.mkdir(import_node_path35.default.dirname(filePath), { recursive: true });
|
|
5318
5645
|
}
|
|
5319
5646
|
async function saveGraphToDisk(graph, outPath) {
|
|
5320
5647
|
await ensureDir(outPath);
|
|
@@ -5324,13 +5651,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
5324
5651
|
graph: graph.export()
|
|
5325
5652
|
};
|
|
5326
5653
|
const tmp = `${outPath}.tmp`;
|
|
5327
|
-
await
|
|
5328
|
-
await
|
|
5654
|
+
await import_node_fs22.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
5655
|
+
await import_node_fs22.promises.rename(tmp, outPath);
|
|
5329
5656
|
}
|
|
5330
5657
|
async function loadGraphFromDisk(graph, outPath) {
|
|
5331
5658
|
let raw;
|
|
5332
5659
|
try {
|
|
5333
|
-
raw = await
|
|
5660
|
+
raw = await import_node_fs22.promises.readFile(outPath, "utf8");
|
|
5334
5661
|
} catch (err) {
|
|
5335
5662
|
if (err.code === "ENOENT") return;
|
|
5336
5663
|
throw err;
|
|
@@ -5389,23 +5716,23 @@ function startPersistLoop(graph, outPath, intervalMs = 6e4) {
|
|
|
5389
5716
|
|
|
5390
5717
|
// src/projects.ts
|
|
5391
5718
|
init_cjs_shims();
|
|
5392
|
-
var
|
|
5719
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
5393
5720
|
function pathsForProject(project, baseDir) {
|
|
5394
5721
|
if (project === DEFAULT_PROJECT) {
|
|
5395
5722
|
return {
|
|
5396
|
-
snapshotPath:
|
|
5397
|
-
errorsPath:
|
|
5398
|
-
staleEventsPath:
|
|
5399
|
-
embeddingsCachePath:
|
|
5400
|
-
policyViolationsPath:
|
|
5723
|
+
snapshotPath: import_node_path36.default.join(baseDir, "graph.json"),
|
|
5724
|
+
errorsPath: import_node_path36.default.join(baseDir, "errors.ndjson"),
|
|
5725
|
+
staleEventsPath: import_node_path36.default.join(baseDir, "stale-events.ndjson"),
|
|
5726
|
+
embeddingsCachePath: import_node_path36.default.join(baseDir, "embeddings.json"),
|
|
5727
|
+
policyViolationsPath: import_node_path36.default.join(baseDir, "policy-violations.ndjson")
|
|
5401
5728
|
};
|
|
5402
5729
|
}
|
|
5403
5730
|
return {
|
|
5404
|
-
snapshotPath:
|
|
5405
|
-
errorsPath:
|
|
5406
|
-
staleEventsPath:
|
|
5407
|
-
embeddingsCachePath:
|
|
5408
|
-
policyViolationsPath:
|
|
5731
|
+
snapshotPath: import_node_path36.default.join(baseDir, `${project}.json`),
|
|
5732
|
+
errorsPath: import_node_path36.default.join(baseDir, `errors.${project}.ndjson`),
|
|
5733
|
+
staleEventsPath: import_node_path36.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
5734
|
+
embeddingsCachePath: import_node_path36.default.join(baseDir, `embeddings.${project}.json`),
|
|
5735
|
+
policyViolationsPath: import_node_path36.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
5409
5736
|
};
|
|
5410
5737
|
}
|
|
5411
5738
|
var Projects = class {
|
|
@@ -5445,23 +5772,23 @@ function parseExtraProjects(raw) {
|
|
|
5445
5772
|
|
|
5446
5773
|
// src/registry.ts
|
|
5447
5774
|
init_cjs_shims();
|
|
5448
|
-
var
|
|
5775
|
+
var import_node_fs23 = require("fs");
|
|
5449
5776
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
5450
|
-
var
|
|
5451
|
-
var
|
|
5777
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
5778
|
+
var import_types23 = require("@neat.is/types");
|
|
5452
5779
|
function neatHome() {
|
|
5453
5780
|
const override = process.env.NEAT_HOME;
|
|
5454
|
-
if (override && override.length > 0) return
|
|
5455
|
-
return
|
|
5781
|
+
if (override && override.length > 0) return import_node_path37.default.resolve(override);
|
|
5782
|
+
return import_node_path37.default.join(import_node_os3.default.homedir(), ".neat");
|
|
5456
5783
|
}
|
|
5457
5784
|
function registryPath() {
|
|
5458
|
-
return
|
|
5785
|
+
return import_node_path37.default.join(neatHome(), "projects.json");
|
|
5459
5786
|
}
|
|
5460
5787
|
async function readRegistry() {
|
|
5461
5788
|
const file = registryPath();
|
|
5462
5789
|
let raw;
|
|
5463
5790
|
try {
|
|
5464
|
-
raw = await
|
|
5791
|
+
raw = await import_node_fs23.promises.readFile(file, "utf8");
|
|
5465
5792
|
} catch (err) {
|
|
5466
5793
|
if (err.code === "ENOENT") {
|
|
5467
5794
|
return { version: 1, projects: [] };
|
|
@@ -5469,7 +5796,7 @@ async function readRegistry() {
|
|
|
5469
5796
|
throw err;
|
|
5470
5797
|
}
|
|
5471
5798
|
const parsed = JSON.parse(raw);
|
|
5472
|
-
return
|
|
5799
|
+
return import_types23.RegistryFileSchema.parse(parsed);
|
|
5473
5800
|
}
|
|
5474
5801
|
async function getProject(name) {
|
|
5475
5802
|
const reg = await readRegistry();
|
|
@@ -5671,11 +5998,11 @@ function registerRoutes(scope, ctx) {
|
|
|
5671
5998
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
5672
5999
|
const parsed = [];
|
|
5673
6000
|
for (const c of candidates) {
|
|
5674
|
-
const r =
|
|
6001
|
+
const r = import_types24.DivergenceTypeSchema.safeParse(c);
|
|
5675
6002
|
if (!r.success) {
|
|
5676
6003
|
return reply.code(400).send({
|
|
5677
6004
|
error: `unknown divergence type "${c}"`,
|
|
5678
|
-
allowed:
|
|
6005
|
+
allowed: import_types24.DivergenceTypeSchema.options
|
|
5679
6006
|
});
|
|
5680
6007
|
}
|
|
5681
6008
|
parsed.push(r.data);
|
|
@@ -5888,7 +6215,7 @@ function registerRoutes(scope, ctx) {
|
|
|
5888
6215
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
5889
6216
|
let violations = await log.readAll();
|
|
5890
6217
|
if (req.query.severity) {
|
|
5891
|
-
const sev =
|
|
6218
|
+
const sev = import_types24.PolicySeveritySchema.safeParse(req.query.severity);
|
|
5892
6219
|
if (!sev.success) {
|
|
5893
6220
|
return reply.code(400).send({
|
|
5894
6221
|
error: "invalid severity",
|
|
@@ -5905,7 +6232,7 @@ function registerRoutes(scope, ctx) {
|
|
|
5905
6232
|
scope.post("/policies/check", async (req, reply) => {
|
|
5906
6233
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
5907
6234
|
if (!proj) return;
|
|
5908
|
-
const parsed =
|
|
6235
|
+
const parsed = import_types24.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
5909
6236
|
if (!parsed.success) {
|
|
5910
6237
|
return reply.code(400).send({
|
|
5911
6238
|
error: "invalid /policies/check body",
|
|
@@ -6147,8 +6474,8 @@ init_otel_grpc();
|
|
|
6147
6474
|
|
|
6148
6475
|
// src/search.ts
|
|
6149
6476
|
init_cjs_shims();
|
|
6150
|
-
var
|
|
6151
|
-
var
|
|
6477
|
+
var import_node_fs24 = require("fs");
|
|
6478
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
6152
6479
|
var import_node_crypto3 = require("crypto");
|
|
6153
6480
|
var DEFAULT_LIMIT = 10;
|
|
6154
6481
|
var NOMIC_DIM = 768;
|
|
@@ -6278,7 +6605,7 @@ async function pickEmbedder() {
|
|
|
6278
6605
|
}
|
|
6279
6606
|
async function readCache(cachePath) {
|
|
6280
6607
|
try {
|
|
6281
|
-
const raw = await
|
|
6608
|
+
const raw = await import_node_fs24.promises.readFile(cachePath, "utf8");
|
|
6282
6609
|
const parsed = JSON.parse(raw);
|
|
6283
6610
|
if (parsed.version !== 1) return null;
|
|
6284
6611
|
return parsed;
|
|
@@ -6287,8 +6614,8 @@ async function readCache(cachePath) {
|
|
|
6287
6614
|
}
|
|
6288
6615
|
}
|
|
6289
6616
|
async function writeCache(cachePath, cache) {
|
|
6290
|
-
await
|
|
6291
|
-
await
|
|
6617
|
+
await import_node_fs24.promises.mkdir(import_node_path40.default.dirname(cachePath), { recursive: true });
|
|
6618
|
+
await import_node_fs24.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
6292
6619
|
}
|
|
6293
6620
|
var VectorIndex = class {
|
|
6294
6621
|
constructor(embedder, cachePath) {
|
|
@@ -6468,14 +6795,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
6468
6795
|
async function main() {
|
|
6469
6796
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
6470
6797
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
6471
|
-
const baseDir = baseDirEnv ?
|
|
6472
|
-
const defaultScanPath =
|
|
6798
|
+
const baseDir = baseDirEnv ? import_node_path41.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path41.default.resolve(import_node_path41.default.dirname(legacyOutPath)) : import_node_path41.default.resolve("./neat-out");
|
|
6799
|
+
const defaultScanPath = import_node_path41.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
|
|
6473
6800
|
const registry = new Projects();
|
|
6474
6801
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
6475
6802
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
6476
6803
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
6477
6804
|
const projectScan = process.env[envKey];
|
|
6478
|
-
await bootProject(registry, name, projectScan ?
|
|
6805
|
+
await bootProject(registry, name, projectScan ? import_node_path41.default.resolve(projectScan) : void 0, baseDir);
|
|
6479
6806
|
}
|
|
6480
6807
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
6481
6808
|
const port = Number(process.env.PORT ?? 8080);
|