@neat.is/core 0.9.1-dev.20260819 → 0.9.2-dev.20260821
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-FCO5Z3RW.js → chunk-ERE47MCR.js} +2 -2
- package/dist/{chunk-UUYCTH2E.js → chunk-GDGUY4T6.js} +34 -2
- package/dist/chunk-GDGUY4T6.js.map +1 -0
- package/dist/{chunk-ICO37D3H.js → chunk-L4SZIIER.js} +3 -3
- package/dist/{chunk-JUVJBH23.js → chunk-RQQUI3NQ.js} +1073 -378
- package/dist/chunk-RQQUI3NQ.js.map +1 -0
- package/dist/cli.cjs +1640 -911
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +1303 -574
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +1319 -590
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-CO47JRIN.js → otel-grpc-Y5K4WGWO.js} +3 -3
- package/dist/server.cjs +1206 -477
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-JUVJBH23.js.map +0 -1
- package/dist/chunk-UUYCTH2E.js.map +0 -1
- /package/dist/{chunk-FCO5Z3RW.js.map → chunk-ERE47MCR.js.map} +0 -0
- /package/dist/{chunk-ICO37D3H.js.map → chunk-L4SZIIER.js.map} +0 -0
- /package/dist/{otel-grpc-CO47JRIN.js.map → otel-grpc-Y5K4WGWO.js.map} +0 -0
package/dist/server.cjs
CHANGED
|
@@ -59,8 +59,8 @@ function mountBearerAuth(app, opts) {
|
|
|
59
59
|
]);
|
|
60
60
|
const publicRead = opts.publicRead === true;
|
|
61
61
|
app.addHook("preHandler", (req, reply, done) => {
|
|
62
|
-
const
|
|
63
|
-
if (exactUnauthPaths.has(
|
|
62
|
+
const path76 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
63
|
+
if (exactUnauthPaths.has(path76) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path76)) {
|
|
64
64
|
done();
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -192,8 +192,8 @@ function reshapeGrpcRequest(req) {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
function resolveProtoRoot() {
|
|
195
|
-
const here =
|
|
196
|
-
return
|
|
195
|
+
const here = import_node_path54.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
196
|
+
return import_node_path54.default.resolve(here, "..", "proto");
|
|
197
197
|
}
|
|
198
198
|
function loadTraceService() {
|
|
199
199
|
const protoRoot = resolveProtoRoot();
|
|
@@ -261,13 +261,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
261
261
|
})
|
|
262
262
|
};
|
|
263
263
|
}
|
|
264
|
-
var import_node_url,
|
|
264
|
+
var import_node_url, import_node_path54, import_node_crypto2, grpc, protoLoader;
|
|
265
265
|
var init_otel_grpc = __esm({
|
|
266
266
|
"src/otel-grpc.ts"() {
|
|
267
267
|
"use strict";
|
|
268
268
|
init_cjs_shims();
|
|
269
269
|
import_node_url = require("url");
|
|
270
|
-
|
|
270
|
+
import_node_path54 = __toESM(require("path"), 1);
|
|
271
271
|
import_node_crypto2 = require("crypto");
|
|
272
272
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
273
273
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -413,8 +413,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
413
413
|
const v = attrs[key];
|
|
414
414
|
if (typeof v === "string" && v.length > 0) {
|
|
415
415
|
const q = v.indexOf("?");
|
|
416
|
-
const
|
|
417
|
-
if (
|
|
416
|
+
const path76 = q === -1 ? v : v.slice(0, q);
|
|
417
|
+
if (path76.length > 0) return path76;
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
420
|
return void 0;
|
|
@@ -476,10 +476,10 @@ function parseOtlpRequest(body) {
|
|
|
476
476
|
return out;
|
|
477
477
|
}
|
|
478
478
|
function loadProtoRoot() {
|
|
479
|
-
const here =
|
|
480
|
-
const protoRoot =
|
|
479
|
+
const here = import_node_path55.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
480
|
+
const protoRoot = import_node_path55.default.resolve(here, "..", "proto");
|
|
481
481
|
const root = new import_protobufjs.default.Root();
|
|
482
|
-
root.resolvePath = (_origin, target) =>
|
|
482
|
+
root.resolvePath = (_origin, target) => import_node_path55.default.resolve(protoRoot, target);
|
|
483
483
|
root.loadSync(
|
|
484
484
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
485
485
|
{ keepCase: true }
|
|
@@ -524,11 +524,42 @@ async function decodeProtobufBody(buf) {
|
|
|
524
524
|
const { reshapeGrpcRequest: reshapeGrpcRequest2 } = await Promise.resolve().then(() => (init_otel_grpc(), otel_grpc_exports));
|
|
525
525
|
return reshapeGrpcRequest2(decoded);
|
|
526
526
|
}
|
|
527
|
+
function decompressorForEncoding(encoding) {
|
|
528
|
+
switch (encoding) {
|
|
529
|
+
case "gzip":
|
|
530
|
+
case "x-gzip":
|
|
531
|
+
return import_node_zlib.default.createGunzip();
|
|
532
|
+
case "deflate":
|
|
533
|
+
return import_node_zlib.default.createInflate();
|
|
534
|
+
default:
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
527
538
|
async function buildOtelReceiver(opts) {
|
|
528
539
|
const app = (0, import_fastify.default)({
|
|
529
540
|
logger: false,
|
|
530
541
|
bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024
|
|
531
542
|
});
|
|
543
|
+
app.addHook("preParsing", (req, _reply, payload, done) => {
|
|
544
|
+
const encoding = (req.headers["content-encoding"] ?? "").toString().trim().toLowerCase();
|
|
545
|
+
if (encoding === "" || encoding === "identity") {
|
|
546
|
+
done(null, payload);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const decompressor = decompressorForEncoding(encoding);
|
|
550
|
+
if (!decompressor) {
|
|
551
|
+
done(null, payload);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const tracked = decompressor;
|
|
555
|
+
tracked.receivedEncodedLength = 0;
|
|
556
|
+
payload.on("data", (chunk) => {
|
|
557
|
+
tracked.receivedEncodedLength = (tracked.receivedEncodedLength ?? 0) + chunk.length;
|
|
558
|
+
});
|
|
559
|
+
payload.on("error", (err) => decompressor.destroy(err));
|
|
560
|
+
payload.pipe(decompressor);
|
|
561
|
+
done(null, decompressor);
|
|
562
|
+
});
|
|
532
563
|
const REJECT_WARN_INTERVAL_MS = 6e4;
|
|
533
564
|
let lastRejectWarnAt = 0;
|
|
534
565
|
const warnRejectedOtlp = () => {
|
|
@@ -710,13 +741,14 @@ async function buildOtelReceiver(opts) {
|
|
|
710
741
|
};
|
|
711
742
|
return decorated;
|
|
712
743
|
}
|
|
713
|
-
var
|
|
744
|
+
var import_node_path55, import_node_url2, import_node_zlib, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
714
745
|
var init_otel = __esm({
|
|
715
746
|
"src/otel.ts"() {
|
|
716
747
|
"use strict";
|
|
717
748
|
init_cjs_shims();
|
|
718
|
-
|
|
749
|
+
import_node_path55 = __toESM(require("path"), 1);
|
|
719
750
|
import_node_url2 = require("url");
|
|
751
|
+
import_node_zlib = __toESM(require("zlib"), 1);
|
|
720
752
|
import_fastify = __toESM(require("fastify"), 1);
|
|
721
753
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
722
754
|
init_auth();
|
|
@@ -731,7 +763,7 @@ var init_otel = __esm({
|
|
|
731
763
|
|
|
732
764
|
// src/server.ts
|
|
733
765
|
init_cjs_shims();
|
|
734
|
-
var
|
|
766
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
735
767
|
|
|
736
768
|
// src/graph.ts
|
|
737
769
|
init_cjs_shims();
|
|
@@ -755,7 +787,7 @@ function getGraph(project = DEFAULT_PROJECT) {
|
|
|
755
787
|
init_cjs_shims();
|
|
756
788
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
757
789
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
758
|
-
var
|
|
790
|
+
var import_types92 = require("@neat.is/types");
|
|
759
791
|
|
|
760
792
|
// src/extend/index.ts
|
|
761
793
|
init_cjs_shims();
|
|
@@ -867,12 +899,12 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
867
899
|
]);
|
|
868
900
|
async function findHookFiles(scanPath) {
|
|
869
901
|
const found = [];
|
|
870
|
-
const
|
|
902
|
+
const walk10 = async (dir) => {
|
|
871
903
|
const entries = await import_node_fs2.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
872
904
|
for (const entry of entries) {
|
|
873
905
|
if (entry.isDirectory()) {
|
|
874
906
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
875
|
-
await
|
|
907
|
+
await walk10(import_node_path2.default.join(dir, entry.name));
|
|
876
908
|
} else if (entry.isFile()) {
|
|
877
909
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
878
910
|
const rel = import_node_path2.default.relative(scanPath, import_node_path2.default.join(dir, entry.name));
|
|
@@ -881,7 +913,7 @@ async function findHookFiles(scanPath) {
|
|
|
881
913
|
}
|
|
882
914
|
}
|
|
883
915
|
};
|
|
884
|
-
await
|
|
916
|
+
await walk10(scanPath);
|
|
885
917
|
return found.sort();
|
|
886
918
|
}
|
|
887
919
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
@@ -2007,6 +2039,7 @@ var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
|
2007
2039
|
var import_tree_sitter_go2 = __toESM(require("tree-sitter-go"), 1);
|
|
2008
2040
|
var import_tree_sitter_ruby = __toESM(require("tree-sitter-ruby"), 1);
|
|
2009
2041
|
var import_tree_sitter_php = __toESM(require("tree-sitter-php"), 1);
|
|
2042
|
+
var import_tree_sitter_rust = __toESM(require("tree-sitter-rust"), 1);
|
|
2010
2043
|
var import_types6 = require("@neat.is/types");
|
|
2011
2044
|
|
|
2012
2045
|
// src/extract/shared.ts
|
|
@@ -2287,7 +2320,7 @@ function buildServiceHostIndex(services) {
|
|
|
2287
2320
|
async function walkSourceFiles(dir, excludeDirs = []) {
|
|
2288
2321
|
const excluded = new Set(excludeDirs.map((d) => import_node_path7.default.resolve(d)));
|
|
2289
2322
|
const out = [];
|
|
2290
|
-
async function
|
|
2323
|
+
async function walk10(current) {
|
|
2291
2324
|
const entries = await import_node_fs7.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2292
2325
|
for (const entry of entries) {
|
|
2293
2326
|
const full = import_node_path7.default.join(current, entry.name);
|
|
@@ -2295,7 +2328,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
2295
2328
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2296
2329
|
if (excluded.has(import_node_path7.default.resolve(full))) continue;
|
|
2297
2330
|
if (await isPythonVenvDir(full)) continue;
|
|
2298
|
-
await
|
|
2331
|
+
await walk10(full);
|
|
2299
2332
|
} else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(import_node_path7.default.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
2300
2333
|
// would attribute our instrumentation imports to the user's service.
|
|
2301
2334
|
!isNeatAuthoredSourceFile(entry.name)) {
|
|
@@ -2303,7 +2336,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
2303
2336
|
}
|
|
2304
2337
|
}
|
|
2305
2338
|
}
|
|
2306
|
-
await
|
|
2339
|
+
await walk10(dir);
|
|
2307
2340
|
return out;
|
|
2308
2341
|
}
|
|
2309
2342
|
async function loadSourceFiles(dir, excludeDirs = []) {
|
|
@@ -2823,6 +2856,11 @@ function makePhpParser() {
|
|
|
2823
2856
|
p.setLanguage(import_tree_sitter_php.default.php_only);
|
|
2824
2857
|
return p;
|
|
2825
2858
|
}
|
|
2859
|
+
function makeRustParser() {
|
|
2860
|
+
const p = new import_tree_sitter2.default();
|
|
2861
|
+
p.setLanguage(import_tree_sitter_rust.default);
|
|
2862
|
+
return p;
|
|
2863
|
+
}
|
|
2826
2864
|
var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
2827
2865
|
"get",
|
|
2828
2866
|
"post",
|
|
@@ -2894,8 +2932,8 @@ function chiRoutesFromSource(source, parser) {
|
|
|
2894
2932
|
chiWalk(tree.rootNode, "", out);
|
|
2895
2933
|
return out;
|
|
2896
2934
|
}
|
|
2897
|
-
function stripChiRegex(
|
|
2898
|
-
return
|
|
2935
|
+
function stripChiRegex(path76) {
|
|
2936
|
+
return path76.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
2899
2937
|
}
|
|
2900
2938
|
function chiWalk(node, prefix, out) {
|
|
2901
2939
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -3567,9 +3605,9 @@ function rubyRocketRoute(args) {
|
|
|
3567
3605
|
if (!pair || pair.type !== "pair") continue;
|
|
3568
3606
|
const k = pair.childForFieldName("key");
|
|
3569
3607
|
if (k?.type !== "string") continue;
|
|
3570
|
-
const
|
|
3571
|
-
if (
|
|
3572
|
-
return { path:
|
|
3608
|
+
const path76 = rubyLiteral(k);
|
|
3609
|
+
if (path76 === null) continue;
|
|
3610
|
+
return { path: path76, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3573
3611
|
}
|
|
3574
3612
|
return null;
|
|
3575
3613
|
}
|
|
@@ -3739,6 +3777,48 @@ function railsRoutesFromSource(source, parser) {
|
|
|
3739
3777
|
});
|
|
3740
3778
|
return out;
|
|
3741
3779
|
}
|
|
3780
|
+
var SINATRA_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head"]);
|
|
3781
|
+
function sinatraRoutesFromSource(source, parser) {
|
|
3782
|
+
const tree = parseSource2(parser, source);
|
|
3783
|
+
if (!fileReferencesSinatra(tree.rootNode)) return [];
|
|
3784
|
+
const out = [];
|
|
3785
|
+
walk(tree.rootNode, (node) => {
|
|
3786
|
+
if (node.type !== "call") return;
|
|
3787
|
+
if (node.childForFieldName("receiver")) return;
|
|
3788
|
+
const method = node.childForFieldName("method")?.text;
|
|
3789
|
+
if (!method || !SINATRA_VERBS.has(method)) return;
|
|
3790
|
+
if (!node.childForFieldName("block")) return;
|
|
3791
|
+
const first = node.childForFieldName("arguments")?.namedChild(0);
|
|
3792
|
+
if (first?.type !== "string") return;
|
|
3793
|
+
const p = rubyLiteral(first);
|
|
3794
|
+
if (p === null || !p.startsWith("/")) return;
|
|
3795
|
+
out.push({
|
|
3796
|
+
method: method.toUpperCase(),
|
|
3797
|
+
pathTemplate: canonicalizeTemplate(p),
|
|
3798
|
+
line: node.startPosition.row + 1,
|
|
3799
|
+
framework: "sinatra"
|
|
3800
|
+
});
|
|
3801
|
+
});
|
|
3802
|
+
return out;
|
|
3803
|
+
}
|
|
3804
|
+
function fileReferencesSinatra(root) {
|
|
3805
|
+
let found = false;
|
|
3806
|
+
walk(root, (node) => {
|
|
3807
|
+
if (found) return;
|
|
3808
|
+
if (node.type === "call") {
|
|
3809
|
+
const m = node.childForFieldName("method")?.text;
|
|
3810
|
+
if (m === "require" || m === "require_relative") {
|
|
3811
|
+
const s = rubyLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3812
|
+
if (s !== null && /^sinatra\b/.test(s)) found = true;
|
|
3813
|
+
}
|
|
3814
|
+
return;
|
|
3815
|
+
}
|
|
3816
|
+
if (node.type === "constant" && node.text === "Sinatra" || node.type === "scope_resolution" && node.text.startsWith("Sinatra")) {
|
|
3817
|
+
found = true;
|
|
3818
|
+
}
|
|
3819
|
+
});
|
|
3820
|
+
return found;
|
|
3821
|
+
}
|
|
3742
3822
|
var LARAVEL_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options"]);
|
|
3743
3823
|
var LARAVEL_RESOURCE_ROWS = [
|
|
3744
3824
|
{ action: "index", methods: ["GET"], suffix: "" },
|
|
@@ -3914,6 +3994,223 @@ function laravelRoutesFromSource(source, parser, basePrefix = "") {
|
|
|
3914
3994
|
}
|
|
3915
3995
|
return out;
|
|
3916
3996
|
}
|
|
3997
|
+
var SLIM_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head"]);
|
|
3998
|
+
function isSlimAppCtor(node) {
|
|
3999
|
+
if (!node) return false;
|
|
4000
|
+
if (node.type === "scoped_call_expression") {
|
|
4001
|
+
const scope = node.childForFieldName("scope")?.text ?? "";
|
|
4002
|
+
const name = node.childForFieldName("name")?.text;
|
|
4003
|
+
return name === "create" && (scope === "AppFactory" || scope.endsWith("\\AppFactory"));
|
|
4004
|
+
}
|
|
4005
|
+
if (node.type === "object_creation_expression") {
|
|
4006
|
+
const cls = node.namedChild(0)?.text ?? "";
|
|
4007
|
+
return cls === "App" || cls.endsWith("\\App") || cls.includes("Slim");
|
|
4008
|
+
}
|
|
4009
|
+
return false;
|
|
4010
|
+
}
|
|
4011
|
+
function isSlimAppType(node) {
|
|
4012
|
+
if (!node || node.type !== "named_type") return false;
|
|
4013
|
+
const text = node.text;
|
|
4014
|
+
return text === "App" || text.endsWith("\\App");
|
|
4015
|
+
}
|
|
4016
|
+
function collectSlimAppVars(root) {
|
|
4017
|
+
const vars = /* @__PURE__ */ new Set();
|
|
4018
|
+
walk(root, (node) => {
|
|
4019
|
+
if (node.type === "assignment_expression") {
|
|
4020
|
+
const left = node.childForFieldName("left");
|
|
4021
|
+
if (left?.type === "variable_name" && isSlimAppCtor(node.childForFieldName("right"))) {
|
|
4022
|
+
vars.add(left.text);
|
|
4023
|
+
}
|
|
4024
|
+
return;
|
|
4025
|
+
}
|
|
4026
|
+
if (node.type === "simple_parameter" && isSlimAppType(node.childForFieldName("type"))) {
|
|
4027
|
+
const name = node.childForFieldName("name");
|
|
4028
|
+
if (name?.type === "variable_name") vars.add(name.text);
|
|
4029
|
+
}
|
|
4030
|
+
});
|
|
4031
|
+
return vars;
|
|
4032
|
+
}
|
|
4033
|
+
function slimClosureParamVars(closure) {
|
|
4034
|
+
const out = ["$this"];
|
|
4035
|
+
for (let i = 0; i < closure.namedChildCount; i++) {
|
|
4036
|
+
const params = closure.namedChild(i);
|
|
4037
|
+
if (params?.type !== "formal_parameters") continue;
|
|
4038
|
+
for (let j = 0; j < params.namedChildCount; j++) {
|
|
4039
|
+
const param = params.namedChild(j);
|
|
4040
|
+
if (param?.type !== "simple_parameter") continue;
|
|
4041
|
+
for (let k = 0; k < param.namedChildCount; k++) {
|
|
4042
|
+
const v = param.namedChild(k);
|
|
4043
|
+
if (v?.type === "variable_name") {
|
|
4044
|
+
out.push(v.text);
|
|
4045
|
+
break;
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
return out;
|
|
4051
|
+
}
|
|
4052
|
+
function phpStringArray(node) {
|
|
4053
|
+
const out = [];
|
|
4054
|
+
if (node?.type !== "array_creation_expression") return out;
|
|
4055
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4056
|
+
const el = node.namedChild(i);
|
|
4057
|
+
if (el?.type !== "array_element_initializer") continue;
|
|
4058
|
+
const s = phpStaticString(el.namedChild(0));
|
|
4059
|
+
if (s !== null) out.push(s);
|
|
4060
|
+
}
|
|
4061
|
+
return out;
|
|
4062
|
+
}
|
|
4063
|
+
function slimRoutesFromSource(source, parser) {
|
|
4064
|
+
const tree = parseSource2(parser, source);
|
|
4065
|
+
const appVars = collectSlimAppVars(tree.rootNode);
|
|
4066
|
+
if (appVars.size === 0) return [];
|
|
4067
|
+
const out = [];
|
|
4068
|
+
slimWalk(tree.rootNode, "", appVars, out);
|
|
4069
|
+
return out;
|
|
4070
|
+
}
|
|
4071
|
+
function slimWalk(node, prefix, appVars, out) {
|
|
4072
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4073
|
+
const child = node.namedChild(i);
|
|
4074
|
+
if (child) slimHandle(child, prefix, appVars, out);
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
function slimHandle(node, prefix, appVars, out) {
|
|
4078
|
+
if (node.type === "member_call_expression") {
|
|
4079
|
+
const obj = node.childForFieldName("object");
|
|
4080
|
+
const method = node.childForFieldName("name")?.text;
|
|
4081
|
+
const args = node.childForFieldName("arguments");
|
|
4082
|
+
if (obj?.type === "variable_name" && method && appVars.has(obj.text)) {
|
|
4083
|
+
const line = node.startPosition.row + 1;
|
|
4084
|
+
if (method === "group") {
|
|
4085
|
+
const groupPrefix = phpFirstString(args);
|
|
4086
|
+
const closure = laravelGroupClosure(args);
|
|
4087
|
+
if (groupPrefix !== null && closure) {
|
|
4088
|
+
const inner = new Set(appVars);
|
|
4089
|
+
for (const v of slimClosureParamVars(closure)) inner.add(v);
|
|
4090
|
+
const body = closure.childForFieldName("body");
|
|
4091
|
+
if (body) slimWalk(body, laravelJoinPath(prefix, groupPrefix), inner, out);
|
|
4092
|
+
}
|
|
4093
|
+
return;
|
|
4094
|
+
}
|
|
4095
|
+
if (SLIM_VERBS.has(method)) {
|
|
4096
|
+
const p = phpFirstString(args);
|
|
4097
|
+
if (p !== null) {
|
|
4098
|
+
out.push({
|
|
4099
|
+
method: method.toUpperCase(),
|
|
4100
|
+
pathTemplate: laravelJoinPath(prefix, p),
|
|
4101
|
+
line,
|
|
4102
|
+
framework: "slim"
|
|
4103
|
+
});
|
|
4104
|
+
}
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
4107
|
+
if (method === "any") {
|
|
4108
|
+
const p = phpFirstString(args);
|
|
4109
|
+
if (p !== null) {
|
|
4110
|
+
out.push({ method: "ALL", pathTemplate: laravelJoinPath(prefix, p), line, framework: "slim" });
|
|
4111
|
+
}
|
|
4112
|
+
return;
|
|
4113
|
+
}
|
|
4114
|
+
if (method === "map") {
|
|
4115
|
+
const vals = phpArgumentValues(args);
|
|
4116
|
+
const methods = phpStringArray(vals[0]);
|
|
4117
|
+
const p = vals.length > 1 ? phpStaticString(vals[1]) : null;
|
|
4118
|
+
if (p !== null) {
|
|
4119
|
+
for (const m of methods) {
|
|
4120
|
+
out.push({
|
|
4121
|
+
method: m.toUpperCase(),
|
|
4122
|
+
pathTemplate: laravelJoinPath(prefix, p),
|
|
4123
|
+
line,
|
|
4124
|
+
framework: "slim"
|
|
4125
|
+
});
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
return;
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
}
|
|
4132
|
+
slimWalk(node, prefix, appVars, out);
|
|
4133
|
+
}
|
|
4134
|
+
var ACTIX_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "head", "options", "trace"]);
|
|
4135
|
+
function rustStringContent(node) {
|
|
4136
|
+
if (!node || node.type !== "string_literal") return null;
|
|
4137
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4138
|
+
if (node.namedChild(i)?.type === "string_content") return node.namedChild(i).text;
|
|
4139
|
+
}
|
|
4140
|
+
return "";
|
|
4141
|
+
}
|
|
4142
|
+
function actixRoutesFromSource(source, parser) {
|
|
4143
|
+
const tree = parseSource2(parser, source);
|
|
4144
|
+
const out = [];
|
|
4145
|
+
walk(tree.rootNode, (node) => {
|
|
4146
|
+
if (node.type === "attribute_item") {
|
|
4147
|
+
actixAttributeRoute(node, out);
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4150
|
+
if (node.type === "call_expression") {
|
|
4151
|
+
actixBuilderRoute(node, out);
|
|
4152
|
+
}
|
|
4153
|
+
});
|
|
4154
|
+
return out;
|
|
4155
|
+
}
|
|
4156
|
+
function actixAttributeRoute(attrItem, out) {
|
|
4157
|
+
const attr = attrItem.namedChild(0);
|
|
4158
|
+
if (!attr || attr.type !== "attribute") return;
|
|
4159
|
+
const nameNode = attr.namedChild(0);
|
|
4160
|
+
if (!nameNode) return;
|
|
4161
|
+
const macro = nameNode.type === "identifier" ? nameNode.text : nameNode.type === "scoped_identifier" ? nameNode.childForFieldName("name")?.text ?? null : null;
|
|
4162
|
+
if (!macro) return;
|
|
4163
|
+
const tokens = attr.childForFieldName("arguments");
|
|
4164
|
+
if (!tokens || tokens.type !== "token_tree") return;
|
|
4165
|
+
const strings = [];
|
|
4166
|
+
for (let i = 0; i < tokens.namedChildCount; i++) {
|
|
4167
|
+
const s = rustStringContent(tokens.namedChild(i));
|
|
4168
|
+
if (s !== null) strings.push(s);
|
|
4169
|
+
}
|
|
4170
|
+
const pathStr = strings[0];
|
|
4171
|
+
if (pathStr === void 0 || !pathStr.startsWith("/")) return;
|
|
4172
|
+
const line = attrItem.startPosition.row + 1;
|
|
4173
|
+
const template = canonicalizeTemplate(pathStr);
|
|
4174
|
+
if (ACTIX_METHODS.has(macro)) {
|
|
4175
|
+
out.push({ method: macro.toUpperCase(), pathTemplate: template, line, framework: "actix-web" });
|
|
4176
|
+
return;
|
|
4177
|
+
}
|
|
4178
|
+
if (macro === "route") {
|
|
4179
|
+
const methods = strings.slice(1).filter((m) => ACTIX_METHODS.has(m.toLowerCase()));
|
|
4180
|
+
const list = methods.length > 0 ? methods.map((m) => m.toUpperCase()) : ["ALL"];
|
|
4181
|
+
for (const m of list) {
|
|
4182
|
+
out.push({ method: m, pathTemplate: template, line, framework: "actix-web" });
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
function actixBuilderRoute(call, out) {
|
|
4187
|
+
const fn = call.childForFieldName("function");
|
|
4188
|
+
if (fn?.type !== "field_expression") return;
|
|
4189
|
+
if (fn.childForFieldName("field")?.text !== "route") return;
|
|
4190
|
+
const args = call.childForFieldName("arguments");
|
|
4191
|
+
const pathStr = rustStringContent(args?.namedChild(0));
|
|
4192
|
+
if (pathStr === null || !pathStr.startsWith("/")) return;
|
|
4193
|
+
const second = args?.namedChild(1);
|
|
4194
|
+
if (!second) return;
|
|
4195
|
+
const method = actixBuilderMethod(second);
|
|
4196
|
+
if (!method) return;
|
|
4197
|
+
out.push({
|
|
4198
|
+
method,
|
|
4199
|
+
pathTemplate: canonicalizeTemplate(pathStr),
|
|
4200
|
+
line: call.startPosition.row + 1,
|
|
4201
|
+
framework: "actix-web"
|
|
4202
|
+
});
|
|
4203
|
+
}
|
|
4204
|
+
function actixBuilderMethod(node) {
|
|
4205
|
+
let method = null;
|
|
4206
|
+
walk(node, (n) => {
|
|
4207
|
+
if (method || n.type !== "scoped_identifier") return;
|
|
4208
|
+
const verb = n.childForFieldName("name")?.text;
|
|
4209
|
+
const scopeLeaf = n.childForFieldName("path")?.text?.split("::").pop();
|
|
4210
|
+
if (scopeLeaf === "web" && verb && ACTIX_METHODS.has(verb)) method = verb.toUpperCase();
|
|
4211
|
+
});
|
|
4212
|
+
return method;
|
|
4213
|
+
}
|
|
3917
4214
|
function namedArgs(argsNode) {
|
|
3918
4215
|
const out = [];
|
|
3919
4216
|
if (!argsNode) return out;
|
|
@@ -4230,6 +4527,7 @@ async function addRoutes(graph, services) {
|
|
|
4230
4527
|
const goParser = makeGoParser2();
|
|
4231
4528
|
const rubyParser = makeRubyParser();
|
|
4232
4529
|
const phpParser = makePhpParser();
|
|
4530
|
+
const rustParser = makeRustParser();
|
|
4233
4531
|
let nodesAdded = 0;
|
|
4234
4532
|
let edgesAdded = 0;
|
|
4235
4533
|
for (const service of services) {
|
|
@@ -4252,7 +4550,10 @@ async function addRoutes(graph, services) {
|
|
|
4252
4550
|
const isGoService = service.node.language === "go";
|
|
4253
4551
|
const hasRails = deps["rails"] !== void 0;
|
|
4254
4552
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4255
|
-
|
|
4553
|
+
const hasSlim = deps["slim/slim"] !== void 0;
|
|
4554
|
+
const hasSinatra = deps["sinatra"] !== void 0;
|
|
4555
|
+
const hasActix = deps["actix-web"] !== void 0;
|
|
4556
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel && !hasSlim && !hasSinatra && !hasActix)
|
|
4256
4557
|
continue;
|
|
4257
4558
|
const files = await loadSourceFiles(service.dir, service.excludeDirs);
|
|
4258
4559
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4263,7 +4564,8 @@ async function addRoutes(graph, services) {
|
|
|
4263
4564
|
const isGo = ext === ".go";
|
|
4264
4565
|
const isRb = ext === ".rb";
|
|
4265
4566
|
const isPhp = ext === ".php";
|
|
4266
|
-
|
|
4567
|
+
const isRs = ext === ".rs";
|
|
4568
|
+
if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy && !isGo && !isRb && !isPhp && !isRs) continue;
|
|
4267
4569
|
const relFile = toPosix(import_node_path9.default.relative(service.dir, file.path));
|
|
4268
4570
|
let routes;
|
|
4269
4571
|
try {
|
|
@@ -4273,8 +4575,12 @@ async function addRoutes(graph, services) {
|
|
|
4273
4575
|
phpParser,
|
|
4274
4576
|
relFile === "routes/api.php" ? "/api" : ""
|
|
4275
4577
|
) : [];
|
|
4578
|
+
if (hasSlim) routes = routes.concat(slimRoutesFromSource(file.content, phpParser));
|
|
4276
4579
|
} else if (isRb) {
|
|
4277
4580
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4581
|
+
if (hasSinatra) routes = routes.concat(sinatraRoutesFromSource(file.content, rubyParser));
|
|
4582
|
+
} else if (isRs) {
|
|
4583
|
+
routes = hasActix ? actixRoutesFromSource(file.content, rustParser) : [];
|
|
4278
4584
|
} else if (isGo) {
|
|
4279
4585
|
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4280
4586
|
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
@@ -4458,6 +4764,37 @@ function loadIncidentThresholdsFromEnv() {
|
|
|
4458
4764
|
return DEFAULT_INCIDENT_THRESHOLDS;
|
|
4459
4765
|
}
|
|
4460
4766
|
}
|
|
4767
|
+
var DEFAULT_LATENCY_STREAM_CEILING_MS = 6e4;
|
|
4768
|
+
function latencyStreamCeilingMs() {
|
|
4769
|
+
const raw = process.env.NEAT_LATENCY_STREAM_CEILING_MS;
|
|
4770
|
+
if (!raw) return DEFAULT_LATENCY_STREAM_CEILING_MS;
|
|
4771
|
+
const n = Number(raw);
|
|
4772
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
4773
|
+
console.warn(
|
|
4774
|
+
`[neat] NEAT_LATENCY_STREAM_CEILING_MS could not be parsed (${raw}); using default`
|
|
4775
|
+
);
|
|
4776
|
+
return DEFAULT_LATENCY_STREAM_CEILING_MS;
|
|
4777
|
+
}
|
|
4778
|
+
function spanServesEventStream(attrs) {
|
|
4779
|
+
for (const key of [
|
|
4780
|
+
"http.response.header.content-type",
|
|
4781
|
+
"http.response.header.content_type"
|
|
4782
|
+
]) {
|
|
4783
|
+
const v = attrs[key];
|
|
4784
|
+
const values = Array.isArray(v) ? v : v !== void 0 && v !== null ? [v] : [];
|
|
4785
|
+
for (const item of values) {
|
|
4786
|
+
if (typeof item === "string" && item.toLowerCase().includes("text/event-stream")) {
|
|
4787
|
+
return true;
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
return false;
|
|
4792
|
+
}
|
|
4793
|
+
function spanIsStreaming(span, ceilingMs = latencyStreamCeilingMs()) {
|
|
4794
|
+
if (span.websocketChannel !== void 0) return true;
|
|
4795
|
+
if (spanServesEventStream(span.attributes)) return true;
|
|
4796
|
+
return span.durationNanos > BigInt(Math.round(ceilingMs)) * 1000000n;
|
|
4797
|
+
}
|
|
4461
4798
|
function httpResponseStatusFromAttrs(attrs) {
|
|
4462
4799
|
for (const key of ["http.response.status_code", "http.status_code"]) {
|
|
4463
4800
|
const v = attrs[key];
|
|
@@ -4509,6 +4846,14 @@ function grpcStatusCodeFromAttrs(attrs) {
|
|
|
4509
4846
|
}
|
|
4510
4847
|
return void 0;
|
|
4511
4848
|
}
|
|
4849
|
+
function spanRecordsError(span) {
|
|
4850
|
+
if (span.statusCode === 2) return true;
|
|
4851
|
+
const grpc2 = grpcStatusCodeFromAttrs(span.attributes);
|
|
4852
|
+
if (grpc2 !== void 0 && grpc2 !== 0) return true;
|
|
4853
|
+
const httpStatus = httpResponseStatusFromAttrs(span.attributes);
|
|
4854
|
+
if (httpStatus !== void 0 && httpStatus >= 500) return true;
|
|
4855
|
+
return false;
|
|
4856
|
+
}
|
|
4512
4857
|
function nonHttpFailureMessageFromAttrs(attrs) {
|
|
4513
4858
|
const grpc2 = grpcStatusCodeFromAttrs(attrs);
|
|
4514
4859
|
if (grpc2 !== void 0 && grpc2 !== 0) {
|
|
@@ -5282,6 +5627,21 @@ async function recordExceptionIncident(ctx, span, ts) {
|
|
|
5282
5627
|
};
|
|
5283
5628
|
await appendErrorEvent(ctx, ev);
|
|
5284
5629
|
}
|
|
5630
|
+
async function recordGrpcFailureIncident(ctx, span, ts) {
|
|
5631
|
+
const attrs = sanitizeAttributes(span.attributes);
|
|
5632
|
+
const ev = {
|
|
5633
|
+
id: `${span.traceId}:${span.spanId}`,
|
|
5634
|
+
timestamp: ts,
|
|
5635
|
+
service: span.service,
|
|
5636
|
+
traceId: span.traceId,
|
|
5637
|
+
spanId: span.spanId,
|
|
5638
|
+
errorType: "grpc-failure",
|
|
5639
|
+
errorMessage: incidentMessage(span),
|
|
5640
|
+
...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
|
|
5641
|
+
affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
|
|
5642
|
+
};
|
|
5643
|
+
await appendErrorEvent(ctx, ev);
|
|
5644
|
+
}
|
|
5285
5645
|
async function advance4xxBurst(ctx, span, affectedNode, ts, nowMs, status2) {
|
|
5286
5646
|
const { threshold, windowMs } = loadIncidentThresholdsFromEnv();
|
|
5287
5647
|
if (!ctx.burstState) ctx.burstState = /* @__PURE__ */ new Map();
|
|
@@ -5325,6 +5685,12 @@ async function advance4xxBurst(ctx, span, affectedNode, ts, nowMs, status2) {
|
|
|
5325
5685
|
);
|
|
5326
5686
|
ctx.burstState.delete(key);
|
|
5327
5687
|
}
|
|
5688
|
+
var NEXT_API_ROUTE_SPAN_NAME = /^executing api route \((?:pages|app)\) (\/\S*)$/;
|
|
5689
|
+
function nextApiRouteTemplate(span) {
|
|
5690
|
+
const raw = pickAttr(span, "next.span_name") ?? span.name;
|
|
5691
|
+
const match = raw ? NEXT_API_ROUTE_SPAN_NAME.exec(raw) : null;
|
|
5692
|
+
return match ? match[1] : void 0;
|
|
5693
|
+
}
|
|
5328
5694
|
function findRouteNodeByHttpRoute(graph, serviceName, method, httpRoute) {
|
|
5329
5695
|
const target = normalizePathTemplate(httpRoute);
|
|
5330
5696
|
const m = method?.toUpperCase();
|
|
@@ -5346,8 +5712,8 @@ async function handleSpan(ctx, span) {
|
|
|
5346
5712
|
warnUnidentifiedSpan(ctx.project ?? DEFAULT_PROJECT);
|
|
5347
5713
|
}
|
|
5348
5714
|
const sourceId = ensureServiceNode(ctx.graph, span.service, env);
|
|
5349
|
-
const isError = span
|
|
5350
|
-
const durationMs = span.durationNanos > 0n ? Number(span.durationNanos) / 1e6 : void 0;
|
|
5715
|
+
const isError = spanRecordsError(span);
|
|
5716
|
+
const durationMs = span.durationNanos > 0n && !spanIsStreaming(span) ? Number(span.durationNanos) / 1e6 : void 0;
|
|
5351
5717
|
const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId);
|
|
5352
5718
|
const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath);
|
|
5353
5719
|
cacheSpanService(span, nowMs, callSite);
|
|
@@ -5544,12 +5910,13 @@ async function handleSpan(ctx, span) {
|
|
|
5544
5910
|
}
|
|
5545
5911
|
}
|
|
5546
5912
|
}
|
|
5547
|
-
|
|
5913
|
+
const fusionRoute = nextApiRouteTemplate(span) ?? span.httpRoute;
|
|
5914
|
+
if (fusionRoute && (span.kind === 2 || span.kind === 1 || span.kind === 0 || span.kind === void 0)) {
|
|
5548
5915
|
const routeNodeId = findRouteNodeByHttpRoute(
|
|
5549
5916
|
ctx.graph,
|
|
5550
5917
|
span.service,
|
|
5551
5918
|
span.httpMethod,
|
|
5552
|
-
|
|
5919
|
+
fusionRoute
|
|
5553
5920
|
);
|
|
5554
5921
|
if (routeNodeId) {
|
|
5555
5922
|
const routeSvc = ctx.graph.getNodeAttributes(routeNodeId).service;
|
|
@@ -5581,10 +5948,13 @@ async function handleSpan(ctx, span) {
|
|
|
5581
5948
|
}
|
|
5582
5949
|
if (span.statusCode !== 2) {
|
|
5583
5950
|
const status2 = httpResponseStatus(span);
|
|
5951
|
+
const grpcStatus = grpcStatusCodeFromAttrs(span.attributes);
|
|
5584
5952
|
if (span.exception) {
|
|
5585
5953
|
await recordExceptionIncident(ctx, span, ts);
|
|
5586
5954
|
} else if (status2 !== void 0 && status2 >= 500) {
|
|
5587
5955
|
await recordFailingResponseIncident(ctx, span, sourceId, ts, status2, 1);
|
|
5956
|
+
} else if (grpcStatus !== void 0 && grpcStatus !== 0) {
|
|
5957
|
+
await recordGrpcFailureIncident(ctx, span, ts);
|
|
5588
5958
|
} else if (status2 !== void 0 && status2 >= 400 && spanMintsObservedEdge(span.kind)) {
|
|
5589
5959
|
await advance4xxBurst(ctx, span, sourceId, ts, nowMs, status2);
|
|
5590
5960
|
}
|
|
@@ -5953,19 +6323,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
5953
6323
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
5954
6324
|
let best = { path: [start], edges: [] };
|
|
5955
6325
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
5956
|
-
function step(node,
|
|
5957
|
-
if (
|
|
5958
|
-
best = { path: [...
|
|
6326
|
+
function step(node, path76, edges) {
|
|
6327
|
+
if (path76.length > best.path.length) {
|
|
6328
|
+
best = { path: [...path76], edges: [...edges] };
|
|
5959
6329
|
}
|
|
5960
|
-
if (
|
|
6330
|
+
if (path76.length - 1 >= maxDepth) return;
|
|
5961
6331
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
5962
6332
|
for (const [srcId, edge] of incoming) {
|
|
5963
6333
|
if (visited.has(srcId)) continue;
|
|
5964
6334
|
visited.add(srcId);
|
|
5965
|
-
|
|
6335
|
+
path76.push(srcId);
|
|
5966
6336
|
edges.push(edge);
|
|
5967
|
-
step(srcId,
|
|
5968
|
-
|
|
6337
|
+
step(srcId, path76, edges);
|
|
6338
|
+
path76.pop();
|
|
5969
6339
|
edges.pop();
|
|
5970
6340
|
visited.delete(srcId);
|
|
5971
6341
|
}
|
|
@@ -5973,11 +6343,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
5973
6343
|
step(start, [start], []);
|
|
5974
6344
|
return best;
|
|
5975
6345
|
}
|
|
5976
|
-
function databaseRootCauseShape(graph, origin,
|
|
6346
|
+
function databaseRootCauseShape(graph, origin, walk10) {
|
|
5977
6347
|
const targetDb = origin;
|
|
5978
6348
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
5979
6349
|
if (candidatePairs.length === 0) return null;
|
|
5980
|
-
for (const id of
|
|
6350
|
+
for (const id of walk10.path) {
|
|
5981
6351
|
const owner = resolveOwningService(graph, id);
|
|
5982
6352
|
if (!owner) continue;
|
|
5983
6353
|
const { id: serviceId15, svc } = owner;
|
|
@@ -6004,8 +6374,8 @@ function databaseRootCauseShape(graph, origin, walk9) {
|
|
|
6004
6374
|
}
|
|
6005
6375
|
return null;
|
|
6006
6376
|
}
|
|
6007
|
-
function serviceRootCauseShape(graph, _origin,
|
|
6008
|
-
for (const id of
|
|
6377
|
+
function serviceRootCauseShape(graph, _origin, walk10) {
|
|
6378
|
+
for (const id of walk10.path) {
|
|
6009
6379
|
const owner = resolveOwningService(graph, id);
|
|
6010
6380
|
if (!owner) continue;
|
|
6011
6381
|
const { id: serviceId15, svc } = owner;
|
|
@@ -6041,15 +6411,15 @@ function serviceRootCauseShape(graph, _origin, walk9) {
|
|
|
6041
6411
|
}
|
|
6042
6412
|
return null;
|
|
6043
6413
|
}
|
|
6044
|
-
function fileRootCauseShape(graph, origin,
|
|
6414
|
+
function fileRootCauseShape(graph, origin, walk10) {
|
|
6045
6415
|
const owner = resolveOwningService(graph, origin.id);
|
|
6046
6416
|
if (!owner) return null;
|
|
6047
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
6417
|
+
return serviceRootCauseShape(graph, owner.svc, walk10);
|
|
6048
6418
|
}
|
|
6049
|
-
function symbolRootCauseShape(graph, origin,
|
|
6419
|
+
function symbolRootCauseShape(graph, origin, walk10) {
|
|
6050
6420
|
const owner = resolveOwningService(graph, origin.id);
|
|
6051
6421
|
if (!owner) return null;
|
|
6052
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
6422
|
+
return serviceRootCauseShape(graph, owner.svc, walk10);
|
|
6053
6423
|
}
|
|
6054
6424
|
var rootCauseShapes = {
|
|
6055
6425
|
[import_types8.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -6062,25 +6432,29 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
6062
6432
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
6063
6433
|
const shape = rootCauseShapes[origin.type];
|
|
6064
6434
|
if (shape) {
|
|
6065
|
-
const
|
|
6066
|
-
const match = shape(graph, origin,
|
|
6435
|
+
const walk10 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
6436
|
+
const match = shape(graph, origin, walk10);
|
|
6067
6437
|
if (match) {
|
|
6068
6438
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
6069
|
-
return
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6439
|
+
return {
|
|
6440
|
+
source: "compat",
|
|
6441
|
+
result: import_types8.RootCauseResultSchema.parse({
|
|
6442
|
+
rootCauseNode: match.rootCauseNode,
|
|
6443
|
+
rootCauseReason: reason,
|
|
6444
|
+
traversalPath: walk10.path,
|
|
6445
|
+
edgeProvenances: walk10.edges.map((e) => e.provenance),
|
|
6446
|
+
confidence: confidenceFromMix(walk10.edges),
|
|
6447
|
+
fixRecommendation: match.fixRecommendation
|
|
6448
|
+
})
|
|
6449
|
+
};
|
|
6077
6450
|
}
|
|
6078
6451
|
}
|
|
6079
6452
|
if (origin.type === import_types8.NodeType.ServiceNode) {
|
|
6080
6453
|
const crossService = crossServiceRootCause(graph, errorNodeId, incidents, errorEvent);
|
|
6081
|
-
if (crossService) return crossService;
|
|
6454
|
+
if (crossService) return { result: crossService, source: "cross-service" };
|
|
6082
6455
|
}
|
|
6083
|
-
|
|
6456
|
+
const incident = rootCauseFromIncidents(errorNodeId, incidents, errorEvent);
|
|
6457
|
+
return incident ? { result: incident, source: "incident" } : null;
|
|
6084
6458
|
}
|
|
6085
6459
|
var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
|
|
6086
6460
|
function incidentMatchesNode(ev, nodeId) {
|
|
@@ -6176,26 +6550,75 @@ function dominantFailingCall(graph, serviceId15, visited) {
|
|
|
6176
6550
|
return best;
|
|
6177
6551
|
}
|
|
6178
6552
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
6179
|
-
const
|
|
6553
|
+
const path76 = [originServiceId];
|
|
6180
6554
|
const edges = [];
|
|
6181
6555
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
6182
6556
|
let current = originServiceId;
|
|
6183
6557
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
6184
6558
|
const hop = dominantFailingCall(graph, current, visited);
|
|
6185
6559
|
if (!hop) break;
|
|
6186
|
-
|
|
6560
|
+
path76.push(hop.nextService);
|
|
6561
|
+
edges.push(hop.edge);
|
|
6562
|
+
visited.add(hop.nextService);
|
|
6563
|
+
current = hop.nextService;
|
|
6564
|
+
}
|
|
6565
|
+
if (edges.length === 0) return null;
|
|
6566
|
+
return { path: path76, edges, culprit: current };
|
|
6567
|
+
}
|
|
6568
|
+
function isStaleCallEdge(e) {
|
|
6569
|
+
return e.type === import_types8.EdgeType.CALLS && e.provenance === import_types8.Provenance.STALE;
|
|
6570
|
+
}
|
|
6571
|
+
function staleCallDominates(e, id, curEdge, curId) {
|
|
6572
|
+
const ev = e.signal?.spanCount ?? e.callCount ?? 0;
|
|
6573
|
+
const cv = curEdge.signal?.spanCount ?? curEdge.callCount ?? 0;
|
|
6574
|
+
if (ev !== cv) return ev > cv;
|
|
6575
|
+
return id < curId;
|
|
6576
|
+
}
|
|
6577
|
+
function dominantStaleCall(graph, serviceId15, visited) {
|
|
6578
|
+
const bestByCallee = /* @__PURE__ */ new Map();
|
|
6579
|
+
for (const src of callSourcesForService(graph, serviceId15)) {
|
|
6580
|
+
for (const edgeId of graph.outboundEdges(src)) {
|
|
6581
|
+
const e = graph.getEdgeAttributes(edgeId);
|
|
6582
|
+
if (e.type !== import_types8.EdgeType.CALLS) continue;
|
|
6583
|
+
if (isFrontierNode(graph, e.target)) continue;
|
|
6584
|
+
const owner = resolveOwningService(graph, e.target);
|
|
6585
|
+
if (!owner || visited.has(owner.id)) continue;
|
|
6586
|
+
const cur = bestByCallee.get(owner.id);
|
|
6587
|
+
if (!cur || import_types8.PROV_RANK[e.provenance] > import_types8.PROV_RANK[cur.provenance]) {
|
|
6588
|
+
bestByCallee.set(owner.id, e);
|
|
6589
|
+
}
|
|
6590
|
+
}
|
|
6591
|
+
}
|
|
6592
|
+
let best = null;
|
|
6593
|
+
for (const [id, edge] of bestByCallee) {
|
|
6594
|
+
if (!isStaleCallEdge(edge)) continue;
|
|
6595
|
+
if (!best || staleCallDominates(edge, id, best.edge, best.nextService)) {
|
|
6596
|
+
best = { nextService: id, edge };
|
|
6597
|
+
}
|
|
6598
|
+
}
|
|
6599
|
+
return best;
|
|
6600
|
+
}
|
|
6601
|
+
function followStaleCallChain(graph, originServiceId, maxDepth) {
|
|
6602
|
+
const path76 = [originServiceId];
|
|
6603
|
+
const edges = [];
|
|
6604
|
+
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
6605
|
+
let current = originServiceId;
|
|
6606
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
6607
|
+
const hop = dominantStaleCall(graph, current, visited);
|
|
6608
|
+
if (!hop) break;
|
|
6609
|
+
path76.push(hop.nextService);
|
|
6187
6610
|
edges.push(hop.edge);
|
|
6188
6611
|
visited.add(hop.nextService);
|
|
6189
6612
|
current = hop.nextService;
|
|
6190
6613
|
}
|
|
6191
6614
|
if (edges.length === 0) return null;
|
|
6192
|
-
return { path:
|
|
6615
|
+
return { path: path76, edges, culprit: current };
|
|
6193
6616
|
}
|
|
6194
6617
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
6195
6618
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
6196
6619
|
if (!chain) return null;
|
|
6197
6620
|
const culprit = chain.culprit;
|
|
6198
|
-
const
|
|
6621
|
+
const path76 = [...chain.path];
|
|
6199
6622
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
6200
6623
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
6201
6624
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -6203,14 +6626,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
6203
6626
|
if (loc) {
|
|
6204
6627
|
let rootCauseNode = culprit;
|
|
6205
6628
|
if (loc.fileNode) {
|
|
6206
|
-
|
|
6629
|
+
path76.push(loc.fileNode);
|
|
6207
6630
|
edgeProvenances.push(import_types8.Provenance.OBSERVED);
|
|
6208
6631
|
rootCauseNode = loc.fileNode;
|
|
6209
6632
|
}
|
|
6210
6633
|
return import_types8.RootCauseResultSchema.parse({
|
|
6211
6634
|
rootCauseNode,
|
|
6212
6635
|
rootCauseReason: loc.rootCauseReason,
|
|
6213
|
-
traversalPath:
|
|
6636
|
+
traversalPath: path76,
|
|
6214
6637
|
edgeProvenances,
|
|
6215
6638
|
confidence,
|
|
6216
6639
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -6222,7 +6645,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
6222
6645
|
return import_types8.RootCauseResultSchema.parse({
|
|
6223
6646
|
rootCauseNode: culprit,
|
|
6224
6647
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
6225
|
-
traversalPath:
|
|
6648
|
+
traversalPath: path76,
|
|
6226
6649
|
edgeProvenances,
|
|
6227
6650
|
confidence,
|
|
6228
6651
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -6609,17 +7032,20 @@ function displayNameOf(nodeId) {
|
|
|
6609
7032
|
return nodeId.replace(/^[a-z]+:/, "");
|
|
6610
7033
|
}
|
|
6611
7034
|
function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
|
|
6612
|
-
const
|
|
6613
|
-
if (!
|
|
7035
|
+
const tagged = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
|
|
7036
|
+
if (!tagged) return null;
|
|
6614
7037
|
const navigation = opts?.navigation ?? process.env.NEAT_RCA_NAVIGATION !== "0";
|
|
6615
|
-
if (!navigation) return
|
|
6616
|
-
return enrichWithNavigation(graph, errorNodeId,
|
|
7038
|
+
if (!navigation) return tagged.result;
|
|
7039
|
+
return enrichWithNavigation(graph, errorNodeId, tagged, incidents, opts?.now ?? Date.now());
|
|
6617
7040
|
}
|
|
6618
|
-
function enrichWithNavigation(graph, errorNodeId,
|
|
7041
|
+
function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
7042
|
+
const legacy = tagged.result;
|
|
6619
7043
|
const seedNode = legacy.rootCauseNode;
|
|
6620
7044
|
const seedCtx = graph.hasNode(seedNode) ? nodeContext(graph, seedNode, incidents, now) : null;
|
|
6621
7045
|
const lastProv = legacy.edgeProvenances[legacy.edgeProvenances.length - 1];
|
|
6622
7046
|
const candidates = [];
|
|
7047
|
+
const deadEndOnSymptom = tagged.source === "incident" && seedNode === errorNodeId && legacy.traversalPath.length === 1;
|
|
7048
|
+
const staleChain = deadEndOnSymptom && !(seedCtx && isVictimSeed(seedCtx)) ? followStaleCallChain(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH) : null;
|
|
6623
7049
|
if (seedCtx && isVictimSeed(seedCtx)) {
|
|
6624
7050
|
const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
|
|
6625
7051
|
const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
|
|
@@ -6644,6 +7070,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
6644
7070
|
confidence: Math.min(legacy.confidence, 0.4),
|
|
6645
7071
|
...lastProv ? { provenance: lastProv } : {}
|
|
6646
7072
|
});
|
|
7073
|
+
} else if (staleChain) {
|
|
7074
|
+
const culprit = staleChain.culprit;
|
|
7075
|
+
const culpritName = displayNameOf(culprit);
|
|
7076
|
+
const seedName = displayNameOf(seedNode);
|
|
7077
|
+
const staleConfidence = confidenceFromMix(staleChain.edges, now);
|
|
7078
|
+
candidates.push({
|
|
7079
|
+
node: culprit,
|
|
7080
|
+
classification: "primary-failure",
|
|
7081
|
+
reason: `${culpritName} is the stale-derived root cause (low confidence): live telemetry for this subgraph has gone quiet, but the last-observed topology traces the failure surfacing at ${seedName} downstream through a STALE call chain to ${culpritName}. Provenance is STALE, so confidence is capped low \u2014 restore instrumentation and re-run to confirm before acting.`,
|
|
7082
|
+
context: nodeContext(graph, culprit, incidents, now),
|
|
7083
|
+
confidence: staleConfidence,
|
|
7084
|
+
provenance: import_types8.Provenance.STALE
|
|
7085
|
+
});
|
|
7086
|
+
candidates.push({
|
|
7087
|
+
node: seedNode,
|
|
7088
|
+
classification: "symptom-only",
|
|
7089
|
+
reason: `The failure surfaced here, but the only causal chain the graph still holds is STALE and runs downstream \u2014 ${seedName} is the surface of a stale-traced failure, not a proven origin.`,
|
|
7090
|
+
context: seedCtx ?? EMPTY_CONTEXT,
|
|
7091
|
+
confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.STALE),
|
|
7092
|
+
...lastProv ? { provenance: lastProv } : {}
|
|
7093
|
+
});
|
|
6647
7094
|
} else {
|
|
6648
7095
|
candidates.push({
|
|
6649
7096
|
node: seedNode,
|
|
@@ -6657,11 +7104,14 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
6657
7104
|
const top = candidates[0];
|
|
6658
7105
|
let traversalPath = legacy.traversalPath;
|
|
6659
7106
|
let edgeProvenances = legacy.edgeProvenances;
|
|
6660
|
-
if (top.node
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
7107
|
+
if (staleChain && top.node === staleChain.culprit) {
|
|
7108
|
+
traversalPath = staleChain.path;
|
|
7109
|
+
edgeProvenances = staleChain.edges.map((e) => e.provenance);
|
|
7110
|
+
} else if (top.node !== seedNode) {
|
|
7111
|
+
const path76 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
|
|
7112
|
+
if (path76) {
|
|
7113
|
+
traversalPath = path76.nodes;
|
|
7114
|
+
edgeProvenances = path76.edges.map((e) => e.provenance);
|
|
6665
7115
|
} else {
|
|
6666
7116
|
traversalPath = [errorNodeId, top.node];
|
|
6667
7117
|
edgeProvenances = [top.provenance ?? import_types8.Provenance.OBSERVED];
|
|
@@ -6683,6 +7133,9 @@ function fixRecommendationForTop(top, seedNode, legacy) {
|
|
|
6683
7133
|
return legacy.fixRecommendation;
|
|
6684
7134
|
}
|
|
6685
7135
|
const name = top.node.replace(/^service:/, "");
|
|
7136
|
+
if (top.provenance === import_types8.Provenance.STALE) {
|
|
7137
|
+
return `Live telemetry for this path has gone quiet; the last-observed topology traces the failure downstream to ${name}. Restore instrumentation (or re-run with live traces) to confirm, then inspect ${name}.`;
|
|
7138
|
+
}
|
|
6686
7139
|
if (top.classification === "primary-failure") {
|
|
6687
7140
|
return `Reduce or throttle the load from ${name} (or scale the saturated downstream capacity it drives) \u2014 the failure originates at this overloading source, not the starved callee.`;
|
|
6688
7141
|
}
|
|
@@ -8169,7 +8622,7 @@ var import_tree_sitter_php2 = __toESM(require("tree-sitter-php"), 1);
|
|
|
8169
8622
|
var import_tree_sitter_c_sharp = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
8170
8623
|
var import_tree_sitter_java = __toESM(require("tree-sitter-java"), 1);
|
|
8171
8624
|
var import_tree_sitter_kotlin = __toESM(require("tree-sitter-kotlin"), 1);
|
|
8172
|
-
var
|
|
8625
|
+
var import_tree_sitter_rust2 = __toESM(require("tree-sitter-rust"), 1);
|
|
8173
8626
|
var import_tree_sitter_cpp = __toESM(require("tree-sitter-cpp"), 1);
|
|
8174
8627
|
var import_types21 = require("@neat.is/types");
|
|
8175
8628
|
var PARSE_CHUNK3 = 16384;
|
|
@@ -8190,7 +8643,7 @@ var SYMBOL_GRAMMAR_BY_EXT = {
|
|
|
8190
8643
|
".cs": import_tree_sitter_c_sharp.default,
|
|
8191
8644
|
".java": import_tree_sitter_java.default,
|
|
8192
8645
|
".kt": import_tree_sitter_kotlin.default,
|
|
8193
|
-
".rs":
|
|
8646
|
+
".rs": import_tree_sitter_rust2.default,
|
|
8194
8647
|
// C++ (ADR-202) — only the UNAMBIGUOUS extensions. `.cpp` / `.cc` / `.cxx` /
|
|
8195
8648
|
// `.c++` are implementation files; `.hpp` / `.hh` / `.hxx` / `.h++` are C++-only
|
|
8196
8649
|
// headers. `.h` and `.c` are deliberately absent: they are shared with C (a
|
|
@@ -8630,15 +9083,15 @@ function collectKotlinSymbolDefs(root) {
|
|
|
8630
9083
|
});
|
|
8631
9084
|
};
|
|
8632
9085
|
const join = (prefix, name) => prefix ? `${prefix}.${name}` : name;
|
|
8633
|
-
const
|
|
9086
|
+
const firstChildOfType2 = (node, types) => {
|
|
8634
9087
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8635
9088
|
const child = node.namedChild(i);
|
|
8636
9089
|
if (child && types.includes(child.type)) return child;
|
|
8637
9090
|
}
|
|
8638
9091
|
return void 0;
|
|
8639
9092
|
};
|
|
8640
|
-
const nameOf = (node, ...types) =>
|
|
8641
|
-
const bodyOf = (node) =>
|
|
9093
|
+
const nameOf = (node, ...types) => firstChildOfType2(node, types)?.text;
|
|
9094
|
+
const bodyOf = (node) => firstChildOfType2(node, ["class_body", "enum_class_body"]);
|
|
8642
9095
|
let pkg;
|
|
8643
9096
|
for (let i = 0; i < root.namedChildCount; i++) {
|
|
8644
9097
|
const child = root.namedChild(i);
|
|
@@ -9139,7 +9592,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
9139
9592
|
return best;
|
|
9140
9593
|
};
|
|
9141
9594
|
const requests = [];
|
|
9142
|
-
const
|
|
9595
|
+
const walk10 = (node) => {
|
|
9143
9596
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
9144
9597
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
9145
9598
|
if (self && self.kind === "class") {
|
|
@@ -9185,10 +9638,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
9185
9638
|
}
|
|
9186
9639
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
9187
9640
|
const child = node.namedChild(i);
|
|
9188
|
-
if (child)
|
|
9641
|
+
if (child) walk10(child);
|
|
9189
9642
|
}
|
|
9190
9643
|
};
|
|
9191
|
-
|
|
9644
|
+
walk10(root);
|
|
9192
9645
|
for (const req of requests) {
|
|
9193
9646
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
9194
9647
|
if (!targetSid) continue;
|
|
@@ -9484,7 +9937,7 @@ async function addServerActions(graph, services) {
|
|
|
9484
9937
|
|
|
9485
9938
|
// src/extract/databases/index.ts
|
|
9486
9939
|
init_cjs_shims();
|
|
9487
|
-
var
|
|
9940
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
9488
9941
|
var import_types24 = require("@neat.is/types");
|
|
9489
9942
|
|
|
9490
9943
|
// src/extract/databases/db-config-yaml.ts
|
|
@@ -9919,9 +10372,163 @@ async function parse8(serviceDir) {
|
|
|
9919
10372
|
}
|
|
9920
10373
|
var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
9921
10374
|
|
|
9922
|
-
// src/extract/databases/
|
|
10375
|
+
// src/extract/databases/csharp.ts
|
|
9923
10376
|
init_cjs_shims();
|
|
10377
|
+
var import_node_fs24 = require("fs");
|
|
9924
10378
|
var import_node_path34 = __toESM(require("path"), 1);
|
|
10379
|
+
var CS_EXT = ".cs";
|
|
10380
|
+
var NPGSQL_GATE = /\bUseNpgsql\b|\bNpgsql\b/;
|
|
10381
|
+
var REDIS_GATE = /\bConnectionMultiplexer\b|\bStackExchange\.Redis\b|\bConfigurationOptions\.Parse\b|\bAddStackExchangeRedisCache\b/;
|
|
10382
|
+
var ENV_READ_RE = /(?:GetEnvironmentVariable|GetConnectionString)\(\s*"([^"]+)"\s*\)|Configuration\s*\[\s*"([^"]+)"\s*\]/g;
|
|
10383
|
+
var STRING_LITERAL_RE = /@?"([^"\\]*(?:\\.[^"\\]*)*)"/g;
|
|
10384
|
+
function hostIsUnresolved(host) {
|
|
10385
|
+
return host === "" || /[${}]/.test(host);
|
|
10386
|
+
}
|
|
10387
|
+
function looksLikePostgres(s) {
|
|
10388
|
+
return /(?:^|;)\s*(?:host|server|data\s*source)\s*=/i.test(s) || /^postgres(?:ql)?:\/\//i.test(s);
|
|
10389
|
+
}
|
|
10390
|
+
function looksLikeRedis(s) {
|
|
10391
|
+
return /^rediss?:\/\//i.test(s) || /^[A-Za-z0-9_.-]+:\d+(?:$|,)/.test(s) || /,\s*(?:ssl|abortconnect|allowadmin|connecttimeout|password|user)\s*=/i.test(s);
|
|
10392
|
+
}
|
|
10393
|
+
function parsePostgresConnection(raw) {
|
|
10394
|
+
const s = raw.trim();
|
|
10395
|
+
if (/^postgres(?:ql)?:\/\//i.test(s)) return parseConnectionString(s);
|
|
10396
|
+
const fields = /* @__PURE__ */ new Map();
|
|
10397
|
+
for (const part of s.split(";")) {
|
|
10398
|
+
const eq = part.indexOf("=");
|
|
10399
|
+
if (eq < 0) continue;
|
|
10400
|
+
const key = part.slice(0, eq).trim().toLowerCase().replace(/\s+/g, " ");
|
|
10401
|
+
const value = part.slice(eq + 1).trim();
|
|
10402
|
+
if (value && !fields.has(key)) fields.set(key, value);
|
|
10403
|
+
}
|
|
10404
|
+
const hostRaw = fields.get("host") ?? fields.get("server") ?? fields.get("data source");
|
|
10405
|
+
if (!hostRaw) return null;
|
|
10406
|
+
const host = hostRaw.split(",")[0].trim();
|
|
10407
|
+
if (hostIsUnresolved(host)) return null;
|
|
10408
|
+
const portRaw = fields.get("port");
|
|
10409
|
+
const port = portRaw && /^\d+$/.test(portRaw) ? Number(portRaw) : void 0;
|
|
10410
|
+
const database = fields.get("database") ?? fields.get("db") ?? "";
|
|
10411
|
+
return { host, port, database, engine: "postgresql", engineVersion: "unknown" };
|
|
10412
|
+
}
|
|
10413
|
+
function parseRedisEndpoint(raw) {
|
|
10414
|
+
const s = raw.trim();
|
|
10415
|
+
if (/^rediss?:\/\//i.test(s)) return parseConnectionString(s);
|
|
10416
|
+
const first = s.split(",")[0].trim();
|
|
10417
|
+
const m = first.match(/^([A-Za-z0-9_.-]+)(?::(\d+))?$/);
|
|
10418
|
+
if (!m) return null;
|
|
10419
|
+
const host = m[1];
|
|
10420
|
+
if (hostIsUnresolved(host) || host.includes("=")) return null;
|
|
10421
|
+
const port = m[2] ? Number(m[2]) : void 0;
|
|
10422
|
+
return { host, port, database: "", engine: "redis", engineVersion: "unknown" };
|
|
10423
|
+
}
|
|
10424
|
+
async function resolveEnvUpTree(startDir, name) {
|
|
10425
|
+
let dir = import_node_path34.default.resolve(startDir);
|
|
10426
|
+
for (let depth = 0; depth < 12; depth++) {
|
|
10427
|
+
const value = await resolveEnvVar(dir, name);
|
|
10428
|
+
if (value !== null) return value;
|
|
10429
|
+
const atRepoRoot = await import_node_fs24.promises.access(import_node_path34.default.join(dir, ".git")).then(() => true).catch(() => false);
|
|
10430
|
+
const parent = import_node_path34.default.dirname(dir);
|
|
10431
|
+
if (atRepoRoot || parent === dir) break;
|
|
10432
|
+
dir = parent;
|
|
10433
|
+
}
|
|
10434
|
+
return null;
|
|
10435
|
+
}
|
|
10436
|
+
async function interpolateEnvRefs(value, dir) {
|
|
10437
|
+
const refs = /* @__PURE__ */ new Set();
|
|
10438
|
+
for (const m of value.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
10439
|
+
refs.add(m[1] ?? m[2]);
|
|
10440
|
+
}
|
|
10441
|
+
let out = value;
|
|
10442
|
+
for (const name of refs) {
|
|
10443
|
+
const resolved = await resolveEnvUpTree(dir, name);
|
|
10444
|
+
if (resolved === null) continue;
|
|
10445
|
+
out = out.split(`\${${name}}`).join(resolved).replace(new RegExp(`\\$${name}\\b`, "g"), resolved);
|
|
10446
|
+
}
|
|
10447
|
+
return out;
|
|
10448
|
+
}
|
|
10449
|
+
function stringLiterals(masked) {
|
|
10450
|
+
const out = [];
|
|
10451
|
+
STRING_LITERAL_RE.lastIndex = 0;
|
|
10452
|
+
let m;
|
|
10453
|
+
while ((m = STRING_LITERAL_RE.exec(masked)) !== null) out.push(m[1]);
|
|
10454
|
+
return out;
|
|
10455
|
+
}
|
|
10456
|
+
function envKeys(masked) {
|
|
10457
|
+
const out = [];
|
|
10458
|
+
ENV_READ_RE.lastIndex = 0;
|
|
10459
|
+
let m;
|
|
10460
|
+
while ((m = ENV_READ_RE.exec(masked)) !== null) {
|
|
10461
|
+
const key = m[1] ?? m[2];
|
|
10462
|
+
if (key) out.push(key);
|
|
10463
|
+
}
|
|
10464
|
+
return out;
|
|
10465
|
+
}
|
|
10466
|
+
async function resolveConfigs(literals, keys, serviceDir, looksLike, parse11) {
|
|
10467
|
+
const out = [];
|
|
10468
|
+
for (const key of keys) {
|
|
10469
|
+
const raw = await resolveEnvUpTree(serviceDir, key);
|
|
10470
|
+
if (raw === null) continue;
|
|
10471
|
+
const value = await interpolateEnvRefs(raw, serviceDir);
|
|
10472
|
+
if (!looksLike(value)) continue;
|
|
10473
|
+
const parsed = parse11(value);
|
|
10474
|
+
if (parsed) out.push(parsed);
|
|
10475
|
+
}
|
|
10476
|
+
for (const lit of literals) {
|
|
10477
|
+
if (!looksLike(lit)) continue;
|
|
10478
|
+
const parsed = parse11(lit);
|
|
10479
|
+
if (parsed) out.push(parsed);
|
|
10480
|
+
}
|
|
10481
|
+
return out;
|
|
10482
|
+
}
|
|
10483
|
+
async function parse9(serviceDir) {
|
|
10484
|
+
const files = (await walkSourceFiles(serviceDir).catch(() => [])).filter(
|
|
10485
|
+
(f) => import_node_path34.default.extname(f) === CS_EXT
|
|
10486
|
+
);
|
|
10487
|
+
if (files.length === 0) return [];
|
|
10488
|
+
const sources = [];
|
|
10489
|
+
for (const file of files) {
|
|
10490
|
+
const content = await import_node_fs24.promises.readFile(file, "utf8").catch(() => null);
|
|
10491
|
+
if (content !== null) sources.push({ file, content });
|
|
10492
|
+
}
|
|
10493
|
+
let pgGateFile = null;
|
|
10494
|
+
let redisGateFile = null;
|
|
10495
|
+
for (const { file, content } of sources) {
|
|
10496
|
+
if (pgGateFile === null && NPGSQL_GATE.test(content)) pgGateFile = file;
|
|
10497
|
+
if (redisGateFile === null && REDIS_GATE.test(content)) redisGateFile = file;
|
|
10498
|
+
}
|
|
10499
|
+
if (!pgGateFile && !redisGateFile) return [];
|
|
10500
|
+
const literals = [];
|
|
10501
|
+
const keys = [];
|
|
10502
|
+
for (const { content } of sources) {
|
|
10503
|
+
const masked = maskCommentsInSource(content);
|
|
10504
|
+
literals.push(...stringLiterals(masked));
|
|
10505
|
+
keys.push(...envKeys(masked));
|
|
10506
|
+
}
|
|
10507
|
+
const out = [];
|
|
10508
|
+
const seenHosts = /* @__PURE__ */ new Set();
|
|
10509
|
+
const push = (config, sourceFile) => {
|
|
10510
|
+
const dedupe = `${config.engine}:${config.host}`;
|
|
10511
|
+
if (seenHosts.has(dedupe)) return;
|
|
10512
|
+
seenHosts.add(dedupe);
|
|
10513
|
+
out.push({ ...config, sourceFile });
|
|
10514
|
+
};
|
|
10515
|
+
if (pgGateFile) {
|
|
10516
|
+
for (const pg3 of await resolveConfigs(literals, keys, serviceDir, looksLikePostgres, parsePostgresConnection)) {
|
|
10517
|
+
push(pg3, pgGateFile);
|
|
10518
|
+
}
|
|
10519
|
+
}
|
|
10520
|
+
if (redisGateFile) {
|
|
10521
|
+
for (const redis of await resolveConfigs(literals, keys, serviceDir, looksLikeRedis, parseRedisEndpoint)) {
|
|
10522
|
+
push(redis, redisGateFile);
|
|
10523
|
+
}
|
|
10524
|
+
}
|
|
10525
|
+
return out;
|
|
10526
|
+
}
|
|
10527
|
+
var csharpParser = { name: "csharp", parse: parse9 };
|
|
10528
|
+
|
|
10529
|
+
// src/extract/databases/docker-compose.ts
|
|
10530
|
+
init_cjs_shims();
|
|
10531
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
9925
10532
|
function portFromService(svc) {
|
|
9926
10533
|
for (const raw of svc.ports ?? []) {
|
|
9927
10534
|
const str = String(raw);
|
|
@@ -9946,9 +10553,9 @@ function databaseFromEnv(svc) {
|
|
|
9946
10553
|
};
|
|
9947
10554
|
return get("POSTGRES_DB") ?? get("MYSQL_DATABASE") ?? get("MONGO_INITDB_DATABASE") ?? "";
|
|
9948
10555
|
}
|
|
9949
|
-
async function
|
|
10556
|
+
async function parse10(serviceDir) {
|
|
9950
10557
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
9951
|
-
const abs =
|
|
10558
|
+
const abs = import_node_path35.default.join(serviceDir, name);
|
|
9952
10559
|
if (!await exists2(abs)) continue;
|
|
9953
10560
|
const raw = await readYaml(abs);
|
|
9954
10561
|
if (!raw?.services) return [];
|
|
@@ -9970,7 +10577,7 @@ async function parse9(serviceDir) {
|
|
|
9970
10577
|
}
|
|
9971
10578
|
return [];
|
|
9972
10579
|
}
|
|
9973
|
-
var dockerComposeParser = { name: "docker-compose", parse:
|
|
10580
|
+
var dockerComposeParser = { name: "docker-compose", parse: parse10 };
|
|
9974
10581
|
|
|
9975
10582
|
// src/extract/databases/index.ts
|
|
9976
10583
|
var DB_PARSERS = [
|
|
@@ -9982,6 +10589,7 @@ var DB_PARSERS = [
|
|
|
9982
10589
|
ormconfigParser,
|
|
9983
10590
|
typeormParser,
|
|
9984
10591
|
sequelizeParser,
|
|
10592
|
+
csharpParser,
|
|
9985
10593
|
dockerComposeParser
|
|
9986
10594
|
];
|
|
9987
10595
|
function compatibleDriversFor(engine) {
|
|
@@ -10120,7 +10728,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10120
10728
|
discoveredVia: mergedDiscoveredVia
|
|
10121
10729
|
});
|
|
10122
10730
|
}
|
|
10123
|
-
const relConfigFile = toPosix(
|
|
10731
|
+
const relConfigFile = toPosix(import_node_path36.default.relative(service.dir, config.sourceFile));
|
|
10124
10732
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
10125
10733
|
graph,
|
|
10126
10734
|
service.pkg.name,
|
|
@@ -10129,7 +10737,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10129
10737
|
);
|
|
10130
10738
|
nodesAdded += fn;
|
|
10131
10739
|
edgesAdded += fe;
|
|
10132
|
-
const evidenceFile = toPosix(
|
|
10740
|
+
const evidenceFile = toPosix(import_node_path36.default.relative(scanPath, config.sourceFile));
|
|
10133
10741
|
const edge = {
|
|
10134
10742
|
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types24.EdgeType.CONNECTS_TO),
|
|
10135
10743
|
source: fileNodeId,
|
|
@@ -10147,15 +10755,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10147
10755
|
if (allConfigs.length === 1) {
|
|
10148
10756
|
const primary = allConfigs[0];
|
|
10149
10757
|
service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
|
|
10150
|
-
const relPath =
|
|
10758
|
+
const relPath = import_node_path36.default.relative(scanPath, primary.sourceFile);
|
|
10151
10759
|
const cfgId = (0, import_types24.configId)(relPath);
|
|
10152
10760
|
if (!graph.hasNode(cfgId)) {
|
|
10153
10761
|
const cfgNode = {
|
|
10154
10762
|
id: cfgId,
|
|
10155
10763
|
type: import_types24.NodeType.ConfigNode,
|
|
10156
|
-
name:
|
|
10764
|
+
name: import_node_path36.default.basename(primary.sourceFile),
|
|
10157
10765
|
path: relPath,
|
|
10158
|
-
fileType: isConfigFile(
|
|
10766
|
+
fileType: isConfigFile(import_node_path36.default.basename(primary.sourceFile)).fileType || "config"
|
|
10159
10767
|
};
|
|
10160
10768
|
graph.addNode(cfgId, cfgNode);
|
|
10161
10769
|
nodesAdded++;
|
|
@@ -10196,27 +10804,27 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10196
10804
|
|
|
10197
10805
|
// src/extract/configs.ts
|
|
10198
10806
|
init_cjs_shims();
|
|
10199
|
-
var
|
|
10200
|
-
var
|
|
10807
|
+
var import_node_fs25 = require("fs");
|
|
10808
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
10201
10809
|
var import_types25 = require("@neat.is/types");
|
|
10202
10810
|
async function walkConfigFiles(dir, excludeDirs = []) {
|
|
10203
|
-
const excluded = new Set(excludeDirs.map((d) =>
|
|
10811
|
+
const excluded = new Set(excludeDirs.map((d) => import_node_path37.default.resolve(d)));
|
|
10204
10812
|
const out = [];
|
|
10205
|
-
async function
|
|
10206
|
-
const entries = await
|
|
10813
|
+
async function walk10(current) {
|
|
10814
|
+
const entries = await import_node_fs25.promises.readdir(current, { withFileTypes: true });
|
|
10207
10815
|
for (const entry of entries) {
|
|
10208
|
-
const full =
|
|
10816
|
+
const full = import_node_path37.default.join(current, entry.name);
|
|
10209
10817
|
if (entry.isDirectory()) {
|
|
10210
10818
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
10211
|
-
if (excluded.has(
|
|
10819
|
+
if (excluded.has(import_node_path37.default.resolve(full))) continue;
|
|
10212
10820
|
if (await isPythonVenvDir(full)) continue;
|
|
10213
|
-
await
|
|
10821
|
+
await walk10(full);
|
|
10214
10822
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
10215
10823
|
out.push(full);
|
|
10216
10824
|
}
|
|
10217
10825
|
}
|
|
10218
10826
|
}
|
|
10219
|
-
await
|
|
10827
|
+
await walk10(dir);
|
|
10220
10828
|
return out;
|
|
10221
10829
|
}
|
|
10222
10830
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -10225,19 +10833,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
10225
10833
|
for (const service of services) {
|
|
10226
10834
|
const configFiles = await walkConfigFiles(service.dir, service.excludeDirs);
|
|
10227
10835
|
for (const file of configFiles) {
|
|
10228
|
-
const relPath =
|
|
10836
|
+
const relPath = import_node_path37.default.relative(scanPath, file);
|
|
10229
10837
|
const node = {
|
|
10230
10838
|
id: (0, import_types25.configId)(relPath),
|
|
10231
10839
|
type: import_types25.NodeType.ConfigNode,
|
|
10232
|
-
name:
|
|
10840
|
+
name: import_node_path37.default.basename(file),
|
|
10233
10841
|
path: relPath,
|
|
10234
|
-
fileType: isConfigFile(
|
|
10842
|
+
fileType: isConfigFile(import_node_path37.default.basename(file)).fileType
|
|
10235
10843
|
};
|
|
10236
10844
|
if (!graph.hasNode(node.id)) {
|
|
10237
10845
|
graph.addNode(node.id, node);
|
|
10238
10846
|
nodesAdded++;
|
|
10239
10847
|
}
|
|
10240
|
-
const relToService = toPosix(
|
|
10848
|
+
const relToService = toPosix(import_node_path37.default.relative(service.dir, file));
|
|
10241
10849
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
10242
10850
|
graph,
|
|
10243
10851
|
service.pkg.name,
|
|
@@ -10253,7 +10861,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
10253
10861
|
type: import_types25.EdgeType.CONFIGURED_BY,
|
|
10254
10862
|
provenance: import_types25.Provenance.EXTRACTED,
|
|
10255
10863
|
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
10256
|
-
evidence: { file: relPath.split(
|
|
10864
|
+
evidence: { file: relPath.split(import_node_path37.default.sep).join("/") }
|
|
10257
10865
|
};
|
|
10258
10866
|
if (!graph.hasEdge(edge.id)) {
|
|
10259
10867
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -10266,8 +10874,8 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
10266
10874
|
|
|
10267
10875
|
// src/extract/proto.ts
|
|
10268
10876
|
init_cjs_shims();
|
|
10269
|
-
var
|
|
10270
|
-
var
|
|
10877
|
+
var import_node_fs26 = require("fs");
|
|
10878
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
10271
10879
|
var import_types26 = require("@neat.is/types");
|
|
10272
10880
|
var PROTO_EXTENSION = ".proto";
|
|
10273
10881
|
function packageOf(content) {
|
|
@@ -10305,23 +10913,23 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
10305
10913
|
return out;
|
|
10306
10914
|
}
|
|
10307
10915
|
async function walkProtoFiles(dir, excludeDirs = []) {
|
|
10308
|
-
const excluded = new Set(excludeDirs.map((d) =>
|
|
10916
|
+
const excluded = new Set(excludeDirs.map((d) => import_node_path38.default.resolve(d)));
|
|
10309
10917
|
const out = [];
|
|
10310
|
-
async function
|
|
10311
|
-
const entries = await
|
|
10918
|
+
async function walk10(current) {
|
|
10919
|
+
const entries = await import_node_fs26.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
10312
10920
|
for (const entry of entries) {
|
|
10313
|
-
const full =
|
|
10921
|
+
const full = import_node_path38.default.join(current, entry.name);
|
|
10314
10922
|
if (entry.isDirectory()) {
|
|
10315
10923
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
10316
|
-
if (excluded.has(
|
|
10924
|
+
if (excluded.has(import_node_path38.default.resolve(full))) continue;
|
|
10317
10925
|
if (await isPythonVenvDir(full)) continue;
|
|
10318
|
-
await
|
|
10319
|
-
} else if (entry.isFile() &&
|
|
10926
|
+
await walk10(full);
|
|
10927
|
+
} else if (entry.isFile() && import_node_path38.default.extname(entry.name) === PROTO_EXTENSION) {
|
|
10320
10928
|
out.push(full);
|
|
10321
10929
|
}
|
|
10322
10930
|
}
|
|
10323
10931
|
}
|
|
10324
|
-
await
|
|
10932
|
+
await walk10(dir);
|
|
10325
10933
|
return out;
|
|
10326
10934
|
}
|
|
10327
10935
|
async function addGrpcMethods(graph, services) {
|
|
@@ -10331,10 +10939,10 @@ async function addGrpcMethods(graph, services) {
|
|
|
10331
10939
|
const protoPaths = await walkProtoFiles(service.dir, service.excludeDirs);
|
|
10332
10940
|
for (const protoPath of protoPaths) {
|
|
10333
10941
|
if (isTestPath(protoPath)) continue;
|
|
10334
|
-
const relFile = toPosix(
|
|
10942
|
+
const relFile = toPosix(import_node_path38.default.relative(service.dir, protoPath));
|
|
10335
10943
|
let content;
|
|
10336
10944
|
try {
|
|
10337
|
-
content = await
|
|
10945
|
+
content = await import_node_fs26.promises.readFile(protoPath, "utf8");
|
|
10338
10946
|
} catch (err) {
|
|
10339
10947
|
recordExtractionError("proto extraction", protoPath, err);
|
|
10340
10948
|
continue;
|
|
@@ -10389,11 +10997,11 @@ async function addGrpcMethods(graph, services) {
|
|
|
10389
10997
|
|
|
10390
10998
|
// src/extract/calls/index.ts
|
|
10391
10999
|
init_cjs_shims();
|
|
10392
|
-
var
|
|
11000
|
+
var import_types45 = require("@neat.is/types");
|
|
10393
11001
|
|
|
10394
11002
|
// src/extract/calls/http.ts
|
|
10395
11003
|
init_cjs_shims();
|
|
10396
|
-
var
|
|
11004
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
10397
11005
|
var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
|
|
10398
11006
|
var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
|
|
10399
11007
|
var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
|
|
@@ -10476,7 +11084,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
10476
11084
|
const seen = /* @__PURE__ */ new Set();
|
|
10477
11085
|
for (const file of files) {
|
|
10478
11086
|
if (isTestPath(file.path)) continue;
|
|
10479
|
-
const parser = parserForExt(
|
|
11087
|
+
const parser = parserForExt(import_node_path39.default.extname(file.path), parserCache);
|
|
10480
11088
|
let sites;
|
|
10481
11089
|
try {
|
|
10482
11090
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -10485,7 +11093,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
10485
11093
|
continue;
|
|
10486
11094
|
}
|
|
10487
11095
|
if (sites.length === 0) continue;
|
|
10488
|
-
const relFile = toPosix(
|
|
11096
|
+
const relFile = toPosix(import_node_path39.default.relative(service.dir, file.path));
|
|
10489
11097
|
for (const site of sites) {
|
|
10490
11098
|
const targetId = hostToNodeId.get(site.host);
|
|
10491
11099
|
if (!targetId || targetId === service.node.id) continue;
|
|
@@ -10539,7 +11147,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
10539
11147
|
|
|
10540
11148
|
// src/extract/calls/route-match.ts
|
|
10541
11149
|
init_cjs_shims();
|
|
10542
|
-
var
|
|
11150
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
10543
11151
|
var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
|
|
10544
11152
|
var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
|
|
10545
11153
|
var import_types28 = require("@neat.is/types");
|
|
@@ -10738,7 +11346,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10738
11346
|
const seen = /* @__PURE__ */ new Set();
|
|
10739
11347
|
for (const file of files) {
|
|
10740
11348
|
if (isTestPath(file.path)) continue;
|
|
10741
|
-
if (!JS_CLIENT_EXTENSIONS.has(
|
|
11349
|
+
if (!JS_CLIENT_EXTENSIONS.has(import_node_path40.default.extname(file.path))) continue;
|
|
10742
11350
|
let sites;
|
|
10743
11351
|
try {
|
|
10744
11352
|
sites = clientCallSitesFromSource(file.content, jsParser, knownHosts);
|
|
@@ -10747,7 +11355,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10747
11355
|
continue;
|
|
10748
11356
|
}
|
|
10749
11357
|
if (sites.length === 0) continue;
|
|
10750
|
-
const relFile = toPosix(
|
|
11358
|
+
const relFile = toPosix(import_node_path40.default.relative(service.dir, file.path));
|
|
10751
11359
|
for (const site of sites) {
|
|
10752
11360
|
const serverServiceId = hostToNodeId.get(site.host);
|
|
10753
11361
|
if (!serverServiceId || serverServiceId === service.node.id) continue;
|
|
@@ -10808,7 +11416,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10808
11416
|
|
|
10809
11417
|
// src/extract/calls/kafka.ts
|
|
10810
11418
|
init_cjs_shims();
|
|
10811
|
-
var
|
|
11419
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
10812
11420
|
var import_types29 = require("@neat.is/types");
|
|
10813
11421
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10814
11422
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
@@ -10896,13 +11504,13 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
10896
11504
|
// call sites — verified-call-site tier (ADR-066).
|
|
10897
11505
|
confidenceKind: "verified-call-site",
|
|
10898
11506
|
evidence: {
|
|
10899
|
-
file:
|
|
11507
|
+
file: import_node_path41.default.relative(serviceDir, file.path),
|
|
10900
11508
|
line,
|
|
10901
11509
|
snippet: snippet(file.content, line)
|
|
10902
11510
|
}
|
|
10903
11511
|
});
|
|
10904
11512
|
};
|
|
10905
|
-
if (
|
|
11513
|
+
if (import_node_path41.default.extname(file.path) === ".go") {
|
|
10906
11514
|
goSaramaEndpoints(file.content, make);
|
|
10907
11515
|
} else {
|
|
10908
11516
|
for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, "PUBLISHES_TO");
|
|
@@ -10913,7 +11521,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
10913
11521
|
|
|
10914
11522
|
// src/extract/calls/redis.ts
|
|
10915
11523
|
init_cjs_shims();
|
|
10916
|
-
var
|
|
11524
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
10917
11525
|
var import_types30 = require("@neat.is/types");
|
|
10918
11526
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
10919
11527
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
@@ -10936,7 +11544,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10936
11544
|
// support tier (ADR-066).
|
|
10937
11545
|
confidenceKind: "url-with-structural-support",
|
|
10938
11546
|
evidence: {
|
|
10939
|
-
file:
|
|
11547
|
+
file: import_node_path42.default.relative(serviceDir, file.path),
|
|
10940
11548
|
line,
|
|
10941
11549
|
snippet: snippet(file.content, line)
|
|
10942
11550
|
}
|
|
@@ -10947,7 +11555,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10947
11555
|
|
|
10948
11556
|
// src/extract/calls/aws.ts
|
|
10949
11557
|
init_cjs_shims();
|
|
10950
|
-
var
|
|
11558
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
10951
11559
|
var import_types31 = require("@neat.is/types");
|
|
10952
11560
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10953
11561
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
@@ -10981,7 +11589,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
10981
11589
|
// (ADR-066).
|
|
10982
11590
|
confidenceKind: "verified-call-site",
|
|
10983
11591
|
evidence: {
|
|
10984
|
-
file:
|
|
11592
|
+
file: import_node_path43.default.relative(serviceDir, file.path),
|
|
10985
11593
|
line,
|
|
10986
11594
|
snippet: snippet(file.content, line)
|
|
10987
11595
|
}
|
|
@@ -11006,7 +11614,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
11006
11614
|
|
|
11007
11615
|
// src/extract/calls/grpc.ts
|
|
11008
11616
|
init_cjs_shims();
|
|
11009
|
-
var
|
|
11617
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
11010
11618
|
var import_types32 = require("@neat.is/types");
|
|
11011
11619
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
11012
11620
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
@@ -11065,7 +11673,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
11065
11673
|
// tier (ADR-066).
|
|
11066
11674
|
confidenceKind: "verified-call-site",
|
|
11067
11675
|
evidence: {
|
|
11068
|
-
file:
|
|
11676
|
+
file: import_node_path44.default.relative(serviceDir, file.path),
|
|
11069
11677
|
line,
|
|
11070
11678
|
snippet: snippet(file.content, line)
|
|
11071
11679
|
}
|
|
@@ -11076,7 +11684,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
11076
11684
|
|
|
11077
11685
|
// src/extract/calls/supabase.ts
|
|
11078
11686
|
init_cjs_shims();
|
|
11079
|
-
var
|
|
11687
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
11080
11688
|
var import_types33 = require("@neat.is/types");
|
|
11081
11689
|
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
11082
11690
|
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
@@ -11135,7 +11743,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11135
11743
|
// tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
|
|
11136
11744
|
confidenceKind: "verified-call-site",
|
|
11137
11745
|
evidence: {
|
|
11138
|
-
file:
|
|
11746
|
+
file: import_node_path45.default.relative(serviceDir, file.path),
|
|
11139
11747
|
line,
|
|
11140
11748
|
snippet: snippet(file.content, line)
|
|
11141
11749
|
}
|
|
@@ -11162,7 +11770,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11162
11770
|
edgeType: "CALLS",
|
|
11163
11771
|
confidenceKind: "verified-call-site",
|
|
11164
11772
|
evidence: {
|
|
11165
|
-
file:
|
|
11773
|
+
file: import_node_path45.default.relative(serviceDir, file.path),
|
|
11166
11774
|
line,
|
|
11167
11775
|
snippet: snippet(file.content, line)
|
|
11168
11776
|
}
|
|
@@ -11174,7 +11782,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11174
11782
|
|
|
11175
11783
|
// src/extract/calls/firestore.ts
|
|
11176
11784
|
init_cjs_shims();
|
|
11177
|
-
var
|
|
11785
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
11178
11786
|
var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
|
|
11179
11787
|
var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
|
|
11180
11788
|
var import_types34 = require("@neat.is/types");
|
|
@@ -11213,7 +11821,7 @@ function isFirestoreClientFactory(node) {
|
|
|
11213
11821
|
}
|
|
11214
11822
|
function firestoreClientVars(root) {
|
|
11215
11823
|
const vars = /* @__PURE__ */ new Set();
|
|
11216
|
-
const
|
|
11824
|
+
const walk10 = (node) => {
|
|
11217
11825
|
if (node.type === "variable_declarator") {
|
|
11218
11826
|
const name = node.childForFieldName("name");
|
|
11219
11827
|
let value = node.childForFieldName("value");
|
|
@@ -11222,9 +11830,9 @@ function firestoreClientVars(root) {
|
|
|
11222
11830
|
vars.add(name.text);
|
|
11223
11831
|
}
|
|
11224
11832
|
}
|
|
11225
|
-
for (const c of namedChildren(node))
|
|
11833
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
11226
11834
|
};
|
|
11227
|
-
|
|
11835
|
+
walk10(root);
|
|
11228
11836
|
return vars;
|
|
11229
11837
|
}
|
|
11230
11838
|
function isClientExpr(node, clientVars) {
|
|
@@ -11345,7 +11953,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11345
11953
|
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
|
|
11346
11954
|
if (!hasClient && !hasAdmin) return [];
|
|
11347
11955
|
const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
11348
|
-
const tree = parseSource3(parserForExt2(
|
|
11956
|
+
const tree = parseSource3(parserForExt2(import_node_path46.default.extname(file.path)), file.content);
|
|
11349
11957
|
const clientVars = firestoreClientVars(tree.rootNode);
|
|
11350
11958
|
const collLine = /* @__PURE__ */ new Map();
|
|
11351
11959
|
const writes = /* @__PURE__ */ new Map();
|
|
@@ -11379,7 +11987,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11379
11987
|
}
|
|
11380
11988
|
s.add(field);
|
|
11381
11989
|
};
|
|
11382
|
-
const
|
|
11990
|
+
const walk10 = (node) => {
|
|
11383
11991
|
if (node.type === "call_expression") {
|
|
11384
11992
|
const fn = node.childForFieldName("function");
|
|
11385
11993
|
const line = node.startPosition.row + 1;
|
|
@@ -11419,9 +12027,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11419
12027
|
}
|
|
11420
12028
|
}
|
|
11421
12029
|
}
|
|
11422
|
-
for (const c of namedChildren(node))
|
|
12030
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
11423
12031
|
};
|
|
11424
|
-
|
|
12032
|
+
walk10(tree.rootNode);
|
|
11425
12033
|
const out = [];
|
|
11426
12034
|
for (const [collPath, line] of collLine) {
|
|
11427
12035
|
const byField = writes.get(collPath);
|
|
@@ -11449,7 +12057,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11449
12057
|
...columnSet.size > 0 ? { columns: [...columnSet] } : {},
|
|
11450
12058
|
...sdkWrites ? { sdkWrites } : {},
|
|
11451
12059
|
evidence: {
|
|
11452
|
-
file:
|
|
12060
|
+
file: import_node_path46.default.relative(serviceDir, file.path),
|
|
11453
12061
|
line,
|
|
11454
12062
|
snippet: snippet(file.content, line)
|
|
11455
12063
|
}
|
|
@@ -11460,7 +12068,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11460
12068
|
|
|
11461
12069
|
// src/extract/calls/mongoose.ts
|
|
11462
12070
|
init_cjs_shims();
|
|
11463
|
-
var
|
|
12071
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
11464
12072
|
var import_types35 = require("@neat.is/types");
|
|
11465
12073
|
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
11466
12074
|
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
@@ -11611,7 +12219,7 @@ function endpoint(r, file, serviceDir, matchText) {
|
|
|
11611
12219
|
kind: r.kind,
|
|
11612
12220
|
edgeType: "CALLS",
|
|
11613
12221
|
confidenceKind: "verified-call-site",
|
|
11614
|
-
evidence: { file:
|
|
12222
|
+
evidence: { file: import_node_path47.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
11615
12223
|
};
|
|
11616
12224
|
}
|
|
11617
12225
|
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
@@ -11701,7 +12309,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11701
12309
|
const registry = /* @__PURE__ */ new Map();
|
|
11702
12310
|
for (const f of mongooseFiles) {
|
|
11703
12311
|
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
11704
|
-
if (fx) registry.set(toPosix(
|
|
12312
|
+
if (fx) registry.set(toPosix(import_node_path47.default.relative(serviceDir, f.path)), fx);
|
|
11705
12313
|
}
|
|
11706
12314
|
if (registry.size === 0) return [];
|
|
11707
12315
|
const out = [];
|
|
@@ -11712,7 +12320,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11712
12320
|
const directColl = /* @__PURE__ */ new Map();
|
|
11713
12321
|
const nsExports = /* @__PURE__ */ new Map();
|
|
11714
12322
|
for (const b of bindings) {
|
|
11715
|
-
const resolvedRel = await resolveJsImport(b.specifier,
|
|
12323
|
+
const resolvedRel = await resolveJsImport(b.specifier, import_node_path47.default.dirname(f.path), serviceDir, null);
|
|
11716
12324
|
if (!resolvedRel) continue;
|
|
11717
12325
|
const fx = registry.get(resolvedRel);
|
|
11718
12326
|
if (!fx) continue;
|
|
@@ -11756,7 +12364,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11756
12364
|
|
|
11757
12365
|
// src/extract/calls/sqlalchemy.ts
|
|
11758
12366
|
init_cjs_shims();
|
|
11759
|
-
var
|
|
12367
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11760
12368
|
var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
|
|
11761
12369
|
var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
11762
12370
|
var import_types36 = require("@neat.is/types");
|
|
@@ -11895,7 +12503,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
|
|
|
11895
12503
|
childTable,
|
|
11896
12504
|
parentTable,
|
|
11897
12505
|
evidence: {
|
|
11898
|
-
file:
|
|
12506
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11899
12507
|
line,
|
|
11900
12508
|
snippet: snippet(file.content, line)
|
|
11901
12509
|
}
|
|
@@ -11920,7 +12528,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
11920
12528
|
confidenceKind: "verified-call-site",
|
|
11921
12529
|
...columns && columns.length > 0 ? { columns } : {},
|
|
11922
12530
|
evidence: {
|
|
11923
|
-
file:
|
|
12531
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11924
12532
|
line,
|
|
11925
12533
|
snippet: snippet(file.content, line)
|
|
11926
12534
|
}
|
|
@@ -12027,7 +12635,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
12027
12635
|
edgeType: "CALLS",
|
|
12028
12636
|
confidenceKind: "verified-call-site",
|
|
12029
12637
|
evidence: {
|
|
12030
|
-
file:
|
|
12638
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
12031
12639
|
line,
|
|
12032
12640
|
snippet: snippet(file.content, line)
|
|
12033
12641
|
}
|
|
@@ -12039,7 +12647,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
12039
12647
|
|
|
12040
12648
|
// src/extract/calls/django-orm.ts
|
|
12041
12649
|
init_cjs_shims();
|
|
12042
|
-
var
|
|
12650
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
12043
12651
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
12044
12652
|
var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
|
|
12045
12653
|
var import_types37 = require("@neat.is/types");
|
|
@@ -12109,7 +12717,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12109
12717
|
const tree = parseSource7(makePyParser4(), file.content);
|
|
12110
12718
|
const out = [];
|
|
12111
12719
|
const seen = /* @__PURE__ */ new Set();
|
|
12112
|
-
const defaultAppLabel =
|
|
12720
|
+
const defaultAppLabel = import_node_path49.default.basename(import_node_path49.default.dirname(file.path));
|
|
12113
12721
|
walk4(tree.rootNode, (node) => {
|
|
12114
12722
|
if (node.type !== "class_definition") return;
|
|
12115
12723
|
if (!extendsDjangoModel(node)) return;
|
|
@@ -12127,7 +12735,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12127
12735
|
kind: "sql-table",
|
|
12128
12736
|
edgeType: "CALLS",
|
|
12129
12737
|
confidenceKind: "verified-call-site",
|
|
12130
|
-
evidence: { file:
|
|
12738
|
+
evidence: { file: import_node_path49.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
12131
12739
|
});
|
|
12132
12740
|
});
|
|
12133
12741
|
return out;
|
|
@@ -12135,7 +12743,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12135
12743
|
|
|
12136
12744
|
// src/extract/calls/drizzle.ts
|
|
12137
12745
|
init_cjs_shims();
|
|
12138
|
-
var
|
|
12746
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
12139
12747
|
var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
|
|
12140
12748
|
var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12141
12749
|
var import_types38 = require("@neat.is/types");
|
|
@@ -12213,10 +12821,10 @@ function columnsFromObject(obj) {
|
|
|
12213
12821
|
}
|
|
12214
12822
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
12215
12823
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12216
|
-
const tree = parseSource3(parserForExt3(
|
|
12824
|
+
const tree = parseSource3(parserForExt3(import_node_path50.default.extname(file.path)), file.content);
|
|
12217
12825
|
const out = [];
|
|
12218
12826
|
const seen = /* @__PURE__ */ new Set();
|
|
12219
|
-
const
|
|
12827
|
+
const walk10 = (node) => {
|
|
12220
12828
|
if (node.type === "call_expression") {
|
|
12221
12829
|
const fn = node.childForFieldName("function");
|
|
12222
12830
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -12236,7 +12844,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12236
12844
|
confidenceKind: "structural",
|
|
12237
12845
|
columns,
|
|
12238
12846
|
evidence: {
|
|
12239
|
-
file:
|
|
12847
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12240
12848
|
line,
|
|
12241
12849
|
snippet: snippet(file.content, line)
|
|
12242
12850
|
}
|
|
@@ -12244,9 +12852,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12244
12852
|
}
|
|
12245
12853
|
}
|
|
12246
12854
|
}
|
|
12247
|
-
for (const c of namedChildren4(node))
|
|
12855
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12248
12856
|
};
|
|
12249
|
-
|
|
12857
|
+
walk10(tree.rootNode);
|
|
12250
12858
|
return out;
|
|
12251
12859
|
}
|
|
12252
12860
|
function enclosingVarName(call) {
|
|
@@ -12268,7 +12876,7 @@ function enclosingVarName(call) {
|
|
|
12268
12876
|
function collectDrizzleTables(root) {
|
|
12269
12877
|
const tables = [];
|
|
12270
12878
|
const varToTable = /* @__PURE__ */ new Map();
|
|
12271
|
-
const
|
|
12879
|
+
const walk10 = (node) => {
|
|
12272
12880
|
if (node.type === "call_expression") {
|
|
12273
12881
|
const fn = node.childForFieldName("function");
|
|
12274
12882
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -12283,9 +12891,9 @@ function collectDrizzleTables(root) {
|
|
|
12283
12891
|
}
|
|
12284
12892
|
}
|
|
12285
12893
|
}
|
|
12286
|
-
for (const c of namedChildren4(node))
|
|
12894
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12287
12895
|
};
|
|
12288
|
-
|
|
12896
|
+
walk10(root);
|
|
12289
12897
|
return { tables, varToTable };
|
|
12290
12898
|
}
|
|
12291
12899
|
function referencesTargetVar(call) {
|
|
@@ -12302,13 +12910,13 @@ function referencesTargetVar(call) {
|
|
|
12302
12910
|
}
|
|
12303
12911
|
function drizzleForeignKeys(file, serviceDir) {
|
|
12304
12912
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12305
|
-
const tree = parseSource3(parserForExt3(
|
|
12913
|
+
const tree = parseSource3(parserForExt3(import_node_path50.default.extname(file.path)), file.content);
|
|
12306
12914
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
12307
12915
|
const out = [];
|
|
12308
12916
|
const seen = /* @__PURE__ */ new Set();
|
|
12309
12917
|
for (const table of tables) {
|
|
12310
12918
|
if (!table.object) continue;
|
|
12311
|
-
const
|
|
12919
|
+
const walk10 = (node) => {
|
|
12312
12920
|
if (node.type === "call_expression") {
|
|
12313
12921
|
const targetVar = referencesTargetVar(node);
|
|
12314
12922
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -12321,7 +12929,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12321
12929
|
childTable: table.tableName,
|
|
12322
12930
|
parentTable,
|
|
12323
12931
|
evidence: {
|
|
12324
|
-
file:
|
|
12932
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12325
12933
|
line,
|
|
12326
12934
|
snippet: snippet(file.content, line)
|
|
12327
12935
|
}
|
|
@@ -12329,16 +12937,16 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12329
12937
|
}
|
|
12330
12938
|
}
|
|
12331
12939
|
}
|
|
12332
|
-
for (const c of namedChildren4(node))
|
|
12940
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12333
12941
|
};
|
|
12334
|
-
|
|
12942
|
+
walk10(table.object);
|
|
12335
12943
|
}
|
|
12336
12944
|
return out;
|
|
12337
12945
|
}
|
|
12338
12946
|
|
|
12339
12947
|
// src/extract/calls/prisma.ts
|
|
12340
12948
|
init_cjs_shims();
|
|
12341
|
-
var
|
|
12949
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12342
12950
|
var import_types39 = require("@neat.is/types");
|
|
12343
12951
|
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
12344
12952
|
"Int",
|
|
@@ -12394,7 +13002,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12394
13002
|
confidenceKind: "structural",
|
|
12395
13003
|
columns: b.columns,
|
|
12396
13004
|
evidence: {
|
|
12397
|
-
file:
|
|
13005
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12398
13006
|
line: b.startLine,
|
|
12399
13007
|
snippet: snippet(content, b.startLine)
|
|
12400
13008
|
}
|
|
@@ -12455,7 +13063,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12455
13063
|
}
|
|
12456
13064
|
async function prismaColumnEndpoints(serviceDir) {
|
|
12457
13065
|
const schemaPath = await findFirst(serviceDir, [
|
|
12458
|
-
|
|
13066
|
+
import_node_path51.default.join("prisma", "schema.prisma"),
|
|
12459
13067
|
"schema.prisma"
|
|
12460
13068
|
]);
|
|
12461
13069
|
if (!schemaPath) return [];
|
|
@@ -12530,7 +13138,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12530
13138
|
childTable: current.table,
|
|
12531
13139
|
parentTable,
|
|
12532
13140
|
evidence: {
|
|
12533
|
-
file:
|
|
13141
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12534
13142
|
line: lineNo,
|
|
12535
13143
|
snippet: snippet(content, lineNo)
|
|
12536
13144
|
}
|
|
@@ -12545,7 +13153,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12545
13153
|
}
|
|
12546
13154
|
async function prismaForeignKeys(serviceDir) {
|
|
12547
13155
|
const schemaPath = await findFirst(serviceDir, [
|
|
12548
|
-
|
|
13156
|
+
import_node_path51.default.join("prisma", "schema.prisma"),
|
|
12549
13157
|
"schema.prisma"
|
|
12550
13158
|
]);
|
|
12551
13159
|
if (!schemaPath) return [];
|
|
@@ -12556,7 +13164,7 @@ async function prismaForeignKeys(serviceDir) {
|
|
|
12556
13164
|
|
|
12557
13165
|
// src/extract/calls/activerecord.ts
|
|
12558
13166
|
init_cjs_shims();
|
|
12559
|
-
var
|
|
13167
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
12560
13168
|
var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
|
|
12561
13169
|
var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
|
|
12562
13170
|
var import_types40 = require("@neat.is/types");
|
|
@@ -12764,7 +13372,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
|
12764
13372
|
confidenceKind: "structural",
|
|
12765
13373
|
...table.columns.length > 0 ? { columns: table.columns } : {},
|
|
12766
13374
|
evidence: {
|
|
12767
|
-
file:
|
|
13375
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12768
13376
|
line: table.line,
|
|
12769
13377
|
snippet: snippet(file.content, table.line)
|
|
12770
13378
|
}
|
|
@@ -12786,7 +13394,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
|
|
|
12786
13394
|
childTable,
|
|
12787
13395
|
parentTable,
|
|
12788
13396
|
evidence: {
|
|
12789
|
-
file:
|
|
13397
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12790
13398
|
line,
|
|
12791
13399
|
snippet: snippet(file.content, line)
|
|
12792
13400
|
}
|
|
@@ -12869,7 +13477,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
|
|
|
12869
13477
|
edgeType: "CALLS",
|
|
12870
13478
|
confidenceKind: "verified-call-site",
|
|
12871
13479
|
evidence: {
|
|
12872
|
-
file:
|
|
13480
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12873
13481
|
line,
|
|
12874
13482
|
snippet: snippet(file.content, line)
|
|
12875
13483
|
}
|
|
@@ -12906,7 +13514,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12906
13514
|
childTable,
|
|
12907
13515
|
parentTable,
|
|
12908
13516
|
evidence: {
|
|
12909
|
-
file:
|
|
13517
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12910
13518
|
line,
|
|
12911
13519
|
snippet: snippet(file.content, line)
|
|
12912
13520
|
}
|
|
@@ -12918,7 +13526,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12918
13526
|
|
|
12919
13527
|
// src/extract/calls/eloquent.ts
|
|
12920
13528
|
init_cjs_shims();
|
|
12921
|
-
var
|
|
13529
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
12922
13530
|
var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
|
|
12923
13531
|
var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
|
|
12924
13532
|
var import_types41 = require("@neat.is/types");
|
|
@@ -13175,7 +13783,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
13175
13783
|
confidenceKind: "structural",
|
|
13176
13784
|
...columns.length > 0 ? { columns } : {},
|
|
13177
13785
|
evidence: {
|
|
13178
|
-
file:
|
|
13786
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13179
13787
|
line: bp.line,
|
|
13180
13788
|
snippet: snippet(file.content, bp.line)
|
|
13181
13789
|
}
|
|
@@ -13197,7 +13805,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
|
|
|
13197
13805
|
childTable,
|
|
13198
13806
|
parentTable,
|
|
13199
13807
|
evidence: {
|
|
13200
|
-
file:
|
|
13808
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13201
13809
|
line,
|
|
13202
13810
|
snippet: snippet(file.content, line)
|
|
13203
13811
|
}
|
|
@@ -13317,7 +13925,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
|
13317
13925
|
edgeType: "CALLS",
|
|
13318
13926
|
confidenceKind: "verified-call-site",
|
|
13319
13927
|
evidence: {
|
|
13320
|
-
file:
|
|
13928
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13321
13929
|
line,
|
|
13322
13930
|
snippet: snippet(file.content, line)
|
|
13323
13931
|
}
|
|
@@ -13353,7 +13961,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13353
13961
|
childTable,
|
|
13354
13962
|
parentTable,
|
|
13355
13963
|
evidence: {
|
|
13356
|
-
file:
|
|
13964
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13357
13965
|
line,
|
|
13358
13966
|
snippet: snippet(file.content, line)
|
|
13359
13967
|
}
|
|
@@ -13365,7 +13973,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13365
13973
|
|
|
13366
13974
|
// src/extract/calls/go.ts
|
|
13367
13975
|
init_cjs_shims();
|
|
13368
|
-
var
|
|
13976
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
13369
13977
|
var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
|
|
13370
13978
|
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
13371
13979
|
var import_types42 = require("@neat.is/types");
|
|
@@ -13440,7 +14048,7 @@ function firstStringLiteralArg(argsNode) {
|
|
|
13440
14048
|
return null;
|
|
13441
14049
|
}
|
|
13442
14050
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
13443
|
-
if (
|
|
14051
|
+
if (import_node_path56.default.extname(file.path) !== ".go") return [];
|
|
13444
14052
|
if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
|
|
13445
14053
|
const tree = parseSource10(makeGoParser3(), file.content);
|
|
13446
14054
|
const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
|
|
@@ -13469,7 +14077,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13469
14077
|
confidenceKind: "verified-call-site",
|
|
13470
14078
|
...columns.length > 0 ? { columns } : {},
|
|
13471
14079
|
evidence: {
|
|
13472
|
-
file: toPosix(
|
|
14080
|
+
file: toPosix(import_node_path56.default.relative(serviceDir, file.path)),
|
|
13473
14081
|
line,
|
|
13474
14082
|
snippet: snippet(file.content, line)
|
|
13475
14083
|
}
|
|
@@ -13480,7 +14088,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13480
14088
|
|
|
13481
14089
|
// src/extract/calls/gorm.ts
|
|
13482
14090
|
init_cjs_shims();
|
|
13483
|
-
var
|
|
14091
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
13484
14092
|
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
13485
14093
|
var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
|
|
13486
14094
|
var import_types43 = require("@neat.is/types");
|
|
@@ -13913,7 +14521,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
|
13913
14521
|
seen.delete(struct.name);
|
|
13914
14522
|
}
|
|
13915
14523
|
function gormEndpointsFromFile(file, serviceDir) {
|
|
13916
|
-
if (
|
|
14524
|
+
if (import_node_path57.default.extname(file.path) !== ".go") return [];
|
|
13917
14525
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13918
14526
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13919
14527
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13935,7 +14543,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13935
14543
|
confidenceKind: "structural",
|
|
13936
14544
|
...columns.length > 0 ? { columns } : {},
|
|
13937
14545
|
evidence: {
|
|
13938
|
-
file: toPosix(
|
|
14546
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
13939
14547
|
line: struct.line,
|
|
13940
14548
|
snippet: snippet(file.content, struct.line)
|
|
13941
14549
|
}
|
|
@@ -13944,7 +14552,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13944
14552
|
return out;
|
|
13945
14553
|
}
|
|
13946
14554
|
function gormForeignKeys(file, serviceDir) {
|
|
13947
|
-
if (
|
|
14555
|
+
if (import_node_path57.default.extname(file.path) !== ".go") return [];
|
|
13948
14556
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13949
14557
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13950
14558
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13959,7 +14567,7 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13959
14567
|
childTable,
|
|
13960
14568
|
parentTable,
|
|
13961
14569
|
evidence: {
|
|
13962
|
-
file: toPosix(
|
|
14570
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
13963
14571
|
line,
|
|
13964
14572
|
snippet: snippet(file.content, line)
|
|
13965
14573
|
}
|
|
@@ -13994,15 +14602,131 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13994
14602
|
return out;
|
|
13995
14603
|
}
|
|
13996
14604
|
|
|
14605
|
+
// src/extract/calls/efcore.ts
|
|
14606
|
+
init_cjs_shims();
|
|
14607
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
14608
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
14609
|
+
var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
14610
|
+
var import_types44 = require("@neat.is/types");
|
|
14611
|
+
var EFCORE_GATE = /Microsoft\.EntityFrameworkCore|DataAnnotations\.Schema|\bDbContext\b|\bDbSet\s*</;
|
|
14612
|
+
var PARSE_CHUNK12 = 16384;
|
|
14613
|
+
function makeCsParser() {
|
|
14614
|
+
const p = new import_tree_sitter16.default();
|
|
14615
|
+
p.setLanguage(import_tree_sitter_c_sharp2.default);
|
|
14616
|
+
return p;
|
|
14617
|
+
}
|
|
14618
|
+
function parseSource12(parser, source) {
|
|
14619
|
+
return parser.parse(
|
|
14620
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK12)
|
|
14621
|
+
);
|
|
14622
|
+
}
|
|
14623
|
+
function walk9(node, visit) {
|
|
14624
|
+
visit(node);
|
|
14625
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14626
|
+
const c = node.namedChild(i);
|
|
14627
|
+
if (c) walk9(c, visit);
|
|
14628
|
+
}
|
|
14629
|
+
}
|
|
14630
|
+
function firstChildOfType(node, type) {
|
|
14631
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14632
|
+
const c = node.namedChild(i);
|
|
14633
|
+
if (c?.type === type) return c;
|
|
14634
|
+
}
|
|
14635
|
+
return null;
|
|
14636
|
+
}
|
|
14637
|
+
function csStringLiteral(node) {
|
|
14638
|
+
if (node.type === "string_literal") {
|
|
14639
|
+
let out = "";
|
|
14640
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14641
|
+
const c = node.namedChild(i);
|
|
14642
|
+
if (c?.type === "string_literal_content") out += c.text;
|
|
14643
|
+
}
|
|
14644
|
+
return out;
|
|
14645
|
+
}
|
|
14646
|
+
if (node.type === "verbatim_string_literal") {
|
|
14647
|
+
const t = node.text;
|
|
14648
|
+
return t.length >= 3 ? t.slice(2, -1).replace(/""/g, '"') : "";
|
|
14649
|
+
}
|
|
14650
|
+
return null;
|
|
14651
|
+
}
|
|
14652
|
+
function attributeName(attr) {
|
|
14653
|
+
const nameNode = attr.childForFieldName("name") ?? attr.namedChild(0);
|
|
14654
|
+
if (!nameNode) return null;
|
|
14655
|
+
const text = nameNode.text;
|
|
14656
|
+
const base = text.includes(".") ? text.slice(text.lastIndexOf(".") + 1) : text;
|
|
14657
|
+
return base.endsWith("Attribute") ? base.slice(0, -"Attribute".length) : base;
|
|
14658
|
+
}
|
|
14659
|
+
function tableFromAttribute(attr) {
|
|
14660
|
+
if (attributeName(attr) !== "Table") return null;
|
|
14661
|
+
const args = attr.childForFieldName("arguments") ?? firstChildOfType(attr, "attribute_argument_list");
|
|
14662
|
+
if (!args) return null;
|
|
14663
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
14664
|
+
const arg = args.namedChild(i);
|
|
14665
|
+
if (arg?.type !== "attribute_argument") continue;
|
|
14666
|
+
const first = arg.namedChild(0);
|
|
14667
|
+
if (!first) continue;
|
|
14668
|
+
const value = csStringLiteral(first);
|
|
14669
|
+
if (value !== null) return value;
|
|
14670
|
+
return null;
|
|
14671
|
+
}
|
|
14672
|
+
return null;
|
|
14673
|
+
}
|
|
14674
|
+
function tableFromToTable(call) {
|
|
14675
|
+
const fn = call.childForFieldName("function");
|
|
14676
|
+
if (fn?.type !== "member_access_expression") return null;
|
|
14677
|
+
const method = fn.childForFieldName("name") ?? fn.namedChild(fn.namedChildCount - 1);
|
|
14678
|
+
if (method?.text !== "ToTable") return null;
|
|
14679
|
+
const args = call.childForFieldName("arguments");
|
|
14680
|
+
const firstArg2 = args?.namedChild(0);
|
|
14681
|
+
if (firstArg2?.type !== "argument") return null;
|
|
14682
|
+
const value = firstArg2.namedChild(0);
|
|
14683
|
+
return value ? csStringLiteral(value) : null;
|
|
14684
|
+
}
|
|
14685
|
+
function efcoreEndpointsFromFile(file, serviceDir) {
|
|
14686
|
+
if (import_node_path58.default.extname(file.path) !== ".cs") return [];
|
|
14687
|
+
if (!EFCORE_GATE.test(file.content)) return [];
|
|
14688
|
+
const tree = parseSource12(makeCsParser(), file.content);
|
|
14689
|
+
const out = [];
|
|
14690
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14691
|
+
const push = (name, line) => {
|
|
14692
|
+
if (!name || seen.has(name)) return;
|
|
14693
|
+
seen.add(name);
|
|
14694
|
+
out.push({
|
|
14695
|
+
infraId: (0, import_types44.infraId)("sql-table", name),
|
|
14696
|
+
name,
|
|
14697
|
+
kind: "sql-table",
|
|
14698
|
+
edgeType: "CALLS",
|
|
14699
|
+
confidenceKind: "structural",
|
|
14700
|
+
evidence: {
|
|
14701
|
+
file: toPosix(import_node_path58.default.relative(serviceDir, file.path)),
|
|
14702
|
+
line,
|
|
14703
|
+
snippet: snippet(file.content, line)
|
|
14704
|
+
}
|
|
14705
|
+
});
|
|
14706
|
+
};
|
|
14707
|
+
walk9(tree.rootNode, (node) => {
|
|
14708
|
+
if (node.type === "attribute") {
|
|
14709
|
+
const table = tableFromAttribute(node);
|
|
14710
|
+
if (table) push(table, node.startPosition.row + 1);
|
|
14711
|
+
return;
|
|
14712
|
+
}
|
|
14713
|
+
if (node.type === "invocation_expression") {
|
|
14714
|
+
const table = tableFromToTable(node);
|
|
14715
|
+
if (table) push(table, node.startPosition.row + 1);
|
|
14716
|
+
}
|
|
14717
|
+
});
|
|
14718
|
+
return out;
|
|
14719
|
+
}
|
|
14720
|
+
|
|
13997
14721
|
// src/extract/calls/index.ts
|
|
13998
14722
|
function edgeTypeFromEndpoint(ep) {
|
|
13999
14723
|
switch (ep.edgeType) {
|
|
14000
14724
|
case "PUBLISHES_TO":
|
|
14001
|
-
return
|
|
14725
|
+
return import_types45.EdgeType.PUBLISHES_TO;
|
|
14002
14726
|
case "CONSUMES_FROM":
|
|
14003
|
-
return
|
|
14727
|
+
return import_types45.EdgeType.CONSUMES_FROM;
|
|
14004
14728
|
default:
|
|
14005
|
-
return
|
|
14729
|
+
return import_types45.EdgeType.CALLS;
|
|
14006
14730
|
}
|
|
14007
14731
|
}
|
|
14008
14732
|
function isAwsKind(kind) {
|
|
@@ -14052,6 +14776,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14052
14776
|
} catch (err) {
|
|
14053
14777
|
recordExtractionError("laravel eloquent extraction", file.path, err);
|
|
14054
14778
|
}
|
|
14779
|
+
try {
|
|
14780
|
+
endpoints.push(...efcoreEndpointsFromFile(file, service.dir));
|
|
14781
|
+
} catch (err) {
|
|
14782
|
+
recordExtractionError("efcore data-axis extraction", file.path, err);
|
|
14783
|
+
}
|
|
14055
14784
|
}
|
|
14056
14785
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
14057
14786
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
@@ -14062,7 +14791,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14062
14791
|
if (!graph.hasNode(ep.infraId)) {
|
|
14063
14792
|
const node = {
|
|
14064
14793
|
id: ep.infraId,
|
|
14065
|
-
type:
|
|
14794
|
+
type: import_types45.NodeType.InfraNode,
|
|
14066
14795
|
name: ep.name,
|
|
14067
14796
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
14068
14797
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -14075,21 +14804,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14075
14804
|
}
|
|
14076
14805
|
if (ep.columns && ep.columns.length > 0) {
|
|
14077
14806
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14078
|
-
if (node.type ===
|
|
14807
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14079
14808
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14080
14809
|
...node,
|
|
14081
14810
|
columns: foldColumns(
|
|
14082
14811
|
node.columns,
|
|
14083
14812
|
ep.columns,
|
|
14084
|
-
|
|
14085
|
-
(0,
|
|
14813
|
+
import_types45.Provenance.EXTRACTED,
|
|
14814
|
+
(0, import_types45.confidenceForExtracted)(ep.confidenceKind)
|
|
14086
14815
|
)
|
|
14087
14816
|
});
|
|
14088
14817
|
}
|
|
14089
14818
|
}
|
|
14090
14819
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
14091
14820
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14092
|
-
if (node.type ===
|
|
14821
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14093
14822
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14094
14823
|
...node,
|
|
14095
14824
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -14097,7 +14826,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14097
14826
|
}
|
|
14098
14827
|
}
|
|
14099
14828
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
14100
|
-
const confidence = (0,
|
|
14829
|
+
const confidence = (0, import_types45.confidenceForExtracted)(ep.confidenceKind);
|
|
14101
14830
|
const relFile = toPosix(ep.evidence.file);
|
|
14102
14831
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
14103
14832
|
graph,
|
|
@@ -14107,7 +14836,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14107
14836
|
);
|
|
14108
14837
|
nodesAdded += n;
|
|
14109
14838
|
edgesAdded += e;
|
|
14110
|
-
if (!(0,
|
|
14839
|
+
if (!(0, import_types45.passesExtractedFloor)(confidence)) {
|
|
14111
14840
|
noteExtractedDropped({
|
|
14112
14841
|
source: fileNodeId,
|
|
14113
14842
|
target: ep.infraId,
|
|
@@ -14127,7 +14856,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14127
14856
|
source: fileNodeId,
|
|
14128
14857
|
target: ep.infraId,
|
|
14129
14858
|
type: edgeType,
|
|
14130
|
-
provenance:
|
|
14859
|
+
provenance: import_types45.Provenance.EXTRACTED,
|
|
14131
14860
|
confidence,
|
|
14132
14861
|
evidence: ep.evidence
|
|
14133
14862
|
};
|
|
@@ -14150,7 +14879,7 @@ async function addCallEdges(graph, services) {
|
|
|
14150
14879
|
|
|
14151
14880
|
// src/extract/table-edges.ts
|
|
14152
14881
|
init_cjs_shims();
|
|
14153
|
-
var
|
|
14882
|
+
var import_types46 = require("@neat.is/types");
|
|
14154
14883
|
async function addTableEdges(graph, services) {
|
|
14155
14884
|
let nodesAdded = 0;
|
|
14156
14885
|
let edgesAdded = 0;
|
|
@@ -14178,20 +14907,20 @@ async function addTableEdges(graph, services) {
|
|
|
14178
14907
|
}
|
|
14179
14908
|
refs.push(...modelRefs);
|
|
14180
14909
|
for (const ref of refs) {
|
|
14181
|
-
const childId = (0,
|
|
14182
|
-
const parentId = (0,
|
|
14910
|
+
const childId = (0, import_types46.infraId)("sql-table", ref.childTable);
|
|
14911
|
+
const parentId = (0, import_types46.infraId)("sql-table", ref.parentTable);
|
|
14183
14912
|
if (childId === parentId) continue;
|
|
14184
14913
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
14185
14914
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
14186
|
-
const edgeId = (0,
|
|
14915
|
+
const edgeId = (0, import_types46.extractedEdgeId)(childId, parentId, import_types46.EdgeType.REFERENCES);
|
|
14187
14916
|
if (graph.hasEdge(edgeId)) continue;
|
|
14188
14917
|
const edge = {
|
|
14189
14918
|
id: edgeId,
|
|
14190
14919
|
source: childId,
|
|
14191
14920
|
target: parentId,
|
|
14192
|
-
type:
|
|
14193
|
-
provenance:
|
|
14194
|
-
confidence: (0,
|
|
14921
|
+
type: import_types46.EdgeType.REFERENCES,
|
|
14922
|
+
provenance: import_types46.Provenance.EXTRACTED,
|
|
14923
|
+
confidence: (0, import_types46.confidenceForExtracted)("structural"),
|
|
14195
14924
|
evidence: ref.evidence
|
|
14196
14925
|
};
|
|
14197
14926
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -14204,7 +14933,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
14204
14933
|
if (graph.hasNode(id)) return 0;
|
|
14205
14934
|
const node = {
|
|
14206
14935
|
id,
|
|
14207
|
-
type:
|
|
14936
|
+
type: import_types46.NodeType.InfraNode,
|
|
14208
14937
|
name,
|
|
14209
14938
|
provider: "self",
|
|
14210
14939
|
kind: "sql-table"
|
|
@@ -14218,16 +14947,16 @@ init_cjs_shims();
|
|
|
14218
14947
|
|
|
14219
14948
|
// src/extract/infra/docker-compose.ts
|
|
14220
14949
|
init_cjs_shims();
|
|
14221
|
-
var
|
|
14222
|
-
var
|
|
14950
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14951
|
+
var import_types48 = require("@neat.is/types");
|
|
14223
14952
|
|
|
14224
14953
|
// src/extract/infra/shared.ts
|
|
14225
14954
|
init_cjs_shims();
|
|
14226
|
-
var
|
|
14955
|
+
var import_types47 = require("@neat.is/types");
|
|
14227
14956
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
14228
14957
|
return {
|
|
14229
|
-
id: (0,
|
|
14230
|
-
type:
|
|
14958
|
+
id: (0, import_types47.infraId)(kind, name),
|
|
14959
|
+
type: import_types47.NodeType.InfraNode,
|
|
14231
14960
|
name,
|
|
14232
14961
|
provider,
|
|
14233
14962
|
kind,
|
|
@@ -14271,8 +15000,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
14271
15000
|
source: anchorId,
|
|
14272
15001
|
target: node.id,
|
|
14273
15002
|
type: edgeType,
|
|
14274
|
-
provenance:
|
|
14275
|
-
confidence: (0,
|
|
15003
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
15004
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
14276
15005
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14277
15006
|
};
|
|
14278
15007
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14289,7 +15018,7 @@ function dependsOnList(value) {
|
|
|
14289
15018
|
}
|
|
14290
15019
|
function serviceNameToServiceNode(name, services) {
|
|
14291
15020
|
for (const s of services) {
|
|
14292
|
-
if (s.node.name === name ||
|
|
15021
|
+
if (s.node.name === name || import_node_path59.default.basename(s.dir) === name) return s.node.id;
|
|
14293
15022
|
}
|
|
14294
15023
|
return null;
|
|
14295
15024
|
}
|
|
@@ -14298,7 +15027,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14298
15027
|
let edgesAdded = 0;
|
|
14299
15028
|
let composePath = null;
|
|
14300
15029
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
14301
|
-
const abs =
|
|
15030
|
+
const abs = import_node_path59.default.join(scanPath, name);
|
|
14302
15031
|
if (await exists2(abs)) {
|
|
14303
15032
|
composePath = abs;
|
|
14304
15033
|
break;
|
|
@@ -14311,13 +15040,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14311
15040
|
} catch (err) {
|
|
14312
15041
|
recordExtractionError(
|
|
14313
15042
|
"infra docker-compose",
|
|
14314
|
-
|
|
15043
|
+
import_node_path59.default.relative(scanPath, composePath),
|
|
14315
15044
|
err
|
|
14316
15045
|
);
|
|
14317
15046
|
return { nodesAdded, edgesAdded };
|
|
14318
15047
|
}
|
|
14319
15048
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
14320
|
-
const evidenceFile =
|
|
15049
|
+
const evidenceFile = import_node_path59.default.relative(scanPath, composePath).split(import_node_path59.default.sep).join("/");
|
|
14321
15050
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
14322
15051
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
14323
15052
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -14339,15 +15068,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14339
15068
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
14340
15069
|
const targetId = composeNameToNodeId.get(dep);
|
|
14341
15070
|
if (!targetId) continue;
|
|
14342
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
15071
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types48.EdgeType.DEPENDS_ON);
|
|
14343
15072
|
if (graph.hasEdge(edgeId)) continue;
|
|
14344
15073
|
const edge = {
|
|
14345
15074
|
id: edgeId,
|
|
14346
15075
|
source: sourceId,
|
|
14347
15076
|
target: targetId,
|
|
14348
|
-
type:
|
|
14349
|
-
provenance:
|
|
14350
|
-
confidence: (0,
|
|
15077
|
+
type: import_types48.EdgeType.DEPENDS_ON,
|
|
15078
|
+
provenance: import_types48.Provenance.EXTRACTED,
|
|
15079
|
+
confidence: (0, import_types48.confidenceForExtracted)("structural"),
|
|
14351
15080
|
evidence: { file: evidenceFile }
|
|
14352
15081
|
};
|
|
14353
15082
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14359,9 +15088,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14359
15088
|
|
|
14360
15089
|
// src/extract/infra/dockerfile.ts
|
|
14361
15090
|
init_cjs_shims();
|
|
14362
|
-
var
|
|
14363
|
-
var
|
|
14364
|
-
var
|
|
15091
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
15092
|
+
var import_node_fs27 = require("fs");
|
|
15093
|
+
var import_types49 = require("@neat.is/types");
|
|
14365
15094
|
function readDockerfile(content) {
|
|
14366
15095
|
let image = null;
|
|
14367
15096
|
const ports = [];
|
|
@@ -14390,15 +15119,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14390
15119
|
let nodesAdded = 0;
|
|
14391
15120
|
let edgesAdded = 0;
|
|
14392
15121
|
for (const service of services) {
|
|
14393
|
-
const dockerfilePath =
|
|
15122
|
+
const dockerfilePath = import_node_path60.default.join(service.dir, "Dockerfile");
|
|
14394
15123
|
if (!await exists2(dockerfilePath)) continue;
|
|
14395
15124
|
let content;
|
|
14396
15125
|
try {
|
|
14397
|
-
content = await
|
|
15126
|
+
content = await import_node_fs27.promises.readFile(dockerfilePath, "utf8");
|
|
14398
15127
|
} catch (err) {
|
|
14399
15128
|
recordExtractionError(
|
|
14400
15129
|
"infra dockerfile",
|
|
14401
|
-
|
|
15130
|
+
import_node_path60.default.relative(scanPath, dockerfilePath),
|
|
14402
15131
|
err
|
|
14403
15132
|
);
|
|
14404
15133
|
continue;
|
|
@@ -14410,8 +15139,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14410
15139
|
graph.addNode(node.id, node);
|
|
14411
15140
|
nodesAdded++;
|
|
14412
15141
|
}
|
|
14413
|
-
const relDockerfile = toPosix(
|
|
14414
|
-
const evidenceFile = toPosix(
|
|
15142
|
+
const relDockerfile = toPosix(import_node_path60.default.relative(service.dir, dockerfilePath));
|
|
15143
|
+
const evidenceFile = toPosix(import_node_path60.default.relative(scanPath, dockerfilePath));
|
|
14415
15144
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14416
15145
|
graph,
|
|
14417
15146
|
service.pkg.name,
|
|
@@ -14420,15 +15149,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14420
15149
|
);
|
|
14421
15150
|
nodesAdded += fn;
|
|
14422
15151
|
edgesAdded += fe;
|
|
14423
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
15152
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types49.EdgeType.RUNS_ON);
|
|
14424
15153
|
if (!graph.hasEdge(edgeId)) {
|
|
14425
15154
|
const edge = {
|
|
14426
15155
|
id: edgeId,
|
|
14427
15156
|
source: fileNodeId,
|
|
14428
15157
|
target: node.id,
|
|
14429
|
-
type:
|
|
14430
|
-
provenance:
|
|
14431
|
-
confidence: (0,
|
|
15158
|
+
type: import_types49.EdgeType.RUNS_ON,
|
|
15159
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15160
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14432
15161
|
evidence: {
|
|
14433
15162
|
file: evidenceFile,
|
|
14434
15163
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -14443,15 +15172,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14443
15172
|
graph.addNode(portNode.id, portNode);
|
|
14444
15173
|
nodesAdded++;
|
|
14445
15174
|
}
|
|
14446
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
15175
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types49.EdgeType.CONNECTS_TO);
|
|
14447
15176
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
14448
15177
|
const portEdge = {
|
|
14449
15178
|
id: portEdgeId,
|
|
14450
15179
|
source: fileNodeId,
|
|
14451
15180
|
target: portNode.id,
|
|
14452
|
-
type:
|
|
14453
|
-
provenance:
|
|
14454
|
-
confidence: (0,
|
|
15181
|
+
type: import_types49.EdgeType.CONNECTS_TO,
|
|
15182
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15183
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14455
15184
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
14456
15185
|
};
|
|
14457
15186
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -14463,23 +15192,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14463
15192
|
|
|
14464
15193
|
// src/extract/infra/terraform.ts
|
|
14465
15194
|
init_cjs_shims();
|
|
14466
|
-
var
|
|
14467
|
-
var
|
|
14468
|
-
var
|
|
15195
|
+
var import_node_fs28 = require("fs");
|
|
15196
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
15197
|
+
var import_types50 = require("@neat.is/types");
|
|
14469
15198
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
14470
15199
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
14471
15200
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
14472
15201
|
if (depth > max) return [];
|
|
14473
15202
|
const out = [];
|
|
14474
|
-
const entries = await
|
|
15203
|
+
const entries = await import_node_fs28.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
14475
15204
|
for (const entry of entries) {
|
|
14476
15205
|
if (entry.isDirectory()) {
|
|
14477
15206
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
14478
|
-
const child =
|
|
15207
|
+
const child = import_node_path61.default.join(start, entry.name);
|
|
14479
15208
|
if (await isPythonVenvDir(child)) continue;
|
|
14480
15209
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
14481
15210
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
14482
|
-
out.push(
|
|
15211
|
+
out.push(import_node_path61.default.join(start, entry.name));
|
|
14483
15212
|
}
|
|
14484
15213
|
}
|
|
14485
15214
|
return out;
|
|
@@ -14510,8 +15239,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14510
15239
|
let edgesAdded = 0;
|
|
14511
15240
|
const files = await walkTfFiles(scanPath);
|
|
14512
15241
|
for (const file of files) {
|
|
14513
|
-
const content = await
|
|
14514
|
-
const evidenceFile = toPosix(
|
|
15242
|
+
const content = await import_node_fs28.promises.readFile(file, "utf8");
|
|
15243
|
+
const evidenceFile = toPosix(import_node_path61.default.relative(scanPath, file));
|
|
14515
15244
|
const resources = [];
|
|
14516
15245
|
const byKey = /* @__PURE__ */ new Map();
|
|
14517
15246
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -14546,16 +15275,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14546
15275
|
if (!target) continue;
|
|
14547
15276
|
if (seen.has(target.nodeId)) continue;
|
|
14548
15277
|
seen.add(target.nodeId);
|
|
14549
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
15278
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types50.EdgeType.DEPENDS_ON);
|
|
14550
15279
|
if (graph.hasEdge(edgeId)) continue;
|
|
14551
15280
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
14552
15281
|
const edge = {
|
|
14553
15282
|
id: edgeId,
|
|
14554
15283
|
source: resource.nodeId,
|
|
14555
15284
|
target: target.nodeId,
|
|
14556
|
-
type:
|
|
14557
|
-
provenance:
|
|
14558
|
-
confidence: (0,
|
|
15285
|
+
type: import_types50.EdgeType.DEPENDS_ON,
|
|
15286
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
15287
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
14559
15288
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
14560
15289
|
};
|
|
14561
15290
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14568,8 +15297,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14568
15297
|
|
|
14569
15298
|
// src/extract/infra/k8s.ts
|
|
14570
15299
|
init_cjs_shims();
|
|
14571
|
-
var
|
|
14572
|
-
var
|
|
15300
|
+
var import_node_fs29 = require("fs");
|
|
15301
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
14573
15302
|
var import_yaml3 = require("yaml");
|
|
14574
15303
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
14575
15304
|
Service: "k8s-service",
|
|
@@ -14583,15 +15312,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
14583
15312
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
14584
15313
|
if (depth > max) return [];
|
|
14585
15314
|
const out = [];
|
|
14586
|
-
const entries = await
|
|
15315
|
+
const entries = await import_node_fs29.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
14587
15316
|
for (const entry of entries) {
|
|
14588
15317
|
if (entry.isDirectory()) {
|
|
14589
15318
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
14590
|
-
const child =
|
|
15319
|
+
const child = import_node_path62.default.join(start, entry.name);
|
|
14591
15320
|
if (await isPythonVenvDir(child)) continue;
|
|
14592
15321
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
14593
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
14594
|
-
out.push(
|
|
15322
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path62.default.extname(entry.name))) {
|
|
15323
|
+
out.push(import_node_path62.default.join(start, entry.name));
|
|
14595
15324
|
}
|
|
14596
15325
|
}
|
|
14597
15326
|
return out;
|
|
@@ -14600,7 +15329,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14600
15329
|
let nodesAdded = 0;
|
|
14601
15330
|
const files = await walkYamlFiles2(scanPath);
|
|
14602
15331
|
for (const file of files) {
|
|
14603
|
-
const content = await
|
|
15332
|
+
const content = await import_node_fs29.promises.readFile(file, "utf8");
|
|
14604
15333
|
let docs;
|
|
14605
15334
|
try {
|
|
14606
15335
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -14624,16 +15353,16 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14624
15353
|
|
|
14625
15354
|
// src/extract/infra/cloudflare.ts
|
|
14626
15355
|
init_cjs_shims();
|
|
14627
|
-
var
|
|
14628
|
-
var
|
|
15356
|
+
var import_node_fs30 = require("fs");
|
|
15357
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
14629
15358
|
var import_smol_toml3 = require("smol-toml");
|
|
14630
|
-
var
|
|
15359
|
+
var import_types51 = require("@neat.is/types");
|
|
14631
15360
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
14632
15361
|
async function readWranglerConfig(dir) {
|
|
14633
15362
|
for (const filename of WRANGLER_FILENAMES) {
|
|
14634
|
-
const abs =
|
|
15363
|
+
const abs = import_node_path63.default.join(dir, filename);
|
|
14635
15364
|
if (!await exists2(abs)) continue;
|
|
14636
|
-
const raw = await
|
|
15365
|
+
const raw = await import_node_fs30.promises.readFile(abs, "utf8");
|
|
14637
15366
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14638
15367
|
return { config, relFile: filename, raw };
|
|
14639
15368
|
}
|
|
@@ -14675,8 +15404,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
14675
15404
|
source: anchorId,
|
|
14676
15405
|
target: node.id,
|
|
14677
15406
|
type: edgeType,
|
|
14678
|
-
provenance:
|
|
14679
|
-
confidence: (0,
|
|
15407
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15408
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14680
15409
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14681
15410
|
};
|
|
14682
15411
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14694,11 +15423,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14694
15423
|
try {
|
|
14695
15424
|
read = await readWranglerConfig(service.dir);
|
|
14696
15425
|
} catch (err) {
|
|
14697
|
-
recordExtractionError("infra cloudflare",
|
|
15426
|
+
recordExtractionError("infra cloudflare", import_node_path63.default.relative(scanPath, service.dir), err);
|
|
14698
15427
|
continue;
|
|
14699
15428
|
}
|
|
14700
15429
|
if (!read || !read.config.name) continue;
|
|
14701
|
-
const evidenceFile = toPosix(
|
|
15430
|
+
const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, import_node_path63.default.join(service.dir, read.relFile)));
|
|
14702
15431
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
14703
15432
|
}
|
|
14704
15433
|
for (const worker of discovered) {
|
|
@@ -14710,7 +15439,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14710
15439
|
}
|
|
14711
15440
|
let anchorId = service.node.id;
|
|
14712
15441
|
if (config.main) {
|
|
14713
|
-
const entryRelPath = toPosix(
|
|
15442
|
+
const entryRelPath = toPosix(import_node_path63.default.normalize(config.main));
|
|
14714
15443
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14715
15444
|
graph,
|
|
14716
15445
|
service.pkg.name,
|
|
@@ -14737,15 +15466,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14737
15466
|
nodesAdded++;
|
|
14738
15467
|
}
|
|
14739
15468
|
if (runtimeNode.id !== anchorId) {
|
|
14740
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
15469
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types51.EdgeType.RUNS_ON);
|
|
14741
15470
|
if (!graph.hasEdge(runsOnId)) {
|
|
14742
15471
|
const edge = {
|
|
14743
15472
|
id: runsOnId,
|
|
14744
15473
|
source: anchorId,
|
|
14745
15474
|
target: runtimeNode.id,
|
|
14746
|
-
type:
|
|
14747
|
-
provenance:
|
|
14748
|
-
confidence: (0,
|
|
15475
|
+
type: import_types51.EdgeType.RUNS_ON,
|
|
15476
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15477
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14749
15478
|
evidence: {
|
|
14750
15479
|
file: evidenceFile,
|
|
14751
15480
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -14759,7 +15488,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14759
15488
|
const result = addResourceEdge(
|
|
14760
15489
|
graph,
|
|
14761
15490
|
anchorId,
|
|
14762
|
-
|
|
15491
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
14763
15492
|
"cloudflare-route",
|
|
14764
15493
|
route,
|
|
14765
15494
|
evidenceFile,
|
|
@@ -14783,7 +15512,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14783
15512
|
const result = addResourceEdge(
|
|
14784
15513
|
graph,
|
|
14785
15514
|
anchorId,
|
|
14786
|
-
|
|
15515
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14787
15516
|
group.kind,
|
|
14788
15517
|
name,
|
|
14789
15518
|
evidenceFile,
|
|
@@ -14797,7 +15526,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14797
15526
|
const result = addResourceEdge(
|
|
14798
15527
|
graph,
|
|
14799
15528
|
anchorId,
|
|
14800
|
-
|
|
15529
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14801
15530
|
"cloudflare-cron",
|
|
14802
15531
|
cron,
|
|
14803
15532
|
evidenceFile,
|
|
@@ -14810,7 +15539,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14810
15539
|
const result = addResourceEdge(
|
|
14811
15540
|
graph,
|
|
14812
15541
|
anchorId,
|
|
14813
|
-
|
|
15542
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14814
15543
|
"cloudflare-env-var",
|
|
14815
15544
|
varName,
|
|
14816
15545
|
evidenceFile,
|
|
@@ -14823,15 +15552,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14823
15552
|
if (!svc.service) continue;
|
|
14824
15553
|
const target = workerIndex.get(svc.service);
|
|
14825
15554
|
if (target && target.anchorId !== anchorId) {
|
|
14826
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
15555
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types51.EdgeType.CALLS);
|
|
14827
15556
|
if (!graph.hasEdge(edgeId)) {
|
|
14828
15557
|
const edge = {
|
|
14829
15558
|
id: edgeId,
|
|
14830
15559
|
source: anchorId,
|
|
14831
15560
|
target: target.anchorId,
|
|
14832
|
-
type:
|
|
14833
|
-
provenance:
|
|
14834
|
-
confidence: (0,
|
|
15561
|
+
type: import_types51.EdgeType.CALLS,
|
|
15562
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15563
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14835
15564
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
14836
15565
|
};
|
|
14837
15566
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14842,7 +15571,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14842
15571
|
const result = addResourceEdge(
|
|
14843
15572
|
graph,
|
|
14844
15573
|
anchorId,
|
|
14845
|
-
|
|
15574
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14846
15575
|
"cloudflare-service-binding",
|
|
14847
15576
|
svc.service,
|
|
14848
15577
|
evidenceFile,
|
|
@@ -14857,24 +15586,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14857
15586
|
|
|
14858
15587
|
// src/extract/infra/vercel.ts
|
|
14859
15588
|
init_cjs_shims();
|
|
14860
|
-
var
|
|
14861
|
-
var
|
|
14862
|
-
var
|
|
15589
|
+
var import_node_fs31 = require("fs");
|
|
15590
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
15591
|
+
var import_types52 = require("@neat.is/types");
|
|
14863
15592
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
14864
15593
|
async function readVercelConfig(dir) {
|
|
14865
15594
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
14866
|
-
const abs =
|
|
15595
|
+
const abs = import_node_path64.default.join(dir, filename);
|
|
14867
15596
|
if (!await exists2(abs)) continue;
|
|
14868
|
-
const raw = await
|
|
15597
|
+
const raw = await import_node_fs31.promises.readFile(abs, "utf8");
|
|
14869
15598
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
14870
15599
|
return { config, relFile: filename, raw };
|
|
14871
15600
|
}
|
|
14872
15601
|
return null;
|
|
14873
15602
|
}
|
|
14874
15603
|
async function readLinkedProjectName(dir) {
|
|
14875
|
-
const abs =
|
|
15604
|
+
const abs = import_node_path64.default.join(dir, ".vercel", "project.json");
|
|
14876
15605
|
if (!await exists2(abs)) return void 0;
|
|
14877
|
-
const parsed = JSON.parse(await
|
|
15606
|
+
const parsed = JSON.parse(await import_node_fs31.promises.readFile(abs, "utf8"));
|
|
14878
15607
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
14879
15608
|
}
|
|
14880
15609
|
function routeSource(route) {
|
|
@@ -14890,7 +15619,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14890
15619
|
read = await readVercelConfig(service.dir);
|
|
14891
15620
|
projectName = await readLinkedProjectName(service.dir);
|
|
14892
15621
|
} catch (err) {
|
|
14893
|
-
recordExtractionError("infra vercel",
|
|
15622
|
+
recordExtractionError("infra vercel", import_node_path64.default.relative(scanPath, service.dir), err);
|
|
14894
15623
|
continue;
|
|
14895
15624
|
}
|
|
14896
15625
|
if (!read && !projectName) continue;
|
|
@@ -14906,7 +15635,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14906
15635
|
const anchorId = service.node.id;
|
|
14907
15636
|
if (!read) continue;
|
|
14908
15637
|
const { config, relFile, raw } = read;
|
|
14909
|
-
const evidenceFile = toPosix(
|
|
15638
|
+
const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, import_node_path64.default.join(service.dir, relFile)));
|
|
14910
15639
|
const add = (edgeType, kind, name) => {
|
|
14911
15640
|
if (!name) return;
|
|
14912
15641
|
const result = emitPlatformResourceEdge(
|
|
@@ -14922,12 +15651,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14922
15651
|
nodesAdded += result.nodesAdded;
|
|
14923
15652
|
edgesAdded += result.edgesAdded;
|
|
14924
15653
|
};
|
|
14925
|
-
add(
|
|
14926
|
-
for (const cron of config.crons ?? []) add(
|
|
14927
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
14928
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
15654
|
+
add(import_types52.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
15655
|
+
for (const cron of config.crons ?? []) add(import_types52.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
15656
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types52.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
15657
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types52.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
14929
15658
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
14930
|
-
add(
|
|
15659
|
+
add(import_types52.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
14931
15660
|
}
|
|
14932
15661
|
}
|
|
14933
15662
|
return { nodesAdded, edgesAdded };
|
|
@@ -14935,16 +15664,16 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14935
15664
|
|
|
14936
15665
|
// src/extract/infra/railway.ts
|
|
14937
15666
|
init_cjs_shims();
|
|
14938
|
-
var
|
|
14939
|
-
var
|
|
15667
|
+
var import_node_fs32 = require("fs");
|
|
15668
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
14940
15669
|
var import_smol_toml4 = require("smol-toml");
|
|
14941
|
-
var
|
|
15670
|
+
var import_types53 = require("@neat.is/types");
|
|
14942
15671
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
14943
15672
|
async function readRailwayConfig(dir) {
|
|
14944
15673
|
for (const filename of RAILWAY_FILENAMES) {
|
|
14945
|
-
const abs =
|
|
15674
|
+
const abs = import_node_path65.default.join(dir, filename);
|
|
14946
15675
|
if (!await exists2(abs)) continue;
|
|
14947
|
-
const raw = await
|
|
15676
|
+
const raw = await import_node_fs32.promises.readFile(abs, "utf8");
|
|
14948
15677
|
const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14949
15678
|
return { config, relFile: filename, raw };
|
|
14950
15679
|
}
|
|
@@ -14958,7 +15687,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14958
15687
|
try {
|
|
14959
15688
|
read = await readRailwayConfig(service.dir);
|
|
14960
15689
|
} catch (err) {
|
|
14961
|
-
recordExtractionError("infra railway",
|
|
15690
|
+
recordExtractionError("infra railway", import_node_path65.default.relative(scanPath, service.dir), err);
|
|
14962
15691
|
continue;
|
|
14963
15692
|
}
|
|
14964
15693
|
if (!read) continue;
|
|
@@ -14968,7 +15697,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14968
15697
|
}
|
|
14969
15698
|
const anchorId = service.node.id;
|
|
14970
15699
|
const { config, relFile, raw } = read;
|
|
14971
|
-
const evidenceFile = toPosix(
|
|
15700
|
+
const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, relFile)));
|
|
14972
15701
|
const add = (edgeType, kind, name) => {
|
|
14973
15702
|
if (!name) return;
|
|
14974
15703
|
const result = emitPlatformResourceEdge(
|
|
@@ -14984,24 +15713,24 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14984
15713
|
nodesAdded += result.nodesAdded;
|
|
14985
15714
|
edgesAdded += result.edgesAdded;
|
|
14986
15715
|
};
|
|
14987
|
-
add(
|
|
14988
|
-
add(
|
|
14989
|
-
add(
|
|
15716
|
+
add(import_types53.EdgeType.RUNS_ON, "railway", "railway");
|
|
15717
|
+
add(import_types53.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
15718
|
+
add(import_types53.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
14990
15719
|
}
|
|
14991
15720
|
return { nodesAdded, edgesAdded };
|
|
14992
15721
|
}
|
|
14993
15722
|
|
|
14994
15723
|
// src/extract/infra/supabase.ts
|
|
14995
15724
|
init_cjs_shims();
|
|
14996
|
-
var
|
|
14997
|
-
var
|
|
15725
|
+
var import_node_fs33 = require("fs");
|
|
15726
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
14998
15727
|
var import_smol_toml5 = require("smol-toml");
|
|
14999
|
-
var
|
|
15728
|
+
var import_types54 = require("@neat.is/types");
|
|
15000
15729
|
async function readSupabaseConfig(dir) {
|
|
15001
|
-
const relFile =
|
|
15002
|
-
const abs =
|
|
15730
|
+
const relFile = import_node_path66.default.join("supabase", "config.toml");
|
|
15731
|
+
const abs = import_node_path66.default.join(dir, relFile);
|
|
15003
15732
|
if (!await exists2(abs)) return null;
|
|
15004
|
-
const raw = await
|
|
15733
|
+
const raw = await import_node_fs33.promises.readFile(abs, "utf8");
|
|
15005
15734
|
const config = (0, import_smol_toml5.parse)(raw);
|
|
15006
15735
|
return { config, relFile, raw };
|
|
15007
15736
|
}
|
|
@@ -15013,7 +15742,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15013
15742
|
try {
|
|
15014
15743
|
read = await readSupabaseConfig(service.dir);
|
|
15015
15744
|
} catch (err) {
|
|
15016
|
-
recordExtractionError("infra supabase",
|
|
15745
|
+
recordExtractionError("infra supabase", import_node_path66.default.relative(scanPath, service.dir), err);
|
|
15017
15746
|
continue;
|
|
15018
15747
|
}
|
|
15019
15748
|
if (!read) continue;
|
|
@@ -15028,7 +15757,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15028
15757
|
});
|
|
15029
15758
|
}
|
|
15030
15759
|
const anchorId = service.node.id;
|
|
15031
|
-
const evidenceFile = toPosix(
|
|
15760
|
+
const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, relFile)));
|
|
15032
15761
|
const add = (edgeType, kind, name) => {
|
|
15033
15762
|
if (!name) return;
|
|
15034
15763
|
const result = emitPlatformResourceEdge(
|
|
@@ -15044,10 +15773,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15044
15773
|
nodesAdded += result.nodesAdded;
|
|
15045
15774
|
edgesAdded += result.edgesAdded;
|
|
15046
15775
|
};
|
|
15047
|
-
add(
|
|
15048
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
15049
|
-
if (config.storage) add(
|
|
15050
|
-
if (config.auth) add(
|
|
15776
|
+
add(import_types54.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
15777
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types54.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
15778
|
+
if (config.storage) add(import_types54.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
15779
|
+
if (config.auth) add(import_types54.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
15051
15780
|
}
|
|
15052
15781
|
return { nodesAdded, edgesAdded };
|
|
15053
15782
|
}
|
|
@@ -15070,14 +15799,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
15070
15799
|
|
|
15071
15800
|
// src/extract/zod-shapes.ts
|
|
15072
15801
|
init_cjs_shims();
|
|
15073
|
-
var
|
|
15074
|
-
var
|
|
15802
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
15803
|
+
var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
|
|
15075
15804
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
15076
|
-
var
|
|
15805
|
+
var import_types55 = require("@neat.is/types");
|
|
15077
15806
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
15078
15807
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
15079
15808
|
function parserForExt4(ext) {
|
|
15080
|
-
const p = new
|
|
15809
|
+
const p = new import_tree_sitter17.default();
|
|
15081
15810
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
15082
15811
|
return p;
|
|
15083
15812
|
}
|
|
@@ -15165,7 +15894,7 @@ function topLevelSchemas(root) {
|
|
|
15165
15894
|
}
|
|
15166
15895
|
function zodShapesFromFile(file, serviceDir) {
|
|
15167
15896
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
15168
|
-
const tree = parseSource3(parserForExt4(
|
|
15897
|
+
const tree = parseSource3(parserForExt4(import_node_path67.default.extname(file.path)), file.content);
|
|
15169
15898
|
const out = [];
|
|
15170
15899
|
const seen = /* @__PURE__ */ new Set();
|
|
15171
15900
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -15179,11 +15908,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
15179
15908
|
seen.add(name);
|
|
15180
15909
|
const line = call.startPosition.row + 1;
|
|
15181
15910
|
out.push({
|
|
15182
|
-
infraId: (0,
|
|
15911
|
+
infraId: (0, import_types55.infraId)("zod-schema", name),
|
|
15183
15912
|
name,
|
|
15184
15913
|
fields,
|
|
15185
15914
|
evidence: {
|
|
15186
|
-
file:
|
|
15915
|
+
file: import_node_path67.default.relative(serviceDir, file.path),
|
|
15187
15916
|
line,
|
|
15188
15917
|
snippet: snippet(file.content, line)
|
|
15189
15918
|
}
|
|
@@ -15214,7 +15943,7 @@ async function addZodShapes(graph, services) {
|
|
|
15214
15943
|
if (!graph.hasNode(shape.infraId)) {
|
|
15215
15944
|
const node = {
|
|
15216
15945
|
id: shape.infraId,
|
|
15217
|
-
type:
|
|
15946
|
+
type: import_types55.NodeType.InfraNode,
|
|
15218
15947
|
name: shape.name,
|
|
15219
15948
|
provider: "self",
|
|
15220
15949
|
kind: "zod-schema"
|
|
@@ -15224,14 +15953,14 @@ async function addZodShapes(graph, services) {
|
|
|
15224
15953
|
}
|
|
15225
15954
|
if (shape.fields.length > 0) {
|
|
15226
15955
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
15227
|
-
if (node.type ===
|
|
15956
|
+
if (node.type === import_types55.NodeType.InfraNode) {
|
|
15228
15957
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
15229
15958
|
...node,
|
|
15230
15959
|
columns: foldColumns(
|
|
15231
15960
|
node.columns,
|
|
15232
15961
|
shape.fields,
|
|
15233
|
-
|
|
15234
|
-
(0,
|
|
15962
|
+
import_types55.Provenance.EXTRACTED,
|
|
15963
|
+
(0, import_types55.confidenceForExtracted)("structural")
|
|
15235
15964
|
)
|
|
15236
15965
|
});
|
|
15237
15966
|
}
|
|
@@ -15245,15 +15974,15 @@ async function addZodShapes(graph, services) {
|
|
|
15245
15974
|
);
|
|
15246
15975
|
nodesAdded += n;
|
|
15247
15976
|
edgesAdded += e;
|
|
15248
|
-
const edgeId = (0,
|
|
15977
|
+
const edgeId = (0, import_types55.extractedEdgeId)(fileNodeId, shape.infraId, import_types55.EdgeType.CONTAINS);
|
|
15249
15978
|
if (!graph.hasEdge(edgeId)) {
|
|
15250
15979
|
const edge = {
|
|
15251
15980
|
id: edgeId,
|
|
15252
15981
|
source: fileNodeId,
|
|
15253
15982
|
target: shape.infraId,
|
|
15254
|
-
type:
|
|
15255
|
-
provenance:
|
|
15256
|
-
confidence: (0,
|
|
15983
|
+
type: import_types55.EdgeType.CONTAINS,
|
|
15984
|
+
provenance: import_types55.Provenance.EXTRACTED,
|
|
15985
|
+
confidence: (0, import_types55.confidenceForExtracted)("structural"),
|
|
15257
15986
|
evidence: shape.evidence
|
|
15258
15987
|
};
|
|
15259
15988
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -15267,7 +15996,7 @@ async function addZodShapes(graph, services) {
|
|
|
15267
15996
|
|
|
15268
15997
|
// src/extract/firestore-rules.ts
|
|
15269
15998
|
init_cjs_shims();
|
|
15270
|
-
var
|
|
15999
|
+
var import_types56 = require("@neat.is/types");
|
|
15271
16000
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
15272
16001
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
15273
16002
|
function stripComments(src) {
|
|
@@ -15407,7 +16136,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
15407
16136
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
15408
16137
|
graph.forEachNode((id, attrs) => {
|
|
15409
16138
|
const node = attrs;
|
|
15410
|
-
if (node.type !==
|
|
16139
|
+
if (node.type !== import_types56.NodeType.InfraNode) return;
|
|
15411
16140
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
15412
16141
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
15413
16142
|
if (!fields || fields.size === 0) return;
|
|
@@ -15420,17 +16149,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
15420
16149
|
}
|
|
15421
16150
|
|
|
15422
16151
|
// src/extract/index.ts
|
|
15423
|
-
var
|
|
16152
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
15424
16153
|
|
|
15425
16154
|
// src/extract/retire.ts
|
|
15426
16155
|
init_cjs_shims();
|
|
15427
|
-
var
|
|
15428
|
-
var
|
|
15429
|
-
var
|
|
16156
|
+
var import_node_fs34 = require("fs");
|
|
16157
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
16158
|
+
var import_types57 = require("@neat.is/types");
|
|
15430
16159
|
function dropOrphanedFileNodes(graph) {
|
|
15431
16160
|
const orphans = [];
|
|
15432
16161
|
graph.forEachNode((id, attrs) => {
|
|
15433
|
-
if (attrs.type !==
|
|
16162
|
+
if (attrs.type !== import_types57.NodeType.FileNode) return;
|
|
15434
16163
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
15435
16164
|
orphans.push(id);
|
|
15436
16165
|
}
|
|
@@ -15443,14 +16172,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
15443
16172
|
const bases = [scanPath, ...serviceDirs];
|
|
15444
16173
|
graph.forEachEdge((id, attrs) => {
|
|
15445
16174
|
const edge = attrs;
|
|
15446
|
-
if (edge.provenance !==
|
|
16175
|
+
if (edge.provenance !== import_types57.Provenance.EXTRACTED) return;
|
|
15447
16176
|
const evidenceFile = edge.evidence?.file;
|
|
15448
16177
|
if (!evidenceFile) return;
|
|
15449
|
-
if (
|
|
15450
|
-
if (!(0,
|
|
16178
|
+
if (import_node_path68.default.isAbsolute(evidenceFile)) {
|
|
16179
|
+
if (!(0, import_node_fs34.existsSync)(evidenceFile)) toDrop.push(id);
|
|
15451
16180
|
return;
|
|
15452
16181
|
}
|
|
15453
|
-
const found = bases.some((base) => (0,
|
|
16182
|
+
const found = bases.some((base) => (0, import_node_fs34.existsSync)(import_node_path68.default.join(base, evidenceFile)));
|
|
15454
16183
|
if (!found) toDrop.push(id);
|
|
15455
16184
|
});
|
|
15456
16185
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -15507,7 +16236,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15507
16236
|
}
|
|
15508
16237
|
const droppedEntries = drainDroppedExtracted();
|
|
15509
16238
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
15510
|
-
const rejectedPath =
|
|
16239
|
+
const rejectedPath = import_node_path69.default.join(import_node_path69.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
15511
16240
|
try {
|
|
15512
16241
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
15513
16242
|
} catch (err) {
|
|
@@ -15541,7 +16270,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15541
16270
|
|
|
15542
16271
|
// src/diff.ts
|
|
15543
16272
|
init_cjs_shims();
|
|
15544
|
-
var
|
|
16273
|
+
var import_node_fs35 = require("fs");
|
|
15545
16274
|
async function loadSnapshotForDiff(target) {
|
|
15546
16275
|
if (/^https?:\/\//i.test(target)) {
|
|
15547
16276
|
const res = await fetch(target);
|
|
@@ -15550,7 +16279,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
15550
16279
|
}
|
|
15551
16280
|
return await res.json();
|
|
15552
16281
|
}
|
|
15553
|
-
const raw = await
|
|
16282
|
+
const raw = await import_node_fs35.promises.readFile(target, "utf8");
|
|
15554
16283
|
return JSON.parse(raw);
|
|
15555
16284
|
}
|
|
15556
16285
|
function indexEntries(entries) {
|
|
@@ -15618,9 +16347,9 @@ function canonicalJson(value) {
|
|
|
15618
16347
|
|
|
15619
16348
|
// src/persist.ts
|
|
15620
16349
|
init_cjs_shims();
|
|
15621
|
-
var
|
|
15622
|
-
var
|
|
15623
|
-
var
|
|
16350
|
+
var import_node_fs36 = require("fs");
|
|
16351
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
16352
|
+
var import_types58 = require("@neat.is/types");
|
|
15624
16353
|
var SCHEMA_VERSION = 7;
|
|
15625
16354
|
function migrateV1ToV2(payload) {
|
|
15626
16355
|
const nodes = payload.graph.nodes;
|
|
@@ -15644,7 +16373,7 @@ function migrateV5ToV6(payload) {
|
|
|
15644
16373
|
if (Array.isArray(nodes)) {
|
|
15645
16374
|
for (const node of nodes) {
|
|
15646
16375
|
const attrs = node.attributes;
|
|
15647
|
-
if (!attrs || attrs.type !==
|
|
16376
|
+
if (!attrs || attrs.type !== import_types58.NodeType.InfraNode) continue;
|
|
15648
16377
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
15649
16378
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
15650
16379
|
}
|
|
@@ -15660,12 +16389,12 @@ function migrateV2ToV3(payload) {
|
|
|
15660
16389
|
for (const edge of edges) {
|
|
15661
16390
|
const attrs = edge.attributes;
|
|
15662
16391
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
15663
|
-
attrs.provenance =
|
|
16392
|
+
attrs.provenance = import_types58.Provenance.OBSERVED;
|
|
15664
16393
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
15665
16394
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
15666
16395
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
15667
16396
|
if (type && source && target) {
|
|
15668
|
-
const newId = (0,
|
|
16397
|
+
const newId = (0, import_types58.observedEdgeId)(source, target, type);
|
|
15669
16398
|
attrs.id = newId;
|
|
15670
16399
|
if (edge.key) edge.key = newId;
|
|
15671
16400
|
}
|
|
@@ -15674,7 +16403,7 @@ function migrateV2ToV3(payload) {
|
|
|
15674
16403
|
return { ...payload, schemaVersion: 3 };
|
|
15675
16404
|
}
|
|
15676
16405
|
async function ensureDir(filePath) {
|
|
15677
|
-
await
|
|
16406
|
+
await import_node_fs36.promises.mkdir(import_node_path70.default.dirname(filePath), { recursive: true });
|
|
15678
16407
|
}
|
|
15679
16408
|
async function saveGraphToDisk(graph, outPath) {
|
|
15680
16409
|
await ensureDir(outPath);
|
|
@@ -15684,13 +16413,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
15684
16413
|
graph: graph.export()
|
|
15685
16414
|
};
|
|
15686
16415
|
const tmp = `${outPath}.tmp`;
|
|
15687
|
-
await
|
|
15688
|
-
await
|
|
16416
|
+
await import_node_fs36.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
16417
|
+
await import_node_fs36.promises.rename(tmp, outPath);
|
|
15689
16418
|
}
|
|
15690
16419
|
async function loadGraphFromDisk(graph, outPath) {
|
|
15691
16420
|
let raw;
|
|
15692
16421
|
try {
|
|
15693
|
-
raw = await
|
|
16422
|
+
raw = await import_node_fs36.promises.readFile(outPath, "utf8");
|
|
15694
16423
|
} catch (err) {
|
|
15695
16424
|
if (err.code === "ENOENT") return;
|
|
15696
16425
|
throw err;
|
|
@@ -15764,23 +16493,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
15764
16493
|
|
|
15765
16494
|
// src/projects.ts
|
|
15766
16495
|
init_cjs_shims();
|
|
15767
|
-
var
|
|
16496
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
15768
16497
|
function pathsForProject(project, baseDir) {
|
|
15769
16498
|
if (project === DEFAULT_PROJECT) {
|
|
15770
16499
|
return {
|
|
15771
|
-
snapshotPath:
|
|
15772
|
-
errorsPath:
|
|
15773
|
-
staleEventsPath:
|
|
15774
|
-
embeddingsCachePath:
|
|
15775
|
-
policyViolationsPath:
|
|
16500
|
+
snapshotPath: import_node_path71.default.join(baseDir, "graph.json"),
|
|
16501
|
+
errorsPath: import_node_path71.default.join(baseDir, "errors.ndjson"),
|
|
16502
|
+
staleEventsPath: import_node_path71.default.join(baseDir, "stale-events.ndjson"),
|
|
16503
|
+
embeddingsCachePath: import_node_path71.default.join(baseDir, "embeddings.json"),
|
|
16504
|
+
policyViolationsPath: import_node_path71.default.join(baseDir, "policy-violations.ndjson")
|
|
15776
16505
|
};
|
|
15777
16506
|
}
|
|
15778
16507
|
return {
|
|
15779
|
-
snapshotPath:
|
|
15780
|
-
errorsPath:
|
|
15781
|
-
staleEventsPath:
|
|
15782
|
-
embeddingsCachePath:
|
|
15783
|
-
policyViolationsPath:
|
|
16508
|
+
snapshotPath: import_node_path71.default.join(baseDir, `${project}.json`),
|
|
16509
|
+
errorsPath: import_node_path71.default.join(baseDir, `errors.${project}.ndjson`),
|
|
16510
|
+
staleEventsPath: import_node_path71.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
16511
|
+
embeddingsCachePath: import_node_path71.default.join(baseDir, `embeddings.${project}.json`),
|
|
16512
|
+
policyViolationsPath: import_node_path71.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
15784
16513
|
};
|
|
15785
16514
|
}
|
|
15786
16515
|
var Projects = class {
|
|
@@ -15820,20 +16549,20 @@ function parseExtraProjects(raw) {
|
|
|
15820
16549
|
|
|
15821
16550
|
// src/registry.ts
|
|
15822
16551
|
init_cjs_shims();
|
|
15823
|
-
var
|
|
16552
|
+
var import_node_fs37 = require("fs");
|
|
15824
16553
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
15825
|
-
var
|
|
15826
|
-
var
|
|
16554
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
16555
|
+
var import_types59 = require("@neat.is/types");
|
|
15827
16556
|
function neatHome() {
|
|
15828
16557
|
const override = process.env.NEAT_HOME;
|
|
15829
|
-
if (override && override.length > 0) return
|
|
15830
|
-
return
|
|
16558
|
+
if (override && override.length > 0) return import_node_path72.default.resolve(override);
|
|
16559
|
+
return import_node_path72.default.join(import_node_os3.default.homedir(), ".neat");
|
|
15831
16560
|
}
|
|
15832
16561
|
function registryPath() {
|
|
15833
|
-
return
|
|
16562
|
+
return import_node_path72.default.join(neatHome(), "projects.json");
|
|
15834
16563
|
}
|
|
15835
16564
|
function daemonsDir() {
|
|
15836
|
-
return
|
|
16565
|
+
return import_node_path72.default.join(neatHome(), "daemons");
|
|
15837
16566
|
}
|
|
15838
16567
|
function isFiniteInt(v) {
|
|
15839
16568
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -15866,7 +16595,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15866
16595
|
const dir = daemonsDir();
|
|
15867
16596
|
let names;
|
|
15868
16597
|
try {
|
|
15869
|
-
names = await
|
|
16598
|
+
names = await import_node_fs37.promises.readdir(dir);
|
|
15870
16599
|
} catch (err) {
|
|
15871
16600
|
if (err.code === "ENOENT") return [];
|
|
15872
16601
|
throw err;
|
|
@@ -15874,10 +16603,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15874
16603
|
const out = [];
|
|
15875
16604
|
for (const name of names) {
|
|
15876
16605
|
if (!name.endsWith(".json")) continue;
|
|
15877
|
-
const file =
|
|
16606
|
+
const file = import_node_path72.default.join(dir, name);
|
|
15878
16607
|
let raw;
|
|
15879
16608
|
try {
|
|
15880
|
-
raw = await
|
|
16609
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15881
16610
|
} catch {
|
|
15882
16611
|
continue;
|
|
15883
16612
|
}
|
|
@@ -15905,7 +16634,7 @@ async function readRegistry() {
|
|
|
15905
16634
|
const file = registryPath();
|
|
15906
16635
|
let raw;
|
|
15907
16636
|
try {
|
|
15908
|
-
raw = await
|
|
16637
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15909
16638
|
} catch (err) {
|
|
15910
16639
|
if (err.code === "ENOENT") {
|
|
15911
16640
|
return { version: 1, projects: [] };
|
|
@@ -15913,7 +16642,7 @@ async function readRegistry() {
|
|
|
15913
16642
|
throw err;
|
|
15914
16643
|
}
|
|
15915
16644
|
const parsed = JSON.parse(raw);
|
|
15916
|
-
return
|
|
16645
|
+
return import_types59.RegistryFileSchema.parse(parsed);
|
|
15917
16646
|
}
|
|
15918
16647
|
async function getProject(name) {
|
|
15919
16648
|
const reg = await readRegistry();
|
|
@@ -15988,8 +16717,8 @@ init_auth();
|
|
|
15988
16717
|
// src/connectors-config.ts
|
|
15989
16718
|
init_cjs_shims();
|
|
15990
16719
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
15991
|
-
var
|
|
15992
|
-
var
|
|
16720
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
16721
|
+
var import_node_fs38 = require("fs");
|
|
15993
16722
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
15994
16723
|
var EnvRefUnsetError = class extends Error {
|
|
15995
16724
|
ref;
|
|
@@ -16003,17 +16732,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
16003
16732
|
};
|
|
16004
16733
|
function neatHome2() {
|
|
16005
16734
|
const override = process.env.NEAT_HOME;
|
|
16006
|
-
if (override && override.length > 0) return
|
|
16007
|
-
return
|
|
16735
|
+
if (override && override.length > 0) return import_node_path73.default.resolve(override);
|
|
16736
|
+
return import_node_path73.default.join(import_node_os4.default.homedir(), ".neat");
|
|
16008
16737
|
}
|
|
16009
16738
|
function connectorsConfigPath(home = neatHome2()) {
|
|
16010
|
-
return
|
|
16739
|
+
return import_node_path73.default.join(home, "connectors.json");
|
|
16011
16740
|
}
|
|
16012
16741
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
16013
16742
|
async function warnIfModeLooserThan0600(file) {
|
|
16014
16743
|
if (process.platform === "win32") return;
|
|
16015
16744
|
try {
|
|
16016
|
-
const stat = await
|
|
16745
|
+
const stat = await import_node_fs38.promises.stat(file);
|
|
16017
16746
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
16018
16747
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
16019
16748
|
console.warn(
|
|
@@ -16027,7 +16756,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
16027
16756
|
const file = connectorsConfigPath(home);
|
|
16028
16757
|
let raw;
|
|
16029
16758
|
try {
|
|
16030
|
-
raw = await
|
|
16759
|
+
raw = await import_node_fs38.promises.readFile(file, "utf8");
|
|
16031
16760
|
} catch (err) {
|
|
16032
16761
|
if (err.code === "ENOENT") {
|
|
16033
16762
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -16194,15 +16923,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
16194
16923
|
|
|
16195
16924
|
// src/connectors/index.ts
|
|
16196
16925
|
init_cjs_shims();
|
|
16197
|
-
var
|
|
16926
|
+
var import_types60 = require("@neat.is/types");
|
|
16198
16927
|
var NO_ENV = "unknown";
|
|
16199
16928
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
16200
16929
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16201
16930
|
const sites = [];
|
|
16202
16931
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
16203
16932
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
16204
|
-
if (edge.provenance !==
|
|
16205
|
-
const parsed = (0,
|
|
16933
|
+
if (edge.provenance !== import_types60.Provenance.EXTRACTED) continue;
|
|
16934
|
+
const parsed = (0, import_types60.parseFileId)(edge.source);
|
|
16206
16935
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
16207
16936
|
const site = { relPath: edge.evidence.file };
|
|
16208
16937
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -16213,7 +16942,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
16213
16942
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
16214
16943
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16215
16944
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
16216
|
-
if (attrs.type !==
|
|
16945
|
+
if (attrs.type !== import_types60.NodeType.RouteNode || !attrs.path) return void 0;
|
|
16217
16946
|
const site = { relPath: attrs.path };
|
|
16218
16947
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
16219
16948
|
return site;
|
|
@@ -16670,10 +17399,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
16670
17399
|
// src/connectors/supabase/map.ts
|
|
16671
17400
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
16672
17401
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
16673
|
-
function targetFromRestPath(
|
|
16674
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
17402
|
+
function targetFromRestPath(path76) {
|
|
17403
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path76);
|
|
16675
17404
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
16676
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
17405
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path76);
|
|
16677
17406
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
16678
17407
|
return null;
|
|
16679
17408
|
}
|
|
@@ -16784,23 +17513,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
16784
17513
|
|
|
16785
17514
|
// src/connectors/supabase/resolve.ts
|
|
16786
17515
|
init_cjs_shims();
|
|
16787
|
-
var
|
|
17516
|
+
var import_types62 = require("@neat.is/types");
|
|
16788
17517
|
function createSupabaseResolveTarget(graph, config) {
|
|
16789
17518
|
return (signal, _ctx) => {
|
|
16790
17519
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
16791
17520
|
return null;
|
|
16792
17521
|
}
|
|
16793
|
-
const subResourceId = (0,
|
|
17522
|
+
const subResourceId = (0, import_types62.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
16794
17523
|
if (graph.hasNode(subResourceId)) {
|
|
16795
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
17524
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16796
17525
|
}
|
|
16797
|
-
const bareResourceId = (0,
|
|
17526
|
+
const bareResourceId = (0, import_types62.infraId)(signal.targetKind, signal.targetName);
|
|
16798
17527
|
if (graph.hasNode(bareResourceId)) {
|
|
16799
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
17528
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16800
17529
|
}
|
|
16801
|
-
const projectLevelId = (0,
|
|
17530
|
+
const projectLevelId = (0, import_types62.infraId)("supabase", config.nodeRef);
|
|
16802
17531
|
if (graph.hasNode(projectLevelId)) {
|
|
16803
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
17532
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16804
17533
|
}
|
|
16805
17534
|
return null;
|
|
16806
17535
|
};
|
|
@@ -16893,7 +17622,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
16893
17622
|
|
|
16894
17623
|
// src/connectors/railway/index.ts
|
|
16895
17624
|
init_cjs_shims();
|
|
16896
|
-
var
|
|
17625
|
+
var import_types66 = require("@neat.is/types");
|
|
16897
17626
|
|
|
16898
17627
|
// src/connectors/railway/client.ts
|
|
16899
17628
|
init_cjs_shims();
|
|
@@ -17044,7 +17773,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
17044
17773
|
const out = [];
|
|
17045
17774
|
graph.forEachNode((_id, attrs) => {
|
|
17046
17775
|
const node = attrs;
|
|
17047
|
-
if (node.type !==
|
|
17776
|
+
if (node.type !== import_types66.NodeType.RouteNode) return;
|
|
17048
17777
|
const route = attrs;
|
|
17049
17778
|
if (route.service !== serviceName) return;
|
|
17050
17779
|
out.push({
|
|
@@ -17148,12 +17877,12 @@ function createRailwayResolveTarget(config) {
|
|
|
17148
17877
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
17149
17878
|
if (!serviceName) return null;
|
|
17150
17879
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
17151
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
17880
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
17152
17881
|
}
|
|
17153
17882
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
17154
17883
|
const peerName = config.serviceNameById[signal.targetName];
|
|
17155
17884
|
if (!peerName) return null;
|
|
17156
|
-
return { targetNodeId: (0,
|
|
17885
|
+
return { targetNodeId: (0, import_types66.serviceId)(peerName), serviceName, edgeType: import_types66.EdgeType.CONNECTS_TO };
|
|
17157
17886
|
}
|
|
17158
17887
|
return null;
|
|
17159
17888
|
};
|
|
@@ -17277,9 +18006,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
17277
18006
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
17278
18007
|
if (secondSep === -1) return null;
|
|
17279
18008
|
const method = rest.slice(0, secondSep);
|
|
17280
|
-
const
|
|
17281
|
-
if (!resourceName || !method || !
|
|
17282
|
-
return { resourceName, method, path:
|
|
18009
|
+
const path76 = rest.slice(secondSep + 1);
|
|
18010
|
+
if (!resourceName || !method || !path76) return null;
|
|
18011
|
+
return { resourceName, method, path: path76 };
|
|
17283
18012
|
}
|
|
17284
18013
|
function resourceNameFor(type, labels) {
|
|
17285
18014
|
if (!labels) return null;
|
|
@@ -17317,14 +18046,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
17317
18046
|
if (!req) return null;
|
|
17318
18047
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
17319
18048
|
const method = req.requestMethod.toUpperCase();
|
|
17320
|
-
const
|
|
17321
|
-
if (
|
|
18049
|
+
const path76 = pathFromRequestUrl(req.requestUrl);
|
|
18050
|
+
if (path76 === null) return null;
|
|
17322
18051
|
const timestamp = entry.timestamp;
|
|
17323
18052
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17324
18053
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
17325
18054
|
return {
|
|
17326
18055
|
targetKind: resourceType,
|
|
17327
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
18056
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path76 }),
|
|
17328
18057
|
callCount: 1,
|
|
17329
18058
|
errorCount: isError ? 1 : 0,
|
|
17330
18059
|
lastObservedIso: timestamp
|
|
@@ -17341,7 +18070,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
17341
18070
|
|
|
17342
18071
|
// src/connectors/firebase/resolve.ts
|
|
17343
18072
|
init_cjs_shims();
|
|
17344
|
-
var
|
|
18073
|
+
var import_types67 = require("@neat.is/types");
|
|
17345
18074
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
17346
18075
|
switch (resourceType) {
|
|
17347
18076
|
case "cloud_function":
|
|
@@ -17356,7 +18085,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
17356
18085
|
const entries = [];
|
|
17357
18086
|
graph.forEachNode((_id, attrs) => {
|
|
17358
18087
|
const node = attrs;
|
|
17359
|
-
if (node.type !==
|
|
18088
|
+
if (node.type !== import_types67.NodeType.RouteNode) return;
|
|
17360
18089
|
const route = attrs;
|
|
17361
18090
|
if (route.service !== serviceName) return;
|
|
17362
18091
|
entries.push({
|
|
@@ -17388,7 +18117,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
17388
18117
|
return {
|
|
17389
18118
|
targetNodeId: match.routeNodeId,
|
|
17390
18119
|
serviceName,
|
|
17391
|
-
edgeType:
|
|
18120
|
+
edgeType: import_types67.EdgeType.CALLS
|
|
17392
18121
|
};
|
|
17393
18122
|
};
|
|
17394
18123
|
}
|
|
@@ -17415,7 +18144,7 @@ init_cjs_shims();
|
|
|
17415
18144
|
|
|
17416
18145
|
// src/connectors/cloudflare/connector.ts
|
|
17417
18146
|
init_cjs_shims();
|
|
17418
|
-
var
|
|
18147
|
+
var import_types69 = require("@neat.is/types");
|
|
17419
18148
|
|
|
17420
18149
|
// src/connectors/cloudflare/client.ts
|
|
17421
18150
|
init_cjs_shims();
|
|
@@ -17531,7 +18260,7 @@ function mapEventToSignal(event) {
|
|
|
17531
18260
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
17532
18261
|
const statusCode = metadata?.statusCode;
|
|
17533
18262
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
17534
|
-
const
|
|
18263
|
+
const path76 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
17535
18264
|
return {
|
|
17536
18265
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
17537
18266
|
targetName: scriptName,
|
|
@@ -17539,7 +18268,7 @@ function mapEventToSignal(event) {
|
|
|
17539
18268
|
errorCount: isError ? 1 : 0,
|
|
17540
18269
|
lastObservedIso: observedAt.toISOString(),
|
|
17541
18270
|
method,
|
|
17542
|
-
...
|
|
18271
|
+
...path76 ? { path: path76 } : {},
|
|
17543
18272
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
17544
18273
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
17545
18274
|
};
|
|
@@ -17579,19 +18308,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
17579
18308
|
graph.forEachNode((id, attrs) => {
|
|
17580
18309
|
if (found) return;
|
|
17581
18310
|
const a = attrs;
|
|
17582
|
-
if (a.type ===
|
|
18311
|
+
if (a.type === import_types69.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
17583
18312
|
found = id;
|
|
17584
18313
|
}
|
|
17585
18314
|
});
|
|
17586
18315
|
return found;
|
|
17587
18316
|
}
|
|
17588
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
17589
|
-
const normalizedPath = normalizePathTemplate(
|
|
18317
|
+
function findMatchingRouteNode(graph, serviceName, method, path76) {
|
|
18318
|
+
const normalizedPath = normalizePathTemplate(path76);
|
|
17590
18319
|
let found = null;
|
|
17591
18320
|
graph.forEachNode((id, attrs) => {
|
|
17592
18321
|
if (found) return;
|
|
17593
18322
|
const a = attrs;
|
|
17594
|
-
if (a.type !==
|
|
18323
|
+
if (a.type !== import_types69.NodeType.RouteNode || a.service !== serviceName) return;
|
|
17595
18324
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
17596
18325
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
17597
18326
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -17603,18 +18332,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17603
18332
|
return (signal) => {
|
|
17604
18333
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
17605
18334
|
const scriptName = signal.targetName;
|
|
17606
|
-
const { method, path:
|
|
18335
|
+
const { method, path: path76 } = signal;
|
|
17607
18336
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
17608
|
-
if (!method || !
|
|
17609
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
18337
|
+
if (!method || !path76) return wholeFileId;
|
|
18338
|
+
return findMatchingRouteNode(graph, serviceName, method, path76) ?? wholeFileId;
|
|
17610
18339
|
};
|
|
17611
18340
|
const mapping = config.workers?.[scriptName];
|
|
17612
18341
|
if (mapping) {
|
|
17613
|
-
const wholeFileId = (0,
|
|
18342
|
+
const wholeFileId = (0, import_types69.fileId)(mapping.service, mapping.entryFile);
|
|
17614
18343
|
return {
|
|
17615
18344
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
17616
18345
|
serviceName: mapping.service,
|
|
17617
|
-
edgeType:
|
|
18346
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17618
18347
|
};
|
|
17619
18348
|
}
|
|
17620
18349
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -17623,13 +18352,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17623
18352
|
return {
|
|
17624
18353
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
17625
18354
|
serviceName: fileNode.service,
|
|
17626
|
-
edgeType:
|
|
18355
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17627
18356
|
};
|
|
17628
18357
|
}
|
|
17629
18358
|
return {
|
|
17630
|
-
targetNodeId: (0,
|
|
18359
|
+
targetNodeId: (0, import_types69.infraId)("cloudflare-worker", scriptName),
|
|
17631
18360
|
serviceName: scriptName,
|
|
17632
|
-
edgeType:
|
|
18361
|
+
edgeType: import_types69.EdgeType.CALLS,
|
|
17633
18362
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
17634
18363
|
};
|
|
17635
18364
|
};
|
|
@@ -17825,14 +18554,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
17825
18554
|
|
|
17826
18555
|
// src/connectors/neon/resolve.ts
|
|
17827
18556
|
init_cjs_shims();
|
|
17828
|
-
var
|
|
18557
|
+
var import_types73 = require("@neat.is/types");
|
|
17829
18558
|
function createNeonResolveTarget(config) {
|
|
17830
18559
|
return (signal) => {
|
|
17831
18560
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
17832
18561
|
return {
|
|
17833
|
-
targetNodeId: (0,
|
|
18562
|
+
targetNodeId: (0, import_types73.infraId)("sql-table", signal.targetName),
|
|
17834
18563
|
serviceName: config.serviceName,
|
|
17835
|
-
edgeType:
|
|
18564
|
+
edgeType: import_types73.EdgeType.CALLS,
|
|
17836
18565
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
17837
18566
|
};
|
|
17838
18567
|
};
|
|
@@ -17958,9 +18687,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
17958
18687
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
17959
18688
|
if (secondSep === -1) return null;
|
|
17960
18689
|
const method = rest.slice(0, secondSep);
|
|
17961
|
-
const
|
|
17962
|
-
if (!serviceName || !method || !
|
|
17963
|
-
return { serviceName, method, path:
|
|
18690
|
+
const path76 = rest.slice(secondSep + 1);
|
|
18691
|
+
if (!serviceName || !method || !path76) return null;
|
|
18692
|
+
return { serviceName, method, path: path76 };
|
|
17964
18693
|
}
|
|
17965
18694
|
|
|
17966
18695
|
// src/connectors/cloud-run/map.ts
|
|
@@ -17989,14 +18718,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
17989
18718
|
if (!req) return null;
|
|
17990
18719
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
17991
18720
|
const method = req.requestMethod.toUpperCase();
|
|
17992
|
-
const
|
|
17993
|
-
if (
|
|
18721
|
+
const path76 = pathFromRequestUrl2(req.requestUrl);
|
|
18722
|
+
if (path76 === null) return null;
|
|
17994
18723
|
const timestamp = entry.timestamp;
|
|
17995
18724
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17996
18725
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
17997
18726
|
return {
|
|
17998
18727
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
17999
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
18728
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path76 }),
|
|
18000
18729
|
callCount: 1,
|
|
18001
18730
|
errorCount: isError ? 1 : 0,
|
|
18002
18731
|
lastObservedIso: timestamp
|
|
@@ -18013,14 +18742,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
18013
18742
|
|
|
18014
18743
|
// src/connectors/cloud-run/resolve.ts
|
|
18015
18744
|
init_cjs_shims();
|
|
18016
|
-
var
|
|
18745
|
+
var import_types77 = require("@neat.is/types");
|
|
18017
18746
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
18018
18747
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
18019
18748
|
let found = null;
|
|
18020
18749
|
graph.forEachNode((_id, attrs) => {
|
|
18021
18750
|
if (found) return;
|
|
18022
18751
|
const node = attrs;
|
|
18023
|
-
if (node.type !==
|
|
18752
|
+
if (node.type !== import_types77.NodeType.RouteNode) return;
|
|
18024
18753
|
const route = attrs;
|
|
18025
18754
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
18026
18755
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -18035,23 +18764,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
18035
18764
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
18036
18765
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
18037
18766
|
if (!identity) return null;
|
|
18038
|
-
const { serviceName: gcpServiceName, method, path:
|
|
18767
|
+
const { serviceName: gcpServiceName, method, path: path76 } = identity;
|
|
18039
18768
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
18040
18769
|
if (mappedService) {
|
|
18041
18770
|
const routeNodeId = findMatchingRouteNode2(
|
|
18042
18771
|
graph,
|
|
18043
18772
|
mappedService,
|
|
18044
18773
|
method,
|
|
18045
|
-
normalizePathTemplate(
|
|
18774
|
+
normalizePathTemplate(path76)
|
|
18046
18775
|
);
|
|
18047
18776
|
if (routeNodeId) {
|
|
18048
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
18777
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types77.EdgeType.CALLS };
|
|
18049
18778
|
}
|
|
18050
18779
|
}
|
|
18051
18780
|
return {
|
|
18052
|
-
targetNodeId: (0,
|
|
18781
|
+
targetNodeId: (0, import_types77.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
18053
18782
|
serviceName: mappedService ?? gcpServiceName,
|
|
18054
|
-
edgeType:
|
|
18783
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
18055
18784
|
ensureInfraNode: {
|
|
18056
18785
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
18057
18786
|
name: gcpServiceName,
|
|
@@ -18092,7 +18821,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
18092
18821
|
|
|
18093
18822
|
// src/connectors/render/index.ts
|
|
18094
18823
|
init_cjs_shims();
|
|
18095
|
-
var
|
|
18824
|
+
var import_types80 = require("@neat.is/types");
|
|
18096
18825
|
|
|
18097
18826
|
// src/connectors/render/types.ts
|
|
18098
18827
|
init_cjs_shims();
|
|
@@ -18170,7 +18899,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
18170
18899
|
const out = [];
|
|
18171
18900
|
graph.forEachNode((_id, attrs) => {
|
|
18172
18901
|
const node = attrs;
|
|
18173
|
-
if (node.type !==
|
|
18902
|
+
if (node.type !== import_types80.NodeType.RouteNode) return;
|
|
18174
18903
|
const route = attrs;
|
|
18175
18904
|
if (route.service !== serviceName) return;
|
|
18176
18905
|
out.push({
|
|
@@ -18255,7 +18984,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
18255
18984
|
function createRenderResolveTarget(config) {
|
|
18256
18985
|
return (signal) => {
|
|
18257
18986
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
18258
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
18987
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types80.EdgeType.CALLS };
|
|
18259
18988
|
}
|
|
18260
18989
|
return null;
|
|
18261
18990
|
};
|
|
@@ -18393,21 +19122,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
18393
19122
|
|
|
18394
19123
|
// src/connectors/planetscale/resolve.ts
|
|
18395
19124
|
init_cjs_shims();
|
|
18396
|
-
var
|
|
19125
|
+
var import_types84 = require("@neat.is/types");
|
|
18397
19126
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
18398
19127
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
18399
19128
|
const databaseName = `${config.organization}/${config.database}`;
|
|
18400
19129
|
return (signal, _ctx) => {
|
|
18401
19130
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
18402
|
-
const tableId = (0,
|
|
19131
|
+
const tableId = (0, import_types84.infraId)("sql-table", signal.targetName);
|
|
18403
19132
|
if (graph.hasNode(tableId)) {
|
|
18404
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
19133
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types84.EdgeType.CALLS };
|
|
18405
19134
|
}
|
|
18406
|
-
const providerId = (0,
|
|
19135
|
+
const providerId = (0, import_types84.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
18407
19136
|
return {
|
|
18408
19137
|
targetNodeId: providerId,
|
|
18409
19138
|
serviceName: config.serviceName,
|
|
18410
|
-
edgeType:
|
|
19139
|
+
edgeType: import_types84.EdgeType.CALLS,
|
|
18411
19140
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
18412
19141
|
};
|
|
18413
19142
|
};
|
|
@@ -18672,7 +19401,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
18672
19401
|
|
|
18673
19402
|
// src/connectors/eas/resolve.ts
|
|
18674
19403
|
init_cjs_shims();
|
|
18675
|
-
var
|
|
19404
|
+
var import_types89 = require("@neat.is/types");
|
|
18676
19405
|
var NO_ENV2 = "unknown";
|
|
18677
19406
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
18678
19407
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -18688,8 +19417,8 @@ function configBasenamesForPhase(phase) {
|
|
|
18688
19417
|
function configNodeService(graph, configNodeId) {
|
|
18689
19418
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
18690
19419
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18691
|
-
if (edge.type !==
|
|
18692
|
-
const parsed = (0,
|
|
19420
|
+
if (edge.type !== import_types89.EdgeType.CONFIGURED_BY) continue;
|
|
19421
|
+
const parsed = (0, import_types89.parseFileId)(edge.source);
|
|
18693
19422
|
if (parsed) return parsed.service;
|
|
18694
19423
|
}
|
|
18695
19424
|
return null;
|
|
@@ -18700,7 +19429,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
18700
19429
|
graph.forEachNode((id, attrs) => {
|
|
18701
19430
|
if (scoped) return;
|
|
18702
19431
|
const node = attrs;
|
|
18703
|
-
if (node.type !==
|
|
19432
|
+
if (node.type !== import_types89.NodeType.ConfigNode) return;
|
|
18704
19433
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
18705
19434
|
if (anyMatch === null) anyMatch = id;
|
|
18706
19435
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -18717,13 +19446,13 @@ function createEasResolveTarget(graph) {
|
|
|
18717
19446
|
if (basenames.length > 0) {
|
|
18718
19447
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
18719
19448
|
if (configNodeId) {
|
|
18720
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
19449
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types89.EdgeType.CALLS };
|
|
18721
19450
|
}
|
|
18722
19451
|
}
|
|
18723
19452
|
return {
|
|
18724
19453
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
18725
19454
|
serviceName,
|
|
18726
|
-
edgeType:
|
|
19455
|
+
edgeType: import_types89.EdgeType.CALLS
|
|
18727
19456
|
};
|
|
18728
19457
|
};
|
|
18729
19458
|
}
|
|
@@ -19402,11 +20131,11 @@ function registerRoutes(scope, ctx) {
|
|
|
19402
20131
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
19403
20132
|
const parsed = [];
|
|
19404
20133
|
for (const c of candidates) {
|
|
19405
|
-
const r =
|
|
20134
|
+
const r = import_types92.DivergenceTypeSchema.safeParse(c);
|
|
19406
20135
|
if (!r.success) {
|
|
19407
20136
|
return reply.code(400).send({
|
|
19408
20137
|
error: `unknown divergence type "${c}"`,
|
|
19409
|
-
allowed:
|
|
20138
|
+
allowed: import_types92.DivergenceTypeSchema.options
|
|
19410
20139
|
});
|
|
19411
20140
|
}
|
|
19412
20141
|
parsed.push(r.data);
|
|
@@ -19748,7 +20477,7 @@ function registerRoutes(scope, ctx) {
|
|
|
19748
20477
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
19749
20478
|
let violations = await log.readAll();
|
|
19750
20479
|
if (req.query.severity) {
|
|
19751
|
-
const sev =
|
|
20480
|
+
const sev = import_types92.PolicySeveritySchema.safeParse(req.query.severity);
|
|
19752
20481
|
if (!sev.success) {
|
|
19753
20482
|
return reply.code(400).send({
|
|
19754
20483
|
error: "invalid severity",
|
|
@@ -19787,7 +20516,7 @@ function registerRoutes(scope, ctx) {
|
|
|
19787
20516
|
scope.post("/policies/check", async (req, reply) => {
|
|
19788
20517
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
19789
20518
|
if (!proj) return;
|
|
19790
|
-
const parsed =
|
|
20519
|
+
const parsed = import_types92.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
19791
20520
|
if (!parsed.success) {
|
|
19792
20521
|
return reply.code(400).send({
|
|
19793
20522
|
error: "invalid /policies/check body",
|
|
@@ -20108,8 +20837,8 @@ init_otel_grpc();
|
|
|
20108
20837
|
|
|
20109
20838
|
// src/search.ts
|
|
20110
20839
|
init_cjs_shims();
|
|
20111
|
-
var
|
|
20112
|
-
var
|
|
20840
|
+
var import_node_fs39 = require("fs");
|
|
20841
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
20113
20842
|
var import_node_crypto4 = require("crypto");
|
|
20114
20843
|
var DEFAULT_LIMIT = 10;
|
|
20115
20844
|
var NOMIC_DIM = 768;
|
|
@@ -20263,7 +20992,7 @@ async function pickEmbedder() {
|
|
|
20263
20992
|
}
|
|
20264
20993
|
async function readCache(cachePath) {
|
|
20265
20994
|
try {
|
|
20266
|
-
const raw = await
|
|
20995
|
+
const raw = await import_node_fs39.promises.readFile(cachePath, "utf8");
|
|
20267
20996
|
const parsed = JSON.parse(raw);
|
|
20268
20997
|
if (parsed.version !== 1) return null;
|
|
20269
20998
|
return parsed;
|
|
@@ -20272,8 +21001,8 @@ async function readCache(cachePath) {
|
|
|
20272
21001
|
}
|
|
20273
21002
|
}
|
|
20274
21003
|
async function writeCache(cachePath, cache) {
|
|
20275
|
-
await
|
|
20276
|
-
await
|
|
21004
|
+
await import_node_fs39.promises.mkdir(import_node_path74.default.dirname(cachePath), { recursive: true });
|
|
21005
|
+
await import_node_fs39.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
20277
21006
|
}
|
|
20278
21007
|
var VectorIndex = class {
|
|
20279
21008
|
constructor(embedder, cachePath) {
|
|
@@ -20487,14 +21216,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
20487
21216
|
async function main() {
|
|
20488
21217
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
20489
21218
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
20490
|
-
const baseDir = baseDirEnv ?
|
|
20491
|
-
const defaultScanPath =
|
|
21219
|
+
const baseDir = baseDirEnv ? import_node_path75.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path75.default.resolve(import_node_path75.default.dirname(legacyOutPath)) : import_node_path75.default.resolve("./neat-out");
|
|
21220
|
+
const defaultScanPath = import_node_path75.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
|
|
20492
21221
|
const registry = new Projects();
|
|
20493
21222
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
20494
21223
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
20495
21224
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
20496
21225
|
const projectScan = process.env[envKey];
|
|
20497
|
-
await bootProject(registry, name, projectScan ?
|
|
21226
|
+
await bootProject(registry, name, projectScan ? import_node_path75.default.resolve(projectScan) : void 0, baseDir);
|
|
20498
21227
|
}
|
|
20499
21228
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
20500
21229
|
const port = Number(process.env.PORT ?? 8080);
|