@neat.is/core 0.9.0 → 0.9.1
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-RDLDSIEY.js → chunk-UN7VFA4H.js} +1112 -382
- package/dist/chunk-UN7VFA4H.js.map +1 -0
- package/dist/{chunk-WMYVJXUF.js → chunk-YKQB622D.js} +2 -2
- package/dist/cli.cjs +1648 -916
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1311 -579
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +1327 -595
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +1214 -482
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-RDLDSIEY.js.map +0 -1
- /package/dist/{chunk-WMYVJXUF.js.map → chunk-YKQB622D.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 }
|
|
@@ -710,12 +710,12 @@ async function buildOtelReceiver(opts) {
|
|
|
710
710
|
};
|
|
711
711
|
return decorated;
|
|
712
712
|
}
|
|
713
|
-
var
|
|
713
|
+
var import_node_path55, import_node_url2, import_fastify, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
714
714
|
var init_otel = __esm({
|
|
715
715
|
"src/otel.ts"() {
|
|
716
716
|
"use strict";
|
|
717
717
|
init_cjs_shims();
|
|
718
|
-
|
|
718
|
+
import_node_path55 = __toESM(require("path"), 1);
|
|
719
719
|
import_node_url2 = require("url");
|
|
720
720
|
import_fastify = __toESM(require("fastify"), 1);
|
|
721
721
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -731,7 +731,7 @@ var init_otel = __esm({
|
|
|
731
731
|
|
|
732
732
|
// src/server.ts
|
|
733
733
|
init_cjs_shims();
|
|
734
|
-
var
|
|
734
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
735
735
|
|
|
736
736
|
// src/graph.ts
|
|
737
737
|
init_cjs_shims();
|
|
@@ -755,7 +755,7 @@ function getGraph(project = DEFAULT_PROJECT) {
|
|
|
755
755
|
init_cjs_shims();
|
|
756
756
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
757
757
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
758
|
-
var
|
|
758
|
+
var import_types92 = require("@neat.is/types");
|
|
759
759
|
|
|
760
760
|
// src/extend/index.ts
|
|
761
761
|
init_cjs_shims();
|
|
@@ -867,12 +867,12 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
867
867
|
]);
|
|
868
868
|
async function findHookFiles(scanPath) {
|
|
869
869
|
const found = [];
|
|
870
|
-
const
|
|
870
|
+
const walk10 = async (dir) => {
|
|
871
871
|
const entries = await import_node_fs2.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
872
872
|
for (const entry of entries) {
|
|
873
873
|
if (entry.isDirectory()) {
|
|
874
874
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
875
|
-
await
|
|
875
|
+
await walk10(import_node_path2.default.join(dir, entry.name));
|
|
876
876
|
} else if (entry.isFile()) {
|
|
877
877
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
878
878
|
const rel = import_node_path2.default.relative(scanPath, import_node_path2.default.join(dir, entry.name));
|
|
@@ -881,7 +881,7 @@ async function findHookFiles(scanPath) {
|
|
|
881
881
|
}
|
|
882
882
|
}
|
|
883
883
|
};
|
|
884
|
-
await
|
|
884
|
+
await walk10(scanPath);
|
|
885
885
|
return found.sort();
|
|
886
886
|
}
|
|
887
887
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
@@ -2007,6 +2007,7 @@ var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
|
2007
2007
|
var import_tree_sitter_go2 = __toESM(require("tree-sitter-go"), 1);
|
|
2008
2008
|
var import_tree_sitter_ruby = __toESM(require("tree-sitter-ruby"), 1);
|
|
2009
2009
|
var import_tree_sitter_php = __toESM(require("tree-sitter-php"), 1);
|
|
2010
|
+
var import_tree_sitter_rust = __toESM(require("tree-sitter-rust"), 1);
|
|
2010
2011
|
var import_types6 = require("@neat.is/types");
|
|
2011
2012
|
|
|
2012
2013
|
// src/extract/shared.ts
|
|
@@ -2287,7 +2288,7 @@ function buildServiceHostIndex(services) {
|
|
|
2287
2288
|
async function walkSourceFiles(dir, excludeDirs = []) {
|
|
2288
2289
|
const excluded = new Set(excludeDirs.map((d) => import_node_path7.default.resolve(d)));
|
|
2289
2290
|
const out = [];
|
|
2290
|
-
async function
|
|
2291
|
+
async function walk10(current) {
|
|
2291
2292
|
const entries = await import_node_fs7.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
2292
2293
|
for (const entry of entries) {
|
|
2293
2294
|
const full = import_node_path7.default.join(current, entry.name);
|
|
@@ -2295,7 +2296,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
2295
2296
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2296
2297
|
if (excluded.has(import_node_path7.default.resolve(full))) continue;
|
|
2297
2298
|
if (await isPythonVenvDir(full)) continue;
|
|
2298
|
-
await
|
|
2299
|
+
await walk10(full);
|
|
2299
2300
|
} 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
2301
|
// would attribute our instrumentation imports to the user's service.
|
|
2301
2302
|
!isNeatAuthoredSourceFile(entry.name)) {
|
|
@@ -2303,7 +2304,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
2303
2304
|
}
|
|
2304
2305
|
}
|
|
2305
2306
|
}
|
|
2306
|
-
await
|
|
2307
|
+
await walk10(dir);
|
|
2307
2308
|
return out;
|
|
2308
2309
|
}
|
|
2309
2310
|
async function loadSourceFiles(dir, excludeDirs = []) {
|
|
@@ -2823,6 +2824,11 @@ function makePhpParser() {
|
|
|
2823
2824
|
p.setLanguage(import_tree_sitter_php.default.php_only);
|
|
2824
2825
|
return p;
|
|
2825
2826
|
}
|
|
2827
|
+
function makeRustParser() {
|
|
2828
|
+
const p = new import_tree_sitter2.default();
|
|
2829
|
+
p.setLanguage(import_tree_sitter_rust.default);
|
|
2830
|
+
return p;
|
|
2831
|
+
}
|
|
2826
2832
|
var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
2827
2833
|
"get",
|
|
2828
2834
|
"post",
|
|
@@ -2894,8 +2900,8 @@ function chiRoutesFromSource(source, parser) {
|
|
|
2894
2900
|
chiWalk(tree.rootNode, "", out);
|
|
2895
2901
|
return out;
|
|
2896
2902
|
}
|
|
2897
|
-
function stripChiRegex(
|
|
2898
|
-
return
|
|
2903
|
+
function stripChiRegex(path76) {
|
|
2904
|
+
return path76.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
2899
2905
|
}
|
|
2900
2906
|
function chiWalk(node, prefix, out) {
|
|
2901
2907
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -3567,9 +3573,9 @@ function rubyRocketRoute(args) {
|
|
|
3567
3573
|
if (!pair || pair.type !== "pair") continue;
|
|
3568
3574
|
const k = pair.childForFieldName("key");
|
|
3569
3575
|
if (k?.type !== "string") continue;
|
|
3570
|
-
const
|
|
3571
|
-
if (
|
|
3572
|
-
return { path:
|
|
3576
|
+
const path76 = rubyLiteral(k);
|
|
3577
|
+
if (path76 === null) continue;
|
|
3578
|
+
return { path: path76, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
3573
3579
|
}
|
|
3574
3580
|
return null;
|
|
3575
3581
|
}
|
|
@@ -3739,6 +3745,48 @@ function railsRoutesFromSource(source, parser) {
|
|
|
3739
3745
|
});
|
|
3740
3746
|
return out;
|
|
3741
3747
|
}
|
|
3748
|
+
var SINATRA_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head"]);
|
|
3749
|
+
function sinatraRoutesFromSource(source, parser) {
|
|
3750
|
+
const tree = parseSource2(parser, source);
|
|
3751
|
+
if (!fileReferencesSinatra(tree.rootNode)) return [];
|
|
3752
|
+
const out = [];
|
|
3753
|
+
walk(tree.rootNode, (node) => {
|
|
3754
|
+
if (node.type !== "call") return;
|
|
3755
|
+
if (node.childForFieldName("receiver")) return;
|
|
3756
|
+
const method = node.childForFieldName("method")?.text;
|
|
3757
|
+
if (!method || !SINATRA_VERBS.has(method)) return;
|
|
3758
|
+
if (!node.childForFieldName("block")) return;
|
|
3759
|
+
const first = node.childForFieldName("arguments")?.namedChild(0);
|
|
3760
|
+
if (first?.type !== "string") return;
|
|
3761
|
+
const p = rubyLiteral(first);
|
|
3762
|
+
if (p === null || !p.startsWith("/")) return;
|
|
3763
|
+
out.push({
|
|
3764
|
+
method: method.toUpperCase(),
|
|
3765
|
+
pathTemplate: canonicalizeTemplate(p),
|
|
3766
|
+
line: node.startPosition.row + 1,
|
|
3767
|
+
framework: "sinatra"
|
|
3768
|
+
});
|
|
3769
|
+
});
|
|
3770
|
+
return out;
|
|
3771
|
+
}
|
|
3772
|
+
function fileReferencesSinatra(root) {
|
|
3773
|
+
let found = false;
|
|
3774
|
+
walk(root, (node) => {
|
|
3775
|
+
if (found) return;
|
|
3776
|
+
if (node.type === "call") {
|
|
3777
|
+
const m = node.childForFieldName("method")?.text;
|
|
3778
|
+
if (m === "require" || m === "require_relative") {
|
|
3779
|
+
const s = rubyLiteral(node.childForFieldName("arguments")?.namedChild(0));
|
|
3780
|
+
if (s !== null && /^sinatra\b/.test(s)) found = true;
|
|
3781
|
+
}
|
|
3782
|
+
return;
|
|
3783
|
+
}
|
|
3784
|
+
if (node.type === "constant" && node.text === "Sinatra" || node.type === "scope_resolution" && node.text.startsWith("Sinatra")) {
|
|
3785
|
+
found = true;
|
|
3786
|
+
}
|
|
3787
|
+
});
|
|
3788
|
+
return found;
|
|
3789
|
+
}
|
|
3742
3790
|
var LARAVEL_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options"]);
|
|
3743
3791
|
var LARAVEL_RESOURCE_ROWS = [
|
|
3744
3792
|
{ action: "index", methods: ["GET"], suffix: "" },
|
|
@@ -3914,6 +3962,223 @@ function laravelRoutesFromSource(source, parser, basePrefix = "") {
|
|
|
3914
3962
|
}
|
|
3915
3963
|
return out;
|
|
3916
3964
|
}
|
|
3965
|
+
var SLIM_VERBS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head"]);
|
|
3966
|
+
function isSlimAppCtor(node) {
|
|
3967
|
+
if (!node) return false;
|
|
3968
|
+
if (node.type === "scoped_call_expression") {
|
|
3969
|
+
const scope = node.childForFieldName("scope")?.text ?? "";
|
|
3970
|
+
const name = node.childForFieldName("name")?.text;
|
|
3971
|
+
return name === "create" && (scope === "AppFactory" || scope.endsWith("\\AppFactory"));
|
|
3972
|
+
}
|
|
3973
|
+
if (node.type === "object_creation_expression") {
|
|
3974
|
+
const cls = node.namedChild(0)?.text ?? "";
|
|
3975
|
+
return cls === "App" || cls.endsWith("\\App") || cls.includes("Slim");
|
|
3976
|
+
}
|
|
3977
|
+
return false;
|
|
3978
|
+
}
|
|
3979
|
+
function isSlimAppType(node) {
|
|
3980
|
+
if (!node || node.type !== "named_type") return false;
|
|
3981
|
+
const text = node.text;
|
|
3982
|
+
return text === "App" || text.endsWith("\\App");
|
|
3983
|
+
}
|
|
3984
|
+
function collectSlimAppVars(root) {
|
|
3985
|
+
const vars = /* @__PURE__ */ new Set();
|
|
3986
|
+
walk(root, (node) => {
|
|
3987
|
+
if (node.type === "assignment_expression") {
|
|
3988
|
+
const left = node.childForFieldName("left");
|
|
3989
|
+
if (left?.type === "variable_name" && isSlimAppCtor(node.childForFieldName("right"))) {
|
|
3990
|
+
vars.add(left.text);
|
|
3991
|
+
}
|
|
3992
|
+
return;
|
|
3993
|
+
}
|
|
3994
|
+
if (node.type === "simple_parameter" && isSlimAppType(node.childForFieldName("type"))) {
|
|
3995
|
+
const name = node.childForFieldName("name");
|
|
3996
|
+
if (name?.type === "variable_name") vars.add(name.text);
|
|
3997
|
+
}
|
|
3998
|
+
});
|
|
3999
|
+
return vars;
|
|
4000
|
+
}
|
|
4001
|
+
function slimClosureParamVars(closure) {
|
|
4002
|
+
const out = ["$this"];
|
|
4003
|
+
for (let i = 0; i < closure.namedChildCount; i++) {
|
|
4004
|
+
const params = closure.namedChild(i);
|
|
4005
|
+
if (params?.type !== "formal_parameters") continue;
|
|
4006
|
+
for (let j = 0; j < params.namedChildCount; j++) {
|
|
4007
|
+
const param = params.namedChild(j);
|
|
4008
|
+
if (param?.type !== "simple_parameter") continue;
|
|
4009
|
+
for (let k = 0; k < param.namedChildCount; k++) {
|
|
4010
|
+
const v = param.namedChild(k);
|
|
4011
|
+
if (v?.type === "variable_name") {
|
|
4012
|
+
out.push(v.text);
|
|
4013
|
+
break;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
return out;
|
|
4019
|
+
}
|
|
4020
|
+
function phpStringArray(node) {
|
|
4021
|
+
const out = [];
|
|
4022
|
+
if (node?.type !== "array_creation_expression") return out;
|
|
4023
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4024
|
+
const el = node.namedChild(i);
|
|
4025
|
+
if (el?.type !== "array_element_initializer") continue;
|
|
4026
|
+
const s = phpStaticString(el.namedChild(0));
|
|
4027
|
+
if (s !== null) out.push(s);
|
|
4028
|
+
}
|
|
4029
|
+
return out;
|
|
4030
|
+
}
|
|
4031
|
+
function slimRoutesFromSource(source, parser) {
|
|
4032
|
+
const tree = parseSource2(parser, source);
|
|
4033
|
+
const appVars = collectSlimAppVars(tree.rootNode);
|
|
4034
|
+
if (appVars.size === 0) return [];
|
|
4035
|
+
const out = [];
|
|
4036
|
+
slimWalk(tree.rootNode, "", appVars, out);
|
|
4037
|
+
return out;
|
|
4038
|
+
}
|
|
4039
|
+
function slimWalk(node, prefix, appVars, out) {
|
|
4040
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4041
|
+
const child = node.namedChild(i);
|
|
4042
|
+
if (child) slimHandle(child, prefix, appVars, out);
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
function slimHandle(node, prefix, appVars, out) {
|
|
4046
|
+
if (node.type === "member_call_expression") {
|
|
4047
|
+
const obj = node.childForFieldName("object");
|
|
4048
|
+
const method = node.childForFieldName("name")?.text;
|
|
4049
|
+
const args = node.childForFieldName("arguments");
|
|
4050
|
+
if (obj?.type === "variable_name" && method && appVars.has(obj.text)) {
|
|
4051
|
+
const line = node.startPosition.row + 1;
|
|
4052
|
+
if (method === "group") {
|
|
4053
|
+
const groupPrefix = phpFirstString(args);
|
|
4054
|
+
const closure = laravelGroupClosure(args);
|
|
4055
|
+
if (groupPrefix !== null && closure) {
|
|
4056
|
+
const inner = new Set(appVars);
|
|
4057
|
+
for (const v of slimClosureParamVars(closure)) inner.add(v);
|
|
4058
|
+
const body = closure.childForFieldName("body");
|
|
4059
|
+
if (body) slimWalk(body, laravelJoinPath(prefix, groupPrefix), inner, out);
|
|
4060
|
+
}
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
if (SLIM_VERBS.has(method)) {
|
|
4064
|
+
const p = phpFirstString(args);
|
|
4065
|
+
if (p !== null) {
|
|
4066
|
+
out.push({
|
|
4067
|
+
method: method.toUpperCase(),
|
|
4068
|
+
pathTemplate: laravelJoinPath(prefix, p),
|
|
4069
|
+
line,
|
|
4070
|
+
framework: "slim"
|
|
4071
|
+
});
|
|
4072
|
+
}
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
if (method === "any") {
|
|
4076
|
+
const p = phpFirstString(args);
|
|
4077
|
+
if (p !== null) {
|
|
4078
|
+
out.push({ method: "ALL", pathTemplate: laravelJoinPath(prefix, p), line, framework: "slim" });
|
|
4079
|
+
}
|
|
4080
|
+
return;
|
|
4081
|
+
}
|
|
4082
|
+
if (method === "map") {
|
|
4083
|
+
const vals = phpArgumentValues(args);
|
|
4084
|
+
const methods = phpStringArray(vals[0]);
|
|
4085
|
+
const p = vals.length > 1 ? phpStaticString(vals[1]) : null;
|
|
4086
|
+
if (p !== null) {
|
|
4087
|
+
for (const m of methods) {
|
|
4088
|
+
out.push({
|
|
4089
|
+
method: m.toUpperCase(),
|
|
4090
|
+
pathTemplate: laravelJoinPath(prefix, p),
|
|
4091
|
+
line,
|
|
4092
|
+
framework: "slim"
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
return;
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
slimWalk(node, prefix, appVars, out);
|
|
4101
|
+
}
|
|
4102
|
+
var ACTIX_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "head", "options", "trace"]);
|
|
4103
|
+
function rustStringContent(node) {
|
|
4104
|
+
if (!node || node.type !== "string_literal") return null;
|
|
4105
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4106
|
+
if (node.namedChild(i)?.type === "string_content") return node.namedChild(i).text;
|
|
4107
|
+
}
|
|
4108
|
+
return "";
|
|
4109
|
+
}
|
|
4110
|
+
function actixRoutesFromSource(source, parser) {
|
|
4111
|
+
const tree = parseSource2(parser, source);
|
|
4112
|
+
const out = [];
|
|
4113
|
+
walk(tree.rootNode, (node) => {
|
|
4114
|
+
if (node.type === "attribute_item") {
|
|
4115
|
+
actixAttributeRoute(node, out);
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
4118
|
+
if (node.type === "call_expression") {
|
|
4119
|
+
actixBuilderRoute(node, out);
|
|
4120
|
+
}
|
|
4121
|
+
});
|
|
4122
|
+
return out;
|
|
4123
|
+
}
|
|
4124
|
+
function actixAttributeRoute(attrItem, out) {
|
|
4125
|
+
const attr = attrItem.namedChild(0);
|
|
4126
|
+
if (!attr || attr.type !== "attribute") return;
|
|
4127
|
+
const nameNode = attr.namedChild(0);
|
|
4128
|
+
if (!nameNode) return;
|
|
4129
|
+
const macro = nameNode.type === "identifier" ? nameNode.text : nameNode.type === "scoped_identifier" ? nameNode.childForFieldName("name")?.text ?? null : null;
|
|
4130
|
+
if (!macro) return;
|
|
4131
|
+
const tokens = attr.childForFieldName("arguments");
|
|
4132
|
+
if (!tokens || tokens.type !== "token_tree") return;
|
|
4133
|
+
const strings = [];
|
|
4134
|
+
for (let i = 0; i < tokens.namedChildCount; i++) {
|
|
4135
|
+
const s = rustStringContent(tokens.namedChild(i));
|
|
4136
|
+
if (s !== null) strings.push(s);
|
|
4137
|
+
}
|
|
4138
|
+
const pathStr = strings[0];
|
|
4139
|
+
if (pathStr === void 0 || !pathStr.startsWith("/")) return;
|
|
4140
|
+
const line = attrItem.startPosition.row + 1;
|
|
4141
|
+
const template = canonicalizeTemplate(pathStr);
|
|
4142
|
+
if (ACTIX_METHODS.has(macro)) {
|
|
4143
|
+
out.push({ method: macro.toUpperCase(), pathTemplate: template, line, framework: "actix-web" });
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
if (macro === "route") {
|
|
4147
|
+
const methods = strings.slice(1).filter((m) => ACTIX_METHODS.has(m.toLowerCase()));
|
|
4148
|
+
const list = methods.length > 0 ? methods.map((m) => m.toUpperCase()) : ["ALL"];
|
|
4149
|
+
for (const m of list) {
|
|
4150
|
+
out.push({ method: m, pathTemplate: template, line, framework: "actix-web" });
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
function actixBuilderRoute(call, out) {
|
|
4155
|
+
const fn = call.childForFieldName("function");
|
|
4156
|
+
if (fn?.type !== "field_expression") return;
|
|
4157
|
+
if (fn.childForFieldName("field")?.text !== "route") return;
|
|
4158
|
+
const args = call.childForFieldName("arguments");
|
|
4159
|
+
const pathStr = rustStringContent(args?.namedChild(0));
|
|
4160
|
+
if (pathStr === null || !pathStr.startsWith("/")) return;
|
|
4161
|
+
const second = args?.namedChild(1);
|
|
4162
|
+
if (!second) return;
|
|
4163
|
+
const method = actixBuilderMethod(second);
|
|
4164
|
+
if (!method) return;
|
|
4165
|
+
out.push({
|
|
4166
|
+
method,
|
|
4167
|
+
pathTemplate: canonicalizeTemplate(pathStr),
|
|
4168
|
+
line: call.startPosition.row + 1,
|
|
4169
|
+
framework: "actix-web"
|
|
4170
|
+
});
|
|
4171
|
+
}
|
|
4172
|
+
function actixBuilderMethod(node) {
|
|
4173
|
+
let method = null;
|
|
4174
|
+
walk(node, (n) => {
|
|
4175
|
+
if (method || n.type !== "scoped_identifier") return;
|
|
4176
|
+
const verb = n.childForFieldName("name")?.text;
|
|
4177
|
+
const scopeLeaf = n.childForFieldName("path")?.text?.split("::").pop();
|
|
4178
|
+
if (scopeLeaf === "web" && verb && ACTIX_METHODS.has(verb)) method = verb.toUpperCase();
|
|
4179
|
+
});
|
|
4180
|
+
return method;
|
|
4181
|
+
}
|
|
3917
4182
|
function namedArgs(argsNode) {
|
|
3918
4183
|
const out = [];
|
|
3919
4184
|
if (!argsNode) return out;
|
|
@@ -4230,6 +4495,7 @@ async function addRoutes(graph, services) {
|
|
|
4230
4495
|
const goParser = makeGoParser2();
|
|
4231
4496
|
const rubyParser = makeRubyParser();
|
|
4232
4497
|
const phpParser = makePhpParser();
|
|
4498
|
+
const rustParser = makeRustParser();
|
|
4233
4499
|
let nodesAdded = 0;
|
|
4234
4500
|
let edgesAdded = 0;
|
|
4235
4501
|
for (const service of services) {
|
|
@@ -4252,7 +4518,10 @@ async function addRoutes(graph, services) {
|
|
|
4252
4518
|
const isGoService = service.node.language === "go";
|
|
4253
4519
|
const hasRails = deps["rails"] !== void 0;
|
|
4254
4520
|
const hasLaravel = deps["laravel/framework"] !== void 0;
|
|
4255
|
-
|
|
4521
|
+
const hasSlim = deps["slim/slim"] !== void 0;
|
|
4522
|
+
const hasSinatra = deps["sinatra"] !== void 0;
|
|
4523
|
+
const hasActix = deps["actix-web"] !== void 0;
|
|
4524
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasNestjs && !hasFastapi && !hasFlask && !hasDjango && !hasGin && !hasEcho && !hasFiber && !hasChi && !isGoService && !hasRails && !hasLaravel && !hasSlim && !hasSinatra && !hasActix)
|
|
4256
4525
|
continue;
|
|
4257
4526
|
const files = await loadSourceFiles(service.dir, service.excludeDirs);
|
|
4258
4527
|
const mountPrefixes = hasExpress ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir)) : /* @__PURE__ */ new Map();
|
|
@@ -4263,7 +4532,8 @@ async function addRoutes(graph, services) {
|
|
|
4263
4532
|
const isGo = ext === ".go";
|
|
4264
4533
|
const isRb = ext === ".rb";
|
|
4265
4534
|
const isPhp = ext === ".php";
|
|
4266
|
-
|
|
4535
|
+
const isRs = ext === ".rs";
|
|
4536
|
+
if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy && !isGo && !isRb && !isPhp && !isRs) continue;
|
|
4267
4537
|
const relFile = toPosix(import_node_path9.default.relative(service.dir, file.path));
|
|
4268
4538
|
let routes;
|
|
4269
4539
|
try {
|
|
@@ -4273,8 +4543,12 @@ async function addRoutes(graph, services) {
|
|
|
4273
4543
|
phpParser,
|
|
4274
4544
|
relFile === "routes/api.php" ? "/api" : ""
|
|
4275
4545
|
) : [];
|
|
4546
|
+
if (hasSlim) routes = routes.concat(slimRoutesFromSource(file.content, phpParser));
|
|
4276
4547
|
} else if (isRb) {
|
|
4277
4548
|
routes = hasRails && relFile === "config/routes.rb" ? railsRoutesFromSource(file.content, rubyParser) : [];
|
|
4549
|
+
if (hasSinatra) routes = routes.concat(sinatraRoutesFromSource(file.content, rubyParser));
|
|
4550
|
+
} else if (isRs) {
|
|
4551
|
+
routes = hasActix ? actixRoutesFromSource(file.content, rustParser) : [];
|
|
4278
4552
|
} else if (isGo) {
|
|
4279
4553
|
if (hasGin) routes = ginRoutesFromSource(file.content, goParser);
|
|
4280
4554
|
else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser);
|
|
@@ -4458,6 +4732,37 @@ function loadIncidentThresholdsFromEnv() {
|
|
|
4458
4732
|
return DEFAULT_INCIDENT_THRESHOLDS;
|
|
4459
4733
|
}
|
|
4460
4734
|
}
|
|
4735
|
+
var DEFAULT_LATENCY_STREAM_CEILING_MS = 6e4;
|
|
4736
|
+
function latencyStreamCeilingMs() {
|
|
4737
|
+
const raw = process.env.NEAT_LATENCY_STREAM_CEILING_MS;
|
|
4738
|
+
if (!raw) return DEFAULT_LATENCY_STREAM_CEILING_MS;
|
|
4739
|
+
const n = Number(raw);
|
|
4740
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
4741
|
+
console.warn(
|
|
4742
|
+
`[neat] NEAT_LATENCY_STREAM_CEILING_MS could not be parsed (${raw}); using default`
|
|
4743
|
+
);
|
|
4744
|
+
return DEFAULT_LATENCY_STREAM_CEILING_MS;
|
|
4745
|
+
}
|
|
4746
|
+
function spanServesEventStream(attrs) {
|
|
4747
|
+
for (const key of [
|
|
4748
|
+
"http.response.header.content-type",
|
|
4749
|
+
"http.response.header.content_type"
|
|
4750
|
+
]) {
|
|
4751
|
+
const v = attrs[key];
|
|
4752
|
+
const values = Array.isArray(v) ? v : v !== void 0 && v !== null ? [v] : [];
|
|
4753
|
+
for (const item of values) {
|
|
4754
|
+
if (typeof item === "string" && item.toLowerCase().includes("text/event-stream")) {
|
|
4755
|
+
return true;
|
|
4756
|
+
}
|
|
4757
|
+
}
|
|
4758
|
+
}
|
|
4759
|
+
return false;
|
|
4760
|
+
}
|
|
4761
|
+
function spanIsStreaming(span, ceilingMs = latencyStreamCeilingMs()) {
|
|
4762
|
+
if (span.websocketChannel !== void 0) return true;
|
|
4763
|
+
if (spanServesEventStream(span.attributes)) return true;
|
|
4764
|
+
return span.durationNanos > BigInt(Math.round(ceilingMs)) * 1000000n;
|
|
4765
|
+
}
|
|
4461
4766
|
function httpResponseStatusFromAttrs(attrs) {
|
|
4462
4767
|
for (const key of ["http.response.status_code", "http.status_code"]) {
|
|
4463
4768
|
const v = attrs[key];
|
|
@@ -5325,6 +5630,12 @@ async function advance4xxBurst(ctx, span, affectedNode, ts, nowMs, status2) {
|
|
|
5325
5630
|
);
|
|
5326
5631
|
ctx.burstState.delete(key);
|
|
5327
5632
|
}
|
|
5633
|
+
var NEXT_API_ROUTE_SPAN_NAME = /^executing api route \((?:pages|app)\) (\/\S*)$/;
|
|
5634
|
+
function nextApiRouteTemplate(span) {
|
|
5635
|
+
const raw = pickAttr(span, "next.span_name") ?? span.name;
|
|
5636
|
+
const match = raw ? NEXT_API_ROUTE_SPAN_NAME.exec(raw) : null;
|
|
5637
|
+
return match ? match[1] : void 0;
|
|
5638
|
+
}
|
|
5328
5639
|
function findRouteNodeByHttpRoute(graph, serviceName, method, httpRoute) {
|
|
5329
5640
|
const target = normalizePathTemplate(httpRoute);
|
|
5330
5641
|
const m = method?.toUpperCase();
|
|
@@ -5347,7 +5658,7 @@ async function handleSpan(ctx, span) {
|
|
|
5347
5658
|
}
|
|
5348
5659
|
const sourceId = ensureServiceNode(ctx.graph, span.service, env);
|
|
5349
5660
|
const isError = span.statusCode === 2;
|
|
5350
|
-
const durationMs = span.durationNanos > 0n ? Number(span.durationNanos) / 1e6 : void 0;
|
|
5661
|
+
const durationMs = span.durationNanos > 0n && !spanIsStreaming(span) ? Number(span.durationNanos) / 1e6 : void 0;
|
|
5351
5662
|
const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId);
|
|
5352
5663
|
const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath);
|
|
5353
5664
|
cacheSpanService(span, nowMs, callSite);
|
|
@@ -5544,12 +5855,13 @@ async function handleSpan(ctx, span) {
|
|
|
5544
5855
|
}
|
|
5545
5856
|
}
|
|
5546
5857
|
}
|
|
5547
|
-
|
|
5858
|
+
const fusionRoute = nextApiRouteTemplate(span) ?? span.httpRoute;
|
|
5859
|
+
if (fusionRoute && (span.kind === 2 || span.kind === 1 || span.kind === 0 || span.kind === void 0)) {
|
|
5548
5860
|
const routeNodeId = findRouteNodeByHttpRoute(
|
|
5549
5861
|
ctx.graph,
|
|
5550
5862
|
span.service,
|
|
5551
5863
|
span.httpMethod,
|
|
5552
|
-
|
|
5864
|
+
fusionRoute
|
|
5553
5865
|
);
|
|
5554
5866
|
if (routeNodeId) {
|
|
5555
5867
|
const routeSvc = ctx.graph.getNodeAttributes(routeNodeId).service;
|
|
@@ -5953,19 +6265,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
5953
6265
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
5954
6266
|
let best = { path: [start], edges: [] };
|
|
5955
6267
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
5956
|
-
function step(node,
|
|
5957
|
-
if (
|
|
5958
|
-
best = { path: [...
|
|
6268
|
+
function step(node, path76, edges) {
|
|
6269
|
+
if (path76.length > best.path.length) {
|
|
6270
|
+
best = { path: [...path76], edges: [...edges] };
|
|
5959
6271
|
}
|
|
5960
|
-
if (
|
|
6272
|
+
if (path76.length - 1 >= maxDepth) return;
|
|
5961
6273
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
5962
6274
|
for (const [srcId, edge] of incoming) {
|
|
5963
6275
|
if (visited.has(srcId)) continue;
|
|
5964
6276
|
visited.add(srcId);
|
|
5965
|
-
|
|
6277
|
+
path76.push(srcId);
|
|
5966
6278
|
edges.push(edge);
|
|
5967
|
-
step(srcId,
|
|
5968
|
-
|
|
6279
|
+
step(srcId, path76, edges);
|
|
6280
|
+
path76.pop();
|
|
5969
6281
|
edges.pop();
|
|
5970
6282
|
visited.delete(srcId);
|
|
5971
6283
|
}
|
|
@@ -5973,11 +6285,11 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
5973
6285
|
step(start, [start], []);
|
|
5974
6286
|
return best;
|
|
5975
6287
|
}
|
|
5976
|
-
function databaseRootCauseShape(graph, origin,
|
|
6288
|
+
function databaseRootCauseShape(graph, origin, walk10) {
|
|
5977
6289
|
const targetDb = origin;
|
|
5978
6290
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
5979
6291
|
if (candidatePairs.length === 0) return null;
|
|
5980
|
-
for (const id of
|
|
6292
|
+
for (const id of walk10.path) {
|
|
5981
6293
|
const owner = resolveOwningService(graph, id);
|
|
5982
6294
|
if (!owner) continue;
|
|
5983
6295
|
const { id: serviceId15, svc } = owner;
|
|
@@ -6004,8 +6316,8 @@ function databaseRootCauseShape(graph, origin, walk9) {
|
|
|
6004
6316
|
}
|
|
6005
6317
|
return null;
|
|
6006
6318
|
}
|
|
6007
|
-
function serviceRootCauseShape(graph, _origin,
|
|
6008
|
-
for (const id of
|
|
6319
|
+
function serviceRootCauseShape(graph, _origin, walk10) {
|
|
6320
|
+
for (const id of walk10.path) {
|
|
6009
6321
|
const owner = resolveOwningService(graph, id);
|
|
6010
6322
|
if (!owner) continue;
|
|
6011
6323
|
const { id: serviceId15, svc } = owner;
|
|
@@ -6041,15 +6353,15 @@ function serviceRootCauseShape(graph, _origin, walk9) {
|
|
|
6041
6353
|
}
|
|
6042
6354
|
return null;
|
|
6043
6355
|
}
|
|
6044
|
-
function fileRootCauseShape(graph, origin,
|
|
6356
|
+
function fileRootCauseShape(graph, origin, walk10) {
|
|
6045
6357
|
const owner = resolveOwningService(graph, origin.id);
|
|
6046
6358
|
if (!owner) return null;
|
|
6047
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
6359
|
+
return serviceRootCauseShape(graph, owner.svc, walk10);
|
|
6048
6360
|
}
|
|
6049
|
-
function symbolRootCauseShape(graph, origin,
|
|
6361
|
+
function symbolRootCauseShape(graph, origin, walk10) {
|
|
6050
6362
|
const owner = resolveOwningService(graph, origin.id);
|
|
6051
6363
|
if (!owner) return null;
|
|
6052
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
6364
|
+
return serviceRootCauseShape(graph, owner.svc, walk10);
|
|
6053
6365
|
}
|
|
6054
6366
|
var rootCauseShapes = {
|
|
6055
6367
|
[import_types8.NodeType.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -6062,25 +6374,29 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
6062
6374
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
6063
6375
|
const shape = rootCauseShapes[origin.type];
|
|
6064
6376
|
if (shape) {
|
|
6065
|
-
const
|
|
6066
|
-
const match = shape(graph, origin,
|
|
6377
|
+
const walk10 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
6378
|
+
const match = shape(graph, origin, walk10);
|
|
6067
6379
|
if (match) {
|
|
6068
6380
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
6069
|
-
return
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6381
|
+
return {
|
|
6382
|
+
source: "compat",
|
|
6383
|
+
result: import_types8.RootCauseResultSchema.parse({
|
|
6384
|
+
rootCauseNode: match.rootCauseNode,
|
|
6385
|
+
rootCauseReason: reason,
|
|
6386
|
+
traversalPath: walk10.path,
|
|
6387
|
+
edgeProvenances: walk10.edges.map((e) => e.provenance),
|
|
6388
|
+
confidence: confidenceFromMix(walk10.edges),
|
|
6389
|
+
fixRecommendation: match.fixRecommendation
|
|
6390
|
+
})
|
|
6391
|
+
};
|
|
6077
6392
|
}
|
|
6078
6393
|
}
|
|
6079
6394
|
if (origin.type === import_types8.NodeType.ServiceNode) {
|
|
6080
6395
|
const crossService = crossServiceRootCause(graph, errorNodeId, incidents, errorEvent);
|
|
6081
|
-
if (crossService) return crossService;
|
|
6396
|
+
if (crossService) return { result: crossService, source: "cross-service" };
|
|
6082
6397
|
}
|
|
6083
|
-
|
|
6398
|
+
const incident = rootCauseFromIncidents(errorNodeId, incidents, errorEvent);
|
|
6399
|
+
return incident ? { result: incident, source: "incident" } : null;
|
|
6084
6400
|
}
|
|
6085
6401
|
var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
|
|
6086
6402
|
function incidentMatchesNode(ev, nodeId) {
|
|
@@ -6176,26 +6492,75 @@ function dominantFailingCall(graph, serviceId15, visited) {
|
|
|
6176
6492
|
return best;
|
|
6177
6493
|
}
|
|
6178
6494
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
6179
|
-
const
|
|
6495
|
+
const path76 = [originServiceId];
|
|
6180
6496
|
const edges = [];
|
|
6181
6497
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
6182
6498
|
let current = originServiceId;
|
|
6183
6499
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
6184
6500
|
const hop = dominantFailingCall(graph, current, visited);
|
|
6185
6501
|
if (!hop) break;
|
|
6186
|
-
|
|
6502
|
+
path76.push(hop.nextService);
|
|
6503
|
+
edges.push(hop.edge);
|
|
6504
|
+
visited.add(hop.nextService);
|
|
6505
|
+
current = hop.nextService;
|
|
6506
|
+
}
|
|
6507
|
+
if (edges.length === 0) return null;
|
|
6508
|
+
return { path: path76, edges, culprit: current };
|
|
6509
|
+
}
|
|
6510
|
+
function isStaleCallEdge(e) {
|
|
6511
|
+
return e.type === import_types8.EdgeType.CALLS && e.provenance === import_types8.Provenance.STALE;
|
|
6512
|
+
}
|
|
6513
|
+
function staleCallDominates(e, id, curEdge, curId) {
|
|
6514
|
+
const ev = e.signal?.spanCount ?? e.callCount ?? 0;
|
|
6515
|
+
const cv = curEdge.signal?.spanCount ?? curEdge.callCount ?? 0;
|
|
6516
|
+
if (ev !== cv) return ev > cv;
|
|
6517
|
+
return id < curId;
|
|
6518
|
+
}
|
|
6519
|
+
function dominantStaleCall(graph, serviceId15, visited) {
|
|
6520
|
+
const bestByCallee = /* @__PURE__ */ new Map();
|
|
6521
|
+
for (const src of callSourcesForService(graph, serviceId15)) {
|
|
6522
|
+
for (const edgeId of graph.outboundEdges(src)) {
|
|
6523
|
+
const e = graph.getEdgeAttributes(edgeId);
|
|
6524
|
+
if (e.type !== import_types8.EdgeType.CALLS) continue;
|
|
6525
|
+
if (isFrontierNode(graph, e.target)) continue;
|
|
6526
|
+
const owner = resolveOwningService(graph, e.target);
|
|
6527
|
+
if (!owner || visited.has(owner.id)) continue;
|
|
6528
|
+
const cur = bestByCallee.get(owner.id);
|
|
6529
|
+
if (!cur || import_types8.PROV_RANK[e.provenance] > import_types8.PROV_RANK[cur.provenance]) {
|
|
6530
|
+
bestByCallee.set(owner.id, e);
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
let best = null;
|
|
6535
|
+
for (const [id, edge] of bestByCallee) {
|
|
6536
|
+
if (!isStaleCallEdge(edge)) continue;
|
|
6537
|
+
if (!best || staleCallDominates(edge, id, best.edge, best.nextService)) {
|
|
6538
|
+
best = { nextService: id, edge };
|
|
6539
|
+
}
|
|
6540
|
+
}
|
|
6541
|
+
return best;
|
|
6542
|
+
}
|
|
6543
|
+
function followStaleCallChain(graph, originServiceId, maxDepth) {
|
|
6544
|
+
const path76 = [originServiceId];
|
|
6545
|
+
const edges = [];
|
|
6546
|
+
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
6547
|
+
let current = originServiceId;
|
|
6548
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
6549
|
+
const hop = dominantStaleCall(graph, current, visited);
|
|
6550
|
+
if (!hop) break;
|
|
6551
|
+
path76.push(hop.nextService);
|
|
6187
6552
|
edges.push(hop.edge);
|
|
6188
6553
|
visited.add(hop.nextService);
|
|
6189
6554
|
current = hop.nextService;
|
|
6190
6555
|
}
|
|
6191
6556
|
if (edges.length === 0) return null;
|
|
6192
|
-
return { path:
|
|
6557
|
+
return { path: path76, edges, culprit: current };
|
|
6193
6558
|
}
|
|
6194
6559
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
6195
6560
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
6196
6561
|
if (!chain) return null;
|
|
6197
6562
|
const culprit = chain.culprit;
|
|
6198
|
-
const
|
|
6563
|
+
const path76 = [...chain.path];
|
|
6199
6564
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
6200
6565
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
6201
6566
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -6203,14 +6568,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
6203
6568
|
if (loc) {
|
|
6204
6569
|
let rootCauseNode = culprit;
|
|
6205
6570
|
if (loc.fileNode) {
|
|
6206
|
-
|
|
6571
|
+
path76.push(loc.fileNode);
|
|
6207
6572
|
edgeProvenances.push(import_types8.Provenance.OBSERVED);
|
|
6208
6573
|
rootCauseNode = loc.fileNode;
|
|
6209
6574
|
}
|
|
6210
6575
|
return import_types8.RootCauseResultSchema.parse({
|
|
6211
6576
|
rootCauseNode,
|
|
6212
6577
|
rootCauseReason: loc.rootCauseReason,
|
|
6213
|
-
traversalPath:
|
|
6578
|
+
traversalPath: path76,
|
|
6214
6579
|
edgeProvenances,
|
|
6215
6580
|
confidence,
|
|
6216
6581
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -6222,7 +6587,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
6222
6587
|
return import_types8.RootCauseResultSchema.parse({
|
|
6223
6588
|
rootCauseNode: culprit,
|
|
6224
6589
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
6225
|
-
traversalPath:
|
|
6590
|
+
traversalPath: path76,
|
|
6226
6591
|
edgeProvenances,
|
|
6227
6592
|
confidence,
|
|
6228
6593
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -6609,17 +6974,20 @@ function displayNameOf(nodeId) {
|
|
|
6609
6974
|
return nodeId.replace(/^[a-z]+:/, "");
|
|
6610
6975
|
}
|
|
6611
6976
|
function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
|
|
6612
|
-
const
|
|
6613
|
-
if (!
|
|
6977
|
+
const tagged = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
|
|
6978
|
+
if (!tagged) return null;
|
|
6614
6979
|
const navigation = opts?.navigation ?? process.env.NEAT_RCA_NAVIGATION !== "0";
|
|
6615
|
-
if (!navigation) return
|
|
6616
|
-
return enrichWithNavigation(graph, errorNodeId,
|
|
6980
|
+
if (!navigation) return tagged.result;
|
|
6981
|
+
return enrichWithNavigation(graph, errorNodeId, tagged, incidents, opts?.now ?? Date.now());
|
|
6617
6982
|
}
|
|
6618
|
-
function enrichWithNavigation(graph, errorNodeId,
|
|
6983
|
+
function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
6984
|
+
const legacy = tagged.result;
|
|
6619
6985
|
const seedNode = legacy.rootCauseNode;
|
|
6620
6986
|
const seedCtx = graph.hasNode(seedNode) ? nodeContext(graph, seedNode, incidents, now) : null;
|
|
6621
6987
|
const lastProv = legacy.edgeProvenances[legacy.edgeProvenances.length - 1];
|
|
6622
6988
|
const candidates = [];
|
|
6989
|
+
const deadEndOnSymptom = tagged.source === "incident" && seedNode === errorNodeId && legacy.traversalPath.length === 1;
|
|
6990
|
+
const staleChain = deadEndOnSymptom && !(seedCtx && isVictimSeed(seedCtx)) ? followStaleCallChain(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH) : null;
|
|
6623
6991
|
if (seedCtx && isVictimSeed(seedCtx)) {
|
|
6624
6992
|
const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
|
|
6625
6993
|
const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
|
|
@@ -6644,6 +7012,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
6644
7012
|
confidence: Math.min(legacy.confidence, 0.4),
|
|
6645
7013
|
...lastProv ? { provenance: lastProv } : {}
|
|
6646
7014
|
});
|
|
7015
|
+
} else if (staleChain) {
|
|
7016
|
+
const culprit = staleChain.culprit;
|
|
7017
|
+
const culpritName = displayNameOf(culprit);
|
|
7018
|
+
const seedName = displayNameOf(seedNode);
|
|
7019
|
+
const staleConfidence = confidenceFromMix(staleChain.edges, now);
|
|
7020
|
+
candidates.push({
|
|
7021
|
+
node: culprit,
|
|
7022
|
+
classification: "primary-failure",
|
|
7023
|
+
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.`,
|
|
7024
|
+
context: nodeContext(graph, culprit, incidents, now),
|
|
7025
|
+
confidence: staleConfidence,
|
|
7026
|
+
provenance: import_types8.Provenance.STALE
|
|
7027
|
+
});
|
|
7028
|
+
candidates.push({
|
|
7029
|
+
node: seedNode,
|
|
7030
|
+
classification: "symptom-only",
|
|
7031
|
+
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.`,
|
|
7032
|
+
context: seedCtx ?? EMPTY_CONTEXT,
|
|
7033
|
+
confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.STALE),
|
|
7034
|
+
...lastProv ? { provenance: lastProv } : {}
|
|
7035
|
+
});
|
|
6647
7036
|
} else {
|
|
6648
7037
|
candidates.push({
|
|
6649
7038
|
node: seedNode,
|
|
@@ -6657,11 +7046,14 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
6657
7046
|
const top = candidates[0];
|
|
6658
7047
|
let traversalPath = legacy.traversalPath;
|
|
6659
7048
|
let edgeProvenances = legacy.edgeProvenances;
|
|
6660
|
-
if (top.node
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
7049
|
+
if (staleChain && top.node === staleChain.culprit) {
|
|
7050
|
+
traversalPath = staleChain.path;
|
|
7051
|
+
edgeProvenances = staleChain.edges.map((e) => e.provenance);
|
|
7052
|
+
} else if (top.node !== seedNode) {
|
|
7053
|
+
const path76 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
|
|
7054
|
+
if (path76) {
|
|
7055
|
+
traversalPath = path76.nodes;
|
|
7056
|
+
edgeProvenances = path76.edges.map((e) => e.provenance);
|
|
6665
7057
|
} else {
|
|
6666
7058
|
traversalPath = [errorNodeId, top.node];
|
|
6667
7059
|
edgeProvenances = [top.provenance ?? import_types8.Provenance.OBSERVED];
|
|
@@ -6683,6 +7075,9 @@ function fixRecommendationForTop(top, seedNode, legacy) {
|
|
|
6683
7075
|
return legacy.fixRecommendation;
|
|
6684
7076
|
}
|
|
6685
7077
|
const name = top.node.replace(/^service:/, "");
|
|
7078
|
+
if (top.provenance === import_types8.Provenance.STALE) {
|
|
7079
|
+
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}.`;
|
|
7080
|
+
}
|
|
6686
7081
|
if (top.classification === "primary-failure") {
|
|
6687
7082
|
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
7083
|
}
|
|
@@ -8169,7 +8564,7 @@ var import_tree_sitter_php2 = __toESM(require("tree-sitter-php"), 1);
|
|
|
8169
8564
|
var import_tree_sitter_c_sharp = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
8170
8565
|
var import_tree_sitter_java = __toESM(require("tree-sitter-java"), 1);
|
|
8171
8566
|
var import_tree_sitter_kotlin = __toESM(require("tree-sitter-kotlin"), 1);
|
|
8172
|
-
var
|
|
8567
|
+
var import_tree_sitter_rust2 = __toESM(require("tree-sitter-rust"), 1);
|
|
8173
8568
|
var import_tree_sitter_cpp = __toESM(require("tree-sitter-cpp"), 1);
|
|
8174
8569
|
var import_types21 = require("@neat.is/types");
|
|
8175
8570
|
var PARSE_CHUNK3 = 16384;
|
|
@@ -8190,7 +8585,7 @@ var SYMBOL_GRAMMAR_BY_EXT = {
|
|
|
8190
8585
|
".cs": import_tree_sitter_c_sharp.default,
|
|
8191
8586
|
".java": import_tree_sitter_java.default,
|
|
8192
8587
|
".kt": import_tree_sitter_kotlin.default,
|
|
8193
|
-
".rs":
|
|
8588
|
+
".rs": import_tree_sitter_rust2.default,
|
|
8194
8589
|
// C++ (ADR-202) — only the UNAMBIGUOUS extensions. `.cpp` / `.cc` / `.cxx` /
|
|
8195
8590
|
// `.c++` are implementation files; `.hpp` / `.hh` / `.hxx` / `.h++` are C++-only
|
|
8196
8591
|
// headers. `.h` and `.c` are deliberately absent: they are shared with C (a
|
|
@@ -8630,15 +9025,15 @@ function collectKotlinSymbolDefs(root) {
|
|
|
8630
9025
|
});
|
|
8631
9026
|
};
|
|
8632
9027
|
const join = (prefix, name) => prefix ? `${prefix}.${name}` : name;
|
|
8633
|
-
const
|
|
9028
|
+
const firstChildOfType2 = (node, types) => {
|
|
8634
9029
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8635
9030
|
const child = node.namedChild(i);
|
|
8636
9031
|
if (child && types.includes(child.type)) return child;
|
|
8637
9032
|
}
|
|
8638
9033
|
return void 0;
|
|
8639
9034
|
};
|
|
8640
|
-
const nameOf = (node, ...types) =>
|
|
8641
|
-
const bodyOf = (node) =>
|
|
9035
|
+
const nameOf = (node, ...types) => firstChildOfType2(node, types)?.text;
|
|
9036
|
+
const bodyOf = (node) => firstChildOfType2(node, ["class_body", "enum_class_body"]);
|
|
8642
9037
|
let pkg;
|
|
8643
9038
|
for (let i = 0; i < root.namedChildCount; i++) {
|
|
8644
9039
|
const child = root.namedChild(i);
|
|
@@ -9139,7 +9534,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
9139
9534
|
return best;
|
|
9140
9535
|
};
|
|
9141
9536
|
const requests = [];
|
|
9142
|
-
const
|
|
9537
|
+
const walk10 = (node) => {
|
|
9143
9538
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
9144
9539
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
9145
9540
|
if (self && self.kind === "class") {
|
|
@@ -9185,10 +9580,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
9185
9580
|
}
|
|
9186
9581
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
9187
9582
|
const child = node.namedChild(i);
|
|
9188
|
-
if (child)
|
|
9583
|
+
if (child) walk10(child);
|
|
9189
9584
|
}
|
|
9190
9585
|
};
|
|
9191
|
-
|
|
9586
|
+
walk10(root);
|
|
9192
9587
|
for (const req of requests) {
|
|
9193
9588
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
9194
9589
|
if (!targetSid) continue;
|
|
@@ -9484,7 +9879,7 @@ async function addServerActions(graph, services) {
|
|
|
9484
9879
|
|
|
9485
9880
|
// src/extract/databases/index.ts
|
|
9486
9881
|
init_cjs_shims();
|
|
9487
|
-
var
|
|
9882
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
9488
9883
|
var import_types24 = require("@neat.is/types");
|
|
9489
9884
|
|
|
9490
9885
|
// src/extract/databases/db-config-yaml.ts
|
|
@@ -9919,9 +10314,163 @@ async function parse8(serviceDir) {
|
|
|
9919
10314
|
}
|
|
9920
10315
|
var sequelizeParser = { name: "sequelize", parse: parse8 };
|
|
9921
10316
|
|
|
9922
|
-
// src/extract/databases/
|
|
10317
|
+
// src/extract/databases/csharp.ts
|
|
9923
10318
|
init_cjs_shims();
|
|
10319
|
+
var import_node_fs24 = require("fs");
|
|
9924
10320
|
var import_node_path34 = __toESM(require("path"), 1);
|
|
10321
|
+
var CS_EXT = ".cs";
|
|
10322
|
+
var NPGSQL_GATE = /\bUseNpgsql\b|\bNpgsql\b/;
|
|
10323
|
+
var REDIS_GATE = /\bConnectionMultiplexer\b|\bStackExchange\.Redis\b|\bConfigurationOptions\.Parse\b|\bAddStackExchangeRedisCache\b/;
|
|
10324
|
+
var ENV_READ_RE = /(?:GetEnvironmentVariable|GetConnectionString)\(\s*"([^"]+)"\s*\)|Configuration\s*\[\s*"([^"]+)"\s*\]/g;
|
|
10325
|
+
var STRING_LITERAL_RE = /@?"([^"\\]*(?:\\.[^"\\]*)*)"/g;
|
|
10326
|
+
function hostIsUnresolved(host) {
|
|
10327
|
+
return host === "" || /[${}]/.test(host);
|
|
10328
|
+
}
|
|
10329
|
+
function looksLikePostgres(s) {
|
|
10330
|
+
return /(?:^|;)\s*(?:host|server|data\s*source)\s*=/i.test(s) || /^postgres(?:ql)?:\/\//i.test(s);
|
|
10331
|
+
}
|
|
10332
|
+
function looksLikeRedis(s) {
|
|
10333
|
+
return /^rediss?:\/\//i.test(s) || /^[A-Za-z0-9_.-]+:\d+(?:$|,)/.test(s) || /,\s*(?:ssl|abortconnect|allowadmin|connecttimeout|password|user)\s*=/i.test(s);
|
|
10334
|
+
}
|
|
10335
|
+
function parsePostgresConnection(raw) {
|
|
10336
|
+
const s = raw.trim();
|
|
10337
|
+
if (/^postgres(?:ql)?:\/\//i.test(s)) return parseConnectionString(s);
|
|
10338
|
+
const fields = /* @__PURE__ */ new Map();
|
|
10339
|
+
for (const part of s.split(";")) {
|
|
10340
|
+
const eq = part.indexOf("=");
|
|
10341
|
+
if (eq < 0) continue;
|
|
10342
|
+
const key = part.slice(0, eq).trim().toLowerCase().replace(/\s+/g, " ");
|
|
10343
|
+
const value = part.slice(eq + 1).trim();
|
|
10344
|
+
if (value && !fields.has(key)) fields.set(key, value);
|
|
10345
|
+
}
|
|
10346
|
+
const hostRaw = fields.get("host") ?? fields.get("server") ?? fields.get("data source");
|
|
10347
|
+
if (!hostRaw) return null;
|
|
10348
|
+
const host = hostRaw.split(",")[0].trim();
|
|
10349
|
+
if (hostIsUnresolved(host)) return null;
|
|
10350
|
+
const portRaw = fields.get("port");
|
|
10351
|
+
const port = portRaw && /^\d+$/.test(portRaw) ? Number(portRaw) : void 0;
|
|
10352
|
+
const database = fields.get("database") ?? fields.get("db") ?? "";
|
|
10353
|
+
return { host, port, database, engine: "postgresql", engineVersion: "unknown" };
|
|
10354
|
+
}
|
|
10355
|
+
function parseRedisEndpoint(raw) {
|
|
10356
|
+
const s = raw.trim();
|
|
10357
|
+
if (/^rediss?:\/\//i.test(s)) return parseConnectionString(s);
|
|
10358
|
+
const first = s.split(",")[0].trim();
|
|
10359
|
+
const m = first.match(/^([A-Za-z0-9_.-]+)(?::(\d+))?$/);
|
|
10360
|
+
if (!m) return null;
|
|
10361
|
+
const host = m[1];
|
|
10362
|
+
if (hostIsUnresolved(host) || host.includes("=")) return null;
|
|
10363
|
+
const port = m[2] ? Number(m[2]) : void 0;
|
|
10364
|
+
return { host, port, database: "", engine: "redis", engineVersion: "unknown" };
|
|
10365
|
+
}
|
|
10366
|
+
async function resolveEnvUpTree(startDir, name) {
|
|
10367
|
+
let dir = import_node_path34.default.resolve(startDir);
|
|
10368
|
+
for (let depth = 0; depth < 12; depth++) {
|
|
10369
|
+
const value = await resolveEnvVar(dir, name);
|
|
10370
|
+
if (value !== null) return value;
|
|
10371
|
+
const atRepoRoot = await import_node_fs24.promises.access(import_node_path34.default.join(dir, ".git")).then(() => true).catch(() => false);
|
|
10372
|
+
const parent = import_node_path34.default.dirname(dir);
|
|
10373
|
+
if (atRepoRoot || parent === dir) break;
|
|
10374
|
+
dir = parent;
|
|
10375
|
+
}
|
|
10376
|
+
return null;
|
|
10377
|
+
}
|
|
10378
|
+
async function interpolateEnvRefs(value, dir) {
|
|
10379
|
+
const refs = /* @__PURE__ */ new Set();
|
|
10380
|
+
for (const m of value.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
10381
|
+
refs.add(m[1] ?? m[2]);
|
|
10382
|
+
}
|
|
10383
|
+
let out = value;
|
|
10384
|
+
for (const name of refs) {
|
|
10385
|
+
const resolved = await resolveEnvUpTree(dir, name);
|
|
10386
|
+
if (resolved === null) continue;
|
|
10387
|
+
out = out.split(`\${${name}}`).join(resolved).replace(new RegExp(`\\$${name}\\b`, "g"), resolved);
|
|
10388
|
+
}
|
|
10389
|
+
return out;
|
|
10390
|
+
}
|
|
10391
|
+
function stringLiterals(masked) {
|
|
10392
|
+
const out = [];
|
|
10393
|
+
STRING_LITERAL_RE.lastIndex = 0;
|
|
10394
|
+
let m;
|
|
10395
|
+
while ((m = STRING_LITERAL_RE.exec(masked)) !== null) out.push(m[1]);
|
|
10396
|
+
return out;
|
|
10397
|
+
}
|
|
10398
|
+
function envKeys(masked) {
|
|
10399
|
+
const out = [];
|
|
10400
|
+
ENV_READ_RE.lastIndex = 0;
|
|
10401
|
+
let m;
|
|
10402
|
+
while ((m = ENV_READ_RE.exec(masked)) !== null) {
|
|
10403
|
+
const key = m[1] ?? m[2];
|
|
10404
|
+
if (key) out.push(key);
|
|
10405
|
+
}
|
|
10406
|
+
return out;
|
|
10407
|
+
}
|
|
10408
|
+
async function resolveConfigs(literals, keys, serviceDir, looksLike, parse11) {
|
|
10409
|
+
const out = [];
|
|
10410
|
+
for (const key of keys) {
|
|
10411
|
+
const raw = await resolveEnvUpTree(serviceDir, key);
|
|
10412
|
+
if (raw === null) continue;
|
|
10413
|
+
const value = await interpolateEnvRefs(raw, serviceDir);
|
|
10414
|
+
if (!looksLike(value)) continue;
|
|
10415
|
+
const parsed = parse11(value);
|
|
10416
|
+
if (parsed) out.push(parsed);
|
|
10417
|
+
}
|
|
10418
|
+
for (const lit of literals) {
|
|
10419
|
+
if (!looksLike(lit)) continue;
|
|
10420
|
+
const parsed = parse11(lit);
|
|
10421
|
+
if (parsed) out.push(parsed);
|
|
10422
|
+
}
|
|
10423
|
+
return out;
|
|
10424
|
+
}
|
|
10425
|
+
async function parse9(serviceDir) {
|
|
10426
|
+
const files = (await walkSourceFiles(serviceDir).catch(() => [])).filter(
|
|
10427
|
+
(f) => import_node_path34.default.extname(f) === CS_EXT
|
|
10428
|
+
);
|
|
10429
|
+
if (files.length === 0) return [];
|
|
10430
|
+
const sources = [];
|
|
10431
|
+
for (const file of files) {
|
|
10432
|
+
const content = await import_node_fs24.promises.readFile(file, "utf8").catch(() => null);
|
|
10433
|
+
if (content !== null) sources.push({ file, content });
|
|
10434
|
+
}
|
|
10435
|
+
let pgGateFile = null;
|
|
10436
|
+
let redisGateFile = null;
|
|
10437
|
+
for (const { file, content } of sources) {
|
|
10438
|
+
if (pgGateFile === null && NPGSQL_GATE.test(content)) pgGateFile = file;
|
|
10439
|
+
if (redisGateFile === null && REDIS_GATE.test(content)) redisGateFile = file;
|
|
10440
|
+
}
|
|
10441
|
+
if (!pgGateFile && !redisGateFile) return [];
|
|
10442
|
+
const literals = [];
|
|
10443
|
+
const keys = [];
|
|
10444
|
+
for (const { content } of sources) {
|
|
10445
|
+
const masked = maskCommentsInSource(content);
|
|
10446
|
+
literals.push(...stringLiterals(masked));
|
|
10447
|
+
keys.push(...envKeys(masked));
|
|
10448
|
+
}
|
|
10449
|
+
const out = [];
|
|
10450
|
+
const seenHosts = /* @__PURE__ */ new Set();
|
|
10451
|
+
const push = (config, sourceFile) => {
|
|
10452
|
+
const dedupe = `${config.engine}:${config.host}`;
|
|
10453
|
+
if (seenHosts.has(dedupe)) return;
|
|
10454
|
+
seenHosts.add(dedupe);
|
|
10455
|
+
out.push({ ...config, sourceFile });
|
|
10456
|
+
};
|
|
10457
|
+
if (pgGateFile) {
|
|
10458
|
+
for (const pg3 of await resolveConfigs(literals, keys, serviceDir, looksLikePostgres, parsePostgresConnection)) {
|
|
10459
|
+
push(pg3, pgGateFile);
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
10462
|
+
if (redisGateFile) {
|
|
10463
|
+
for (const redis of await resolveConfigs(literals, keys, serviceDir, looksLikeRedis, parseRedisEndpoint)) {
|
|
10464
|
+
push(redis, redisGateFile);
|
|
10465
|
+
}
|
|
10466
|
+
}
|
|
10467
|
+
return out;
|
|
10468
|
+
}
|
|
10469
|
+
var csharpParser = { name: "csharp", parse: parse9 };
|
|
10470
|
+
|
|
10471
|
+
// src/extract/databases/docker-compose.ts
|
|
10472
|
+
init_cjs_shims();
|
|
10473
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
9925
10474
|
function portFromService(svc) {
|
|
9926
10475
|
for (const raw of svc.ports ?? []) {
|
|
9927
10476
|
const str = String(raw);
|
|
@@ -9946,9 +10495,9 @@ function databaseFromEnv(svc) {
|
|
|
9946
10495
|
};
|
|
9947
10496
|
return get("POSTGRES_DB") ?? get("MYSQL_DATABASE") ?? get("MONGO_INITDB_DATABASE") ?? "";
|
|
9948
10497
|
}
|
|
9949
|
-
async function
|
|
10498
|
+
async function parse10(serviceDir) {
|
|
9950
10499
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
9951
|
-
const abs =
|
|
10500
|
+
const abs = import_node_path35.default.join(serviceDir, name);
|
|
9952
10501
|
if (!await exists2(abs)) continue;
|
|
9953
10502
|
const raw = await readYaml(abs);
|
|
9954
10503
|
if (!raw?.services) return [];
|
|
@@ -9970,7 +10519,7 @@ async function parse9(serviceDir) {
|
|
|
9970
10519
|
}
|
|
9971
10520
|
return [];
|
|
9972
10521
|
}
|
|
9973
|
-
var dockerComposeParser = { name: "docker-compose", parse:
|
|
10522
|
+
var dockerComposeParser = { name: "docker-compose", parse: parse10 };
|
|
9974
10523
|
|
|
9975
10524
|
// src/extract/databases/index.ts
|
|
9976
10525
|
var DB_PARSERS = [
|
|
@@ -9982,6 +10531,7 @@ var DB_PARSERS = [
|
|
|
9982
10531
|
ormconfigParser,
|
|
9983
10532
|
typeormParser,
|
|
9984
10533
|
sequelizeParser,
|
|
10534
|
+
csharpParser,
|
|
9985
10535
|
dockerComposeParser
|
|
9986
10536
|
];
|
|
9987
10537
|
function compatibleDriversFor(engine) {
|
|
@@ -10120,7 +10670,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10120
10670
|
discoveredVia: mergedDiscoveredVia
|
|
10121
10671
|
});
|
|
10122
10672
|
}
|
|
10123
|
-
const relConfigFile = toPosix(
|
|
10673
|
+
const relConfigFile = toPosix(import_node_path36.default.relative(service.dir, config.sourceFile));
|
|
10124
10674
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
10125
10675
|
graph,
|
|
10126
10676
|
service.pkg.name,
|
|
@@ -10129,7 +10679,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10129
10679
|
);
|
|
10130
10680
|
nodesAdded += fn;
|
|
10131
10681
|
edgesAdded += fe;
|
|
10132
|
-
const evidenceFile = toPosix(
|
|
10682
|
+
const evidenceFile = toPosix(import_node_path36.default.relative(scanPath, config.sourceFile));
|
|
10133
10683
|
const edge = {
|
|
10134
10684
|
id: (0, import_types3.extractedEdgeId)(fileNodeId, dbNode.id, import_types24.EdgeType.CONNECTS_TO),
|
|
10135
10685
|
source: fileNodeId,
|
|
@@ -10147,15 +10697,15 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10147
10697
|
if (allConfigs.length === 1) {
|
|
10148
10698
|
const primary = allConfigs[0];
|
|
10149
10699
|
service.node.dbConnectionTarget = primary.port ? `${primary.host}:${primary.port}` : primary.host;
|
|
10150
|
-
const relPath =
|
|
10700
|
+
const relPath = import_node_path36.default.relative(scanPath, primary.sourceFile);
|
|
10151
10701
|
const cfgId = (0, import_types24.configId)(relPath);
|
|
10152
10702
|
if (!graph.hasNode(cfgId)) {
|
|
10153
10703
|
const cfgNode = {
|
|
10154
10704
|
id: cfgId,
|
|
10155
10705
|
type: import_types24.NodeType.ConfigNode,
|
|
10156
|
-
name:
|
|
10706
|
+
name: import_node_path36.default.basename(primary.sourceFile),
|
|
10157
10707
|
path: relPath,
|
|
10158
|
-
fileType: isConfigFile(
|
|
10708
|
+
fileType: isConfigFile(import_node_path36.default.basename(primary.sourceFile)).fileType || "config"
|
|
10159
10709
|
};
|
|
10160
10710
|
graph.addNode(cfgId, cfgNode);
|
|
10161
10711
|
nodesAdded++;
|
|
@@ -10196,27 +10746,27 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
|
|
|
10196
10746
|
|
|
10197
10747
|
// src/extract/configs.ts
|
|
10198
10748
|
init_cjs_shims();
|
|
10199
|
-
var
|
|
10200
|
-
var
|
|
10749
|
+
var import_node_fs25 = require("fs");
|
|
10750
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
10201
10751
|
var import_types25 = require("@neat.is/types");
|
|
10202
10752
|
async function walkConfigFiles(dir, excludeDirs = []) {
|
|
10203
|
-
const excluded = new Set(excludeDirs.map((d) =>
|
|
10753
|
+
const excluded = new Set(excludeDirs.map((d) => import_node_path37.default.resolve(d)));
|
|
10204
10754
|
const out = [];
|
|
10205
|
-
async function
|
|
10206
|
-
const entries = await
|
|
10755
|
+
async function walk10(current) {
|
|
10756
|
+
const entries = await import_node_fs25.promises.readdir(current, { withFileTypes: true });
|
|
10207
10757
|
for (const entry of entries) {
|
|
10208
|
-
const full =
|
|
10758
|
+
const full = import_node_path37.default.join(current, entry.name);
|
|
10209
10759
|
if (entry.isDirectory()) {
|
|
10210
10760
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
10211
|
-
if (excluded.has(
|
|
10761
|
+
if (excluded.has(import_node_path37.default.resolve(full))) continue;
|
|
10212
10762
|
if (await isPythonVenvDir(full)) continue;
|
|
10213
|
-
await
|
|
10763
|
+
await walk10(full);
|
|
10214
10764
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
10215
10765
|
out.push(full);
|
|
10216
10766
|
}
|
|
10217
10767
|
}
|
|
10218
10768
|
}
|
|
10219
|
-
await
|
|
10769
|
+
await walk10(dir);
|
|
10220
10770
|
return out;
|
|
10221
10771
|
}
|
|
10222
10772
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -10225,19 +10775,19 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
10225
10775
|
for (const service of services) {
|
|
10226
10776
|
const configFiles = await walkConfigFiles(service.dir, service.excludeDirs);
|
|
10227
10777
|
for (const file of configFiles) {
|
|
10228
|
-
const relPath =
|
|
10778
|
+
const relPath = import_node_path37.default.relative(scanPath, file);
|
|
10229
10779
|
const node = {
|
|
10230
10780
|
id: (0, import_types25.configId)(relPath),
|
|
10231
10781
|
type: import_types25.NodeType.ConfigNode,
|
|
10232
|
-
name:
|
|
10782
|
+
name: import_node_path37.default.basename(file),
|
|
10233
10783
|
path: relPath,
|
|
10234
|
-
fileType: isConfigFile(
|
|
10784
|
+
fileType: isConfigFile(import_node_path37.default.basename(file)).fileType
|
|
10235
10785
|
};
|
|
10236
10786
|
if (!graph.hasNode(node.id)) {
|
|
10237
10787
|
graph.addNode(node.id, node);
|
|
10238
10788
|
nodesAdded++;
|
|
10239
10789
|
}
|
|
10240
|
-
const relToService = toPosix(
|
|
10790
|
+
const relToService = toPosix(import_node_path37.default.relative(service.dir, file));
|
|
10241
10791
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
10242
10792
|
graph,
|
|
10243
10793
|
service.pkg.name,
|
|
@@ -10253,7 +10803,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
10253
10803
|
type: import_types25.EdgeType.CONFIGURED_BY,
|
|
10254
10804
|
provenance: import_types25.Provenance.EXTRACTED,
|
|
10255
10805
|
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
10256
|
-
evidence: { file: relPath.split(
|
|
10806
|
+
evidence: { file: relPath.split(import_node_path37.default.sep).join("/") }
|
|
10257
10807
|
};
|
|
10258
10808
|
if (!graph.hasEdge(edge.id)) {
|
|
10259
10809
|
graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge);
|
|
@@ -10266,8 +10816,8 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
10266
10816
|
|
|
10267
10817
|
// src/extract/proto.ts
|
|
10268
10818
|
init_cjs_shims();
|
|
10269
|
-
var
|
|
10270
|
-
var
|
|
10819
|
+
var import_node_fs26 = require("fs");
|
|
10820
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
10271
10821
|
var import_types26 = require("@neat.is/types");
|
|
10272
10822
|
var PROTO_EXTENSION = ".proto";
|
|
10273
10823
|
function packageOf(content) {
|
|
@@ -10305,23 +10855,23 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
10305
10855
|
return out;
|
|
10306
10856
|
}
|
|
10307
10857
|
async function walkProtoFiles(dir, excludeDirs = []) {
|
|
10308
|
-
const excluded = new Set(excludeDirs.map((d) =>
|
|
10858
|
+
const excluded = new Set(excludeDirs.map((d) => import_node_path38.default.resolve(d)));
|
|
10309
10859
|
const out = [];
|
|
10310
|
-
async function
|
|
10311
|
-
const entries = await
|
|
10860
|
+
async function walk10(current) {
|
|
10861
|
+
const entries = await import_node_fs26.promises.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
10312
10862
|
for (const entry of entries) {
|
|
10313
|
-
const full =
|
|
10863
|
+
const full = import_node_path38.default.join(current, entry.name);
|
|
10314
10864
|
if (entry.isDirectory()) {
|
|
10315
10865
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
10316
|
-
if (excluded.has(
|
|
10866
|
+
if (excluded.has(import_node_path38.default.resolve(full))) continue;
|
|
10317
10867
|
if (await isPythonVenvDir(full)) continue;
|
|
10318
|
-
await
|
|
10319
|
-
} else if (entry.isFile() &&
|
|
10868
|
+
await walk10(full);
|
|
10869
|
+
} else if (entry.isFile() && import_node_path38.default.extname(entry.name) === PROTO_EXTENSION) {
|
|
10320
10870
|
out.push(full);
|
|
10321
10871
|
}
|
|
10322
10872
|
}
|
|
10323
10873
|
}
|
|
10324
|
-
await
|
|
10874
|
+
await walk10(dir);
|
|
10325
10875
|
return out;
|
|
10326
10876
|
}
|
|
10327
10877
|
async function addGrpcMethods(graph, services) {
|
|
@@ -10331,10 +10881,10 @@ async function addGrpcMethods(graph, services) {
|
|
|
10331
10881
|
const protoPaths = await walkProtoFiles(service.dir, service.excludeDirs);
|
|
10332
10882
|
for (const protoPath of protoPaths) {
|
|
10333
10883
|
if (isTestPath(protoPath)) continue;
|
|
10334
|
-
const relFile = toPosix(
|
|
10884
|
+
const relFile = toPosix(import_node_path38.default.relative(service.dir, protoPath));
|
|
10335
10885
|
let content;
|
|
10336
10886
|
try {
|
|
10337
|
-
content = await
|
|
10887
|
+
content = await import_node_fs26.promises.readFile(protoPath, "utf8");
|
|
10338
10888
|
} catch (err) {
|
|
10339
10889
|
recordExtractionError("proto extraction", protoPath, err);
|
|
10340
10890
|
continue;
|
|
@@ -10389,11 +10939,11 @@ async function addGrpcMethods(graph, services) {
|
|
|
10389
10939
|
|
|
10390
10940
|
// src/extract/calls/index.ts
|
|
10391
10941
|
init_cjs_shims();
|
|
10392
|
-
var
|
|
10942
|
+
var import_types45 = require("@neat.is/types");
|
|
10393
10943
|
|
|
10394
10944
|
// src/extract/calls/http.ts
|
|
10395
10945
|
init_cjs_shims();
|
|
10396
|
-
var
|
|
10946
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
10397
10947
|
var import_tree_sitter6 = __toESM(require("tree-sitter"), 1);
|
|
10398
10948
|
var import_tree_sitter_javascript4 = __toESM(require("tree-sitter-javascript"), 1);
|
|
10399
10949
|
var import_tree_sitter_typescript2 = __toESM(require("tree-sitter-typescript"), 1);
|
|
@@ -10476,7 +11026,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
10476
11026
|
const seen = /* @__PURE__ */ new Set();
|
|
10477
11027
|
for (const file of files) {
|
|
10478
11028
|
if (isTestPath(file.path)) continue;
|
|
10479
|
-
const parser = parserForExt(
|
|
11029
|
+
const parser = parserForExt(import_node_path39.default.extname(file.path), parserCache);
|
|
10480
11030
|
let sites;
|
|
10481
11031
|
try {
|
|
10482
11032
|
sites = callsFromSource(file.content, parser, knownHosts);
|
|
@@ -10485,7 +11035,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
10485
11035
|
continue;
|
|
10486
11036
|
}
|
|
10487
11037
|
if (sites.length === 0) continue;
|
|
10488
|
-
const relFile = toPosix(
|
|
11038
|
+
const relFile = toPosix(import_node_path39.default.relative(service.dir, file.path));
|
|
10489
11039
|
for (const site of sites) {
|
|
10490
11040
|
const targetId = hostToNodeId.get(site.host);
|
|
10491
11041
|
if (!targetId || targetId === service.node.id) continue;
|
|
@@ -10539,7 +11089,7 @@ async function addHttpCallEdges(graph, services) {
|
|
|
10539
11089
|
|
|
10540
11090
|
// src/extract/calls/route-match.ts
|
|
10541
11091
|
init_cjs_shims();
|
|
10542
|
-
var
|
|
11092
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
10543
11093
|
var import_tree_sitter7 = __toESM(require("tree-sitter"), 1);
|
|
10544
11094
|
var import_tree_sitter_javascript5 = __toESM(require("tree-sitter-javascript"), 1);
|
|
10545
11095
|
var import_types28 = require("@neat.is/types");
|
|
@@ -10738,7 +11288,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10738
11288
|
const seen = /* @__PURE__ */ new Set();
|
|
10739
11289
|
for (const file of files) {
|
|
10740
11290
|
if (isTestPath(file.path)) continue;
|
|
10741
|
-
if (!JS_CLIENT_EXTENSIONS.has(
|
|
11291
|
+
if (!JS_CLIENT_EXTENSIONS.has(import_node_path40.default.extname(file.path))) continue;
|
|
10742
11292
|
let sites;
|
|
10743
11293
|
try {
|
|
10744
11294
|
sites = clientCallSitesFromSource(file.content, jsParser, knownHosts);
|
|
@@ -10747,7 +11297,7 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10747
11297
|
continue;
|
|
10748
11298
|
}
|
|
10749
11299
|
if (sites.length === 0) continue;
|
|
10750
|
-
const relFile = toPosix(
|
|
11300
|
+
const relFile = toPosix(import_node_path40.default.relative(service.dir, file.path));
|
|
10751
11301
|
for (const site of sites) {
|
|
10752
11302
|
const serverServiceId = hostToNodeId.get(site.host);
|
|
10753
11303
|
if (!serverServiceId || serverServiceId === service.node.id) continue;
|
|
@@ -10808,10 +11358,15 @@ async function addRouteCallEdges(graph, services) {
|
|
|
10808
11358
|
|
|
10809
11359
|
// src/extract/calls/kafka.ts
|
|
10810
11360
|
init_cjs_shims();
|
|
10811
|
-
var
|
|
11361
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
10812
11362
|
var import_types29 = require("@neat.is/types");
|
|
10813
11363
|
var PRODUCER_TOPIC_RE = /(?:producer|kafkaProducer)[\s\S]{0,40}?\.send\s*\(\s*\{[\s\S]{0,200}?topic\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10814
11364
|
var CONSUMER_TOPIC_RE = /(?:consumer|kafkaConsumer)[\s\S]{0,40}?\.(?:subscribe|run)\s*\(\s*\{[\s\S]{0,200}?topic[s]?\s*:\s*(?:\[\s*)?['"`]([^'"`]+)['"`]/g;
|
|
11365
|
+
var SARAMA_IMPORT_RE = /"[^"]*\/sarama"/;
|
|
11366
|
+
var GO_PRODUCER_RE = /ProducerMessage\s*\{[\s\S]{0,300}?\bTopic\s*:\s*(?:"([^"]+)"|`([^`]+)`|([A-Za-z_]\w*))/g;
|
|
11367
|
+
var GO_CONSUMER_RE = /\.Consume\s*\([\s\S]{0,120}?\[\]string\s*\{([^}]*)\}/g;
|
|
11368
|
+
var GO_STRING_LITERAL_RE = /"([^"]+)"|`([^`]+)`/g;
|
|
11369
|
+
var GO_IDENT_RE = /[A-Za-z_]\w*/g;
|
|
10815
11370
|
function findAll(re, text) {
|
|
10816
11371
|
re.lastIndex = 0;
|
|
10817
11372
|
const out = [];
|
|
@@ -10821,38 +11376,94 @@ function findAll(re, text) {
|
|
|
10821
11376
|
}
|
|
10822
11377
|
return out;
|
|
10823
11378
|
}
|
|
11379
|
+
function resolveGoLiteral(ident, text) {
|
|
11380
|
+
const esc = ident.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11381
|
+
const re = new RegExp(
|
|
11382
|
+
`\\b${esc}(?:\\s+\\w[\\w.\\[\\]*]*)?\\s*(?::=|=)\\s*(?:"([^"]+)"|\`([^\`]+)\`)`
|
|
11383
|
+
);
|
|
11384
|
+
const m = re.exec(text);
|
|
11385
|
+
if (!m) return void 0;
|
|
11386
|
+
return m[1] ?? m[2];
|
|
11387
|
+
}
|
|
11388
|
+
function producerTopicAnchor(match) {
|
|
11389
|
+
const [full] = match;
|
|
11390
|
+
const tokenLen = match[1] ? match[1].length + 2 : match[2] ? match[2].length + 2 : match[3]?.length ?? 0;
|
|
11391
|
+
return match.index + full.length - tokenLen;
|
|
11392
|
+
}
|
|
11393
|
+
function goSaramaEndpoints(text, emit) {
|
|
11394
|
+
if (!SARAMA_IMPORT_RE.test(text)) return;
|
|
11395
|
+
GO_PRODUCER_RE.lastIndex = 0;
|
|
11396
|
+
let m;
|
|
11397
|
+
while ((m = GO_PRODUCER_RE.exec(text)) !== null) {
|
|
11398
|
+
const literal = m[1] ?? m[2];
|
|
11399
|
+
const anchor = producerTopicAnchor(m);
|
|
11400
|
+
if (literal) {
|
|
11401
|
+
emit(literal, "PUBLISHES_TO", anchor);
|
|
11402
|
+
} else if (m[3]) {
|
|
11403
|
+
const resolved = resolveGoLiteral(m[3], text);
|
|
11404
|
+
if (resolved) emit(resolved, "PUBLISHES_TO", anchor);
|
|
11405
|
+
}
|
|
11406
|
+
}
|
|
11407
|
+
GO_CONSUMER_RE.lastIndex = 0;
|
|
11408
|
+
while ((m = GO_CONSUMER_RE.exec(text)) !== null) {
|
|
11409
|
+
const inside = m[1] ?? "";
|
|
11410
|
+
const anchor = m.index + Math.max(0, m[0].indexOf("[]string"));
|
|
11411
|
+
let sawLiteral = false;
|
|
11412
|
+
GO_STRING_LITERAL_RE.lastIndex = 0;
|
|
11413
|
+
let s;
|
|
11414
|
+
while ((s = GO_STRING_LITERAL_RE.exec(inside)) !== null) {
|
|
11415
|
+
const topic = s[1] ?? s[2];
|
|
11416
|
+
if (topic) {
|
|
11417
|
+
emit(topic, "CONSUMES_FROM", anchor);
|
|
11418
|
+
sawLiteral = true;
|
|
11419
|
+
}
|
|
11420
|
+
}
|
|
11421
|
+
if (sawLiteral) continue;
|
|
11422
|
+
GO_IDENT_RE.lastIndex = 0;
|
|
11423
|
+
let id;
|
|
11424
|
+
while ((id = GO_IDENT_RE.exec(inside)) !== null) {
|
|
11425
|
+
const resolved = resolveGoLiteral(id[0], text);
|
|
11426
|
+
if (resolved) emit(resolved, "CONSUMES_FROM", anchor);
|
|
11427
|
+
}
|
|
11428
|
+
}
|
|
11429
|
+
}
|
|
10824
11430
|
function kafkaEndpointsFromFile(file, serviceDir) {
|
|
10825
11431
|
const out = [];
|
|
10826
11432
|
const seen = /* @__PURE__ */ new Set();
|
|
10827
|
-
const make = (topic, edgeType) => {
|
|
11433
|
+
const make = (topic, edgeType, anchor) => {
|
|
10828
11434
|
const key = `${edgeType}|${topic}`;
|
|
10829
11435
|
if (seen.has(key)) return;
|
|
10830
11436
|
seen.add(key);
|
|
10831
|
-
const line = lineOf(file.content, topic);
|
|
11437
|
+
const line = anchor !== void 0 ? file.content.slice(0, anchor).split("\n").length : lineOf(file.content, topic);
|
|
10832
11438
|
out.push({
|
|
10833
11439
|
infraId: (0, import_types29.infraId)("kafka-topic", topic),
|
|
10834
11440
|
name: topic,
|
|
10835
11441
|
kind: "kafka-topic",
|
|
10836
11442
|
edgeType,
|
|
10837
|
-
// `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})`
|
|
10838
|
-
//
|
|
10839
|
-
//
|
|
11443
|
+
// JS: `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})`
|
|
11444
|
+
// (kafkajs / node-rdkafka). Go: `sarama.ProducerMessage{Topic: 'x'}` /
|
|
11445
|
+
// `consumerGroup.Consume(ctx, []string{'x'}, …)`. Both are framework-aware
|
|
11446
|
+
// call sites — verified-call-site tier (ADR-066).
|
|
10840
11447
|
confidenceKind: "verified-call-site",
|
|
10841
11448
|
evidence: {
|
|
10842
|
-
file:
|
|
11449
|
+
file: import_node_path41.default.relative(serviceDir, file.path),
|
|
10843
11450
|
line,
|
|
10844
11451
|
snippet: snippet(file.content, line)
|
|
10845
11452
|
}
|
|
10846
11453
|
});
|
|
10847
11454
|
};
|
|
10848
|
-
|
|
10849
|
-
|
|
11455
|
+
if (import_node_path41.default.extname(file.path) === ".go") {
|
|
11456
|
+
goSaramaEndpoints(file.content, make);
|
|
11457
|
+
} else {
|
|
11458
|
+
for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, "PUBLISHES_TO");
|
|
11459
|
+
for (const { topic } of findAll(CONSUMER_TOPIC_RE, file.content)) make(topic, "CONSUMES_FROM");
|
|
11460
|
+
}
|
|
10850
11461
|
return out;
|
|
10851
11462
|
}
|
|
10852
11463
|
|
|
10853
11464
|
// src/extract/calls/redis.ts
|
|
10854
11465
|
init_cjs_shims();
|
|
10855
|
-
var
|
|
11466
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
10856
11467
|
var import_types30 = require("@neat.is/types");
|
|
10857
11468
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
10858
11469
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
@@ -10875,7 +11486,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10875
11486
|
// support tier (ADR-066).
|
|
10876
11487
|
confidenceKind: "url-with-structural-support",
|
|
10877
11488
|
evidence: {
|
|
10878
|
-
file:
|
|
11489
|
+
file: import_node_path42.default.relative(serviceDir, file.path),
|
|
10879
11490
|
line,
|
|
10880
11491
|
snippet: snippet(file.content, line)
|
|
10881
11492
|
}
|
|
@@ -10886,7 +11497,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10886
11497
|
|
|
10887
11498
|
// src/extract/calls/aws.ts
|
|
10888
11499
|
init_cjs_shims();
|
|
10889
|
-
var
|
|
11500
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
10890
11501
|
var import_types31 = require("@neat.is/types");
|
|
10891
11502
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10892
11503
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
@@ -10920,7 +11531,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
10920
11531
|
// (ADR-066).
|
|
10921
11532
|
confidenceKind: "verified-call-site",
|
|
10922
11533
|
evidence: {
|
|
10923
|
-
file:
|
|
11534
|
+
file: import_node_path43.default.relative(serviceDir, file.path),
|
|
10924
11535
|
line,
|
|
10925
11536
|
snippet: snippet(file.content, line)
|
|
10926
11537
|
}
|
|
@@ -10945,7 +11556,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
10945
11556
|
|
|
10946
11557
|
// src/extract/calls/grpc.ts
|
|
10947
11558
|
init_cjs_shims();
|
|
10948
|
-
var
|
|
11559
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
10949
11560
|
var import_types32 = require("@neat.is/types");
|
|
10950
11561
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
10951
11562
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
@@ -11004,7 +11615,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
11004
11615
|
// tier (ADR-066).
|
|
11005
11616
|
confidenceKind: "verified-call-site",
|
|
11006
11617
|
evidence: {
|
|
11007
|
-
file:
|
|
11618
|
+
file: import_node_path44.default.relative(serviceDir, file.path),
|
|
11008
11619
|
line,
|
|
11009
11620
|
snippet: snippet(file.content, line)
|
|
11010
11621
|
}
|
|
@@ -11015,7 +11626,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
11015
11626
|
|
|
11016
11627
|
// src/extract/calls/supabase.ts
|
|
11017
11628
|
init_cjs_shims();
|
|
11018
|
-
var
|
|
11629
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
11019
11630
|
var import_types33 = require("@neat.is/types");
|
|
11020
11631
|
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
11021
11632
|
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
@@ -11074,7 +11685,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11074
11685
|
// tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
|
|
11075
11686
|
confidenceKind: "verified-call-site",
|
|
11076
11687
|
evidence: {
|
|
11077
|
-
file:
|
|
11688
|
+
file: import_node_path45.default.relative(serviceDir, file.path),
|
|
11078
11689
|
line,
|
|
11079
11690
|
snippet: snippet(file.content, line)
|
|
11080
11691
|
}
|
|
@@ -11101,7 +11712,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11101
11712
|
edgeType: "CALLS",
|
|
11102
11713
|
confidenceKind: "verified-call-site",
|
|
11103
11714
|
evidence: {
|
|
11104
|
-
file:
|
|
11715
|
+
file: import_node_path45.default.relative(serviceDir, file.path),
|
|
11105
11716
|
line,
|
|
11106
11717
|
snippet: snippet(file.content, line)
|
|
11107
11718
|
}
|
|
@@ -11113,7 +11724,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11113
11724
|
|
|
11114
11725
|
// src/extract/calls/firestore.ts
|
|
11115
11726
|
init_cjs_shims();
|
|
11116
|
-
var
|
|
11727
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
11117
11728
|
var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
|
|
11118
11729
|
var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
|
|
11119
11730
|
var import_types34 = require("@neat.is/types");
|
|
@@ -11152,7 +11763,7 @@ function isFirestoreClientFactory(node) {
|
|
|
11152
11763
|
}
|
|
11153
11764
|
function firestoreClientVars(root) {
|
|
11154
11765
|
const vars = /* @__PURE__ */ new Set();
|
|
11155
|
-
const
|
|
11766
|
+
const walk10 = (node) => {
|
|
11156
11767
|
if (node.type === "variable_declarator") {
|
|
11157
11768
|
const name = node.childForFieldName("name");
|
|
11158
11769
|
let value = node.childForFieldName("value");
|
|
@@ -11161,9 +11772,9 @@ function firestoreClientVars(root) {
|
|
|
11161
11772
|
vars.add(name.text);
|
|
11162
11773
|
}
|
|
11163
11774
|
}
|
|
11164
|
-
for (const c of namedChildren(node))
|
|
11775
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
11165
11776
|
};
|
|
11166
|
-
|
|
11777
|
+
walk10(root);
|
|
11167
11778
|
return vars;
|
|
11168
11779
|
}
|
|
11169
11780
|
function isClientExpr(node, clientVars) {
|
|
@@ -11284,7 +11895,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11284
11895
|
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
|
|
11285
11896
|
if (!hasClient && !hasAdmin) return [];
|
|
11286
11897
|
const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
11287
|
-
const tree = parseSource3(parserForExt2(
|
|
11898
|
+
const tree = parseSource3(parserForExt2(import_node_path46.default.extname(file.path)), file.content);
|
|
11288
11899
|
const clientVars = firestoreClientVars(tree.rootNode);
|
|
11289
11900
|
const collLine = /* @__PURE__ */ new Map();
|
|
11290
11901
|
const writes = /* @__PURE__ */ new Map();
|
|
@@ -11318,7 +11929,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11318
11929
|
}
|
|
11319
11930
|
s.add(field);
|
|
11320
11931
|
};
|
|
11321
|
-
const
|
|
11932
|
+
const walk10 = (node) => {
|
|
11322
11933
|
if (node.type === "call_expression") {
|
|
11323
11934
|
const fn = node.childForFieldName("function");
|
|
11324
11935
|
const line = node.startPosition.row + 1;
|
|
@@ -11358,9 +11969,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11358
11969
|
}
|
|
11359
11970
|
}
|
|
11360
11971
|
}
|
|
11361
|
-
for (const c of namedChildren(node))
|
|
11972
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
11362
11973
|
};
|
|
11363
|
-
|
|
11974
|
+
walk10(tree.rootNode);
|
|
11364
11975
|
const out = [];
|
|
11365
11976
|
for (const [collPath, line] of collLine) {
|
|
11366
11977
|
const byField = writes.get(collPath);
|
|
@@ -11388,7 +11999,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11388
11999
|
...columnSet.size > 0 ? { columns: [...columnSet] } : {},
|
|
11389
12000
|
...sdkWrites ? { sdkWrites } : {},
|
|
11390
12001
|
evidence: {
|
|
11391
|
-
file:
|
|
12002
|
+
file: import_node_path46.default.relative(serviceDir, file.path),
|
|
11392
12003
|
line,
|
|
11393
12004
|
snippet: snippet(file.content, line)
|
|
11394
12005
|
}
|
|
@@ -11399,7 +12010,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11399
12010
|
|
|
11400
12011
|
// src/extract/calls/mongoose.ts
|
|
11401
12012
|
init_cjs_shims();
|
|
11402
|
-
var
|
|
12013
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
11403
12014
|
var import_types35 = require("@neat.is/types");
|
|
11404
12015
|
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
11405
12016
|
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
@@ -11550,7 +12161,7 @@ function endpoint(r, file, serviceDir, matchText) {
|
|
|
11550
12161
|
kind: r.kind,
|
|
11551
12162
|
edgeType: "CALLS",
|
|
11552
12163
|
confidenceKind: "verified-call-site",
|
|
11553
|
-
evidence: { file:
|
|
12164
|
+
evidence: { file: import_node_path47.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
11554
12165
|
};
|
|
11555
12166
|
}
|
|
11556
12167
|
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
@@ -11640,7 +12251,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11640
12251
|
const registry = /* @__PURE__ */ new Map();
|
|
11641
12252
|
for (const f of mongooseFiles) {
|
|
11642
12253
|
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
11643
|
-
if (fx) registry.set(toPosix(
|
|
12254
|
+
if (fx) registry.set(toPosix(import_node_path47.default.relative(serviceDir, f.path)), fx);
|
|
11644
12255
|
}
|
|
11645
12256
|
if (registry.size === 0) return [];
|
|
11646
12257
|
const out = [];
|
|
@@ -11651,7 +12262,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11651
12262
|
const directColl = /* @__PURE__ */ new Map();
|
|
11652
12263
|
const nsExports = /* @__PURE__ */ new Map();
|
|
11653
12264
|
for (const b of bindings) {
|
|
11654
|
-
const resolvedRel = await resolveJsImport(b.specifier,
|
|
12265
|
+
const resolvedRel = await resolveJsImport(b.specifier, import_node_path47.default.dirname(f.path), serviceDir, null);
|
|
11655
12266
|
if (!resolvedRel) continue;
|
|
11656
12267
|
const fx = registry.get(resolvedRel);
|
|
11657
12268
|
if (!fx) continue;
|
|
@@ -11695,7 +12306,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11695
12306
|
|
|
11696
12307
|
// src/extract/calls/sqlalchemy.ts
|
|
11697
12308
|
init_cjs_shims();
|
|
11698
|
-
var
|
|
12309
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11699
12310
|
var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
|
|
11700
12311
|
var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
11701
12312
|
var import_types36 = require("@neat.is/types");
|
|
@@ -11834,7 +12445,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
|
|
|
11834
12445
|
childTable,
|
|
11835
12446
|
parentTable,
|
|
11836
12447
|
evidence: {
|
|
11837
|
-
file:
|
|
12448
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11838
12449
|
line,
|
|
11839
12450
|
snippet: snippet(file.content, line)
|
|
11840
12451
|
}
|
|
@@ -11859,7 +12470,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
11859
12470
|
confidenceKind: "verified-call-site",
|
|
11860
12471
|
...columns && columns.length > 0 ? { columns } : {},
|
|
11861
12472
|
evidence: {
|
|
11862
|
-
file:
|
|
12473
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11863
12474
|
line,
|
|
11864
12475
|
snippet: snippet(file.content, line)
|
|
11865
12476
|
}
|
|
@@ -11966,7 +12577,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
11966
12577
|
edgeType: "CALLS",
|
|
11967
12578
|
confidenceKind: "verified-call-site",
|
|
11968
12579
|
evidence: {
|
|
11969
|
-
file:
|
|
12580
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11970
12581
|
line,
|
|
11971
12582
|
snippet: snippet(file.content, line)
|
|
11972
12583
|
}
|
|
@@ -11978,7 +12589,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
11978
12589
|
|
|
11979
12590
|
// src/extract/calls/django-orm.ts
|
|
11980
12591
|
init_cjs_shims();
|
|
11981
|
-
var
|
|
12592
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
11982
12593
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
11983
12594
|
var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
|
|
11984
12595
|
var import_types37 = require("@neat.is/types");
|
|
@@ -12048,7 +12659,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12048
12659
|
const tree = parseSource7(makePyParser4(), file.content);
|
|
12049
12660
|
const out = [];
|
|
12050
12661
|
const seen = /* @__PURE__ */ new Set();
|
|
12051
|
-
const defaultAppLabel =
|
|
12662
|
+
const defaultAppLabel = import_node_path49.default.basename(import_node_path49.default.dirname(file.path));
|
|
12052
12663
|
walk4(tree.rootNode, (node) => {
|
|
12053
12664
|
if (node.type !== "class_definition") return;
|
|
12054
12665
|
if (!extendsDjangoModel(node)) return;
|
|
@@ -12066,7 +12677,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12066
12677
|
kind: "sql-table",
|
|
12067
12678
|
edgeType: "CALLS",
|
|
12068
12679
|
confidenceKind: "verified-call-site",
|
|
12069
|
-
evidence: { file:
|
|
12680
|
+
evidence: { file: import_node_path49.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
12070
12681
|
});
|
|
12071
12682
|
});
|
|
12072
12683
|
return out;
|
|
@@ -12074,7 +12685,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12074
12685
|
|
|
12075
12686
|
// src/extract/calls/drizzle.ts
|
|
12076
12687
|
init_cjs_shims();
|
|
12077
|
-
var
|
|
12688
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
12078
12689
|
var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
|
|
12079
12690
|
var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12080
12691
|
var import_types38 = require("@neat.is/types");
|
|
@@ -12152,10 +12763,10 @@ function columnsFromObject(obj) {
|
|
|
12152
12763
|
}
|
|
12153
12764
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
12154
12765
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12155
|
-
const tree = parseSource3(parserForExt3(
|
|
12766
|
+
const tree = parseSource3(parserForExt3(import_node_path50.default.extname(file.path)), file.content);
|
|
12156
12767
|
const out = [];
|
|
12157
12768
|
const seen = /* @__PURE__ */ new Set();
|
|
12158
|
-
const
|
|
12769
|
+
const walk10 = (node) => {
|
|
12159
12770
|
if (node.type === "call_expression") {
|
|
12160
12771
|
const fn = node.childForFieldName("function");
|
|
12161
12772
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -12175,7 +12786,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12175
12786
|
confidenceKind: "structural",
|
|
12176
12787
|
columns,
|
|
12177
12788
|
evidence: {
|
|
12178
|
-
file:
|
|
12789
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12179
12790
|
line,
|
|
12180
12791
|
snippet: snippet(file.content, line)
|
|
12181
12792
|
}
|
|
@@ -12183,9 +12794,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12183
12794
|
}
|
|
12184
12795
|
}
|
|
12185
12796
|
}
|
|
12186
|
-
for (const c of namedChildren4(node))
|
|
12797
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12187
12798
|
};
|
|
12188
|
-
|
|
12799
|
+
walk10(tree.rootNode);
|
|
12189
12800
|
return out;
|
|
12190
12801
|
}
|
|
12191
12802
|
function enclosingVarName(call) {
|
|
@@ -12207,7 +12818,7 @@ function enclosingVarName(call) {
|
|
|
12207
12818
|
function collectDrizzleTables(root) {
|
|
12208
12819
|
const tables = [];
|
|
12209
12820
|
const varToTable = /* @__PURE__ */ new Map();
|
|
12210
|
-
const
|
|
12821
|
+
const walk10 = (node) => {
|
|
12211
12822
|
if (node.type === "call_expression") {
|
|
12212
12823
|
const fn = node.childForFieldName("function");
|
|
12213
12824
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -12222,9 +12833,9 @@ function collectDrizzleTables(root) {
|
|
|
12222
12833
|
}
|
|
12223
12834
|
}
|
|
12224
12835
|
}
|
|
12225
|
-
for (const c of namedChildren4(node))
|
|
12836
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12226
12837
|
};
|
|
12227
|
-
|
|
12838
|
+
walk10(root);
|
|
12228
12839
|
return { tables, varToTable };
|
|
12229
12840
|
}
|
|
12230
12841
|
function referencesTargetVar(call) {
|
|
@@ -12241,13 +12852,13 @@ function referencesTargetVar(call) {
|
|
|
12241
12852
|
}
|
|
12242
12853
|
function drizzleForeignKeys(file, serviceDir) {
|
|
12243
12854
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12244
|
-
const tree = parseSource3(parserForExt3(
|
|
12855
|
+
const tree = parseSource3(parserForExt3(import_node_path50.default.extname(file.path)), file.content);
|
|
12245
12856
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
12246
12857
|
const out = [];
|
|
12247
12858
|
const seen = /* @__PURE__ */ new Set();
|
|
12248
12859
|
for (const table of tables) {
|
|
12249
12860
|
if (!table.object) continue;
|
|
12250
|
-
const
|
|
12861
|
+
const walk10 = (node) => {
|
|
12251
12862
|
if (node.type === "call_expression") {
|
|
12252
12863
|
const targetVar = referencesTargetVar(node);
|
|
12253
12864
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -12260,7 +12871,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12260
12871
|
childTable: table.tableName,
|
|
12261
12872
|
parentTable,
|
|
12262
12873
|
evidence: {
|
|
12263
|
-
file:
|
|
12874
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12264
12875
|
line,
|
|
12265
12876
|
snippet: snippet(file.content, line)
|
|
12266
12877
|
}
|
|
@@ -12268,16 +12879,16 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12268
12879
|
}
|
|
12269
12880
|
}
|
|
12270
12881
|
}
|
|
12271
|
-
for (const c of namedChildren4(node))
|
|
12882
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12272
12883
|
};
|
|
12273
|
-
|
|
12884
|
+
walk10(table.object);
|
|
12274
12885
|
}
|
|
12275
12886
|
return out;
|
|
12276
12887
|
}
|
|
12277
12888
|
|
|
12278
12889
|
// src/extract/calls/prisma.ts
|
|
12279
12890
|
init_cjs_shims();
|
|
12280
|
-
var
|
|
12891
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12281
12892
|
var import_types39 = require("@neat.is/types");
|
|
12282
12893
|
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
12283
12894
|
"Int",
|
|
@@ -12333,7 +12944,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12333
12944
|
confidenceKind: "structural",
|
|
12334
12945
|
columns: b.columns,
|
|
12335
12946
|
evidence: {
|
|
12336
|
-
file:
|
|
12947
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12337
12948
|
line: b.startLine,
|
|
12338
12949
|
snippet: snippet(content, b.startLine)
|
|
12339
12950
|
}
|
|
@@ -12394,7 +13005,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12394
13005
|
}
|
|
12395
13006
|
async function prismaColumnEndpoints(serviceDir) {
|
|
12396
13007
|
const schemaPath = await findFirst(serviceDir, [
|
|
12397
|
-
|
|
13008
|
+
import_node_path51.default.join("prisma", "schema.prisma"),
|
|
12398
13009
|
"schema.prisma"
|
|
12399
13010
|
]);
|
|
12400
13011
|
if (!schemaPath) return [];
|
|
@@ -12469,7 +13080,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12469
13080
|
childTable: current.table,
|
|
12470
13081
|
parentTable,
|
|
12471
13082
|
evidence: {
|
|
12472
|
-
file:
|
|
13083
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12473
13084
|
line: lineNo,
|
|
12474
13085
|
snippet: snippet(content, lineNo)
|
|
12475
13086
|
}
|
|
@@ -12484,7 +13095,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12484
13095
|
}
|
|
12485
13096
|
async function prismaForeignKeys(serviceDir) {
|
|
12486
13097
|
const schemaPath = await findFirst(serviceDir, [
|
|
12487
|
-
|
|
13098
|
+
import_node_path51.default.join("prisma", "schema.prisma"),
|
|
12488
13099
|
"schema.prisma"
|
|
12489
13100
|
]);
|
|
12490
13101
|
if (!schemaPath) return [];
|
|
@@ -12495,7 +13106,7 @@ async function prismaForeignKeys(serviceDir) {
|
|
|
12495
13106
|
|
|
12496
13107
|
// src/extract/calls/activerecord.ts
|
|
12497
13108
|
init_cjs_shims();
|
|
12498
|
-
var
|
|
13109
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
12499
13110
|
var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
|
|
12500
13111
|
var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
|
|
12501
13112
|
var import_types40 = require("@neat.is/types");
|
|
@@ -12703,7 +13314,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
|
12703
13314
|
confidenceKind: "structural",
|
|
12704
13315
|
...table.columns.length > 0 ? { columns: table.columns } : {},
|
|
12705
13316
|
evidence: {
|
|
12706
|
-
file:
|
|
13317
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12707
13318
|
line: table.line,
|
|
12708
13319
|
snippet: snippet(file.content, table.line)
|
|
12709
13320
|
}
|
|
@@ -12725,7 +13336,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
|
|
|
12725
13336
|
childTable,
|
|
12726
13337
|
parentTable,
|
|
12727
13338
|
evidence: {
|
|
12728
|
-
file:
|
|
13339
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12729
13340
|
line,
|
|
12730
13341
|
snippet: snippet(file.content, line)
|
|
12731
13342
|
}
|
|
@@ -12808,7 +13419,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
|
|
|
12808
13419
|
edgeType: "CALLS",
|
|
12809
13420
|
confidenceKind: "verified-call-site",
|
|
12810
13421
|
evidence: {
|
|
12811
|
-
file:
|
|
13422
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12812
13423
|
line,
|
|
12813
13424
|
snippet: snippet(file.content, line)
|
|
12814
13425
|
}
|
|
@@ -12845,7 +13456,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12845
13456
|
childTable,
|
|
12846
13457
|
parentTable,
|
|
12847
13458
|
evidence: {
|
|
12848
|
-
file:
|
|
13459
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12849
13460
|
line,
|
|
12850
13461
|
snippet: snippet(file.content, line)
|
|
12851
13462
|
}
|
|
@@ -12857,7 +13468,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12857
13468
|
|
|
12858
13469
|
// src/extract/calls/eloquent.ts
|
|
12859
13470
|
init_cjs_shims();
|
|
12860
|
-
var
|
|
13471
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
12861
13472
|
var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
|
|
12862
13473
|
var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
|
|
12863
13474
|
var import_types41 = require("@neat.is/types");
|
|
@@ -13114,7 +13725,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
13114
13725
|
confidenceKind: "structural",
|
|
13115
13726
|
...columns.length > 0 ? { columns } : {},
|
|
13116
13727
|
evidence: {
|
|
13117
|
-
file:
|
|
13728
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13118
13729
|
line: bp.line,
|
|
13119
13730
|
snippet: snippet(file.content, bp.line)
|
|
13120
13731
|
}
|
|
@@ -13136,7 +13747,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
|
|
|
13136
13747
|
childTable,
|
|
13137
13748
|
parentTable,
|
|
13138
13749
|
evidence: {
|
|
13139
|
-
file:
|
|
13750
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13140
13751
|
line,
|
|
13141
13752
|
snippet: snippet(file.content, line)
|
|
13142
13753
|
}
|
|
@@ -13256,7 +13867,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
|
13256
13867
|
edgeType: "CALLS",
|
|
13257
13868
|
confidenceKind: "verified-call-site",
|
|
13258
13869
|
evidence: {
|
|
13259
|
-
file:
|
|
13870
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13260
13871
|
line,
|
|
13261
13872
|
snippet: snippet(file.content, line)
|
|
13262
13873
|
}
|
|
@@ -13292,7 +13903,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13292
13903
|
childTable,
|
|
13293
13904
|
parentTable,
|
|
13294
13905
|
evidence: {
|
|
13295
|
-
file:
|
|
13906
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13296
13907
|
line,
|
|
13297
13908
|
snippet: snippet(file.content, line)
|
|
13298
13909
|
}
|
|
@@ -13304,7 +13915,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13304
13915
|
|
|
13305
13916
|
// src/extract/calls/go.ts
|
|
13306
13917
|
init_cjs_shims();
|
|
13307
|
-
var
|
|
13918
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
13308
13919
|
var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
|
|
13309
13920
|
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
13310
13921
|
var import_types42 = require("@neat.is/types");
|
|
@@ -13379,7 +13990,7 @@ function firstStringLiteralArg(argsNode) {
|
|
|
13379
13990
|
return null;
|
|
13380
13991
|
}
|
|
13381
13992
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
13382
|
-
if (
|
|
13993
|
+
if (import_node_path56.default.extname(file.path) !== ".go") return [];
|
|
13383
13994
|
if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
|
|
13384
13995
|
const tree = parseSource10(makeGoParser3(), file.content);
|
|
13385
13996
|
const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
|
|
@@ -13408,7 +14019,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13408
14019
|
confidenceKind: "verified-call-site",
|
|
13409
14020
|
...columns.length > 0 ? { columns } : {},
|
|
13410
14021
|
evidence: {
|
|
13411
|
-
file: toPosix(
|
|
14022
|
+
file: toPosix(import_node_path56.default.relative(serviceDir, file.path)),
|
|
13412
14023
|
line,
|
|
13413
14024
|
snippet: snippet(file.content, line)
|
|
13414
14025
|
}
|
|
@@ -13419,7 +14030,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13419
14030
|
|
|
13420
14031
|
// src/extract/calls/gorm.ts
|
|
13421
14032
|
init_cjs_shims();
|
|
13422
|
-
var
|
|
14033
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
13423
14034
|
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
13424
14035
|
var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
|
|
13425
14036
|
var import_types43 = require("@neat.is/types");
|
|
@@ -13852,7 +14463,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
|
13852
14463
|
seen.delete(struct.name);
|
|
13853
14464
|
}
|
|
13854
14465
|
function gormEndpointsFromFile(file, serviceDir) {
|
|
13855
|
-
if (
|
|
14466
|
+
if (import_node_path57.default.extname(file.path) !== ".go") return [];
|
|
13856
14467
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13857
14468
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13858
14469
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13874,7 +14485,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13874
14485
|
confidenceKind: "structural",
|
|
13875
14486
|
...columns.length > 0 ? { columns } : {},
|
|
13876
14487
|
evidence: {
|
|
13877
|
-
file: toPosix(
|
|
14488
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
13878
14489
|
line: struct.line,
|
|
13879
14490
|
snippet: snippet(file.content, struct.line)
|
|
13880
14491
|
}
|
|
@@ -13883,7 +14494,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13883
14494
|
return out;
|
|
13884
14495
|
}
|
|
13885
14496
|
function gormForeignKeys(file, serviceDir) {
|
|
13886
|
-
if (
|
|
14497
|
+
if (import_node_path57.default.extname(file.path) !== ".go") return [];
|
|
13887
14498
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13888
14499
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13889
14500
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13898,7 +14509,7 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13898
14509
|
childTable,
|
|
13899
14510
|
parentTable,
|
|
13900
14511
|
evidence: {
|
|
13901
|
-
file: toPosix(
|
|
14512
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
13902
14513
|
line,
|
|
13903
14514
|
snippet: snippet(file.content, line)
|
|
13904
14515
|
}
|
|
@@ -13933,15 +14544,131 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13933
14544
|
return out;
|
|
13934
14545
|
}
|
|
13935
14546
|
|
|
14547
|
+
// src/extract/calls/efcore.ts
|
|
14548
|
+
init_cjs_shims();
|
|
14549
|
+
var import_node_path58 = __toESM(require("path"), 1);
|
|
14550
|
+
var import_tree_sitter16 = __toESM(require("tree-sitter"), 1);
|
|
14551
|
+
var import_tree_sitter_c_sharp2 = __toESM(require("tree-sitter-c-sharp"), 1);
|
|
14552
|
+
var import_types44 = require("@neat.is/types");
|
|
14553
|
+
var EFCORE_GATE = /Microsoft\.EntityFrameworkCore|DataAnnotations\.Schema|\bDbContext\b|\bDbSet\s*</;
|
|
14554
|
+
var PARSE_CHUNK12 = 16384;
|
|
14555
|
+
function makeCsParser() {
|
|
14556
|
+
const p = new import_tree_sitter16.default();
|
|
14557
|
+
p.setLanguage(import_tree_sitter_c_sharp2.default);
|
|
14558
|
+
return p;
|
|
14559
|
+
}
|
|
14560
|
+
function parseSource12(parser, source) {
|
|
14561
|
+
return parser.parse(
|
|
14562
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK12)
|
|
14563
|
+
);
|
|
14564
|
+
}
|
|
14565
|
+
function walk9(node, visit) {
|
|
14566
|
+
visit(node);
|
|
14567
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14568
|
+
const c = node.namedChild(i);
|
|
14569
|
+
if (c) walk9(c, visit);
|
|
14570
|
+
}
|
|
14571
|
+
}
|
|
14572
|
+
function firstChildOfType(node, type) {
|
|
14573
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14574
|
+
const c = node.namedChild(i);
|
|
14575
|
+
if (c?.type === type) return c;
|
|
14576
|
+
}
|
|
14577
|
+
return null;
|
|
14578
|
+
}
|
|
14579
|
+
function csStringLiteral(node) {
|
|
14580
|
+
if (node.type === "string_literal") {
|
|
14581
|
+
let out = "";
|
|
14582
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14583
|
+
const c = node.namedChild(i);
|
|
14584
|
+
if (c?.type === "string_literal_content") out += c.text;
|
|
14585
|
+
}
|
|
14586
|
+
return out;
|
|
14587
|
+
}
|
|
14588
|
+
if (node.type === "verbatim_string_literal") {
|
|
14589
|
+
const t = node.text;
|
|
14590
|
+
return t.length >= 3 ? t.slice(2, -1).replace(/""/g, '"') : "";
|
|
14591
|
+
}
|
|
14592
|
+
return null;
|
|
14593
|
+
}
|
|
14594
|
+
function attributeName(attr) {
|
|
14595
|
+
const nameNode = attr.childForFieldName("name") ?? attr.namedChild(0);
|
|
14596
|
+
if (!nameNode) return null;
|
|
14597
|
+
const text = nameNode.text;
|
|
14598
|
+
const base = text.includes(".") ? text.slice(text.lastIndexOf(".") + 1) : text;
|
|
14599
|
+
return base.endsWith("Attribute") ? base.slice(0, -"Attribute".length) : base;
|
|
14600
|
+
}
|
|
14601
|
+
function tableFromAttribute(attr) {
|
|
14602
|
+
if (attributeName(attr) !== "Table") return null;
|
|
14603
|
+
const args = attr.childForFieldName("arguments") ?? firstChildOfType(attr, "attribute_argument_list");
|
|
14604
|
+
if (!args) return null;
|
|
14605
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
14606
|
+
const arg = args.namedChild(i);
|
|
14607
|
+
if (arg?.type !== "attribute_argument") continue;
|
|
14608
|
+
const first = arg.namedChild(0);
|
|
14609
|
+
if (!first) continue;
|
|
14610
|
+
const value = csStringLiteral(first);
|
|
14611
|
+
if (value !== null) return value;
|
|
14612
|
+
return null;
|
|
14613
|
+
}
|
|
14614
|
+
return null;
|
|
14615
|
+
}
|
|
14616
|
+
function tableFromToTable(call) {
|
|
14617
|
+
const fn = call.childForFieldName("function");
|
|
14618
|
+
if (fn?.type !== "member_access_expression") return null;
|
|
14619
|
+
const method = fn.childForFieldName("name") ?? fn.namedChild(fn.namedChildCount - 1);
|
|
14620
|
+
if (method?.text !== "ToTable") return null;
|
|
14621
|
+
const args = call.childForFieldName("arguments");
|
|
14622
|
+
const firstArg2 = args?.namedChild(0);
|
|
14623
|
+
if (firstArg2?.type !== "argument") return null;
|
|
14624
|
+
const value = firstArg2.namedChild(0);
|
|
14625
|
+
return value ? csStringLiteral(value) : null;
|
|
14626
|
+
}
|
|
14627
|
+
function efcoreEndpointsFromFile(file, serviceDir) {
|
|
14628
|
+
if (import_node_path58.default.extname(file.path) !== ".cs") return [];
|
|
14629
|
+
if (!EFCORE_GATE.test(file.content)) return [];
|
|
14630
|
+
const tree = parseSource12(makeCsParser(), file.content);
|
|
14631
|
+
const out = [];
|
|
14632
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14633
|
+
const push = (name, line) => {
|
|
14634
|
+
if (!name || seen.has(name)) return;
|
|
14635
|
+
seen.add(name);
|
|
14636
|
+
out.push({
|
|
14637
|
+
infraId: (0, import_types44.infraId)("sql-table", name),
|
|
14638
|
+
name,
|
|
14639
|
+
kind: "sql-table",
|
|
14640
|
+
edgeType: "CALLS",
|
|
14641
|
+
confidenceKind: "structural",
|
|
14642
|
+
evidence: {
|
|
14643
|
+
file: toPosix(import_node_path58.default.relative(serviceDir, file.path)),
|
|
14644
|
+
line,
|
|
14645
|
+
snippet: snippet(file.content, line)
|
|
14646
|
+
}
|
|
14647
|
+
});
|
|
14648
|
+
};
|
|
14649
|
+
walk9(tree.rootNode, (node) => {
|
|
14650
|
+
if (node.type === "attribute") {
|
|
14651
|
+
const table = tableFromAttribute(node);
|
|
14652
|
+
if (table) push(table, node.startPosition.row + 1);
|
|
14653
|
+
return;
|
|
14654
|
+
}
|
|
14655
|
+
if (node.type === "invocation_expression") {
|
|
14656
|
+
const table = tableFromToTable(node);
|
|
14657
|
+
if (table) push(table, node.startPosition.row + 1);
|
|
14658
|
+
}
|
|
14659
|
+
});
|
|
14660
|
+
return out;
|
|
14661
|
+
}
|
|
14662
|
+
|
|
13936
14663
|
// src/extract/calls/index.ts
|
|
13937
14664
|
function edgeTypeFromEndpoint(ep) {
|
|
13938
14665
|
switch (ep.edgeType) {
|
|
13939
14666
|
case "PUBLISHES_TO":
|
|
13940
|
-
return
|
|
14667
|
+
return import_types45.EdgeType.PUBLISHES_TO;
|
|
13941
14668
|
case "CONSUMES_FROM":
|
|
13942
|
-
return
|
|
14669
|
+
return import_types45.EdgeType.CONSUMES_FROM;
|
|
13943
14670
|
default:
|
|
13944
|
-
return
|
|
14671
|
+
return import_types45.EdgeType.CALLS;
|
|
13945
14672
|
}
|
|
13946
14673
|
}
|
|
13947
14674
|
function isAwsKind(kind) {
|
|
@@ -13991,6 +14718,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13991
14718
|
} catch (err) {
|
|
13992
14719
|
recordExtractionError("laravel eloquent extraction", file.path, err);
|
|
13993
14720
|
}
|
|
14721
|
+
try {
|
|
14722
|
+
endpoints.push(...efcoreEndpointsFromFile(file, service.dir));
|
|
14723
|
+
} catch (err) {
|
|
14724
|
+
recordExtractionError("efcore data-axis extraction", file.path, err);
|
|
14725
|
+
}
|
|
13994
14726
|
}
|
|
13995
14727
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
13996
14728
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
@@ -14001,7 +14733,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14001
14733
|
if (!graph.hasNode(ep.infraId)) {
|
|
14002
14734
|
const node = {
|
|
14003
14735
|
id: ep.infraId,
|
|
14004
|
-
type:
|
|
14736
|
+
type: import_types45.NodeType.InfraNode,
|
|
14005
14737
|
name: ep.name,
|
|
14006
14738
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
14007
14739
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -14014,21 +14746,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14014
14746
|
}
|
|
14015
14747
|
if (ep.columns && ep.columns.length > 0) {
|
|
14016
14748
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14017
|
-
if (node.type ===
|
|
14749
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14018
14750
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14019
14751
|
...node,
|
|
14020
14752
|
columns: foldColumns(
|
|
14021
14753
|
node.columns,
|
|
14022
14754
|
ep.columns,
|
|
14023
|
-
|
|
14024
|
-
(0,
|
|
14755
|
+
import_types45.Provenance.EXTRACTED,
|
|
14756
|
+
(0, import_types45.confidenceForExtracted)(ep.confidenceKind)
|
|
14025
14757
|
)
|
|
14026
14758
|
});
|
|
14027
14759
|
}
|
|
14028
14760
|
}
|
|
14029
14761
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
14030
14762
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14031
|
-
if (node.type ===
|
|
14763
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14032
14764
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14033
14765
|
...node,
|
|
14034
14766
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -14036,7 +14768,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14036
14768
|
}
|
|
14037
14769
|
}
|
|
14038
14770
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
14039
|
-
const confidence = (0,
|
|
14771
|
+
const confidence = (0, import_types45.confidenceForExtracted)(ep.confidenceKind);
|
|
14040
14772
|
const relFile = toPosix(ep.evidence.file);
|
|
14041
14773
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
14042
14774
|
graph,
|
|
@@ -14046,7 +14778,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14046
14778
|
);
|
|
14047
14779
|
nodesAdded += n;
|
|
14048
14780
|
edgesAdded += e;
|
|
14049
|
-
if (!(0,
|
|
14781
|
+
if (!(0, import_types45.passesExtractedFloor)(confidence)) {
|
|
14050
14782
|
noteExtractedDropped({
|
|
14051
14783
|
source: fileNodeId,
|
|
14052
14784
|
target: ep.infraId,
|
|
@@ -14066,7 +14798,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14066
14798
|
source: fileNodeId,
|
|
14067
14799
|
target: ep.infraId,
|
|
14068
14800
|
type: edgeType,
|
|
14069
|
-
provenance:
|
|
14801
|
+
provenance: import_types45.Provenance.EXTRACTED,
|
|
14070
14802
|
confidence,
|
|
14071
14803
|
evidence: ep.evidence
|
|
14072
14804
|
};
|
|
@@ -14089,7 +14821,7 @@ async function addCallEdges(graph, services) {
|
|
|
14089
14821
|
|
|
14090
14822
|
// src/extract/table-edges.ts
|
|
14091
14823
|
init_cjs_shims();
|
|
14092
|
-
var
|
|
14824
|
+
var import_types46 = require("@neat.is/types");
|
|
14093
14825
|
async function addTableEdges(graph, services) {
|
|
14094
14826
|
let nodesAdded = 0;
|
|
14095
14827
|
let edgesAdded = 0;
|
|
@@ -14117,20 +14849,20 @@ async function addTableEdges(graph, services) {
|
|
|
14117
14849
|
}
|
|
14118
14850
|
refs.push(...modelRefs);
|
|
14119
14851
|
for (const ref of refs) {
|
|
14120
|
-
const childId = (0,
|
|
14121
|
-
const parentId = (0,
|
|
14852
|
+
const childId = (0, import_types46.infraId)("sql-table", ref.childTable);
|
|
14853
|
+
const parentId = (0, import_types46.infraId)("sql-table", ref.parentTable);
|
|
14122
14854
|
if (childId === parentId) continue;
|
|
14123
14855
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
14124
14856
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
14125
|
-
const edgeId = (0,
|
|
14857
|
+
const edgeId = (0, import_types46.extractedEdgeId)(childId, parentId, import_types46.EdgeType.REFERENCES);
|
|
14126
14858
|
if (graph.hasEdge(edgeId)) continue;
|
|
14127
14859
|
const edge = {
|
|
14128
14860
|
id: edgeId,
|
|
14129
14861
|
source: childId,
|
|
14130
14862
|
target: parentId,
|
|
14131
|
-
type:
|
|
14132
|
-
provenance:
|
|
14133
|
-
confidence: (0,
|
|
14863
|
+
type: import_types46.EdgeType.REFERENCES,
|
|
14864
|
+
provenance: import_types46.Provenance.EXTRACTED,
|
|
14865
|
+
confidence: (0, import_types46.confidenceForExtracted)("structural"),
|
|
14134
14866
|
evidence: ref.evidence
|
|
14135
14867
|
};
|
|
14136
14868
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -14143,7 +14875,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
14143
14875
|
if (graph.hasNode(id)) return 0;
|
|
14144
14876
|
const node = {
|
|
14145
14877
|
id,
|
|
14146
|
-
type:
|
|
14878
|
+
type: import_types46.NodeType.InfraNode,
|
|
14147
14879
|
name,
|
|
14148
14880
|
provider: "self",
|
|
14149
14881
|
kind: "sql-table"
|
|
@@ -14157,16 +14889,16 @@ init_cjs_shims();
|
|
|
14157
14889
|
|
|
14158
14890
|
// src/extract/infra/docker-compose.ts
|
|
14159
14891
|
init_cjs_shims();
|
|
14160
|
-
var
|
|
14161
|
-
var
|
|
14892
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14893
|
+
var import_types48 = require("@neat.is/types");
|
|
14162
14894
|
|
|
14163
14895
|
// src/extract/infra/shared.ts
|
|
14164
14896
|
init_cjs_shims();
|
|
14165
|
-
var
|
|
14897
|
+
var import_types47 = require("@neat.is/types");
|
|
14166
14898
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
14167
14899
|
return {
|
|
14168
|
-
id: (0,
|
|
14169
|
-
type:
|
|
14900
|
+
id: (0, import_types47.infraId)(kind, name),
|
|
14901
|
+
type: import_types47.NodeType.InfraNode,
|
|
14170
14902
|
name,
|
|
14171
14903
|
provider,
|
|
14172
14904
|
kind,
|
|
@@ -14210,8 +14942,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
14210
14942
|
source: anchorId,
|
|
14211
14943
|
target: node.id,
|
|
14212
14944
|
type: edgeType,
|
|
14213
|
-
provenance:
|
|
14214
|
-
confidence: (0,
|
|
14945
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
14946
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
14215
14947
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14216
14948
|
};
|
|
14217
14949
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14228,7 +14960,7 @@ function dependsOnList(value) {
|
|
|
14228
14960
|
}
|
|
14229
14961
|
function serviceNameToServiceNode(name, services) {
|
|
14230
14962
|
for (const s of services) {
|
|
14231
|
-
if (s.node.name === name ||
|
|
14963
|
+
if (s.node.name === name || import_node_path59.default.basename(s.dir) === name) return s.node.id;
|
|
14232
14964
|
}
|
|
14233
14965
|
return null;
|
|
14234
14966
|
}
|
|
@@ -14237,7 +14969,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14237
14969
|
let edgesAdded = 0;
|
|
14238
14970
|
let composePath = null;
|
|
14239
14971
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
14240
|
-
const abs =
|
|
14972
|
+
const abs = import_node_path59.default.join(scanPath, name);
|
|
14241
14973
|
if (await exists2(abs)) {
|
|
14242
14974
|
composePath = abs;
|
|
14243
14975
|
break;
|
|
@@ -14250,13 +14982,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14250
14982
|
} catch (err) {
|
|
14251
14983
|
recordExtractionError(
|
|
14252
14984
|
"infra docker-compose",
|
|
14253
|
-
|
|
14985
|
+
import_node_path59.default.relative(scanPath, composePath),
|
|
14254
14986
|
err
|
|
14255
14987
|
);
|
|
14256
14988
|
return { nodesAdded, edgesAdded };
|
|
14257
14989
|
}
|
|
14258
14990
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
14259
|
-
const evidenceFile =
|
|
14991
|
+
const evidenceFile = import_node_path59.default.relative(scanPath, composePath).split(import_node_path59.default.sep).join("/");
|
|
14260
14992
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
14261
14993
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
14262
14994
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -14278,15 +15010,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14278
15010
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
14279
15011
|
const targetId = composeNameToNodeId.get(dep);
|
|
14280
15012
|
if (!targetId) continue;
|
|
14281
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
15013
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types48.EdgeType.DEPENDS_ON);
|
|
14282
15014
|
if (graph.hasEdge(edgeId)) continue;
|
|
14283
15015
|
const edge = {
|
|
14284
15016
|
id: edgeId,
|
|
14285
15017
|
source: sourceId,
|
|
14286
15018
|
target: targetId,
|
|
14287
|
-
type:
|
|
14288
|
-
provenance:
|
|
14289
|
-
confidence: (0,
|
|
15019
|
+
type: import_types48.EdgeType.DEPENDS_ON,
|
|
15020
|
+
provenance: import_types48.Provenance.EXTRACTED,
|
|
15021
|
+
confidence: (0, import_types48.confidenceForExtracted)("structural"),
|
|
14290
15022
|
evidence: { file: evidenceFile }
|
|
14291
15023
|
};
|
|
14292
15024
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14298,9 +15030,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14298
15030
|
|
|
14299
15031
|
// src/extract/infra/dockerfile.ts
|
|
14300
15032
|
init_cjs_shims();
|
|
14301
|
-
var
|
|
14302
|
-
var
|
|
14303
|
-
var
|
|
15033
|
+
var import_node_path60 = __toESM(require("path"), 1);
|
|
15034
|
+
var import_node_fs27 = require("fs");
|
|
15035
|
+
var import_types49 = require("@neat.is/types");
|
|
14304
15036
|
function readDockerfile(content) {
|
|
14305
15037
|
let image = null;
|
|
14306
15038
|
const ports = [];
|
|
@@ -14329,15 +15061,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14329
15061
|
let nodesAdded = 0;
|
|
14330
15062
|
let edgesAdded = 0;
|
|
14331
15063
|
for (const service of services) {
|
|
14332
|
-
const dockerfilePath =
|
|
15064
|
+
const dockerfilePath = import_node_path60.default.join(service.dir, "Dockerfile");
|
|
14333
15065
|
if (!await exists2(dockerfilePath)) continue;
|
|
14334
15066
|
let content;
|
|
14335
15067
|
try {
|
|
14336
|
-
content = await
|
|
15068
|
+
content = await import_node_fs27.promises.readFile(dockerfilePath, "utf8");
|
|
14337
15069
|
} catch (err) {
|
|
14338
15070
|
recordExtractionError(
|
|
14339
15071
|
"infra dockerfile",
|
|
14340
|
-
|
|
15072
|
+
import_node_path60.default.relative(scanPath, dockerfilePath),
|
|
14341
15073
|
err
|
|
14342
15074
|
);
|
|
14343
15075
|
continue;
|
|
@@ -14349,8 +15081,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14349
15081
|
graph.addNode(node.id, node);
|
|
14350
15082
|
nodesAdded++;
|
|
14351
15083
|
}
|
|
14352
|
-
const relDockerfile = toPosix(
|
|
14353
|
-
const evidenceFile = toPosix(
|
|
15084
|
+
const relDockerfile = toPosix(import_node_path60.default.relative(service.dir, dockerfilePath));
|
|
15085
|
+
const evidenceFile = toPosix(import_node_path60.default.relative(scanPath, dockerfilePath));
|
|
14354
15086
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14355
15087
|
graph,
|
|
14356
15088
|
service.pkg.name,
|
|
@@ -14359,15 +15091,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14359
15091
|
);
|
|
14360
15092
|
nodesAdded += fn;
|
|
14361
15093
|
edgesAdded += fe;
|
|
14362
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
15094
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types49.EdgeType.RUNS_ON);
|
|
14363
15095
|
if (!graph.hasEdge(edgeId)) {
|
|
14364
15096
|
const edge = {
|
|
14365
15097
|
id: edgeId,
|
|
14366
15098
|
source: fileNodeId,
|
|
14367
15099
|
target: node.id,
|
|
14368
|
-
type:
|
|
14369
|
-
provenance:
|
|
14370
|
-
confidence: (0,
|
|
15100
|
+
type: import_types49.EdgeType.RUNS_ON,
|
|
15101
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15102
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14371
15103
|
evidence: {
|
|
14372
15104
|
file: evidenceFile,
|
|
14373
15105
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -14382,15 +15114,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14382
15114
|
graph.addNode(portNode.id, portNode);
|
|
14383
15115
|
nodesAdded++;
|
|
14384
15116
|
}
|
|
14385
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
15117
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types49.EdgeType.CONNECTS_TO);
|
|
14386
15118
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
14387
15119
|
const portEdge = {
|
|
14388
15120
|
id: portEdgeId,
|
|
14389
15121
|
source: fileNodeId,
|
|
14390
15122
|
target: portNode.id,
|
|
14391
|
-
type:
|
|
14392
|
-
provenance:
|
|
14393
|
-
confidence: (0,
|
|
15123
|
+
type: import_types49.EdgeType.CONNECTS_TO,
|
|
15124
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15125
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14394
15126
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
14395
15127
|
};
|
|
14396
15128
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -14402,23 +15134,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14402
15134
|
|
|
14403
15135
|
// src/extract/infra/terraform.ts
|
|
14404
15136
|
init_cjs_shims();
|
|
14405
|
-
var
|
|
14406
|
-
var
|
|
14407
|
-
var
|
|
15137
|
+
var import_node_fs28 = require("fs");
|
|
15138
|
+
var import_node_path61 = __toESM(require("path"), 1);
|
|
15139
|
+
var import_types50 = require("@neat.is/types");
|
|
14408
15140
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
14409
15141
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
14410
15142
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
14411
15143
|
if (depth > max) return [];
|
|
14412
15144
|
const out = [];
|
|
14413
|
-
const entries = await
|
|
15145
|
+
const entries = await import_node_fs28.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
14414
15146
|
for (const entry of entries) {
|
|
14415
15147
|
if (entry.isDirectory()) {
|
|
14416
15148
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
14417
|
-
const child =
|
|
15149
|
+
const child = import_node_path61.default.join(start, entry.name);
|
|
14418
15150
|
if (await isPythonVenvDir(child)) continue;
|
|
14419
15151
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
14420
15152
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
14421
|
-
out.push(
|
|
15153
|
+
out.push(import_node_path61.default.join(start, entry.name));
|
|
14422
15154
|
}
|
|
14423
15155
|
}
|
|
14424
15156
|
return out;
|
|
@@ -14449,8 +15181,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14449
15181
|
let edgesAdded = 0;
|
|
14450
15182
|
const files = await walkTfFiles(scanPath);
|
|
14451
15183
|
for (const file of files) {
|
|
14452
|
-
const content = await
|
|
14453
|
-
const evidenceFile = toPosix(
|
|
15184
|
+
const content = await import_node_fs28.promises.readFile(file, "utf8");
|
|
15185
|
+
const evidenceFile = toPosix(import_node_path61.default.relative(scanPath, file));
|
|
14454
15186
|
const resources = [];
|
|
14455
15187
|
const byKey = /* @__PURE__ */ new Map();
|
|
14456
15188
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -14485,16 +15217,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14485
15217
|
if (!target) continue;
|
|
14486
15218
|
if (seen.has(target.nodeId)) continue;
|
|
14487
15219
|
seen.add(target.nodeId);
|
|
14488
|
-
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
15220
|
+
const edgeId = (0, import_types3.extractedEdgeId)(resource.nodeId, target.nodeId, import_types50.EdgeType.DEPENDS_ON);
|
|
14489
15221
|
if (graph.hasEdge(edgeId)) continue;
|
|
14490
15222
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
14491
15223
|
const edge = {
|
|
14492
15224
|
id: edgeId,
|
|
14493
15225
|
source: resource.nodeId,
|
|
14494
15226
|
target: target.nodeId,
|
|
14495
|
-
type:
|
|
14496
|
-
provenance:
|
|
14497
|
-
confidence: (0,
|
|
15227
|
+
type: import_types50.EdgeType.DEPENDS_ON,
|
|
15228
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
15229
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
14498
15230
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
14499
15231
|
};
|
|
14500
15232
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14507,8 +15239,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14507
15239
|
|
|
14508
15240
|
// src/extract/infra/k8s.ts
|
|
14509
15241
|
init_cjs_shims();
|
|
14510
|
-
var
|
|
14511
|
-
var
|
|
15242
|
+
var import_node_fs29 = require("fs");
|
|
15243
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
14512
15244
|
var import_yaml3 = require("yaml");
|
|
14513
15245
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
14514
15246
|
Service: "k8s-service",
|
|
@@ -14522,15 +15254,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
14522
15254
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
14523
15255
|
if (depth > max) return [];
|
|
14524
15256
|
const out = [];
|
|
14525
|
-
const entries = await
|
|
15257
|
+
const entries = await import_node_fs29.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
14526
15258
|
for (const entry of entries) {
|
|
14527
15259
|
if (entry.isDirectory()) {
|
|
14528
15260
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
14529
|
-
const child =
|
|
15261
|
+
const child = import_node_path62.default.join(start, entry.name);
|
|
14530
15262
|
if (await isPythonVenvDir(child)) continue;
|
|
14531
15263
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
14532
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
14533
|
-
out.push(
|
|
15264
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path62.default.extname(entry.name))) {
|
|
15265
|
+
out.push(import_node_path62.default.join(start, entry.name));
|
|
14534
15266
|
}
|
|
14535
15267
|
}
|
|
14536
15268
|
return out;
|
|
@@ -14539,7 +15271,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14539
15271
|
let nodesAdded = 0;
|
|
14540
15272
|
const files = await walkYamlFiles2(scanPath);
|
|
14541
15273
|
for (const file of files) {
|
|
14542
|
-
const content = await
|
|
15274
|
+
const content = await import_node_fs29.promises.readFile(file, "utf8");
|
|
14543
15275
|
let docs;
|
|
14544
15276
|
try {
|
|
14545
15277
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -14563,16 +15295,16 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14563
15295
|
|
|
14564
15296
|
// src/extract/infra/cloudflare.ts
|
|
14565
15297
|
init_cjs_shims();
|
|
14566
|
-
var
|
|
14567
|
-
var
|
|
15298
|
+
var import_node_fs30 = require("fs");
|
|
15299
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
14568
15300
|
var import_smol_toml3 = require("smol-toml");
|
|
14569
|
-
var
|
|
15301
|
+
var import_types51 = require("@neat.is/types");
|
|
14570
15302
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
14571
15303
|
async function readWranglerConfig(dir) {
|
|
14572
15304
|
for (const filename of WRANGLER_FILENAMES) {
|
|
14573
|
-
const abs =
|
|
15305
|
+
const abs = import_node_path63.default.join(dir, filename);
|
|
14574
15306
|
if (!await exists2(abs)) continue;
|
|
14575
|
-
const raw = await
|
|
15307
|
+
const raw = await import_node_fs30.promises.readFile(abs, "utf8");
|
|
14576
15308
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14577
15309
|
return { config, relFile: filename, raw };
|
|
14578
15310
|
}
|
|
@@ -14614,8 +15346,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
14614
15346
|
source: anchorId,
|
|
14615
15347
|
target: node.id,
|
|
14616
15348
|
type: edgeType,
|
|
14617
|
-
provenance:
|
|
14618
|
-
confidence: (0,
|
|
15349
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15350
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14619
15351
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14620
15352
|
};
|
|
14621
15353
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14633,11 +15365,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14633
15365
|
try {
|
|
14634
15366
|
read = await readWranglerConfig(service.dir);
|
|
14635
15367
|
} catch (err) {
|
|
14636
|
-
recordExtractionError("infra cloudflare",
|
|
15368
|
+
recordExtractionError("infra cloudflare", import_node_path63.default.relative(scanPath, service.dir), err);
|
|
14637
15369
|
continue;
|
|
14638
15370
|
}
|
|
14639
15371
|
if (!read || !read.config.name) continue;
|
|
14640
|
-
const evidenceFile = toPosix(
|
|
15372
|
+
const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, import_node_path63.default.join(service.dir, read.relFile)));
|
|
14641
15373
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
14642
15374
|
}
|
|
14643
15375
|
for (const worker of discovered) {
|
|
@@ -14649,7 +15381,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14649
15381
|
}
|
|
14650
15382
|
let anchorId = service.node.id;
|
|
14651
15383
|
if (config.main) {
|
|
14652
|
-
const entryRelPath = toPosix(
|
|
15384
|
+
const entryRelPath = toPosix(import_node_path63.default.normalize(config.main));
|
|
14653
15385
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14654
15386
|
graph,
|
|
14655
15387
|
service.pkg.name,
|
|
@@ -14676,15 +15408,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14676
15408
|
nodesAdded++;
|
|
14677
15409
|
}
|
|
14678
15410
|
if (runtimeNode.id !== anchorId) {
|
|
14679
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
15411
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types51.EdgeType.RUNS_ON);
|
|
14680
15412
|
if (!graph.hasEdge(runsOnId)) {
|
|
14681
15413
|
const edge = {
|
|
14682
15414
|
id: runsOnId,
|
|
14683
15415
|
source: anchorId,
|
|
14684
15416
|
target: runtimeNode.id,
|
|
14685
|
-
type:
|
|
14686
|
-
provenance:
|
|
14687
|
-
confidence: (0,
|
|
15417
|
+
type: import_types51.EdgeType.RUNS_ON,
|
|
15418
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15419
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14688
15420
|
evidence: {
|
|
14689
15421
|
file: evidenceFile,
|
|
14690
15422
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -14698,7 +15430,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14698
15430
|
const result = addResourceEdge(
|
|
14699
15431
|
graph,
|
|
14700
15432
|
anchorId,
|
|
14701
|
-
|
|
15433
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
14702
15434
|
"cloudflare-route",
|
|
14703
15435
|
route,
|
|
14704
15436
|
evidenceFile,
|
|
@@ -14722,7 +15454,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14722
15454
|
const result = addResourceEdge(
|
|
14723
15455
|
graph,
|
|
14724
15456
|
anchorId,
|
|
14725
|
-
|
|
15457
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14726
15458
|
group.kind,
|
|
14727
15459
|
name,
|
|
14728
15460
|
evidenceFile,
|
|
@@ -14736,7 +15468,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14736
15468
|
const result = addResourceEdge(
|
|
14737
15469
|
graph,
|
|
14738
15470
|
anchorId,
|
|
14739
|
-
|
|
15471
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14740
15472
|
"cloudflare-cron",
|
|
14741
15473
|
cron,
|
|
14742
15474
|
evidenceFile,
|
|
@@ -14749,7 +15481,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14749
15481
|
const result = addResourceEdge(
|
|
14750
15482
|
graph,
|
|
14751
15483
|
anchorId,
|
|
14752
|
-
|
|
15484
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14753
15485
|
"cloudflare-env-var",
|
|
14754
15486
|
varName,
|
|
14755
15487
|
evidenceFile,
|
|
@@ -14762,15 +15494,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14762
15494
|
if (!svc.service) continue;
|
|
14763
15495
|
const target = workerIndex.get(svc.service);
|
|
14764
15496
|
if (target && target.anchorId !== anchorId) {
|
|
14765
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
15497
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types51.EdgeType.CALLS);
|
|
14766
15498
|
if (!graph.hasEdge(edgeId)) {
|
|
14767
15499
|
const edge = {
|
|
14768
15500
|
id: edgeId,
|
|
14769
15501
|
source: anchorId,
|
|
14770
15502
|
target: target.anchorId,
|
|
14771
|
-
type:
|
|
14772
|
-
provenance:
|
|
14773
|
-
confidence: (0,
|
|
15503
|
+
type: import_types51.EdgeType.CALLS,
|
|
15504
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15505
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14774
15506
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
14775
15507
|
};
|
|
14776
15508
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14781,7 +15513,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14781
15513
|
const result = addResourceEdge(
|
|
14782
15514
|
graph,
|
|
14783
15515
|
anchorId,
|
|
14784
|
-
|
|
15516
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14785
15517
|
"cloudflare-service-binding",
|
|
14786
15518
|
svc.service,
|
|
14787
15519
|
evidenceFile,
|
|
@@ -14796,24 +15528,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14796
15528
|
|
|
14797
15529
|
// src/extract/infra/vercel.ts
|
|
14798
15530
|
init_cjs_shims();
|
|
14799
|
-
var
|
|
14800
|
-
var
|
|
14801
|
-
var
|
|
15531
|
+
var import_node_fs31 = require("fs");
|
|
15532
|
+
var import_node_path64 = __toESM(require("path"), 1);
|
|
15533
|
+
var import_types52 = require("@neat.is/types");
|
|
14802
15534
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
14803
15535
|
async function readVercelConfig(dir) {
|
|
14804
15536
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
14805
|
-
const abs =
|
|
15537
|
+
const abs = import_node_path64.default.join(dir, filename);
|
|
14806
15538
|
if (!await exists2(abs)) continue;
|
|
14807
|
-
const raw = await
|
|
15539
|
+
const raw = await import_node_fs31.promises.readFile(abs, "utf8");
|
|
14808
15540
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
14809
15541
|
return { config, relFile: filename, raw };
|
|
14810
15542
|
}
|
|
14811
15543
|
return null;
|
|
14812
15544
|
}
|
|
14813
15545
|
async function readLinkedProjectName(dir) {
|
|
14814
|
-
const abs =
|
|
15546
|
+
const abs = import_node_path64.default.join(dir, ".vercel", "project.json");
|
|
14815
15547
|
if (!await exists2(abs)) return void 0;
|
|
14816
|
-
const parsed = JSON.parse(await
|
|
15548
|
+
const parsed = JSON.parse(await import_node_fs31.promises.readFile(abs, "utf8"));
|
|
14817
15549
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
14818
15550
|
}
|
|
14819
15551
|
function routeSource(route) {
|
|
@@ -14829,7 +15561,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14829
15561
|
read = await readVercelConfig(service.dir);
|
|
14830
15562
|
projectName = await readLinkedProjectName(service.dir);
|
|
14831
15563
|
} catch (err) {
|
|
14832
|
-
recordExtractionError("infra vercel",
|
|
15564
|
+
recordExtractionError("infra vercel", import_node_path64.default.relative(scanPath, service.dir), err);
|
|
14833
15565
|
continue;
|
|
14834
15566
|
}
|
|
14835
15567
|
if (!read && !projectName) continue;
|
|
@@ -14845,7 +15577,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14845
15577
|
const anchorId = service.node.id;
|
|
14846
15578
|
if (!read) continue;
|
|
14847
15579
|
const { config, relFile, raw } = read;
|
|
14848
|
-
const evidenceFile = toPosix(
|
|
15580
|
+
const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, import_node_path64.default.join(service.dir, relFile)));
|
|
14849
15581
|
const add = (edgeType, kind, name) => {
|
|
14850
15582
|
if (!name) return;
|
|
14851
15583
|
const result = emitPlatformResourceEdge(
|
|
@@ -14861,12 +15593,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14861
15593
|
nodesAdded += result.nodesAdded;
|
|
14862
15594
|
edgesAdded += result.edgesAdded;
|
|
14863
15595
|
};
|
|
14864
|
-
add(
|
|
14865
|
-
for (const cron of config.crons ?? []) add(
|
|
14866
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
14867
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
15596
|
+
add(import_types52.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
15597
|
+
for (const cron of config.crons ?? []) add(import_types52.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
15598
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types52.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
15599
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types52.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
14868
15600
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
14869
|
-
add(
|
|
15601
|
+
add(import_types52.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
14870
15602
|
}
|
|
14871
15603
|
}
|
|
14872
15604
|
return { nodesAdded, edgesAdded };
|
|
@@ -14874,16 +15606,16 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14874
15606
|
|
|
14875
15607
|
// src/extract/infra/railway.ts
|
|
14876
15608
|
init_cjs_shims();
|
|
14877
|
-
var
|
|
14878
|
-
var
|
|
15609
|
+
var import_node_fs32 = require("fs");
|
|
15610
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
14879
15611
|
var import_smol_toml4 = require("smol-toml");
|
|
14880
|
-
var
|
|
15612
|
+
var import_types53 = require("@neat.is/types");
|
|
14881
15613
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
14882
15614
|
async function readRailwayConfig(dir) {
|
|
14883
15615
|
for (const filename of RAILWAY_FILENAMES) {
|
|
14884
|
-
const abs =
|
|
15616
|
+
const abs = import_node_path65.default.join(dir, filename);
|
|
14885
15617
|
if (!await exists2(abs)) continue;
|
|
14886
|
-
const raw = await
|
|
15618
|
+
const raw = await import_node_fs32.promises.readFile(abs, "utf8");
|
|
14887
15619
|
const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14888
15620
|
return { config, relFile: filename, raw };
|
|
14889
15621
|
}
|
|
@@ -14897,7 +15629,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14897
15629
|
try {
|
|
14898
15630
|
read = await readRailwayConfig(service.dir);
|
|
14899
15631
|
} catch (err) {
|
|
14900
|
-
recordExtractionError("infra railway",
|
|
15632
|
+
recordExtractionError("infra railway", import_node_path65.default.relative(scanPath, service.dir), err);
|
|
14901
15633
|
continue;
|
|
14902
15634
|
}
|
|
14903
15635
|
if (!read) continue;
|
|
@@ -14907,7 +15639,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14907
15639
|
}
|
|
14908
15640
|
const anchorId = service.node.id;
|
|
14909
15641
|
const { config, relFile, raw } = read;
|
|
14910
|
-
const evidenceFile = toPosix(
|
|
15642
|
+
const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, relFile)));
|
|
14911
15643
|
const add = (edgeType, kind, name) => {
|
|
14912
15644
|
if (!name) return;
|
|
14913
15645
|
const result = emitPlatformResourceEdge(
|
|
@@ -14923,24 +15655,24 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14923
15655
|
nodesAdded += result.nodesAdded;
|
|
14924
15656
|
edgesAdded += result.edgesAdded;
|
|
14925
15657
|
};
|
|
14926
|
-
add(
|
|
14927
|
-
add(
|
|
14928
|
-
add(
|
|
15658
|
+
add(import_types53.EdgeType.RUNS_ON, "railway", "railway");
|
|
15659
|
+
add(import_types53.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
15660
|
+
add(import_types53.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
14929
15661
|
}
|
|
14930
15662
|
return { nodesAdded, edgesAdded };
|
|
14931
15663
|
}
|
|
14932
15664
|
|
|
14933
15665
|
// src/extract/infra/supabase.ts
|
|
14934
15666
|
init_cjs_shims();
|
|
14935
|
-
var
|
|
14936
|
-
var
|
|
15667
|
+
var import_node_fs33 = require("fs");
|
|
15668
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
14937
15669
|
var import_smol_toml5 = require("smol-toml");
|
|
14938
|
-
var
|
|
15670
|
+
var import_types54 = require("@neat.is/types");
|
|
14939
15671
|
async function readSupabaseConfig(dir) {
|
|
14940
|
-
const relFile =
|
|
14941
|
-
const abs =
|
|
15672
|
+
const relFile = import_node_path66.default.join("supabase", "config.toml");
|
|
15673
|
+
const abs = import_node_path66.default.join(dir, relFile);
|
|
14942
15674
|
if (!await exists2(abs)) return null;
|
|
14943
|
-
const raw = await
|
|
15675
|
+
const raw = await import_node_fs33.promises.readFile(abs, "utf8");
|
|
14944
15676
|
const config = (0, import_smol_toml5.parse)(raw);
|
|
14945
15677
|
return { config, relFile, raw };
|
|
14946
15678
|
}
|
|
@@ -14952,7 +15684,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14952
15684
|
try {
|
|
14953
15685
|
read = await readSupabaseConfig(service.dir);
|
|
14954
15686
|
} catch (err) {
|
|
14955
|
-
recordExtractionError("infra supabase",
|
|
15687
|
+
recordExtractionError("infra supabase", import_node_path66.default.relative(scanPath, service.dir), err);
|
|
14956
15688
|
continue;
|
|
14957
15689
|
}
|
|
14958
15690
|
if (!read) continue;
|
|
@@ -14967,7 +15699,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14967
15699
|
});
|
|
14968
15700
|
}
|
|
14969
15701
|
const anchorId = service.node.id;
|
|
14970
|
-
const evidenceFile = toPosix(
|
|
15702
|
+
const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, relFile)));
|
|
14971
15703
|
const add = (edgeType, kind, name) => {
|
|
14972
15704
|
if (!name) return;
|
|
14973
15705
|
const result = emitPlatformResourceEdge(
|
|
@@ -14983,10 +15715,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14983
15715
|
nodesAdded += result.nodesAdded;
|
|
14984
15716
|
edgesAdded += result.edgesAdded;
|
|
14985
15717
|
};
|
|
14986
|
-
add(
|
|
14987
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
14988
|
-
if (config.storage) add(
|
|
14989
|
-
if (config.auth) add(
|
|
15718
|
+
add(import_types54.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
15719
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types54.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
15720
|
+
if (config.storage) add(import_types54.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
15721
|
+
if (config.auth) add(import_types54.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
14990
15722
|
}
|
|
14991
15723
|
return { nodesAdded, edgesAdded };
|
|
14992
15724
|
}
|
|
@@ -15009,14 +15741,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
15009
15741
|
|
|
15010
15742
|
// src/extract/zod-shapes.ts
|
|
15011
15743
|
init_cjs_shims();
|
|
15012
|
-
var
|
|
15013
|
-
var
|
|
15744
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
15745
|
+
var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
|
|
15014
15746
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
15015
|
-
var
|
|
15747
|
+
var import_types55 = require("@neat.is/types");
|
|
15016
15748
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
15017
15749
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
15018
15750
|
function parserForExt4(ext) {
|
|
15019
|
-
const p = new
|
|
15751
|
+
const p = new import_tree_sitter17.default();
|
|
15020
15752
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
15021
15753
|
return p;
|
|
15022
15754
|
}
|
|
@@ -15104,7 +15836,7 @@ function topLevelSchemas(root) {
|
|
|
15104
15836
|
}
|
|
15105
15837
|
function zodShapesFromFile(file, serviceDir) {
|
|
15106
15838
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
15107
|
-
const tree = parseSource3(parserForExt4(
|
|
15839
|
+
const tree = parseSource3(parserForExt4(import_node_path67.default.extname(file.path)), file.content);
|
|
15108
15840
|
const out = [];
|
|
15109
15841
|
const seen = /* @__PURE__ */ new Set();
|
|
15110
15842
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -15118,11 +15850,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
15118
15850
|
seen.add(name);
|
|
15119
15851
|
const line = call.startPosition.row + 1;
|
|
15120
15852
|
out.push({
|
|
15121
|
-
infraId: (0,
|
|
15853
|
+
infraId: (0, import_types55.infraId)("zod-schema", name),
|
|
15122
15854
|
name,
|
|
15123
15855
|
fields,
|
|
15124
15856
|
evidence: {
|
|
15125
|
-
file:
|
|
15857
|
+
file: import_node_path67.default.relative(serviceDir, file.path),
|
|
15126
15858
|
line,
|
|
15127
15859
|
snippet: snippet(file.content, line)
|
|
15128
15860
|
}
|
|
@@ -15153,7 +15885,7 @@ async function addZodShapes(graph, services) {
|
|
|
15153
15885
|
if (!graph.hasNode(shape.infraId)) {
|
|
15154
15886
|
const node = {
|
|
15155
15887
|
id: shape.infraId,
|
|
15156
|
-
type:
|
|
15888
|
+
type: import_types55.NodeType.InfraNode,
|
|
15157
15889
|
name: shape.name,
|
|
15158
15890
|
provider: "self",
|
|
15159
15891
|
kind: "zod-schema"
|
|
@@ -15163,14 +15895,14 @@ async function addZodShapes(graph, services) {
|
|
|
15163
15895
|
}
|
|
15164
15896
|
if (shape.fields.length > 0) {
|
|
15165
15897
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
15166
|
-
if (node.type ===
|
|
15898
|
+
if (node.type === import_types55.NodeType.InfraNode) {
|
|
15167
15899
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
15168
15900
|
...node,
|
|
15169
15901
|
columns: foldColumns(
|
|
15170
15902
|
node.columns,
|
|
15171
15903
|
shape.fields,
|
|
15172
|
-
|
|
15173
|
-
(0,
|
|
15904
|
+
import_types55.Provenance.EXTRACTED,
|
|
15905
|
+
(0, import_types55.confidenceForExtracted)("structural")
|
|
15174
15906
|
)
|
|
15175
15907
|
});
|
|
15176
15908
|
}
|
|
@@ -15184,15 +15916,15 @@ async function addZodShapes(graph, services) {
|
|
|
15184
15916
|
);
|
|
15185
15917
|
nodesAdded += n;
|
|
15186
15918
|
edgesAdded += e;
|
|
15187
|
-
const edgeId = (0,
|
|
15919
|
+
const edgeId = (0, import_types55.extractedEdgeId)(fileNodeId, shape.infraId, import_types55.EdgeType.CONTAINS);
|
|
15188
15920
|
if (!graph.hasEdge(edgeId)) {
|
|
15189
15921
|
const edge = {
|
|
15190
15922
|
id: edgeId,
|
|
15191
15923
|
source: fileNodeId,
|
|
15192
15924
|
target: shape.infraId,
|
|
15193
|
-
type:
|
|
15194
|
-
provenance:
|
|
15195
|
-
confidence: (0,
|
|
15925
|
+
type: import_types55.EdgeType.CONTAINS,
|
|
15926
|
+
provenance: import_types55.Provenance.EXTRACTED,
|
|
15927
|
+
confidence: (0, import_types55.confidenceForExtracted)("structural"),
|
|
15196
15928
|
evidence: shape.evidence
|
|
15197
15929
|
};
|
|
15198
15930
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -15206,7 +15938,7 @@ async function addZodShapes(graph, services) {
|
|
|
15206
15938
|
|
|
15207
15939
|
// src/extract/firestore-rules.ts
|
|
15208
15940
|
init_cjs_shims();
|
|
15209
|
-
var
|
|
15941
|
+
var import_types56 = require("@neat.is/types");
|
|
15210
15942
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
15211
15943
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
15212
15944
|
function stripComments(src) {
|
|
@@ -15346,7 +16078,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
15346
16078
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
15347
16079
|
graph.forEachNode((id, attrs) => {
|
|
15348
16080
|
const node = attrs;
|
|
15349
|
-
if (node.type !==
|
|
16081
|
+
if (node.type !== import_types56.NodeType.InfraNode) return;
|
|
15350
16082
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
15351
16083
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
15352
16084
|
if (!fields || fields.size === 0) return;
|
|
@@ -15359,17 +16091,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
15359
16091
|
}
|
|
15360
16092
|
|
|
15361
16093
|
// src/extract/index.ts
|
|
15362
|
-
var
|
|
16094
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
15363
16095
|
|
|
15364
16096
|
// src/extract/retire.ts
|
|
15365
16097
|
init_cjs_shims();
|
|
15366
|
-
var
|
|
15367
|
-
var
|
|
15368
|
-
var
|
|
16098
|
+
var import_node_fs34 = require("fs");
|
|
16099
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
16100
|
+
var import_types57 = require("@neat.is/types");
|
|
15369
16101
|
function dropOrphanedFileNodes(graph) {
|
|
15370
16102
|
const orphans = [];
|
|
15371
16103
|
graph.forEachNode((id, attrs) => {
|
|
15372
|
-
if (attrs.type !==
|
|
16104
|
+
if (attrs.type !== import_types57.NodeType.FileNode) return;
|
|
15373
16105
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
15374
16106
|
orphans.push(id);
|
|
15375
16107
|
}
|
|
@@ -15382,14 +16114,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
15382
16114
|
const bases = [scanPath, ...serviceDirs];
|
|
15383
16115
|
graph.forEachEdge((id, attrs) => {
|
|
15384
16116
|
const edge = attrs;
|
|
15385
|
-
if (edge.provenance !==
|
|
16117
|
+
if (edge.provenance !== import_types57.Provenance.EXTRACTED) return;
|
|
15386
16118
|
const evidenceFile = edge.evidence?.file;
|
|
15387
16119
|
if (!evidenceFile) return;
|
|
15388
|
-
if (
|
|
15389
|
-
if (!(0,
|
|
16120
|
+
if (import_node_path68.default.isAbsolute(evidenceFile)) {
|
|
16121
|
+
if (!(0, import_node_fs34.existsSync)(evidenceFile)) toDrop.push(id);
|
|
15390
16122
|
return;
|
|
15391
16123
|
}
|
|
15392
|
-
const found = bases.some((base) => (0,
|
|
16124
|
+
const found = bases.some((base) => (0, import_node_fs34.existsSync)(import_node_path68.default.join(base, evidenceFile)));
|
|
15393
16125
|
if (!found) toDrop.push(id);
|
|
15394
16126
|
});
|
|
15395
16127
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -15446,7 +16178,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15446
16178
|
}
|
|
15447
16179
|
const droppedEntries = drainDroppedExtracted();
|
|
15448
16180
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
15449
|
-
const rejectedPath =
|
|
16181
|
+
const rejectedPath = import_node_path69.default.join(import_node_path69.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
15450
16182
|
try {
|
|
15451
16183
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
15452
16184
|
} catch (err) {
|
|
@@ -15480,7 +16212,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15480
16212
|
|
|
15481
16213
|
// src/diff.ts
|
|
15482
16214
|
init_cjs_shims();
|
|
15483
|
-
var
|
|
16215
|
+
var import_node_fs35 = require("fs");
|
|
15484
16216
|
async function loadSnapshotForDiff(target) {
|
|
15485
16217
|
if (/^https?:\/\//i.test(target)) {
|
|
15486
16218
|
const res = await fetch(target);
|
|
@@ -15489,7 +16221,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
15489
16221
|
}
|
|
15490
16222
|
return await res.json();
|
|
15491
16223
|
}
|
|
15492
|
-
const raw = await
|
|
16224
|
+
const raw = await import_node_fs35.promises.readFile(target, "utf8");
|
|
15493
16225
|
return JSON.parse(raw);
|
|
15494
16226
|
}
|
|
15495
16227
|
function indexEntries(entries) {
|
|
@@ -15557,9 +16289,9 @@ function canonicalJson(value) {
|
|
|
15557
16289
|
|
|
15558
16290
|
// src/persist.ts
|
|
15559
16291
|
init_cjs_shims();
|
|
15560
|
-
var
|
|
15561
|
-
var
|
|
15562
|
-
var
|
|
16292
|
+
var import_node_fs36 = require("fs");
|
|
16293
|
+
var import_node_path70 = __toESM(require("path"), 1);
|
|
16294
|
+
var import_types58 = require("@neat.is/types");
|
|
15563
16295
|
var SCHEMA_VERSION = 7;
|
|
15564
16296
|
function migrateV1ToV2(payload) {
|
|
15565
16297
|
const nodes = payload.graph.nodes;
|
|
@@ -15583,7 +16315,7 @@ function migrateV5ToV6(payload) {
|
|
|
15583
16315
|
if (Array.isArray(nodes)) {
|
|
15584
16316
|
for (const node of nodes) {
|
|
15585
16317
|
const attrs = node.attributes;
|
|
15586
|
-
if (!attrs || attrs.type !==
|
|
16318
|
+
if (!attrs || attrs.type !== import_types58.NodeType.InfraNode) continue;
|
|
15587
16319
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
15588
16320
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
15589
16321
|
}
|
|
@@ -15599,12 +16331,12 @@ function migrateV2ToV3(payload) {
|
|
|
15599
16331
|
for (const edge of edges) {
|
|
15600
16332
|
const attrs = edge.attributes;
|
|
15601
16333
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
15602
|
-
attrs.provenance =
|
|
16334
|
+
attrs.provenance = import_types58.Provenance.OBSERVED;
|
|
15603
16335
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
15604
16336
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
15605
16337
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
15606
16338
|
if (type && source && target) {
|
|
15607
|
-
const newId = (0,
|
|
16339
|
+
const newId = (0, import_types58.observedEdgeId)(source, target, type);
|
|
15608
16340
|
attrs.id = newId;
|
|
15609
16341
|
if (edge.key) edge.key = newId;
|
|
15610
16342
|
}
|
|
@@ -15613,7 +16345,7 @@ function migrateV2ToV3(payload) {
|
|
|
15613
16345
|
return { ...payload, schemaVersion: 3 };
|
|
15614
16346
|
}
|
|
15615
16347
|
async function ensureDir(filePath) {
|
|
15616
|
-
await
|
|
16348
|
+
await import_node_fs36.promises.mkdir(import_node_path70.default.dirname(filePath), { recursive: true });
|
|
15617
16349
|
}
|
|
15618
16350
|
async function saveGraphToDisk(graph, outPath) {
|
|
15619
16351
|
await ensureDir(outPath);
|
|
@@ -15623,13 +16355,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
15623
16355
|
graph: graph.export()
|
|
15624
16356
|
};
|
|
15625
16357
|
const tmp = `${outPath}.tmp`;
|
|
15626
|
-
await
|
|
15627
|
-
await
|
|
16358
|
+
await import_node_fs36.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
16359
|
+
await import_node_fs36.promises.rename(tmp, outPath);
|
|
15628
16360
|
}
|
|
15629
16361
|
async function loadGraphFromDisk(graph, outPath) {
|
|
15630
16362
|
let raw;
|
|
15631
16363
|
try {
|
|
15632
|
-
raw = await
|
|
16364
|
+
raw = await import_node_fs36.promises.readFile(outPath, "utf8");
|
|
15633
16365
|
} catch (err) {
|
|
15634
16366
|
if (err.code === "ENOENT") return;
|
|
15635
16367
|
throw err;
|
|
@@ -15703,23 +16435,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
15703
16435
|
|
|
15704
16436
|
// src/projects.ts
|
|
15705
16437
|
init_cjs_shims();
|
|
15706
|
-
var
|
|
16438
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
15707
16439
|
function pathsForProject(project, baseDir) {
|
|
15708
16440
|
if (project === DEFAULT_PROJECT) {
|
|
15709
16441
|
return {
|
|
15710
|
-
snapshotPath:
|
|
15711
|
-
errorsPath:
|
|
15712
|
-
staleEventsPath:
|
|
15713
|
-
embeddingsCachePath:
|
|
15714
|
-
policyViolationsPath:
|
|
16442
|
+
snapshotPath: import_node_path71.default.join(baseDir, "graph.json"),
|
|
16443
|
+
errorsPath: import_node_path71.default.join(baseDir, "errors.ndjson"),
|
|
16444
|
+
staleEventsPath: import_node_path71.default.join(baseDir, "stale-events.ndjson"),
|
|
16445
|
+
embeddingsCachePath: import_node_path71.default.join(baseDir, "embeddings.json"),
|
|
16446
|
+
policyViolationsPath: import_node_path71.default.join(baseDir, "policy-violations.ndjson")
|
|
15715
16447
|
};
|
|
15716
16448
|
}
|
|
15717
16449
|
return {
|
|
15718
|
-
snapshotPath:
|
|
15719
|
-
errorsPath:
|
|
15720
|
-
staleEventsPath:
|
|
15721
|
-
embeddingsCachePath:
|
|
15722
|
-
policyViolationsPath:
|
|
16450
|
+
snapshotPath: import_node_path71.default.join(baseDir, `${project}.json`),
|
|
16451
|
+
errorsPath: import_node_path71.default.join(baseDir, `errors.${project}.ndjson`),
|
|
16452
|
+
staleEventsPath: import_node_path71.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
16453
|
+
embeddingsCachePath: import_node_path71.default.join(baseDir, `embeddings.${project}.json`),
|
|
16454
|
+
policyViolationsPath: import_node_path71.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
15723
16455
|
};
|
|
15724
16456
|
}
|
|
15725
16457
|
var Projects = class {
|
|
@@ -15759,20 +16491,20 @@ function parseExtraProjects(raw) {
|
|
|
15759
16491
|
|
|
15760
16492
|
// src/registry.ts
|
|
15761
16493
|
init_cjs_shims();
|
|
15762
|
-
var
|
|
16494
|
+
var import_node_fs37 = require("fs");
|
|
15763
16495
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
15764
|
-
var
|
|
15765
|
-
var
|
|
16496
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
16497
|
+
var import_types59 = require("@neat.is/types");
|
|
15766
16498
|
function neatHome() {
|
|
15767
16499
|
const override = process.env.NEAT_HOME;
|
|
15768
|
-
if (override && override.length > 0) return
|
|
15769
|
-
return
|
|
16500
|
+
if (override && override.length > 0) return import_node_path72.default.resolve(override);
|
|
16501
|
+
return import_node_path72.default.join(import_node_os3.default.homedir(), ".neat");
|
|
15770
16502
|
}
|
|
15771
16503
|
function registryPath() {
|
|
15772
|
-
return
|
|
16504
|
+
return import_node_path72.default.join(neatHome(), "projects.json");
|
|
15773
16505
|
}
|
|
15774
16506
|
function daemonsDir() {
|
|
15775
|
-
return
|
|
16507
|
+
return import_node_path72.default.join(neatHome(), "daemons");
|
|
15776
16508
|
}
|
|
15777
16509
|
function isFiniteInt(v) {
|
|
15778
16510
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -15805,7 +16537,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15805
16537
|
const dir = daemonsDir();
|
|
15806
16538
|
let names;
|
|
15807
16539
|
try {
|
|
15808
|
-
names = await
|
|
16540
|
+
names = await import_node_fs37.promises.readdir(dir);
|
|
15809
16541
|
} catch (err) {
|
|
15810
16542
|
if (err.code === "ENOENT") return [];
|
|
15811
16543
|
throw err;
|
|
@@ -15813,10 +16545,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15813
16545
|
const out = [];
|
|
15814
16546
|
for (const name of names) {
|
|
15815
16547
|
if (!name.endsWith(".json")) continue;
|
|
15816
|
-
const file =
|
|
16548
|
+
const file = import_node_path72.default.join(dir, name);
|
|
15817
16549
|
let raw;
|
|
15818
16550
|
try {
|
|
15819
|
-
raw = await
|
|
16551
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15820
16552
|
} catch {
|
|
15821
16553
|
continue;
|
|
15822
16554
|
}
|
|
@@ -15844,7 +16576,7 @@ async function readRegistry() {
|
|
|
15844
16576
|
const file = registryPath();
|
|
15845
16577
|
let raw;
|
|
15846
16578
|
try {
|
|
15847
|
-
raw = await
|
|
16579
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15848
16580
|
} catch (err) {
|
|
15849
16581
|
if (err.code === "ENOENT") {
|
|
15850
16582
|
return { version: 1, projects: [] };
|
|
@@ -15852,7 +16584,7 @@ async function readRegistry() {
|
|
|
15852
16584
|
throw err;
|
|
15853
16585
|
}
|
|
15854
16586
|
const parsed = JSON.parse(raw);
|
|
15855
|
-
return
|
|
16587
|
+
return import_types59.RegistryFileSchema.parse(parsed);
|
|
15856
16588
|
}
|
|
15857
16589
|
async function getProject(name) {
|
|
15858
16590
|
const reg = await readRegistry();
|
|
@@ -15927,8 +16659,8 @@ init_auth();
|
|
|
15927
16659
|
// src/connectors-config.ts
|
|
15928
16660
|
init_cjs_shims();
|
|
15929
16661
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
15930
|
-
var
|
|
15931
|
-
var
|
|
16662
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
16663
|
+
var import_node_fs38 = require("fs");
|
|
15932
16664
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
15933
16665
|
var EnvRefUnsetError = class extends Error {
|
|
15934
16666
|
ref;
|
|
@@ -15942,17 +16674,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
15942
16674
|
};
|
|
15943
16675
|
function neatHome2() {
|
|
15944
16676
|
const override = process.env.NEAT_HOME;
|
|
15945
|
-
if (override && override.length > 0) return
|
|
15946
|
-
return
|
|
16677
|
+
if (override && override.length > 0) return import_node_path73.default.resolve(override);
|
|
16678
|
+
return import_node_path73.default.join(import_node_os4.default.homedir(), ".neat");
|
|
15947
16679
|
}
|
|
15948
16680
|
function connectorsConfigPath(home = neatHome2()) {
|
|
15949
|
-
return
|
|
16681
|
+
return import_node_path73.default.join(home, "connectors.json");
|
|
15950
16682
|
}
|
|
15951
16683
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
15952
16684
|
async function warnIfModeLooserThan0600(file) {
|
|
15953
16685
|
if (process.platform === "win32") return;
|
|
15954
16686
|
try {
|
|
15955
|
-
const stat = await
|
|
16687
|
+
const stat = await import_node_fs38.promises.stat(file);
|
|
15956
16688
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
15957
16689
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
15958
16690
|
console.warn(
|
|
@@ -15966,7 +16698,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
15966
16698
|
const file = connectorsConfigPath(home);
|
|
15967
16699
|
let raw;
|
|
15968
16700
|
try {
|
|
15969
|
-
raw = await
|
|
16701
|
+
raw = await import_node_fs38.promises.readFile(file, "utf8");
|
|
15970
16702
|
} catch (err) {
|
|
15971
16703
|
if (err.code === "ENOENT") {
|
|
15972
16704
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -16133,15 +16865,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
16133
16865
|
|
|
16134
16866
|
// src/connectors/index.ts
|
|
16135
16867
|
init_cjs_shims();
|
|
16136
|
-
var
|
|
16868
|
+
var import_types60 = require("@neat.is/types");
|
|
16137
16869
|
var NO_ENV = "unknown";
|
|
16138
16870
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
16139
16871
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16140
16872
|
const sites = [];
|
|
16141
16873
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
16142
16874
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
16143
|
-
if (edge.provenance !==
|
|
16144
|
-
const parsed = (0,
|
|
16875
|
+
if (edge.provenance !== import_types60.Provenance.EXTRACTED) continue;
|
|
16876
|
+
const parsed = (0, import_types60.parseFileId)(edge.source);
|
|
16145
16877
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
16146
16878
|
const site = { relPath: edge.evidence.file };
|
|
16147
16879
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -16152,7 +16884,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
16152
16884
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
16153
16885
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16154
16886
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
16155
|
-
if (attrs.type !==
|
|
16887
|
+
if (attrs.type !== import_types60.NodeType.RouteNode || !attrs.path) return void 0;
|
|
16156
16888
|
const site = { relPath: attrs.path };
|
|
16157
16889
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
16158
16890
|
return site;
|
|
@@ -16609,10 +17341,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
16609
17341
|
// src/connectors/supabase/map.ts
|
|
16610
17342
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
16611
17343
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
16612
|
-
function targetFromRestPath(
|
|
16613
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
17344
|
+
function targetFromRestPath(path76) {
|
|
17345
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path76);
|
|
16614
17346
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
16615
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
17347
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path76);
|
|
16616
17348
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
16617
17349
|
return null;
|
|
16618
17350
|
}
|
|
@@ -16723,23 +17455,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
16723
17455
|
|
|
16724
17456
|
// src/connectors/supabase/resolve.ts
|
|
16725
17457
|
init_cjs_shims();
|
|
16726
|
-
var
|
|
17458
|
+
var import_types62 = require("@neat.is/types");
|
|
16727
17459
|
function createSupabaseResolveTarget(graph, config) {
|
|
16728
17460
|
return (signal, _ctx) => {
|
|
16729
17461
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
16730
17462
|
return null;
|
|
16731
17463
|
}
|
|
16732
|
-
const subResourceId = (0,
|
|
17464
|
+
const subResourceId = (0, import_types62.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
16733
17465
|
if (graph.hasNode(subResourceId)) {
|
|
16734
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
17466
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16735
17467
|
}
|
|
16736
|
-
const bareResourceId = (0,
|
|
17468
|
+
const bareResourceId = (0, import_types62.infraId)(signal.targetKind, signal.targetName);
|
|
16737
17469
|
if (graph.hasNode(bareResourceId)) {
|
|
16738
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
17470
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16739
17471
|
}
|
|
16740
|
-
const projectLevelId = (0,
|
|
17472
|
+
const projectLevelId = (0, import_types62.infraId)("supabase", config.nodeRef);
|
|
16741
17473
|
if (graph.hasNode(projectLevelId)) {
|
|
16742
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
17474
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16743
17475
|
}
|
|
16744
17476
|
return null;
|
|
16745
17477
|
};
|
|
@@ -16832,7 +17564,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
16832
17564
|
|
|
16833
17565
|
// src/connectors/railway/index.ts
|
|
16834
17566
|
init_cjs_shims();
|
|
16835
|
-
var
|
|
17567
|
+
var import_types66 = require("@neat.is/types");
|
|
16836
17568
|
|
|
16837
17569
|
// src/connectors/railway/client.ts
|
|
16838
17570
|
init_cjs_shims();
|
|
@@ -16983,7 +17715,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
16983
17715
|
const out = [];
|
|
16984
17716
|
graph.forEachNode((_id, attrs) => {
|
|
16985
17717
|
const node = attrs;
|
|
16986
|
-
if (node.type !==
|
|
17718
|
+
if (node.type !== import_types66.NodeType.RouteNode) return;
|
|
16987
17719
|
const route = attrs;
|
|
16988
17720
|
if (route.service !== serviceName) return;
|
|
16989
17721
|
out.push({
|
|
@@ -17087,12 +17819,12 @@ function createRailwayResolveTarget(config) {
|
|
|
17087
17819
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
17088
17820
|
if (!serviceName) return null;
|
|
17089
17821
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
17090
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
17822
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
17091
17823
|
}
|
|
17092
17824
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
17093
17825
|
const peerName = config.serviceNameById[signal.targetName];
|
|
17094
17826
|
if (!peerName) return null;
|
|
17095
|
-
return { targetNodeId: (0,
|
|
17827
|
+
return { targetNodeId: (0, import_types66.serviceId)(peerName), serviceName, edgeType: import_types66.EdgeType.CONNECTS_TO };
|
|
17096
17828
|
}
|
|
17097
17829
|
return null;
|
|
17098
17830
|
};
|
|
@@ -17216,9 +17948,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
17216
17948
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
17217
17949
|
if (secondSep === -1) return null;
|
|
17218
17950
|
const method = rest.slice(0, secondSep);
|
|
17219
|
-
const
|
|
17220
|
-
if (!resourceName || !method || !
|
|
17221
|
-
return { resourceName, method, path:
|
|
17951
|
+
const path76 = rest.slice(secondSep + 1);
|
|
17952
|
+
if (!resourceName || !method || !path76) return null;
|
|
17953
|
+
return { resourceName, method, path: path76 };
|
|
17222
17954
|
}
|
|
17223
17955
|
function resourceNameFor(type, labels) {
|
|
17224
17956
|
if (!labels) return null;
|
|
@@ -17256,14 +17988,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
17256
17988
|
if (!req) return null;
|
|
17257
17989
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
17258
17990
|
const method = req.requestMethod.toUpperCase();
|
|
17259
|
-
const
|
|
17260
|
-
if (
|
|
17991
|
+
const path76 = pathFromRequestUrl(req.requestUrl);
|
|
17992
|
+
if (path76 === null) return null;
|
|
17261
17993
|
const timestamp = entry.timestamp;
|
|
17262
17994
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17263
17995
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
17264
17996
|
return {
|
|
17265
17997
|
targetKind: resourceType,
|
|
17266
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
17998
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path76 }),
|
|
17267
17999
|
callCount: 1,
|
|
17268
18000
|
errorCount: isError ? 1 : 0,
|
|
17269
18001
|
lastObservedIso: timestamp
|
|
@@ -17280,7 +18012,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
17280
18012
|
|
|
17281
18013
|
// src/connectors/firebase/resolve.ts
|
|
17282
18014
|
init_cjs_shims();
|
|
17283
|
-
var
|
|
18015
|
+
var import_types67 = require("@neat.is/types");
|
|
17284
18016
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
17285
18017
|
switch (resourceType) {
|
|
17286
18018
|
case "cloud_function":
|
|
@@ -17295,7 +18027,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
17295
18027
|
const entries = [];
|
|
17296
18028
|
graph.forEachNode((_id, attrs) => {
|
|
17297
18029
|
const node = attrs;
|
|
17298
|
-
if (node.type !==
|
|
18030
|
+
if (node.type !== import_types67.NodeType.RouteNode) return;
|
|
17299
18031
|
const route = attrs;
|
|
17300
18032
|
if (route.service !== serviceName) return;
|
|
17301
18033
|
entries.push({
|
|
@@ -17327,7 +18059,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
17327
18059
|
return {
|
|
17328
18060
|
targetNodeId: match.routeNodeId,
|
|
17329
18061
|
serviceName,
|
|
17330
|
-
edgeType:
|
|
18062
|
+
edgeType: import_types67.EdgeType.CALLS
|
|
17331
18063
|
};
|
|
17332
18064
|
};
|
|
17333
18065
|
}
|
|
@@ -17354,7 +18086,7 @@ init_cjs_shims();
|
|
|
17354
18086
|
|
|
17355
18087
|
// src/connectors/cloudflare/connector.ts
|
|
17356
18088
|
init_cjs_shims();
|
|
17357
|
-
var
|
|
18089
|
+
var import_types69 = require("@neat.is/types");
|
|
17358
18090
|
|
|
17359
18091
|
// src/connectors/cloudflare/client.ts
|
|
17360
18092
|
init_cjs_shims();
|
|
@@ -17470,7 +18202,7 @@ function mapEventToSignal(event) {
|
|
|
17470
18202
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
17471
18203
|
const statusCode = metadata?.statusCode;
|
|
17472
18204
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
17473
|
-
const
|
|
18205
|
+
const path76 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
17474
18206
|
return {
|
|
17475
18207
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
17476
18208
|
targetName: scriptName,
|
|
@@ -17478,7 +18210,7 @@ function mapEventToSignal(event) {
|
|
|
17478
18210
|
errorCount: isError ? 1 : 0,
|
|
17479
18211
|
lastObservedIso: observedAt.toISOString(),
|
|
17480
18212
|
method,
|
|
17481
|
-
...
|
|
18213
|
+
...path76 ? { path: path76 } : {},
|
|
17482
18214
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
17483
18215
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
17484
18216
|
};
|
|
@@ -17518,19 +18250,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
17518
18250
|
graph.forEachNode((id, attrs) => {
|
|
17519
18251
|
if (found) return;
|
|
17520
18252
|
const a = attrs;
|
|
17521
|
-
if (a.type ===
|
|
18253
|
+
if (a.type === import_types69.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
17522
18254
|
found = id;
|
|
17523
18255
|
}
|
|
17524
18256
|
});
|
|
17525
18257
|
return found;
|
|
17526
18258
|
}
|
|
17527
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
17528
|
-
const normalizedPath = normalizePathTemplate(
|
|
18259
|
+
function findMatchingRouteNode(graph, serviceName, method, path76) {
|
|
18260
|
+
const normalizedPath = normalizePathTemplate(path76);
|
|
17529
18261
|
let found = null;
|
|
17530
18262
|
graph.forEachNode((id, attrs) => {
|
|
17531
18263
|
if (found) return;
|
|
17532
18264
|
const a = attrs;
|
|
17533
|
-
if (a.type !==
|
|
18265
|
+
if (a.type !== import_types69.NodeType.RouteNode || a.service !== serviceName) return;
|
|
17534
18266
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
17535
18267
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
17536
18268
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -17542,18 +18274,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17542
18274
|
return (signal) => {
|
|
17543
18275
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
17544
18276
|
const scriptName = signal.targetName;
|
|
17545
|
-
const { method, path:
|
|
18277
|
+
const { method, path: path76 } = signal;
|
|
17546
18278
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
17547
|
-
if (!method || !
|
|
17548
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
18279
|
+
if (!method || !path76) return wholeFileId;
|
|
18280
|
+
return findMatchingRouteNode(graph, serviceName, method, path76) ?? wholeFileId;
|
|
17549
18281
|
};
|
|
17550
18282
|
const mapping = config.workers?.[scriptName];
|
|
17551
18283
|
if (mapping) {
|
|
17552
|
-
const wholeFileId = (0,
|
|
18284
|
+
const wholeFileId = (0, import_types69.fileId)(mapping.service, mapping.entryFile);
|
|
17553
18285
|
return {
|
|
17554
18286
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
17555
18287
|
serviceName: mapping.service,
|
|
17556
|
-
edgeType:
|
|
18288
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17557
18289
|
};
|
|
17558
18290
|
}
|
|
17559
18291
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -17562,13 +18294,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17562
18294
|
return {
|
|
17563
18295
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
17564
18296
|
serviceName: fileNode.service,
|
|
17565
|
-
edgeType:
|
|
18297
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17566
18298
|
};
|
|
17567
18299
|
}
|
|
17568
18300
|
return {
|
|
17569
|
-
targetNodeId: (0,
|
|
18301
|
+
targetNodeId: (0, import_types69.infraId)("cloudflare-worker", scriptName),
|
|
17570
18302
|
serviceName: scriptName,
|
|
17571
|
-
edgeType:
|
|
18303
|
+
edgeType: import_types69.EdgeType.CALLS,
|
|
17572
18304
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
17573
18305
|
};
|
|
17574
18306
|
};
|
|
@@ -17764,14 +18496,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
17764
18496
|
|
|
17765
18497
|
// src/connectors/neon/resolve.ts
|
|
17766
18498
|
init_cjs_shims();
|
|
17767
|
-
var
|
|
18499
|
+
var import_types73 = require("@neat.is/types");
|
|
17768
18500
|
function createNeonResolveTarget(config) {
|
|
17769
18501
|
return (signal) => {
|
|
17770
18502
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
17771
18503
|
return {
|
|
17772
|
-
targetNodeId: (0,
|
|
18504
|
+
targetNodeId: (0, import_types73.infraId)("sql-table", signal.targetName),
|
|
17773
18505
|
serviceName: config.serviceName,
|
|
17774
|
-
edgeType:
|
|
18506
|
+
edgeType: import_types73.EdgeType.CALLS,
|
|
17775
18507
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
17776
18508
|
};
|
|
17777
18509
|
};
|
|
@@ -17897,9 +18629,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
17897
18629
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
17898
18630
|
if (secondSep === -1) return null;
|
|
17899
18631
|
const method = rest.slice(0, secondSep);
|
|
17900
|
-
const
|
|
17901
|
-
if (!serviceName || !method || !
|
|
17902
|
-
return { serviceName, method, path:
|
|
18632
|
+
const path76 = rest.slice(secondSep + 1);
|
|
18633
|
+
if (!serviceName || !method || !path76) return null;
|
|
18634
|
+
return { serviceName, method, path: path76 };
|
|
17903
18635
|
}
|
|
17904
18636
|
|
|
17905
18637
|
// src/connectors/cloud-run/map.ts
|
|
@@ -17928,14 +18660,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
17928
18660
|
if (!req) return null;
|
|
17929
18661
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
17930
18662
|
const method = req.requestMethod.toUpperCase();
|
|
17931
|
-
const
|
|
17932
|
-
if (
|
|
18663
|
+
const path76 = pathFromRequestUrl2(req.requestUrl);
|
|
18664
|
+
if (path76 === null) return null;
|
|
17933
18665
|
const timestamp = entry.timestamp;
|
|
17934
18666
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17935
18667
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
17936
18668
|
return {
|
|
17937
18669
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
17938
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
18670
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path76 }),
|
|
17939
18671
|
callCount: 1,
|
|
17940
18672
|
errorCount: isError ? 1 : 0,
|
|
17941
18673
|
lastObservedIso: timestamp
|
|
@@ -17952,14 +18684,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
17952
18684
|
|
|
17953
18685
|
// src/connectors/cloud-run/resolve.ts
|
|
17954
18686
|
init_cjs_shims();
|
|
17955
|
-
var
|
|
18687
|
+
var import_types77 = require("@neat.is/types");
|
|
17956
18688
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
17957
18689
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
17958
18690
|
let found = null;
|
|
17959
18691
|
graph.forEachNode((_id, attrs) => {
|
|
17960
18692
|
if (found) return;
|
|
17961
18693
|
const node = attrs;
|
|
17962
|
-
if (node.type !==
|
|
18694
|
+
if (node.type !== import_types77.NodeType.RouteNode) return;
|
|
17963
18695
|
const route = attrs;
|
|
17964
18696
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
17965
18697
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -17974,23 +18706,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
17974
18706
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
17975
18707
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
17976
18708
|
if (!identity) return null;
|
|
17977
|
-
const { serviceName: gcpServiceName, method, path:
|
|
18709
|
+
const { serviceName: gcpServiceName, method, path: path76 } = identity;
|
|
17978
18710
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
17979
18711
|
if (mappedService) {
|
|
17980
18712
|
const routeNodeId = findMatchingRouteNode2(
|
|
17981
18713
|
graph,
|
|
17982
18714
|
mappedService,
|
|
17983
18715
|
method,
|
|
17984
|
-
normalizePathTemplate(
|
|
18716
|
+
normalizePathTemplate(path76)
|
|
17985
18717
|
);
|
|
17986
18718
|
if (routeNodeId) {
|
|
17987
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
18719
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types77.EdgeType.CALLS };
|
|
17988
18720
|
}
|
|
17989
18721
|
}
|
|
17990
18722
|
return {
|
|
17991
|
-
targetNodeId: (0,
|
|
18723
|
+
targetNodeId: (0, import_types77.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
17992
18724
|
serviceName: mappedService ?? gcpServiceName,
|
|
17993
|
-
edgeType:
|
|
18725
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
17994
18726
|
ensureInfraNode: {
|
|
17995
18727
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
17996
18728
|
name: gcpServiceName,
|
|
@@ -18031,7 +18763,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
18031
18763
|
|
|
18032
18764
|
// src/connectors/render/index.ts
|
|
18033
18765
|
init_cjs_shims();
|
|
18034
|
-
var
|
|
18766
|
+
var import_types80 = require("@neat.is/types");
|
|
18035
18767
|
|
|
18036
18768
|
// src/connectors/render/types.ts
|
|
18037
18769
|
init_cjs_shims();
|
|
@@ -18109,7 +18841,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
18109
18841
|
const out = [];
|
|
18110
18842
|
graph.forEachNode((_id, attrs) => {
|
|
18111
18843
|
const node = attrs;
|
|
18112
|
-
if (node.type !==
|
|
18844
|
+
if (node.type !== import_types80.NodeType.RouteNode) return;
|
|
18113
18845
|
const route = attrs;
|
|
18114
18846
|
if (route.service !== serviceName) return;
|
|
18115
18847
|
out.push({
|
|
@@ -18194,7 +18926,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
18194
18926
|
function createRenderResolveTarget(config) {
|
|
18195
18927
|
return (signal) => {
|
|
18196
18928
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
18197
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
18929
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types80.EdgeType.CALLS };
|
|
18198
18930
|
}
|
|
18199
18931
|
return null;
|
|
18200
18932
|
};
|
|
@@ -18332,21 +19064,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
18332
19064
|
|
|
18333
19065
|
// src/connectors/planetscale/resolve.ts
|
|
18334
19066
|
init_cjs_shims();
|
|
18335
|
-
var
|
|
19067
|
+
var import_types84 = require("@neat.is/types");
|
|
18336
19068
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
18337
19069
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
18338
19070
|
const databaseName = `${config.organization}/${config.database}`;
|
|
18339
19071
|
return (signal, _ctx) => {
|
|
18340
19072
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
18341
|
-
const tableId = (0,
|
|
19073
|
+
const tableId = (0, import_types84.infraId)("sql-table", signal.targetName);
|
|
18342
19074
|
if (graph.hasNode(tableId)) {
|
|
18343
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
19075
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types84.EdgeType.CALLS };
|
|
18344
19076
|
}
|
|
18345
|
-
const providerId = (0,
|
|
19077
|
+
const providerId = (0, import_types84.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
18346
19078
|
return {
|
|
18347
19079
|
targetNodeId: providerId,
|
|
18348
19080
|
serviceName: config.serviceName,
|
|
18349
|
-
edgeType:
|
|
19081
|
+
edgeType: import_types84.EdgeType.CALLS,
|
|
18350
19082
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
18351
19083
|
};
|
|
18352
19084
|
};
|
|
@@ -18611,7 +19343,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
18611
19343
|
|
|
18612
19344
|
// src/connectors/eas/resolve.ts
|
|
18613
19345
|
init_cjs_shims();
|
|
18614
|
-
var
|
|
19346
|
+
var import_types89 = require("@neat.is/types");
|
|
18615
19347
|
var NO_ENV2 = "unknown";
|
|
18616
19348
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
18617
19349
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -18627,8 +19359,8 @@ function configBasenamesForPhase(phase) {
|
|
|
18627
19359
|
function configNodeService(graph, configNodeId) {
|
|
18628
19360
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
18629
19361
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18630
|
-
if (edge.type !==
|
|
18631
|
-
const parsed = (0,
|
|
19362
|
+
if (edge.type !== import_types89.EdgeType.CONFIGURED_BY) continue;
|
|
19363
|
+
const parsed = (0, import_types89.parseFileId)(edge.source);
|
|
18632
19364
|
if (parsed) return parsed.service;
|
|
18633
19365
|
}
|
|
18634
19366
|
return null;
|
|
@@ -18639,7 +19371,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
18639
19371
|
graph.forEachNode((id, attrs) => {
|
|
18640
19372
|
if (scoped) return;
|
|
18641
19373
|
const node = attrs;
|
|
18642
|
-
if (node.type !==
|
|
19374
|
+
if (node.type !== import_types89.NodeType.ConfigNode) return;
|
|
18643
19375
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
18644
19376
|
if (anyMatch === null) anyMatch = id;
|
|
18645
19377
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -18656,13 +19388,13 @@ function createEasResolveTarget(graph) {
|
|
|
18656
19388
|
if (basenames.length > 0) {
|
|
18657
19389
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
18658
19390
|
if (configNodeId) {
|
|
18659
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
19391
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types89.EdgeType.CALLS };
|
|
18660
19392
|
}
|
|
18661
19393
|
}
|
|
18662
19394
|
return {
|
|
18663
19395
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
18664
19396
|
serviceName,
|
|
18665
|
-
edgeType:
|
|
19397
|
+
edgeType: import_types89.EdgeType.CALLS
|
|
18666
19398
|
};
|
|
18667
19399
|
};
|
|
18668
19400
|
}
|
|
@@ -19341,11 +20073,11 @@ function registerRoutes(scope, ctx) {
|
|
|
19341
20073
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
19342
20074
|
const parsed = [];
|
|
19343
20075
|
for (const c of candidates) {
|
|
19344
|
-
const r =
|
|
20076
|
+
const r = import_types92.DivergenceTypeSchema.safeParse(c);
|
|
19345
20077
|
if (!r.success) {
|
|
19346
20078
|
return reply.code(400).send({
|
|
19347
20079
|
error: `unknown divergence type "${c}"`,
|
|
19348
|
-
allowed:
|
|
20080
|
+
allowed: import_types92.DivergenceTypeSchema.options
|
|
19349
20081
|
});
|
|
19350
20082
|
}
|
|
19351
20083
|
parsed.push(r.data);
|
|
@@ -19687,7 +20419,7 @@ function registerRoutes(scope, ctx) {
|
|
|
19687
20419
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
19688
20420
|
let violations = await log.readAll();
|
|
19689
20421
|
if (req.query.severity) {
|
|
19690
|
-
const sev =
|
|
20422
|
+
const sev = import_types92.PolicySeveritySchema.safeParse(req.query.severity);
|
|
19691
20423
|
if (!sev.success) {
|
|
19692
20424
|
return reply.code(400).send({
|
|
19693
20425
|
error: "invalid severity",
|
|
@@ -19726,7 +20458,7 @@ function registerRoutes(scope, ctx) {
|
|
|
19726
20458
|
scope.post("/policies/check", async (req, reply) => {
|
|
19727
20459
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
19728
20460
|
if (!proj) return;
|
|
19729
|
-
const parsed =
|
|
20461
|
+
const parsed = import_types92.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
19730
20462
|
if (!parsed.success) {
|
|
19731
20463
|
return reply.code(400).send({
|
|
19732
20464
|
error: "invalid /policies/check body",
|
|
@@ -20047,8 +20779,8 @@ init_otel_grpc();
|
|
|
20047
20779
|
|
|
20048
20780
|
// src/search.ts
|
|
20049
20781
|
init_cjs_shims();
|
|
20050
|
-
var
|
|
20051
|
-
var
|
|
20782
|
+
var import_node_fs39 = require("fs");
|
|
20783
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
20052
20784
|
var import_node_crypto4 = require("crypto");
|
|
20053
20785
|
var DEFAULT_LIMIT = 10;
|
|
20054
20786
|
var NOMIC_DIM = 768;
|
|
@@ -20202,7 +20934,7 @@ async function pickEmbedder() {
|
|
|
20202
20934
|
}
|
|
20203
20935
|
async function readCache(cachePath) {
|
|
20204
20936
|
try {
|
|
20205
|
-
const raw = await
|
|
20937
|
+
const raw = await import_node_fs39.promises.readFile(cachePath, "utf8");
|
|
20206
20938
|
const parsed = JSON.parse(raw);
|
|
20207
20939
|
if (parsed.version !== 1) return null;
|
|
20208
20940
|
return parsed;
|
|
@@ -20211,8 +20943,8 @@ async function readCache(cachePath) {
|
|
|
20211
20943
|
}
|
|
20212
20944
|
}
|
|
20213
20945
|
async function writeCache(cachePath, cache) {
|
|
20214
|
-
await
|
|
20215
|
-
await
|
|
20946
|
+
await import_node_fs39.promises.mkdir(import_node_path74.default.dirname(cachePath), { recursive: true });
|
|
20947
|
+
await import_node_fs39.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
20216
20948
|
}
|
|
20217
20949
|
var VectorIndex = class {
|
|
20218
20950
|
constructor(embedder, cachePath) {
|
|
@@ -20426,14 +21158,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
20426
21158
|
async function main() {
|
|
20427
21159
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
20428
21160
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
20429
|
-
const baseDir = baseDirEnv ?
|
|
20430
|
-
const defaultScanPath =
|
|
21161
|
+
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");
|
|
21162
|
+
const defaultScanPath = import_node_path75.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
|
|
20431
21163
|
const registry = new Projects();
|
|
20432
21164
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
20433
21165
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
20434
21166
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
20435
21167
|
const projectScan = process.env[envKey];
|
|
20436
|
-
await bootProject(registry, name, projectScan ?
|
|
21168
|
+
await bootProject(registry, name, projectScan ? import_node_path75.default.resolve(projectScan) : void 0, baseDir);
|
|
20437
21169
|
}
|
|
20438
21170
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
20439
21171
|
const port = Number(process.env.PORT ?? 8080);
|