@neat.is/core 0.9.1-dev.20260819 → 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-JUVJBH23.js → chunk-UN7VFA4H.js} +1045 -376
- package/dist/chunk-UN7VFA4H.js.map +1 -0
- package/dist/{chunk-ICO37D3H.js → chunk-YKQB622D.js} +2 -2
- package/dist/cli.cjs +1581 -910
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1244 -573
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +1260 -589
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +1147 -476
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-JUVJBH23.js.map +0 -1
- /package/dist/{chunk-ICO37D3H.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);
|
|
6187
6503
|
edges.push(hop.edge);
|
|
6188
6504
|
visited.add(hop.nextService);
|
|
6189
6505
|
current = hop.nextService;
|
|
6190
6506
|
}
|
|
6191
6507
|
if (edges.length === 0) return null;
|
|
6192
|
-
return { path:
|
|
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);
|
|
6552
|
+
edges.push(hop.edge);
|
|
6553
|
+
visited.add(hop.nextService);
|
|
6554
|
+
current = hop.nextService;
|
|
6555
|
+
}
|
|
6556
|
+
if (edges.length === 0) return null;
|
|
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,7 +11358,7 @@ 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;
|
|
@@ -10896,13 +11446,13 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
10896
11446
|
// call sites — verified-call-site tier (ADR-066).
|
|
10897
11447
|
confidenceKind: "verified-call-site",
|
|
10898
11448
|
evidence: {
|
|
10899
|
-
file:
|
|
11449
|
+
file: import_node_path41.default.relative(serviceDir, file.path),
|
|
10900
11450
|
line,
|
|
10901
11451
|
snippet: snippet(file.content, line)
|
|
10902
11452
|
}
|
|
10903
11453
|
});
|
|
10904
11454
|
};
|
|
10905
|
-
if (
|
|
11455
|
+
if (import_node_path41.default.extname(file.path) === ".go") {
|
|
10906
11456
|
goSaramaEndpoints(file.content, make);
|
|
10907
11457
|
} else {
|
|
10908
11458
|
for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, "PUBLISHES_TO");
|
|
@@ -10913,7 +11463,7 @@ function kafkaEndpointsFromFile(file, serviceDir) {
|
|
|
10913
11463
|
|
|
10914
11464
|
// src/extract/calls/redis.ts
|
|
10915
11465
|
init_cjs_shims();
|
|
10916
|
-
var
|
|
11466
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
10917
11467
|
var import_types30 = require("@neat.is/types");
|
|
10918
11468
|
var REDIS_URL_RE = /redis(?:s)?:\/\/(?:[^@'"`\s]+@)?([^:/'"`\s]+)(?::(\d+))?/g;
|
|
10919
11469
|
function redisEndpointsFromFile(file, serviceDir) {
|
|
@@ -10936,7 +11486,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10936
11486
|
// support tier (ADR-066).
|
|
10937
11487
|
confidenceKind: "url-with-structural-support",
|
|
10938
11488
|
evidence: {
|
|
10939
|
-
file:
|
|
11489
|
+
file: import_node_path42.default.relative(serviceDir, file.path),
|
|
10940
11490
|
line,
|
|
10941
11491
|
snippet: snippet(file.content, line)
|
|
10942
11492
|
}
|
|
@@ -10947,7 +11497,7 @@ function redisEndpointsFromFile(file, serviceDir) {
|
|
|
10947
11497
|
|
|
10948
11498
|
// src/extract/calls/aws.ts
|
|
10949
11499
|
init_cjs_shims();
|
|
10950
|
-
var
|
|
11500
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
10951
11501
|
var import_types31 = require("@neat.is/types");
|
|
10952
11502
|
var S3_BUCKET_RE = /Bucket\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
10953
11503
|
var DYNAMO_TABLE_RE = /TableName\s*:\s*['"`]([^'"`]+)['"`]/g;
|
|
@@ -10981,7 +11531,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
10981
11531
|
// (ADR-066).
|
|
10982
11532
|
confidenceKind: "verified-call-site",
|
|
10983
11533
|
evidence: {
|
|
10984
|
-
file:
|
|
11534
|
+
file: import_node_path43.default.relative(serviceDir, file.path),
|
|
10985
11535
|
line,
|
|
10986
11536
|
snippet: snippet(file.content, line)
|
|
10987
11537
|
}
|
|
@@ -11006,7 +11556,7 @@ function awsEndpointsFromFile(file, serviceDir) {
|
|
|
11006
11556
|
|
|
11007
11557
|
// src/extract/calls/grpc.ts
|
|
11008
11558
|
init_cjs_shims();
|
|
11009
|
-
var
|
|
11559
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
11010
11560
|
var import_types32 = require("@neat.is/types");
|
|
11011
11561
|
var GRPC_CLIENT_RE = /new\s+([A-Z][A-Za-z0-9_]*)Client\s*\(\s*['"`]?([^,'"`)]+)?/g;
|
|
11012
11562
|
var AWS_SDK_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@aws-sdk\/client-([a-z0-9-]+)['"`]/g;
|
|
@@ -11065,7 +11615,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
11065
11615
|
// tier (ADR-066).
|
|
11066
11616
|
confidenceKind: "verified-call-site",
|
|
11067
11617
|
evidence: {
|
|
11068
|
-
file:
|
|
11618
|
+
file: import_node_path44.default.relative(serviceDir, file.path),
|
|
11069
11619
|
line,
|
|
11070
11620
|
snippet: snippet(file.content, line)
|
|
11071
11621
|
}
|
|
@@ -11076,7 +11626,7 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
11076
11626
|
|
|
11077
11627
|
// src/extract/calls/supabase.ts
|
|
11078
11628
|
init_cjs_shims();
|
|
11079
|
-
var
|
|
11629
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
11080
11630
|
var import_types33 = require("@neat.is/types");
|
|
11081
11631
|
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
11082
11632
|
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
@@ -11135,7 +11685,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11135
11685
|
// tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
|
|
11136
11686
|
confidenceKind: "verified-call-site",
|
|
11137
11687
|
evidence: {
|
|
11138
|
-
file:
|
|
11688
|
+
file: import_node_path45.default.relative(serviceDir, file.path),
|
|
11139
11689
|
line,
|
|
11140
11690
|
snippet: snippet(file.content, line)
|
|
11141
11691
|
}
|
|
@@ -11162,7 +11712,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11162
11712
|
edgeType: "CALLS",
|
|
11163
11713
|
confidenceKind: "verified-call-site",
|
|
11164
11714
|
evidence: {
|
|
11165
|
-
file:
|
|
11715
|
+
file: import_node_path45.default.relative(serviceDir, file.path),
|
|
11166
11716
|
line,
|
|
11167
11717
|
snippet: snippet(file.content, line)
|
|
11168
11718
|
}
|
|
@@ -11174,7 +11724,7 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
11174
11724
|
|
|
11175
11725
|
// src/extract/calls/firestore.ts
|
|
11176
11726
|
init_cjs_shims();
|
|
11177
|
-
var
|
|
11727
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
11178
11728
|
var import_tree_sitter8 = __toESM(require("tree-sitter"), 1);
|
|
11179
11729
|
var import_tree_sitter_javascript6 = __toESM(require("tree-sitter-javascript"), 1);
|
|
11180
11730
|
var import_types34 = require("@neat.is/types");
|
|
@@ -11213,7 +11763,7 @@ function isFirestoreClientFactory(node) {
|
|
|
11213
11763
|
}
|
|
11214
11764
|
function firestoreClientVars(root) {
|
|
11215
11765
|
const vars = /* @__PURE__ */ new Set();
|
|
11216
|
-
const
|
|
11766
|
+
const walk10 = (node) => {
|
|
11217
11767
|
if (node.type === "variable_declarator") {
|
|
11218
11768
|
const name = node.childForFieldName("name");
|
|
11219
11769
|
let value = node.childForFieldName("value");
|
|
@@ -11222,9 +11772,9 @@ function firestoreClientVars(root) {
|
|
|
11222
11772
|
vars.add(name.text);
|
|
11223
11773
|
}
|
|
11224
11774
|
}
|
|
11225
|
-
for (const c of namedChildren(node))
|
|
11775
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
11226
11776
|
};
|
|
11227
|
-
|
|
11777
|
+
walk10(root);
|
|
11228
11778
|
return vars;
|
|
11229
11779
|
}
|
|
11230
11780
|
function isClientExpr(node, clientVars) {
|
|
@@ -11345,7 +11895,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11345
11895
|
const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
|
|
11346
11896
|
if (!hasClient && !hasAdmin) return [];
|
|
11347
11897
|
const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
|
|
11348
|
-
const tree = parseSource3(parserForExt2(
|
|
11898
|
+
const tree = parseSource3(parserForExt2(import_node_path46.default.extname(file.path)), file.content);
|
|
11349
11899
|
const clientVars = firestoreClientVars(tree.rootNode);
|
|
11350
11900
|
const collLine = /* @__PURE__ */ new Map();
|
|
11351
11901
|
const writes = /* @__PURE__ */ new Map();
|
|
@@ -11379,7 +11929,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11379
11929
|
}
|
|
11380
11930
|
s.add(field);
|
|
11381
11931
|
};
|
|
11382
|
-
const
|
|
11932
|
+
const walk10 = (node) => {
|
|
11383
11933
|
if (node.type === "call_expression") {
|
|
11384
11934
|
const fn = node.childForFieldName("function");
|
|
11385
11935
|
const line = node.startPosition.row + 1;
|
|
@@ -11419,9 +11969,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11419
11969
|
}
|
|
11420
11970
|
}
|
|
11421
11971
|
}
|
|
11422
|
-
for (const c of namedChildren(node))
|
|
11972
|
+
for (const c of namedChildren(node)) walk10(c);
|
|
11423
11973
|
};
|
|
11424
|
-
|
|
11974
|
+
walk10(tree.rootNode);
|
|
11425
11975
|
const out = [];
|
|
11426
11976
|
for (const [collPath, line] of collLine) {
|
|
11427
11977
|
const byField = writes.get(collPath);
|
|
@@ -11449,7 +11999,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11449
11999
|
...columnSet.size > 0 ? { columns: [...columnSet] } : {},
|
|
11450
12000
|
...sdkWrites ? { sdkWrites } : {},
|
|
11451
12001
|
evidence: {
|
|
11452
|
-
file:
|
|
12002
|
+
file: import_node_path46.default.relative(serviceDir, file.path),
|
|
11453
12003
|
line,
|
|
11454
12004
|
snippet: snippet(file.content, line)
|
|
11455
12005
|
}
|
|
@@ -11460,7 +12010,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11460
12010
|
|
|
11461
12011
|
// src/extract/calls/mongoose.ts
|
|
11462
12012
|
init_cjs_shims();
|
|
11463
|
-
var
|
|
12013
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
11464
12014
|
var import_types35 = require("@neat.is/types");
|
|
11465
12015
|
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
11466
12016
|
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
@@ -11611,7 +12161,7 @@ function endpoint(r, file, serviceDir, matchText) {
|
|
|
11611
12161
|
kind: r.kind,
|
|
11612
12162
|
edgeType: "CALLS",
|
|
11613
12163
|
confidenceKind: "verified-call-site",
|
|
11614
|
-
evidence: { file:
|
|
12164
|
+
evidence: { file: import_node_path47.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
11615
12165
|
};
|
|
11616
12166
|
}
|
|
11617
12167
|
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
@@ -11701,7 +12251,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11701
12251
|
const registry = /* @__PURE__ */ new Map();
|
|
11702
12252
|
for (const f of mongooseFiles) {
|
|
11703
12253
|
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
11704
|
-
if (fx) registry.set(toPosix(
|
|
12254
|
+
if (fx) registry.set(toPosix(import_node_path47.default.relative(serviceDir, f.path)), fx);
|
|
11705
12255
|
}
|
|
11706
12256
|
if (registry.size === 0) return [];
|
|
11707
12257
|
const out = [];
|
|
@@ -11712,7 +12262,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11712
12262
|
const directColl = /* @__PURE__ */ new Map();
|
|
11713
12263
|
const nsExports = /* @__PURE__ */ new Map();
|
|
11714
12264
|
for (const b of bindings) {
|
|
11715
|
-
const resolvedRel = await resolveJsImport(b.specifier,
|
|
12265
|
+
const resolvedRel = await resolveJsImport(b.specifier, import_node_path47.default.dirname(f.path), serviceDir, null);
|
|
11716
12266
|
if (!resolvedRel) continue;
|
|
11717
12267
|
const fx = registry.get(resolvedRel);
|
|
11718
12268
|
if (!fx) continue;
|
|
@@ -11756,7 +12306,7 @@ async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
|
11756
12306
|
|
|
11757
12307
|
// src/extract/calls/sqlalchemy.ts
|
|
11758
12308
|
init_cjs_shims();
|
|
11759
|
-
var
|
|
12309
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
11760
12310
|
var import_tree_sitter9 = __toESM(require("tree-sitter"), 1);
|
|
11761
12311
|
var import_tree_sitter_python5 = __toESM(require("tree-sitter-python"), 1);
|
|
11762
12312
|
var import_types36 = require("@neat.is/types");
|
|
@@ -11895,7 +12445,7 @@ function sqlalchemyForeignKeys(file, serviceDir) {
|
|
|
11895
12445
|
childTable,
|
|
11896
12446
|
parentTable,
|
|
11897
12447
|
evidence: {
|
|
11898
|
-
file:
|
|
12448
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11899
12449
|
line,
|
|
11900
12450
|
snippet: snippet(file.content, line)
|
|
11901
12451
|
}
|
|
@@ -11920,7 +12470,7 @@ function sqlalchemyEndpointsFromFile(file, serviceDir) {
|
|
|
11920
12470
|
confidenceKind: "verified-call-site",
|
|
11921
12471
|
...columns && columns.length > 0 ? { columns } : {},
|
|
11922
12472
|
evidence: {
|
|
11923
|
-
file:
|
|
12473
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
11924
12474
|
line,
|
|
11925
12475
|
snippet: snippet(file.content, line)
|
|
11926
12476
|
}
|
|
@@ -12027,7 +12577,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
12027
12577
|
edgeType: "CALLS",
|
|
12028
12578
|
confidenceKind: "verified-call-site",
|
|
12029
12579
|
evidence: {
|
|
12030
|
-
file:
|
|
12580
|
+
file: import_node_path48.default.relative(serviceDir, file.path),
|
|
12031
12581
|
line,
|
|
12032
12582
|
snippet: snippet(file.content, line)
|
|
12033
12583
|
}
|
|
@@ -12039,7 +12589,7 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
12039
12589
|
|
|
12040
12590
|
// src/extract/calls/django-orm.ts
|
|
12041
12591
|
init_cjs_shims();
|
|
12042
|
-
var
|
|
12592
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
12043
12593
|
var import_tree_sitter10 = __toESM(require("tree-sitter"), 1);
|
|
12044
12594
|
var import_tree_sitter_python6 = __toESM(require("tree-sitter-python"), 1);
|
|
12045
12595
|
var import_types37 = require("@neat.is/types");
|
|
@@ -12109,7 +12659,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12109
12659
|
const tree = parseSource7(makePyParser4(), file.content);
|
|
12110
12660
|
const out = [];
|
|
12111
12661
|
const seen = /* @__PURE__ */ new Set();
|
|
12112
|
-
const defaultAppLabel =
|
|
12662
|
+
const defaultAppLabel = import_node_path49.default.basename(import_node_path49.default.dirname(file.path));
|
|
12113
12663
|
walk4(tree.rootNode, (node) => {
|
|
12114
12664
|
if (node.type !== "class_definition") return;
|
|
12115
12665
|
if (!extendsDjangoModel(node)) return;
|
|
@@ -12127,7 +12677,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12127
12677
|
kind: "sql-table",
|
|
12128
12678
|
edgeType: "CALLS",
|
|
12129
12679
|
confidenceKind: "verified-call-site",
|
|
12130
|
-
evidence: { file:
|
|
12680
|
+
evidence: { file: import_node_path49.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
12131
12681
|
});
|
|
12132
12682
|
});
|
|
12133
12683
|
return out;
|
|
@@ -12135,7 +12685,7 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
12135
12685
|
|
|
12136
12686
|
// src/extract/calls/drizzle.ts
|
|
12137
12687
|
init_cjs_shims();
|
|
12138
|
-
var
|
|
12688
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
12139
12689
|
var import_tree_sitter11 = __toESM(require("tree-sitter"), 1);
|
|
12140
12690
|
var import_tree_sitter_javascript7 = __toESM(require("tree-sitter-javascript"), 1);
|
|
12141
12691
|
var import_types38 = require("@neat.is/types");
|
|
@@ -12213,10 +12763,10 @@ function columnsFromObject(obj) {
|
|
|
12213
12763
|
}
|
|
12214
12764
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
12215
12765
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12216
|
-
const tree = parseSource3(parserForExt3(
|
|
12766
|
+
const tree = parseSource3(parserForExt3(import_node_path50.default.extname(file.path)), file.content);
|
|
12217
12767
|
const out = [];
|
|
12218
12768
|
const seen = /* @__PURE__ */ new Set();
|
|
12219
|
-
const
|
|
12769
|
+
const walk10 = (node) => {
|
|
12220
12770
|
if (node.type === "call_expression") {
|
|
12221
12771
|
const fn = node.childForFieldName("function");
|
|
12222
12772
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -12236,7 +12786,7 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12236
12786
|
confidenceKind: "structural",
|
|
12237
12787
|
columns,
|
|
12238
12788
|
evidence: {
|
|
12239
|
-
file:
|
|
12789
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12240
12790
|
line,
|
|
12241
12791
|
snippet: snippet(file.content, line)
|
|
12242
12792
|
}
|
|
@@ -12244,9 +12794,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
12244
12794
|
}
|
|
12245
12795
|
}
|
|
12246
12796
|
}
|
|
12247
|
-
for (const c of namedChildren4(node))
|
|
12797
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12248
12798
|
};
|
|
12249
|
-
|
|
12799
|
+
walk10(tree.rootNode);
|
|
12250
12800
|
return out;
|
|
12251
12801
|
}
|
|
12252
12802
|
function enclosingVarName(call) {
|
|
@@ -12268,7 +12818,7 @@ function enclosingVarName(call) {
|
|
|
12268
12818
|
function collectDrizzleTables(root) {
|
|
12269
12819
|
const tables = [];
|
|
12270
12820
|
const varToTable = /* @__PURE__ */ new Map();
|
|
12271
|
-
const
|
|
12821
|
+
const walk10 = (node) => {
|
|
12272
12822
|
if (node.type === "call_expression") {
|
|
12273
12823
|
const fn = node.childForFieldName("function");
|
|
12274
12824
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
@@ -12283,9 +12833,9 @@ function collectDrizzleTables(root) {
|
|
|
12283
12833
|
}
|
|
12284
12834
|
}
|
|
12285
12835
|
}
|
|
12286
|
-
for (const c of namedChildren4(node))
|
|
12836
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12287
12837
|
};
|
|
12288
|
-
|
|
12838
|
+
walk10(root);
|
|
12289
12839
|
return { tables, varToTable };
|
|
12290
12840
|
}
|
|
12291
12841
|
function referencesTargetVar(call) {
|
|
@@ -12302,13 +12852,13 @@ function referencesTargetVar(call) {
|
|
|
12302
12852
|
}
|
|
12303
12853
|
function drizzleForeignKeys(file, serviceDir) {
|
|
12304
12854
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
12305
|
-
const tree = parseSource3(parserForExt3(
|
|
12855
|
+
const tree = parseSource3(parserForExt3(import_node_path50.default.extname(file.path)), file.content);
|
|
12306
12856
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
12307
12857
|
const out = [];
|
|
12308
12858
|
const seen = /* @__PURE__ */ new Set();
|
|
12309
12859
|
for (const table of tables) {
|
|
12310
12860
|
if (!table.object) continue;
|
|
12311
|
-
const
|
|
12861
|
+
const walk10 = (node) => {
|
|
12312
12862
|
if (node.type === "call_expression") {
|
|
12313
12863
|
const targetVar = referencesTargetVar(node);
|
|
12314
12864
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -12321,7 +12871,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12321
12871
|
childTable: table.tableName,
|
|
12322
12872
|
parentTable,
|
|
12323
12873
|
evidence: {
|
|
12324
|
-
file:
|
|
12874
|
+
file: import_node_path50.default.relative(serviceDir, file.path),
|
|
12325
12875
|
line,
|
|
12326
12876
|
snippet: snippet(file.content, line)
|
|
12327
12877
|
}
|
|
@@ -12329,16 +12879,16 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
12329
12879
|
}
|
|
12330
12880
|
}
|
|
12331
12881
|
}
|
|
12332
|
-
for (const c of namedChildren4(node))
|
|
12882
|
+
for (const c of namedChildren4(node)) walk10(c);
|
|
12333
12883
|
};
|
|
12334
|
-
|
|
12884
|
+
walk10(table.object);
|
|
12335
12885
|
}
|
|
12336
12886
|
return out;
|
|
12337
12887
|
}
|
|
12338
12888
|
|
|
12339
12889
|
// src/extract/calls/prisma.ts
|
|
12340
12890
|
init_cjs_shims();
|
|
12341
|
-
var
|
|
12891
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
12342
12892
|
var import_types39 = require("@neat.is/types");
|
|
12343
12893
|
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
12344
12894
|
"Int",
|
|
@@ -12394,7 +12944,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12394
12944
|
confidenceKind: "structural",
|
|
12395
12945
|
columns: b.columns,
|
|
12396
12946
|
evidence: {
|
|
12397
|
-
file:
|
|
12947
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12398
12948
|
line: b.startLine,
|
|
12399
12949
|
snippet: snippet(content, b.startLine)
|
|
12400
12950
|
}
|
|
@@ -12455,7 +13005,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12455
13005
|
}
|
|
12456
13006
|
async function prismaColumnEndpoints(serviceDir) {
|
|
12457
13007
|
const schemaPath = await findFirst(serviceDir, [
|
|
12458
|
-
|
|
13008
|
+
import_node_path51.default.join("prisma", "schema.prisma"),
|
|
12459
13009
|
"schema.prisma"
|
|
12460
13010
|
]);
|
|
12461
13011
|
if (!schemaPath) return [];
|
|
@@ -12530,7 +13080,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12530
13080
|
childTable: current.table,
|
|
12531
13081
|
parentTable,
|
|
12532
13082
|
evidence: {
|
|
12533
|
-
file:
|
|
13083
|
+
file: import_node_path51.default.relative(serviceDir, file.path),
|
|
12534
13084
|
line: lineNo,
|
|
12535
13085
|
snippet: snippet(content, lineNo)
|
|
12536
13086
|
}
|
|
@@ -12545,7 +13095,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12545
13095
|
}
|
|
12546
13096
|
async function prismaForeignKeys(serviceDir) {
|
|
12547
13097
|
const schemaPath = await findFirst(serviceDir, [
|
|
12548
|
-
|
|
13098
|
+
import_node_path51.default.join("prisma", "schema.prisma"),
|
|
12549
13099
|
"schema.prisma"
|
|
12550
13100
|
]);
|
|
12551
13101
|
if (!schemaPath) return [];
|
|
@@ -12556,7 +13106,7 @@ async function prismaForeignKeys(serviceDir) {
|
|
|
12556
13106
|
|
|
12557
13107
|
// src/extract/calls/activerecord.ts
|
|
12558
13108
|
init_cjs_shims();
|
|
12559
|
-
var
|
|
13109
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
12560
13110
|
var import_tree_sitter12 = __toESM(require("tree-sitter"), 1);
|
|
12561
13111
|
var import_tree_sitter_ruby3 = __toESM(require("tree-sitter-ruby"), 1);
|
|
12562
13112
|
var import_types40 = require("@neat.is/types");
|
|
@@ -12764,7 +13314,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
|
12764
13314
|
confidenceKind: "structural",
|
|
12765
13315
|
...table.columns.length > 0 ? { columns: table.columns } : {},
|
|
12766
13316
|
evidence: {
|
|
12767
|
-
file:
|
|
13317
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12768
13318
|
line: table.line,
|
|
12769
13319
|
snippet: snippet(file.content, table.line)
|
|
12770
13320
|
}
|
|
@@ -12786,7 +13336,7 @@ function railsSchemaForeignKeys(file, serviceDir) {
|
|
|
12786
13336
|
childTable,
|
|
12787
13337
|
parentTable,
|
|
12788
13338
|
evidence: {
|
|
12789
|
-
file:
|
|
13339
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12790
13340
|
line,
|
|
12791
13341
|
snippet: snippet(file.content, line)
|
|
12792
13342
|
}
|
|
@@ -12869,7 +13419,7 @@ function railsModelEndpointsFromFile(file, serviceDir) {
|
|
|
12869
13419
|
edgeType: "CALLS",
|
|
12870
13420
|
confidenceKind: "verified-call-site",
|
|
12871
13421
|
evidence: {
|
|
12872
|
-
file:
|
|
13422
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12873
13423
|
line,
|
|
12874
13424
|
snippet: snippet(file.content, line)
|
|
12875
13425
|
}
|
|
@@ -12906,7 +13456,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12906
13456
|
childTable,
|
|
12907
13457
|
parentTable,
|
|
12908
13458
|
evidence: {
|
|
12909
|
-
file:
|
|
13459
|
+
file: import_node_path52.default.relative(serviceDir, file.path),
|
|
12910
13460
|
line,
|
|
12911
13461
|
snippet: snippet(file.content, line)
|
|
12912
13462
|
}
|
|
@@ -12918,7 +13468,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12918
13468
|
|
|
12919
13469
|
// src/extract/calls/eloquent.ts
|
|
12920
13470
|
init_cjs_shims();
|
|
12921
|
-
var
|
|
13471
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
12922
13472
|
var import_tree_sitter13 = __toESM(require("tree-sitter"), 1);
|
|
12923
13473
|
var import_tree_sitter_php3 = __toESM(require("tree-sitter-php"), 1);
|
|
12924
13474
|
var import_types41 = require("@neat.is/types");
|
|
@@ -13175,7 +13725,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
13175
13725
|
confidenceKind: "structural",
|
|
13176
13726
|
...columns.length > 0 ? { columns } : {},
|
|
13177
13727
|
evidence: {
|
|
13178
|
-
file:
|
|
13728
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13179
13729
|
line: bp.line,
|
|
13180
13730
|
snippet: snippet(file.content, bp.line)
|
|
13181
13731
|
}
|
|
@@ -13197,7 +13747,7 @@ function laravelMigrationForeignKeys(file, serviceDir) {
|
|
|
13197
13747
|
childTable,
|
|
13198
13748
|
parentTable,
|
|
13199
13749
|
evidence: {
|
|
13200
|
-
file:
|
|
13750
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13201
13751
|
line,
|
|
13202
13752
|
snippet: snippet(file.content, line)
|
|
13203
13753
|
}
|
|
@@ -13317,7 +13867,7 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
|
13317
13867
|
edgeType: "CALLS",
|
|
13318
13868
|
confidenceKind: "verified-call-site",
|
|
13319
13869
|
evidence: {
|
|
13320
|
-
file:
|
|
13870
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13321
13871
|
line,
|
|
13322
13872
|
snippet: snippet(file.content, line)
|
|
13323
13873
|
}
|
|
@@ -13353,7 +13903,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13353
13903
|
childTable,
|
|
13354
13904
|
parentTable,
|
|
13355
13905
|
evidence: {
|
|
13356
|
-
file:
|
|
13906
|
+
file: import_node_path53.default.relative(serviceDir, file.path),
|
|
13357
13907
|
line,
|
|
13358
13908
|
snippet: snippet(file.content, line)
|
|
13359
13909
|
}
|
|
@@ -13365,7 +13915,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13365
13915
|
|
|
13366
13916
|
// src/extract/calls/go.ts
|
|
13367
13917
|
init_cjs_shims();
|
|
13368
|
-
var
|
|
13918
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
13369
13919
|
var import_tree_sitter14 = __toESM(require("tree-sitter"), 1);
|
|
13370
13920
|
var import_tree_sitter_go4 = __toESM(require("tree-sitter-go"), 1);
|
|
13371
13921
|
var import_types42 = require("@neat.is/types");
|
|
@@ -13440,7 +13990,7 @@ function firstStringLiteralArg(argsNode) {
|
|
|
13440
13990
|
return null;
|
|
13441
13991
|
}
|
|
13442
13992
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
13443
|
-
if (
|
|
13993
|
+
if (import_node_path56.default.extname(file.path) !== ".go") return [];
|
|
13444
13994
|
if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
|
|
13445
13995
|
const tree = parseSource10(makeGoParser3(), file.content);
|
|
13446
13996
|
const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
|
|
@@ -13469,7 +14019,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13469
14019
|
confidenceKind: "verified-call-site",
|
|
13470
14020
|
...columns.length > 0 ? { columns } : {},
|
|
13471
14021
|
evidence: {
|
|
13472
|
-
file: toPosix(
|
|
14022
|
+
file: toPosix(import_node_path56.default.relative(serviceDir, file.path)),
|
|
13473
14023
|
line,
|
|
13474
14024
|
snippet: snippet(file.content, line)
|
|
13475
14025
|
}
|
|
@@ -13480,7 +14030,7 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13480
14030
|
|
|
13481
14031
|
// src/extract/calls/gorm.ts
|
|
13482
14032
|
init_cjs_shims();
|
|
13483
|
-
var
|
|
14033
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
13484
14034
|
var import_tree_sitter15 = __toESM(require("tree-sitter"), 1);
|
|
13485
14035
|
var import_tree_sitter_go5 = __toESM(require("tree-sitter-go"), 1);
|
|
13486
14036
|
var import_types43 = require("@neat.is/types");
|
|
@@ -13913,7 +14463,7 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
|
13913
14463
|
seen.delete(struct.name);
|
|
13914
14464
|
}
|
|
13915
14465
|
function gormEndpointsFromFile(file, serviceDir) {
|
|
13916
|
-
if (
|
|
14466
|
+
if (import_node_path57.default.extname(file.path) !== ".go") return [];
|
|
13917
14467
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13918
14468
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13919
14469
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13935,7 +14485,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13935
14485
|
confidenceKind: "structural",
|
|
13936
14486
|
...columns.length > 0 ? { columns } : {},
|
|
13937
14487
|
evidence: {
|
|
13938
|
-
file: toPosix(
|
|
14488
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
13939
14489
|
line: struct.line,
|
|
13940
14490
|
snippet: snippet(file.content, struct.line)
|
|
13941
14491
|
}
|
|
@@ -13944,7 +14494,7 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13944
14494
|
return out;
|
|
13945
14495
|
}
|
|
13946
14496
|
function gormForeignKeys(file, serviceDir) {
|
|
13947
|
-
if (
|
|
14497
|
+
if (import_node_path57.default.extname(file.path) !== ".go") return [];
|
|
13948
14498
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13949
14499
|
const tree = parseSource11(makeGoParser4(), file.content);
|
|
13950
14500
|
const { structs, models, tableFor } = analyze(tree);
|
|
@@ -13959,7 +14509,7 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13959
14509
|
childTable,
|
|
13960
14510
|
parentTable,
|
|
13961
14511
|
evidence: {
|
|
13962
|
-
file: toPosix(
|
|
14512
|
+
file: toPosix(import_node_path57.default.relative(serviceDir, file.path)),
|
|
13963
14513
|
line,
|
|
13964
14514
|
snippet: snippet(file.content, line)
|
|
13965
14515
|
}
|
|
@@ -13994,15 +14544,131 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13994
14544
|
return out;
|
|
13995
14545
|
}
|
|
13996
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
|
+
|
|
13997
14663
|
// src/extract/calls/index.ts
|
|
13998
14664
|
function edgeTypeFromEndpoint(ep) {
|
|
13999
14665
|
switch (ep.edgeType) {
|
|
14000
14666
|
case "PUBLISHES_TO":
|
|
14001
|
-
return
|
|
14667
|
+
return import_types45.EdgeType.PUBLISHES_TO;
|
|
14002
14668
|
case "CONSUMES_FROM":
|
|
14003
|
-
return
|
|
14669
|
+
return import_types45.EdgeType.CONSUMES_FROM;
|
|
14004
14670
|
default:
|
|
14005
|
-
return
|
|
14671
|
+
return import_types45.EdgeType.CALLS;
|
|
14006
14672
|
}
|
|
14007
14673
|
}
|
|
14008
14674
|
function isAwsKind(kind) {
|
|
@@ -14052,6 +14718,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14052
14718
|
} catch (err) {
|
|
14053
14719
|
recordExtractionError("laravel eloquent extraction", file.path, err);
|
|
14054
14720
|
}
|
|
14721
|
+
try {
|
|
14722
|
+
endpoints.push(...efcoreEndpointsFromFile(file, service.dir));
|
|
14723
|
+
} catch (err) {
|
|
14724
|
+
recordExtractionError("efcore data-axis extraction", file.path, err);
|
|
14725
|
+
}
|
|
14055
14726
|
}
|
|
14056
14727
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
14057
14728
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
@@ -14062,7 +14733,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14062
14733
|
if (!graph.hasNode(ep.infraId)) {
|
|
14063
14734
|
const node = {
|
|
14064
14735
|
id: ep.infraId,
|
|
14065
|
-
type:
|
|
14736
|
+
type: import_types45.NodeType.InfraNode,
|
|
14066
14737
|
name: ep.name,
|
|
14067
14738
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
14068
14739
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -14075,21 +14746,21 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14075
14746
|
}
|
|
14076
14747
|
if (ep.columns && ep.columns.length > 0) {
|
|
14077
14748
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14078
|
-
if (node.type ===
|
|
14749
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14079
14750
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14080
14751
|
...node,
|
|
14081
14752
|
columns: foldColumns(
|
|
14082
14753
|
node.columns,
|
|
14083
14754
|
ep.columns,
|
|
14084
|
-
|
|
14085
|
-
(0,
|
|
14755
|
+
import_types45.Provenance.EXTRACTED,
|
|
14756
|
+
(0, import_types45.confidenceForExtracted)(ep.confidenceKind)
|
|
14086
14757
|
)
|
|
14087
14758
|
});
|
|
14088
14759
|
}
|
|
14089
14760
|
}
|
|
14090
14761
|
if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {
|
|
14091
14762
|
const node = graph.getNodeAttributes(ep.infraId);
|
|
14092
|
-
if (node.type ===
|
|
14763
|
+
if (node.type === import_types45.NodeType.InfraNode) {
|
|
14093
14764
|
graph.replaceNodeAttributes(ep.infraId, {
|
|
14094
14765
|
...node,
|
|
14095
14766
|
columns: foldSdkWrites(node.columns, ep.sdkWrites)
|
|
@@ -14097,7 +14768,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14097
14768
|
}
|
|
14098
14769
|
}
|
|
14099
14770
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
14100
|
-
const confidence = (0,
|
|
14771
|
+
const confidence = (0, import_types45.confidenceForExtracted)(ep.confidenceKind);
|
|
14101
14772
|
const relFile = toPosix(ep.evidence.file);
|
|
14102
14773
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
14103
14774
|
graph,
|
|
@@ -14107,7 +14778,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14107
14778
|
);
|
|
14108
14779
|
nodesAdded += n;
|
|
14109
14780
|
edgesAdded += e;
|
|
14110
|
-
if (!(0,
|
|
14781
|
+
if (!(0, import_types45.passesExtractedFloor)(confidence)) {
|
|
14111
14782
|
noteExtractedDropped({
|
|
14112
14783
|
source: fileNodeId,
|
|
14113
14784
|
target: ep.infraId,
|
|
@@ -14127,7 +14798,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
14127
14798
|
source: fileNodeId,
|
|
14128
14799
|
target: ep.infraId,
|
|
14129
14800
|
type: edgeType,
|
|
14130
|
-
provenance:
|
|
14801
|
+
provenance: import_types45.Provenance.EXTRACTED,
|
|
14131
14802
|
confidence,
|
|
14132
14803
|
evidence: ep.evidence
|
|
14133
14804
|
};
|
|
@@ -14150,7 +14821,7 @@ async function addCallEdges(graph, services) {
|
|
|
14150
14821
|
|
|
14151
14822
|
// src/extract/table-edges.ts
|
|
14152
14823
|
init_cjs_shims();
|
|
14153
|
-
var
|
|
14824
|
+
var import_types46 = require("@neat.is/types");
|
|
14154
14825
|
async function addTableEdges(graph, services) {
|
|
14155
14826
|
let nodesAdded = 0;
|
|
14156
14827
|
let edgesAdded = 0;
|
|
@@ -14178,20 +14849,20 @@ async function addTableEdges(graph, services) {
|
|
|
14178
14849
|
}
|
|
14179
14850
|
refs.push(...modelRefs);
|
|
14180
14851
|
for (const ref of refs) {
|
|
14181
|
-
const childId = (0,
|
|
14182
|
-
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);
|
|
14183
14854
|
if (childId === parentId) continue;
|
|
14184
14855
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
14185
14856
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
14186
|
-
const edgeId = (0,
|
|
14857
|
+
const edgeId = (0, import_types46.extractedEdgeId)(childId, parentId, import_types46.EdgeType.REFERENCES);
|
|
14187
14858
|
if (graph.hasEdge(edgeId)) continue;
|
|
14188
14859
|
const edge = {
|
|
14189
14860
|
id: edgeId,
|
|
14190
14861
|
source: childId,
|
|
14191
14862
|
target: parentId,
|
|
14192
|
-
type:
|
|
14193
|
-
provenance:
|
|
14194
|
-
confidence: (0,
|
|
14863
|
+
type: import_types46.EdgeType.REFERENCES,
|
|
14864
|
+
provenance: import_types46.Provenance.EXTRACTED,
|
|
14865
|
+
confidence: (0, import_types46.confidenceForExtracted)("structural"),
|
|
14195
14866
|
evidence: ref.evidence
|
|
14196
14867
|
};
|
|
14197
14868
|
graph.addEdgeWithKey(edgeId, childId, parentId, edge);
|
|
@@ -14204,7 +14875,7 @@ function ensureTableNode(graph, id, name) {
|
|
|
14204
14875
|
if (graph.hasNode(id)) return 0;
|
|
14205
14876
|
const node = {
|
|
14206
14877
|
id,
|
|
14207
|
-
type:
|
|
14878
|
+
type: import_types46.NodeType.InfraNode,
|
|
14208
14879
|
name,
|
|
14209
14880
|
provider: "self",
|
|
14210
14881
|
kind: "sql-table"
|
|
@@ -14218,16 +14889,16 @@ init_cjs_shims();
|
|
|
14218
14889
|
|
|
14219
14890
|
// src/extract/infra/docker-compose.ts
|
|
14220
14891
|
init_cjs_shims();
|
|
14221
|
-
var
|
|
14222
|
-
var
|
|
14892
|
+
var import_node_path59 = __toESM(require("path"), 1);
|
|
14893
|
+
var import_types48 = require("@neat.is/types");
|
|
14223
14894
|
|
|
14224
14895
|
// src/extract/infra/shared.ts
|
|
14225
14896
|
init_cjs_shims();
|
|
14226
|
-
var
|
|
14897
|
+
var import_types47 = require("@neat.is/types");
|
|
14227
14898
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
14228
14899
|
return {
|
|
14229
|
-
id: (0,
|
|
14230
|
-
type:
|
|
14900
|
+
id: (0, import_types47.infraId)(kind, name),
|
|
14901
|
+
type: import_types47.NodeType.InfraNode,
|
|
14231
14902
|
name,
|
|
14232
14903
|
provider,
|
|
14233
14904
|
kind,
|
|
@@ -14271,8 +14942,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
14271
14942
|
source: anchorId,
|
|
14272
14943
|
target: node.id,
|
|
14273
14944
|
type: edgeType,
|
|
14274
|
-
provenance:
|
|
14275
|
-
confidence: (0,
|
|
14945
|
+
provenance: import_types47.Provenance.EXTRACTED,
|
|
14946
|
+
confidence: (0, import_types47.confidenceForExtracted)("structural"),
|
|
14276
14947
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14277
14948
|
};
|
|
14278
14949
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14289,7 +14960,7 @@ function dependsOnList(value) {
|
|
|
14289
14960
|
}
|
|
14290
14961
|
function serviceNameToServiceNode(name, services) {
|
|
14291
14962
|
for (const s of services) {
|
|
14292
|
-
if (s.node.name === name ||
|
|
14963
|
+
if (s.node.name === name || import_node_path59.default.basename(s.dir) === name) return s.node.id;
|
|
14293
14964
|
}
|
|
14294
14965
|
return null;
|
|
14295
14966
|
}
|
|
@@ -14298,7 +14969,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14298
14969
|
let edgesAdded = 0;
|
|
14299
14970
|
let composePath = null;
|
|
14300
14971
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
14301
|
-
const abs =
|
|
14972
|
+
const abs = import_node_path59.default.join(scanPath, name);
|
|
14302
14973
|
if (await exists2(abs)) {
|
|
14303
14974
|
composePath = abs;
|
|
14304
14975
|
break;
|
|
@@ -14311,13 +14982,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14311
14982
|
} catch (err) {
|
|
14312
14983
|
recordExtractionError(
|
|
14313
14984
|
"infra docker-compose",
|
|
14314
|
-
|
|
14985
|
+
import_node_path59.default.relative(scanPath, composePath),
|
|
14315
14986
|
err
|
|
14316
14987
|
);
|
|
14317
14988
|
return { nodesAdded, edgesAdded };
|
|
14318
14989
|
}
|
|
14319
14990
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
14320
|
-
const evidenceFile =
|
|
14991
|
+
const evidenceFile = import_node_path59.default.relative(scanPath, composePath).split(import_node_path59.default.sep).join("/");
|
|
14321
14992
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
14322
14993
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
14323
14994
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -14339,15 +15010,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14339
15010
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
14340
15011
|
const targetId = composeNameToNodeId.get(dep);
|
|
14341
15012
|
if (!targetId) continue;
|
|
14342
|
-
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId,
|
|
15013
|
+
const edgeId = (0, import_types3.extractedEdgeId)(sourceId, targetId, import_types48.EdgeType.DEPENDS_ON);
|
|
14343
15014
|
if (graph.hasEdge(edgeId)) continue;
|
|
14344
15015
|
const edge = {
|
|
14345
15016
|
id: edgeId,
|
|
14346
15017
|
source: sourceId,
|
|
14347
15018
|
target: targetId,
|
|
14348
|
-
type:
|
|
14349
|
-
provenance:
|
|
14350
|
-
confidence: (0,
|
|
15019
|
+
type: import_types48.EdgeType.DEPENDS_ON,
|
|
15020
|
+
provenance: import_types48.Provenance.EXTRACTED,
|
|
15021
|
+
confidence: (0, import_types48.confidenceForExtracted)("structural"),
|
|
14351
15022
|
evidence: { file: evidenceFile }
|
|
14352
15023
|
};
|
|
14353
15024
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14359,9 +15030,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14359
15030
|
|
|
14360
15031
|
// src/extract/infra/dockerfile.ts
|
|
14361
15032
|
init_cjs_shims();
|
|
14362
|
-
var
|
|
14363
|
-
var
|
|
14364
|
-
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");
|
|
14365
15036
|
function readDockerfile(content) {
|
|
14366
15037
|
let image = null;
|
|
14367
15038
|
const ports = [];
|
|
@@ -14390,15 +15061,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14390
15061
|
let nodesAdded = 0;
|
|
14391
15062
|
let edgesAdded = 0;
|
|
14392
15063
|
for (const service of services) {
|
|
14393
|
-
const dockerfilePath =
|
|
15064
|
+
const dockerfilePath = import_node_path60.default.join(service.dir, "Dockerfile");
|
|
14394
15065
|
if (!await exists2(dockerfilePath)) continue;
|
|
14395
15066
|
let content;
|
|
14396
15067
|
try {
|
|
14397
|
-
content = await
|
|
15068
|
+
content = await import_node_fs27.promises.readFile(dockerfilePath, "utf8");
|
|
14398
15069
|
} catch (err) {
|
|
14399
15070
|
recordExtractionError(
|
|
14400
15071
|
"infra dockerfile",
|
|
14401
|
-
|
|
15072
|
+
import_node_path60.default.relative(scanPath, dockerfilePath),
|
|
14402
15073
|
err
|
|
14403
15074
|
);
|
|
14404
15075
|
continue;
|
|
@@ -14410,8 +15081,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14410
15081
|
graph.addNode(node.id, node);
|
|
14411
15082
|
nodesAdded++;
|
|
14412
15083
|
}
|
|
14413
|
-
const relDockerfile = toPosix(
|
|
14414
|
-
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));
|
|
14415
15086
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14416
15087
|
graph,
|
|
14417
15088
|
service.pkg.name,
|
|
@@ -14420,15 +15091,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14420
15091
|
);
|
|
14421
15092
|
nodesAdded += fn;
|
|
14422
15093
|
edgesAdded += fe;
|
|
14423
|
-
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id,
|
|
15094
|
+
const edgeId = (0, import_types3.extractedEdgeId)(fileNodeId, node.id, import_types49.EdgeType.RUNS_ON);
|
|
14424
15095
|
if (!graph.hasEdge(edgeId)) {
|
|
14425
15096
|
const edge = {
|
|
14426
15097
|
id: edgeId,
|
|
14427
15098
|
source: fileNodeId,
|
|
14428
15099
|
target: node.id,
|
|
14429
|
-
type:
|
|
14430
|
-
provenance:
|
|
14431
|
-
confidence: (0,
|
|
15100
|
+
type: import_types49.EdgeType.RUNS_ON,
|
|
15101
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15102
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14432
15103
|
evidence: {
|
|
14433
15104
|
file: evidenceFile,
|
|
14434
15105
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -14443,15 +15114,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14443
15114
|
graph.addNode(portNode.id, portNode);
|
|
14444
15115
|
nodesAdded++;
|
|
14445
15116
|
}
|
|
14446
|
-
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id,
|
|
15117
|
+
const portEdgeId = (0, import_types3.extractedEdgeId)(fileNodeId, portNode.id, import_types49.EdgeType.CONNECTS_TO);
|
|
14447
15118
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
14448
15119
|
const portEdge = {
|
|
14449
15120
|
id: portEdgeId,
|
|
14450
15121
|
source: fileNodeId,
|
|
14451
15122
|
target: portNode.id,
|
|
14452
|
-
type:
|
|
14453
|
-
provenance:
|
|
14454
|
-
confidence: (0,
|
|
15123
|
+
type: import_types49.EdgeType.CONNECTS_TO,
|
|
15124
|
+
provenance: import_types49.Provenance.EXTRACTED,
|
|
15125
|
+
confidence: (0, import_types49.confidenceForExtracted)("structural"),
|
|
14455
15126
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
14456
15127
|
};
|
|
14457
15128
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -14463,23 +15134,23 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14463
15134
|
|
|
14464
15135
|
// src/extract/infra/terraform.ts
|
|
14465
15136
|
init_cjs_shims();
|
|
14466
|
-
var
|
|
14467
|
-
var
|
|
14468
|
-
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");
|
|
14469
15140
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
14470
15141
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
14471
15142
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
14472
15143
|
if (depth > max) return [];
|
|
14473
15144
|
const out = [];
|
|
14474
|
-
const entries = await
|
|
15145
|
+
const entries = await import_node_fs28.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
14475
15146
|
for (const entry of entries) {
|
|
14476
15147
|
if (entry.isDirectory()) {
|
|
14477
15148
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
14478
|
-
const child =
|
|
15149
|
+
const child = import_node_path61.default.join(start, entry.name);
|
|
14479
15150
|
if (await isPythonVenvDir(child)) continue;
|
|
14480
15151
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
14481
15152
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
14482
|
-
out.push(
|
|
15153
|
+
out.push(import_node_path61.default.join(start, entry.name));
|
|
14483
15154
|
}
|
|
14484
15155
|
}
|
|
14485
15156
|
return out;
|
|
@@ -14510,8 +15181,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14510
15181
|
let edgesAdded = 0;
|
|
14511
15182
|
const files = await walkTfFiles(scanPath);
|
|
14512
15183
|
for (const file of files) {
|
|
14513
|
-
const content = await
|
|
14514
|
-
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));
|
|
14515
15186
|
const resources = [];
|
|
14516
15187
|
const byKey = /* @__PURE__ */ new Map();
|
|
14517
15188
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -14546,16 +15217,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14546
15217
|
if (!target) continue;
|
|
14547
15218
|
if (seen.has(target.nodeId)) continue;
|
|
14548
15219
|
seen.add(target.nodeId);
|
|
14549
|
-
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);
|
|
14550
15221
|
if (graph.hasEdge(edgeId)) continue;
|
|
14551
15222
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
14552
15223
|
const edge = {
|
|
14553
15224
|
id: edgeId,
|
|
14554
15225
|
source: resource.nodeId,
|
|
14555
15226
|
target: target.nodeId,
|
|
14556
|
-
type:
|
|
14557
|
-
provenance:
|
|
14558
|
-
confidence: (0,
|
|
15227
|
+
type: import_types50.EdgeType.DEPENDS_ON,
|
|
15228
|
+
provenance: import_types50.Provenance.EXTRACTED,
|
|
15229
|
+
confidence: (0, import_types50.confidenceForExtracted)("structural"),
|
|
14559
15230
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
14560
15231
|
};
|
|
14561
15232
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14568,8 +15239,8 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14568
15239
|
|
|
14569
15240
|
// src/extract/infra/k8s.ts
|
|
14570
15241
|
init_cjs_shims();
|
|
14571
|
-
var
|
|
14572
|
-
var
|
|
15242
|
+
var import_node_fs29 = require("fs");
|
|
15243
|
+
var import_node_path62 = __toESM(require("path"), 1);
|
|
14573
15244
|
var import_yaml3 = require("yaml");
|
|
14574
15245
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
14575
15246
|
Service: "k8s-service",
|
|
@@ -14583,15 +15254,15 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
14583
15254
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
14584
15255
|
if (depth > max) return [];
|
|
14585
15256
|
const out = [];
|
|
14586
|
-
const entries = await
|
|
15257
|
+
const entries = await import_node_fs29.promises.readdir(start, { withFileTypes: true }).catch(() => []);
|
|
14587
15258
|
for (const entry of entries) {
|
|
14588
15259
|
if (entry.isDirectory()) {
|
|
14589
15260
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
14590
|
-
const child =
|
|
15261
|
+
const child = import_node_path62.default.join(start, entry.name);
|
|
14591
15262
|
if (await isPythonVenvDir(child)) continue;
|
|
14592
15263
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
14593
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
14594
|
-
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));
|
|
14595
15266
|
}
|
|
14596
15267
|
}
|
|
14597
15268
|
return out;
|
|
@@ -14600,7 +15271,7 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14600
15271
|
let nodesAdded = 0;
|
|
14601
15272
|
const files = await walkYamlFiles2(scanPath);
|
|
14602
15273
|
for (const file of files) {
|
|
14603
|
-
const content = await
|
|
15274
|
+
const content = await import_node_fs29.promises.readFile(file, "utf8");
|
|
14604
15275
|
let docs;
|
|
14605
15276
|
try {
|
|
14606
15277
|
docs = (0, import_yaml3.parseAllDocuments)(content).map((d) => d.toJSON());
|
|
@@ -14624,16 +15295,16 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14624
15295
|
|
|
14625
15296
|
// src/extract/infra/cloudflare.ts
|
|
14626
15297
|
init_cjs_shims();
|
|
14627
|
-
var
|
|
14628
|
-
var
|
|
15298
|
+
var import_node_fs30 = require("fs");
|
|
15299
|
+
var import_node_path63 = __toESM(require("path"), 1);
|
|
14629
15300
|
var import_smol_toml3 = require("smol-toml");
|
|
14630
|
-
var
|
|
15301
|
+
var import_types51 = require("@neat.is/types");
|
|
14631
15302
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
14632
15303
|
async function readWranglerConfig(dir) {
|
|
14633
15304
|
for (const filename of WRANGLER_FILENAMES) {
|
|
14634
|
-
const abs =
|
|
15305
|
+
const abs = import_node_path63.default.join(dir, filename);
|
|
14635
15306
|
if (!await exists2(abs)) continue;
|
|
14636
|
-
const raw = await
|
|
15307
|
+
const raw = await import_node_fs30.promises.readFile(abs, "utf8");
|
|
14637
15308
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14638
15309
|
return { config, relFile: filename, raw };
|
|
14639
15310
|
}
|
|
@@ -14675,8 +15346,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
14675
15346
|
source: anchorId,
|
|
14676
15347
|
target: node.id,
|
|
14677
15348
|
type: edgeType,
|
|
14678
|
-
provenance:
|
|
14679
|
-
confidence: (0,
|
|
15349
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15350
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14680
15351
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
14681
15352
|
};
|
|
14682
15353
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14694,11 +15365,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14694
15365
|
try {
|
|
14695
15366
|
read = await readWranglerConfig(service.dir);
|
|
14696
15367
|
} catch (err) {
|
|
14697
|
-
recordExtractionError("infra cloudflare",
|
|
15368
|
+
recordExtractionError("infra cloudflare", import_node_path63.default.relative(scanPath, service.dir), err);
|
|
14698
15369
|
continue;
|
|
14699
15370
|
}
|
|
14700
15371
|
if (!read || !read.config.name) continue;
|
|
14701
|
-
const evidenceFile = toPosix(
|
|
15372
|
+
const evidenceFile = toPosix(import_node_path63.default.relative(scanPath, import_node_path63.default.join(service.dir, read.relFile)));
|
|
14702
15373
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
14703
15374
|
}
|
|
14704
15375
|
for (const worker of discovered) {
|
|
@@ -14710,7 +15381,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14710
15381
|
}
|
|
14711
15382
|
let anchorId = service.node.id;
|
|
14712
15383
|
if (config.main) {
|
|
14713
|
-
const entryRelPath = toPosix(
|
|
15384
|
+
const entryRelPath = toPosix(import_node_path63.default.normalize(config.main));
|
|
14714
15385
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14715
15386
|
graph,
|
|
14716
15387
|
service.pkg.name,
|
|
@@ -14737,15 +15408,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14737
15408
|
nodesAdded++;
|
|
14738
15409
|
}
|
|
14739
15410
|
if (runtimeNode.id !== anchorId) {
|
|
14740
|
-
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
15411
|
+
const runsOnId = (0, import_types3.extractedEdgeId)(anchorId, runtimeNode.id, import_types51.EdgeType.RUNS_ON);
|
|
14741
15412
|
if (!graph.hasEdge(runsOnId)) {
|
|
14742
15413
|
const edge = {
|
|
14743
15414
|
id: runsOnId,
|
|
14744
15415
|
source: anchorId,
|
|
14745
15416
|
target: runtimeNode.id,
|
|
14746
|
-
type:
|
|
14747
|
-
provenance:
|
|
14748
|
-
confidence: (0,
|
|
15417
|
+
type: import_types51.EdgeType.RUNS_ON,
|
|
15418
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15419
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14749
15420
|
evidence: {
|
|
14750
15421
|
file: evidenceFile,
|
|
14751
15422
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -14759,7 +15430,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14759
15430
|
const result = addResourceEdge(
|
|
14760
15431
|
graph,
|
|
14761
15432
|
anchorId,
|
|
14762
|
-
|
|
15433
|
+
import_types51.EdgeType.CONNECTS_TO,
|
|
14763
15434
|
"cloudflare-route",
|
|
14764
15435
|
route,
|
|
14765
15436
|
evidenceFile,
|
|
@@ -14783,7 +15454,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14783
15454
|
const result = addResourceEdge(
|
|
14784
15455
|
graph,
|
|
14785
15456
|
anchorId,
|
|
14786
|
-
|
|
15457
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14787
15458
|
group.kind,
|
|
14788
15459
|
name,
|
|
14789
15460
|
evidenceFile,
|
|
@@ -14797,7 +15468,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14797
15468
|
const result = addResourceEdge(
|
|
14798
15469
|
graph,
|
|
14799
15470
|
anchorId,
|
|
14800
|
-
|
|
15471
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14801
15472
|
"cloudflare-cron",
|
|
14802
15473
|
cron,
|
|
14803
15474
|
evidenceFile,
|
|
@@ -14810,7 +15481,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14810
15481
|
const result = addResourceEdge(
|
|
14811
15482
|
graph,
|
|
14812
15483
|
anchorId,
|
|
14813
|
-
|
|
15484
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14814
15485
|
"cloudflare-env-var",
|
|
14815
15486
|
varName,
|
|
14816
15487
|
evidenceFile,
|
|
@@ -14823,15 +15494,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14823
15494
|
if (!svc.service) continue;
|
|
14824
15495
|
const target = workerIndex.get(svc.service);
|
|
14825
15496
|
if (target && target.anchorId !== anchorId) {
|
|
14826
|
-
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId,
|
|
15497
|
+
const edgeId = (0, import_types3.extractedEdgeId)(anchorId, target.anchorId, import_types51.EdgeType.CALLS);
|
|
14827
15498
|
if (!graph.hasEdge(edgeId)) {
|
|
14828
15499
|
const edge = {
|
|
14829
15500
|
id: edgeId,
|
|
14830
15501
|
source: anchorId,
|
|
14831
15502
|
target: target.anchorId,
|
|
14832
|
-
type:
|
|
14833
|
-
provenance:
|
|
14834
|
-
confidence: (0,
|
|
15503
|
+
type: import_types51.EdgeType.CALLS,
|
|
15504
|
+
provenance: import_types51.Provenance.EXTRACTED,
|
|
15505
|
+
confidence: (0, import_types51.confidenceForExtracted)("structural"),
|
|
14835
15506
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
14836
15507
|
};
|
|
14837
15508
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -14842,7 +15513,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14842
15513
|
const result = addResourceEdge(
|
|
14843
15514
|
graph,
|
|
14844
15515
|
anchorId,
|
|
14845
|
-
|
|
15516
|
+
import_types51.EdgeType.DEPENDS_ON,
|
|
14846
15517
|
"cloudflare-service-binding",
|
|
14847
15518
|
svc.service,
|
|
14848
15519
|
evidenceFile,
|
|
@@ -14857,24 +15528,24 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14857
15528
|
|
|
14858
15529
|
// src/extract/infra/vercel.ts
|
|
14859
15530
|
init_cjs_shims();
|
|
14860
|
-
var
|
|
14861
|
-
var
|
|
14862
|
-
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");
|
|
14863
15534
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
14864
15535
|
async function readVercelConfig(dir) {
|
|
14865
15536
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
14866
|
-
const abs =
|
|
15537
|
+
const abs = import_node_path64.default.join(dir, filename);
|
|
14867
15538
|
if (!await exists2(abs)) continue;
|
|
14868
|
-
const raw = await
|
|
15539
|
+
const raw = await import_node_fs31.promises.readFile(abs, "utf8");
|
|
14869
15540
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
14870
15541
|
return { config, relFile: filename, raw };
|
|
14871
15542
|
}
|
|
14872
15543
|
return null;
|
|
14873
15544
|
}
|
|
14874
15545
|
async function readLinkedProjectName(dir) {
|
|
14875
|
-
const abs =
|
|
15546
|
+
const abs = import_node_path64.default.join(dir, ".vercel", "project.json");
|
|
14876
15547
|
if (!await exists2(abs)) return void 0;
|
|
14877
|
-
const parsed = JSON.parse(await
|
|
15548
|
+
const parsed = JSON.parse(await import_node_fs31.promises.readFile(abs, "utf8"));
|
|
14878
15549
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
14879
15550
|
}
|
|
14880
15551
|
function routeSource(route) {
|
|
@@ -14890,7 +15561,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14890
15561
|
read = await readVercelConfig(service.dir);
|
|
14891
15562
|
projectName = await readLinkedProjectName(service.dir);
|
|
14892
15563
|
} catch (err) {
|
|
14893
|
-
recordExtractionError("infra vercel",
|
|
15564
|
+
recordExtractionError("infra vercel", import_node_path64.default.relative(scanPath, service.dir), err);
|
|
14894
15565
|
continue;
|
|
14895
15566
|
}
|
|
14896
15567
|
if (!read && !projectName) continue;
|
|
@@ -14906,7 +15577,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14906
15577
|
const anchorId = service.node.id;
|
|
14907
15578
|
if (!read) continue;
|
|
14908
15579
|
const { config, relFile, raw } = read;
|
|
14909
|
-
const evidenceFile = toPosix(
|
|
15580
|
+
const evidenceFile = toPosix(import_node_path64.default.relative(scanPath, import_node_path64.default.join(service.dir, relFile)));
|
|
14910
15581
|
const add = (edgeType, kind, name) => {
|
|
14911
15582
|
if (!name) return;
|
|
14912
15583
|
const result = emitPlatformResourceEdge(
|
|
@@ -14922,12 +15593,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14922
15593
|
nodesAdded += result.nodesAdded;
|
|
14923
15594
|
edgesAdded += result.edgesAdded;
|
|
14924
15595
|
};
|
|
14925
|
-
add(
|
|
14926
|
-
for (const cron of config.crons ?? []) add(
|
|
14927
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
14928
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
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);
|
|
14929
15600
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
14930
|
-
add(
|
|
15601
|
+
add(import_types52.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
14931
15602
|
}
|
|
14932
15603
|
}
|
|
14933
15604
|
return { nodesAdded, edgesAdded };
|
|
@@ -14935,16 +15606,16 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14935
15606
|
|
|
14936
15607
|
// src/extract/infra/railway.ts
|
|
14937
15608
|
init_cjs_shims();
|
|
14938
|
-
var
|
|
14939
|
-
var
|
|
15609
|
+
var import_node_fs32 = require("fs");
|
|
15610
|
+
var import_node_path65 = __toESM(require("path"), 1);
|
|
14940
15611
|
var import_smol_toml4 = require("smol-toml");
|
|
14941
|
-
var
|
|
15612
|
+
var import_types53 = require("@neat.is/types");
|
|
14942
15613
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
14943
15614
|
async function readRailwayConfig(dir) {
|
|
14944
15615
|
for (const filename of RAILWAY_FILENAMES) {
|
|
14945
|
-
const abs =
|
|
15616
|
+
const abs = import_node_path65.default.join(dir, filename);
|
|
14946
15617
|
if (!await exists2(abs)) continue;
|
|
14947
|
-
const raw = await
|
|
15618
|
+
const raw = await import_node_fs32.promises.readFile(abs, "utf8");
|
|
14948
15619
|
const config = filename === "railway.toml" ? (0, import_smol_toml4.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
14949
15620
|
return { config, relFile: filename, raw };
|
|
14950
15621
|
}
|
|
@@ -14958,7 +15629,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14958
15629
|
try {
|
|
14959
15630
|
read = await readRailwayConfig(service.dir);
|
|
14960
15631
|
} catch (err) {
|
|
14961
|
-
recordExtractionError("infra railway",
|
|
15632
|
+
recordExtractionError("infra railway", import_node_path65.default.relative(scanPath, service.dir), err);
|
|
14962
15633
|
continue;
|
|
14963
15634
|
}
|
|
14964
15635
|
if (!read) continue;
|
|
@@ -14968,7 +15639,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14968
15639
|
}
|
|
14969
15640
|
const anchorId = service.node.id;
|
|
14970
15641
|
const { config, relFile, raw } = read;
|
|
14971
|
-
const evidenceFile = toPosix(
|
|
15642
|
+
const evidenceFile = toPosix(import_node_path65.default.relative(scanPath, import_node_path65.default.join(service.dir, relFile)));
|
|
14972
15643
|
const add = (edgeType, kind, name) => {
|
|
14973
15644
|
if (!name) return;
|
|
14974
15645
|
const result = emitPlatformResourceEdge(
|
|
@@ -14984,24 +15655,24 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14984
15655
|
nodesAdded += result.nodesAdded;
|
|
14985
15656
|
edgesAdded += result.edgesAdded;
|
|
14986
15657
|
};
|
|
14987
|
-
add(
|
|
14988
|
-
add(
|
|
14989
|
-
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);
|
|
14990
15661
|
}
|
|
14991
15662
|
return { nodesAdded, edgesAdded };
|
|
14992
15663
|
}
|
|
14993
15664
|
|
|
14994
15665
|
// src/extract/infra/supabase.ts
|
|
14995
15666
|
init_cjs_shims();
|
|
14996
|
-
var
|
|
14997
|
-
var
|
|
15667
|
+
var import_node_fs33 = require("fs");
|
|
15668
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
14998
15669
|
var import_smol_toml5 = require("smol-toml");
|
|
14999
|
-
var
|
|
15670
|
+
var import_types54 = require("@neat.is/types");
|
|
15000
15671
|
async function readSupabaseConfig(dir) {
|
|
15001
|
-
const relFile =
|
|
15002
|
-
const abs =
|
|
15672
|
+
const relFile = import_node_path66.default.join("supabase", "config.toml");
|
|
15673
|
+
const abs = import_node_path66.default.join(dir, relFile);
|
|
15003
15674
|
if (!await exists2(abs)) return null;
|
|
15004
|
-
const raw = await
|
|
15675
|
+
const raw = await import_node_fs33.promises.readFile(abs, "utf8");
|
|
15005
15676
|
const config = (0, import_smol_toml5.parse)(raw);
|
|
15006
15677
|
return { config, relFile, raw };
|
|
15007
15678
|
}
|
|
@@ -15013,7 +15684,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15013
15684
|
try {
|
|
15014
15685
|
read = await readSupabaseConfig(service.dir);
|
|
15015
15686
|
} catch (err) {
|
|
15016
|
-
recordExtractionError("infra supabase",
|
|
15687
|
+
recordExtractionError("infra supabase", import_node_path66.default.relative(scanPath, service.dir), err);
|
|
15017
15688
|
continue;
|
|
15018
15689
|
}
|
|
15019
15690
|
if (!read) continue;
|
|
@@ -15028,7 +15699,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15028
15699
|
});
|
|
15029
15700
|
}
|
|
15030
15701
|
const anchorId = service.node.id;
|
|
15031
|
-
const evidenceFile = toPosix(
|
|
15702
|
+
const evidenceFile = toPosix(import_node_path66.default.relative(scanPath, import_node_path66.default.join(service.dir, relFile)));
|
|
15032
15703
|
const add = (edgeType, kind, name) => {
|
|
15033
15704
|
if (!name) return;
|
|
15034
15705
|
const result = emitPlatformResourceEdge(
|
|
@@ -15044,10 +15715,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
15044
15715
|
nodesAdded += result.nodesAdded;
|
|
15045
15716
|
edgesAdded += result.edgesAdded;
|
|
15046
15717
|
};
|
|
15047
|
-
add(
|
|
15048
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
15049
|
-
if (config.storage) add(
|
|
15050
|
-
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");
|
|
15051
15722
|
}
|
|
15052
15723
|
return { nodesAdded, edgesAdded };
|
|
15053
15724
|
}
|
|
@@ -15070,14 +15741,14 @@ async function addInfra(graph, scanPath, services) {
|
|
|
15070
15741
|
|
|
15071
15742
|
// src/extract/zod-shapes.ts
|
|
15072
15743
|
init_cjs_shims();
|
|
15073
|
-
var
|
|
15074
|
-
var
|
|
15744
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
15745
|
+
var import_tree_sitter17 = __toESM(require("tree-sitter"), 1);
|
|
15075
15746
|
var import_tree_sitter_javascript8 = __toESM(require("tree-sitter-javascript"), 1);
|
|
15076
|
-
var
|
|
15747
|
+
var import_types55 = require("@neat.is/types");
|
|
15077
15748
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
15078
15749
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
15079
15750
|
function parserForExt4(ext) {
|
|
15080
|
-
const p = new
|
|
15751
|
+
const p = new import_tree_sitter17.default();
|
|
15081
15752
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? import_tree_sitter_javascript8.default);
|
|
15082
15753
|
return p;
|
|
15083
15754
|
}
|
|
@@ -15165,7 +15836,7 @@ function topLevelSchemas(root) {
|
|
|
15165
15836
|
}
|
|
15166
15837
|
function zodShapesFromFile(file, serviceDir) {
|
|
15167
15838
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
15168
|
-
const tree = parseSource3(parserForExt4(
|
|
15839
|
+
const tree = parseSource3(parserForExt4(import_node_path67.default.extname(file.path)), file.content);
|
|
15169
15840
|
const out = [];
|
|
15170
15841
|
const seen = /* @__PURE__ */ new Set();
|
|
15171
15842
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -15179,11 +15850,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
15179
15850
|
seen.add(name);
|
|
15180
15851
|
const line = call.startPosition.row + 1;
|
|
15181
15852
|
out.push({
|
|
15182
|
-
infraId: (0,
|
|
15853
|
+
infraId: (0, import_types55.infraId)("zod-schema", name),
|
|
15183
15854
|
name,
|
|
15184
15855
|
fields,
|
|
15185
15856
|
evidence: {
|
|
15186
|
-
file:
|
|
15857
|
+
file: import_node_path67.default.relative(serviceDir, file.path),
|
|
15187
15858
|
line,
|
|
15188
15859
|
snippet: snippet(file.content, line)
|
|
15189
15860
|
}
|
|
@@ -15214,7 +15885,7 @@ async function addZodShapes(graph, services) {
|
|
|
15214
15885
|
if (!graph.hasNode(shape.infraId)) {
|
|
15215
15886
|
const node = {
|
|
15216
15887
|
id: shape.infraId,
|
|
15217
|
-
type:
|
|
15888
|
+
type: import_types55.NodeType.InfraNode,
|
|
15218
15889
|
name: shape.name,
|
|
15219
15890
|
provider: "self",
|
|
15220
15891
|
kind: "zod-schema"
|
|
@@ -15224,14 +15895,14 @@ async function addZodShapes(graph, services) {
|
|
|
15224
15895
|
}
|
|
15225
15896
|
if (shape.fields.length > 0) {
|
|
15226
15897
|
const node = graph.getNodeAttributes(shape.infraId);
|
|
15227
|
-
if (node.type ===
|
|
15898
|
+
if (node.type === import_types55.NodeType.InfraNode) {
|
|
15228
15899
|
graph.replaceNodeAttributes(shape.infraId, {
|
|
15229
15900
|
...node,
|
|
15230
15901
|
columns: foldColumns(
|
|
15231
15902
|
node.columns,
|
|
15232
15903
|
shape.fields,
|
|
15233
|
-
|
|
15234
|
-
(0,
|
|
15904
|
+
import_types55.Provenance.EXTRACTED,
|
|
15905
|
+
(0, import_types55.confidenceForExtracted)("structural")
|
|
15235
15906
|
)
|
|
15236
15907
|
});
|
|
15237
15908
|
}
|
|
@@ -15245,15 +15916,15 @@ async function addZodShapes(graph, services) {
|
|
|
15245
15916
|
);
|
|
15246
15917
|
nodesAdded += n;
|
|
15247
15918
|
edgesAdded += e;
|
|
15248
|
-
const edgeId = (0,
|
|
15919
|
+
const edgeId = (0, import_types55.extractedEdgeId)(fileNodeId, shape.infraId, import_types55.EdgeType.CONTAINS);
|
|
15249
15920
|
if (!graph.hasEdge(edgeId)) {
|
|
15250
15921
|
const edge = {
|
|
15251
15922
|
id: edgeId,
|
|
15252
15923
|
source: fileNodeId,
|
|
15253
15924
|
target: shape.infraId,
|
|
15254
|
-
type:
|
|
15255
|
-
provenance:
|
|
15256
|
-
confidence: (0,
|
|
15925
|
+
type: import_types55.EdgeType.CONTAINS,
|
|
15926
|
+
provenance: import_types55.Provenance.EXTRACTED,
|
|
15927
|
+
confidence: (0, import_types55.confidenceForExtracted)("structural"),
|
|
15257
15928
|
evidence: shape.evidence
|
|
15258
15929
|
};
|
|
15259
15930
|
graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge);
|
|
@@ -15267,7 +15938,7 @@ async function addZodShapes(graph, services) {
|
|
|
15267
15938
|
|
|
15268
15939
|
// src/extract/firestore-rules.ts
|
|
15269
15940
|
init_cjs_shims();
|
|
15270
|
-
var
|
|
15941
|
+
var import_types56 = require("@neat.is/types");
|
|
15271
15942
|
var FIRESTORE_COLLECTION_KIND = "firestore-collection";
|
|
15272
15943
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["write", "create", "update"]);
|
|
15273
15944
|
function stripComments(src) {
|
|
@@ -15407,7 +16078,7 @@ async function addFirestoreRules(graph, services) {
|
|
|
15407
16078
|
if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 };
|
|
15408
16079
|
graph.forEachNode((id, attrs) => {
|
|
15409
16080
|
const node = attrs;
|
|
15410
|
-
if (node.type !==
|
|
16081
|
+
if (node.type !== import_types56.NodeType.InfraNode) return;
|
|
15411
16082
|
if (node.kind !== FIRESTORE_COLLECTION_KIND) return;
|
|
15412
16083
|
const fields = guards.get(collectionKeyFromName(node.name));
|
|
15413
16084
|
if (!fields || fields.size === 0) return;
|
|
@@ -15420,17 +16091,17 @@ async function addFirestoreRules(graph, services) {
|
|
|
15420
16091
|
}
|
|
15421
16092
|
|
|
15422
16093
|
// src/extract/index.ts
|
|
15423
|
-
var
|
|
16094
|
+
var import_node_path69 = __toESM(require("path"), 1);
|
|
15424
16095
|
|
|
15425
16096
|
// src/extract/retire.ts
|
|
15426
16097
|
init_cjs_shims();
|
|
15427
|
-
var
|
|
15428
|
-
var
|
|
15429
|
-
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");
|
|
15430
16101
|
function dropOrphanedFileNodes(graph) {
|
|
15431
16102
|
const orphans = [];
|
|
15432
16103
|
graph.forEachNode((id, attrs) => {
|
|
15433
|
-
if (attrs.type !==
|
|
16104
|
+
if (attrs.type !== import_types57.NodeType.FileNode) return;
|
|
15434
16105
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
15435
16106
|
orphans.push(id);
|
|
15436
16107
|
}
|
|
@@ -15443,14 +16114,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
15443
16114
|
const bases = [scanPath, ...serviceDirs];
|
|
15444
16115
|
graph.forEachEdge((id, attrs) => {
|
|
15445
16116
|
const edge = attrs;
|
|
15446
|
-
if (edge.provenance !==
|
|
16117
|
+
if (edge.provenance !== import_types57.Provenance.EXTRACTED) return;
|
|
15447
16118
|
const evidenceFile = edge.evidence?.file;
|
|
15448
16119
|
if (!evidenceFile) return;
|
|
15449
|
-
if (
|
|
15450
|
-
if (!(0,
|
|
16120
|
+
if (import_node_path68.default.isAbsolute(evidenceFile)) {
|
|
16121
|
+
if (!(0, import_node_fs34.existsSync)(evidenceFile)) toDrop.push(id);
|
|
15451
16122
|
return;
|
|
15452
16123
|
}
|
|
15453
|
-
const found = bases.some((base) => (0,
|
|
16124
|
+
const found = bases.some((base) => (0, import_node_fs34.existsSync)(import_node_path68.default.join(base, evidenceFile)));
|
|
15454
16125
|
if (!found) toDrop.push(id);
|
|
15455
16126
|
});
|
|
15456
16127
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -15507,7 +16178,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15507
16178
|
}
|
|
15508
16179
|
const droppedEntries = drainDroppedExtracted();
|
|
15509
16180
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
15510
|
-
const rejectedPath =
|
|
16181
|
+
const rejectedPath = import_node_path69.default.join(import_node_path69.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
15511
16182
|
try {
|
|
15512
16183
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
15513
16184
|
} catch (err) {
|
|
@@ -15541,7 +16212,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15541
16212
|
|
|
15542
16213
|
// src/diff.ts
|
|
15543
16214
|
init_cjs_shims();
|
|
15544
|
-
var
|
|
16215
|
+
var import_node_fs35 = require("fs");
|
|
15545
16216
|
async function loadSnapshotForDiff(target) {
|
|
15546
16217
|
if (/^https?:\/\//i.test(target)) {
|
|
15547
16218
|
const res = await fetch(target);
|
|
@@ -15550,7 +16221,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
15550
16221
|
}
|
|
15551
16222
|
return await res.json();
|
|
15552
16223
|
}
|
|
15553
|
-
const raw = await
|
|
16224
|
+
const raw = await import_node_fs35.promises.readFile(target, "utf8");
|
|
15554
16225
|
return JSON.parse(raw);
|
|
15555
16226
|
}
|
|
15556
16227
|
function indexEntries(entries) {
|
|
@@ -15618,9 +16289,9 @@ function canonicalJson(value) {
|
|
|
15618
16289
|
|
|
15619
16290
|
// src/persist.ts
|
|
15620
16291
|
init_cjs_shims();
|
|
15621
|
-
var
|
|
15622
|
-
var
|
|
15623
|
-
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");
|
|
15624
16295
|
var SCHEMA_VERSION = 7;
|
|
15625
16296
|
function migrateV1ToV2(payload) {
|
|
15626
16297
|
const nodes = payload.graph.nodes;
|
|
@@ -15644,7 +16315,7 @@ function migrateV5ToV6(payload) {
|
|
|
15644
16315
|
if (Array.isArray(nodes)) {
|
|
15645
16316
|
for (const node of nodes) {
|
|
15646
16317
|
const attrs = node.attributes;
|
|
15647
|
-
if (!attrs || attrs.type !==
|
|
16318
|
+
if (!attrs || attrs.type !== import_types58.NodeType.InfraNode) continue;
|
|
15648
16319
|
if (attrs.kind !== "sql-table" && attrs.kind !== "supabase-table") continue;
|
|
15649
16320
|
if (!Array.isArray(attrs.columns)) attrs.columns = [];
|
|
15650
16321
|
}
|
|
@@ -15660,12 +16331,12 @@ function migrateV2ToV3(payload) {
|
|
|
15660
16331
|
for (const edge of edges) {
|
|
15661
16332
|
const attrs = edge.attributes;
|
|
15662
16333
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
15663
|
-
attrs.provenance =
|
|
16334
|
+
attrs.provenance = import_types58.Provenance.OBSERVED;
|
|
15664
16335
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
15665
16336
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
15666
16337
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
15667
16338
|
if (type && source && target) {
|
|
15668
|
-
const newId = (0,
|
|
16339
|
+
const newId = (0, import_types58.observedEdgeId)(source, target, type);
|
|
15669
16340
|
attrs.id = newId;
|
|
15670
16341
|
if (edge.key) edge.key = newId;
|
|
15671
16342
|
}
|
|
@@ -15674,7 +16345,7 @@ function migrateV2ToV3(payload) {
|
|
|
15674
16345
|
return { ...payload, schemaVersion: 3 };
|
|
15675
16346
|
}
|
|
15676
16347
|
async function ensureDir(filePath) {
|
|
15677
|
-
await
|
|
16348
|
+
await import_node_fs36.promises.mkdir(import_node_path70.default.dirname(filePath), { recursive: true });
|
|
15678
16349
|
}
|
|
15679
16350
|
async function saveGraphToDisk(graph, outPath) {
|
|
15680
16351
|
await ensureDir(outPath);
|
|
@@ -15684,13 +16355,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
15684
16355
|
graph: graph.export()
|
|
15685
16356
|
};
|
|
15686
16357
|
const tmp = `${outPath}.tmp`;
|
|
15687
|
-
await
|
|
15688
|
-
await
|
|
16358
|
+
await import_node_fs36.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
16359
|
+
await import_node_fs36.promises.rename(tmp, outPath);
|
|
15689
16360
|
}
|
|
15690
16361
|
async function loadGraphFromDisk(graph, outPath) {
|
|
15691
16362
|
let raw;
|
|
15692
16363
|
try {
|
|
15693
|
-
raw = await
|
|
16364
|
+
raw = await import_node_fs36.promises.readFile(outPath, "utf8");
|
|
15694
16365
|
} catch (err) {
|
|
15695
16366
|
if (err.code === "ENOENT") return;
|
|
15696
16367
|
throw err;
|
|
@@ -15764,23 +16435,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
15764
16435
|
|
|
15765
16436
|
// src/projects.ts
|
|
15766
16437
|
init_cjs_shims();
|
|
15767
|
-
var
|
|
16438
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
15768
16439
|
function pathsForProject(project, baseDir) {
|
|
15769
16440
|
if (project === DEFAULT_PROJECT) {
|
|
15770
16441
|
return {
|
|
15771
|
-
snapshotPath:
|
|
15772
|
-
errorsPath:
|
|
15773
|
-
staleEventsPath:
|
|
15774
|
-
embeddingsCachePath:
|
|
15775
|
-
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")
|
|
15776
16447
|
};
|
|
15777
16448
|
}
|
|
15778
16449
|
return {
|
|
15779
|
-
snapshotPath:
|
|
15780
|
-
errorsPath:
|
|
15781
|
-
staleEventsPath:
|
|
15782
|
-
embeddingsCachePath:
|
|
15783
|
-
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`)
|
|
15784
16455
|
};
|
|
15785
16456
|
}
|
|
15786
16457
|
var Projects = class {
|
|
@@ -15820,20 +16491,20 @@ function parseExtraProjects(raw) {
|
|
|
15820
16491
|
|
|
15821
16492
|
// src/registry.ts
|
|
15822
16493
|
init_cjs_shims();
|
|
15823
|
-
var
|
|
16494
|
+
var import_node_fs37 = require("fs");
|
|
15824
16495
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
15825
|
-
var
|
|
15826
|
-
var
|
|
16496
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
16497
|
+
var import_types59 = require("@neat.is/types");
|
|
15827
16498
|
function neatHome() {
|
|
15828
16499
|
const override = process.env.NEAT_HOME;
|
|
15829
|
-
if (override && override.length > 0) return
|
|
15830
|
-
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");
|
|
15831
16502
|
}
|
|
15832
16503
|
function registryPath() {
|
|
15833
|
-
return
|
|
16504
|
+
return import_node_path72.default.join(neatHome(), "projects.json");
|
|
15834
16505
|
}
|
|
15835
16506
|
function daemonsDir() {
|
|
15836
|
-
return
|
|
16507
|
+
return import_node_path72.default.join(neatHome(), "daemons");
|
|
15837
16508
|
}
|
|
15838
16509
|
function isFiniteInt(v) {
|
|
15839
16510
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -15866,7 +16537,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15866
16537
|
const dir = daemonsDir();
|
|
15867
16538
|
let names;
|
|
15868
16539
|
try {
|
|
15869
|
-
names = await
|
|
16540
|
+
names = await import_node_fs37.promises.readdir(dir);
|
|
15870
16541
|
} catch (err) {
|
|
15871
16542
|
if (err.code === "ENOENT") return [];
|
|
15872
16543
|
throw err;
|
|
@@ -15874,10 +16545,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
15874
16545
|
const out = [];
|
|
15875
16546
|
for (const name of names) {
|
|
15876
16547
|
if (!name.endsWith(".json")) continue;
|
|
15877
|
-
const file =
|
|
16548
|
+
const file = import_node_path72.default.join(dir, name);
|
|
15878
16549
|
let raw;
|
|
15879
16550
|
try {
|
|
15880
|
-
raw = await
|
|
16551
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15881
16552
|
} catch {
|
|
15882
16553
|
continue;
|
|
15883
16554
|
}
|
|
@@ -15905,7 +16576,7 @@ async function readRegistry() {
|
|
|
15905
16576
|
const file = registryPath();
|
|
15906
16577
|
let raw;
|
|
15907
16578
|
try {
|
|
15908
|
-
raw = await
|
|
16579
|
+
raw = await import_node_fs37.promises.readFile(file, "utf8");
|
|
15909
16580
|
} catch (err) {
|
|
15910
16581
|
if (err.code === "ENOENT") {
|
|
15911
16582
|
return { version: 1, projects: [] };
|
|
@@ -15913,7 +16584,7 @@ async function readRegistry() {
|
|
|
15913
16584
|
throw err;
|
|
15914
16585
|
}
|
|
15915
16586
|
const parsed = JSON.parse(raw);
|
|
15916
|
-
return
|
|
16587
|
+
return import_types59.RegistryFileSchema.parse(parsed);
|
|
15917
16588
|
}
|
|
15918
16589
|
async function getProject(name) {
|
|
15919
16590
|
const reg = await readRegistry();
|
|
@@ -15988,8 +16659,8 @@ init_auth();
|
|
|
15988
16659
|
// src/connectors-config.ts
|
|
15989
16660
|
init_cjs_shims();
|
|
15990
16661
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
15991
|
-
var
|
|
15992
|
-
var
|
|
16662
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
16663
|
+
var import_node_fs38 = require("fs");
|
|
15993
16664
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
15994
16665
|
var EnvRefUnsetError = class extends Error {
|
|
15995
16666
|
ref;
|
|
@@ -16003,17 +16674,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
16003
16674
|
};
|
|
16004
16675
|
function neatHome2() {
|
|
16005
16676
|
const override = process.env.NEAT_HOME;
|
|
16006
|
-
if (override && override.length > 0) return
|
|
16007
|
-
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");
|
|
16008
16679
|
}
|
|
16009
16680
|
function connectorsConfigPath(home = neatHome2()) {
|
|
16010
|
-
return
|
|
16681
|
+
return import_node_path73.default.join(home, "connectors.json");
|
|
16011
16682
|
}
|
|
16012
16683
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
16013
16684
|
async function warnIfModeLooserThan0600(file) {
|
|
16014
16685
|
if (process.platform === "win32") return;
|
|
16015
16686
|
try {
|
|
16016
|
-
const stat = await
|
|
16687
|
+
const stat = await import_node_fs38.promises.stat(file);
|
|
16017
16688
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
16018
16689
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
16019
16690
|
console.warn(
|
|
@@ -16027,7 +16698,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
16027
16698
|
const file = connectorsConfigPath(home);
|
|
16028
16699
|
let raw;
|
|
16029
16700
|
try {
|
|
16030
|
-
raw = await
|
|
16701
|
+
raw = await import_node_fs38.promises.readFile(file, "utf8");
|
|
16031
16702
|
} catch (err) {
|
|
16032
16703
|
if (err.code === "ENOENT") {
|
|
16033
16704
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -16194,15 +16865,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
16194
16865
|
|
|
16195
16866
|
// src/connectors/index.ts
|
|
16196
16867
|
init_cjs_shims();
|
|
16197
|
-
var
|
|
16868
|
+
var import_types60 = require("@neat.is/types");
|
|
16198
16869
|
var NO_ENV = "unknown";
|
|
16199
16870
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
16200
16871
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16201
16872
|
const sites = [];
|
|
16202
16873
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
16203
16874
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
16204
|
-
if (edge.provenance !==
|
|
16205
|
-
const parsed = (0,
|
|
16875
|
+
if (edge.provenance !== import_types60.Provenance.EXTRACTED) continue;
|
|
16876
|
+
const parsed = (0, import_types60.parseFileId)(edge.source);
|
|
16206
16877
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
16207
16878
|
const site = { relPath: edge.evidence.file };
|
|
16208
16879
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -16213,7 +16884,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
16213
16884
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
16214
16885
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
16215
16886
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
16216
|
-
if (attrs.type !==
|
|
16887
|
+
if (attrs.type !== import_types60.NodeType.RouteNode || !attrs.path) return void 0;
|
|
16217
16888
|
const site = { relPath: attrs.path };
|
|
16218
16889
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
16219
16890
|
return site;
|
|
@@ -16670,10 +17341,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
16670
17341
|
// src/connectors/supabase/map.ts
|
|
16671
17342
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
16672
17343
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
16673
|
-
function targetFromRestPath(
|
|
16674
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
17344
|
+
function targetFromRestPath(path76) {
|
|
17345
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path76);
|
|
16675
17346
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
16676
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
17347
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path76);
|
|
16677
17348
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
16678
17349
|
return null;
|
|
16679
17350
|
}
|
|
@@ -16784,23 +17455,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
16784
17455
|
|
|
16785
17456
|
// src/connectors/supabase/resolve.ts
|
|
16786
17457
|
init_cjs_shims();
|
|
16787
|
-
var
|
|
17458
|
+
var import_types62 = require("@neat.is/types");
|
|
16788
17459
|
function createSupabaseResolveTarget(graph, config) {
|
|
16789
17460
|
return (signal, _ctx) => {
|
|
16790
17461
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
16791
17462
|
return null;
|
|
16792
17463
|
}
|
|
16793
|
-
const subResourceId = (0,
|
|
17464
|
+
const subResourceId = (0, import_types62.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
16794
17465
|
if (graph.hasNode(subResourceId)) {
|
|
16795
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
17466
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16796
17467
|
}
|
|
16797
|
-
const bareResourceId = (0,
|
|
17468
|
+
const bareResourceId = (0, import_types62.infraId)(signal.targetKind, signal.targetName);
|
|
16798
17469
|
if (graph.hasNode(bareResourceId)) {
|
|
16799
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
17470
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16800
17471
|
}
|
|
16801
|
-
const projectLevelId = (0,
|
|
17472
|
+
const projectLevelId = (0, import_types62.infraId)("supabase", config.nodeRef);
|
|
16802
17473
|
if (graph.hasNode(projectLevelId)) {
|
|
16803
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
17474
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types62.EdgeType.CALLS };
|
|
16804
17475
|
}
|
|
16805
17476
|
return null;
|
|
16806
17477
|
};
|
|
@@ -16893,7 +17564,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
16893
17564
|
|
|
16894
17565
|
// src/connectors/railway/index.ts
|
|
16895
17566
|
init_cjs_shims();
|
|
16896
|
-
var
|
|
17567
|
+
var import_types66 = require("@neat.is/types");
|
|
16897
17568
|
|
|
16898
17569
|
// src/connectors/railway/client.ts
|
|
16899
17570
|
init_cjs_shims();
|
|
@@ -17044,7 +17715,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
17044
17715
|
const out = [];
|
|
17045
17716
|
graph.forEachNode((_id, attrs) => {
|
|
17046
17717
|
const node = attrs;
|
|
17047
|
-
if (node.type !==
|
|
17718
|
+
if (node.type !== import_types66.NodeType.RouteNode) return;
|
|
17048
17719
|
const route = attrs;
|
|
17049
17720
|
if (route.service !== serviceName) return;
|
|
17050
17721
|
out.push({
|
|
@@ -17148,12 +17819,12 @@ function createRailwayResolveTarget(config) {
|
|
|
17148
17819
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
17149
17820
|
if (!serviceName) return null;
|
|
17150
17821
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
17151
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
17822
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types66.EdgeType.CALLS };
|
|
17152
17823
|
}
|
|
17153
17824
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
17154
17825
|
const peerName = config.serviceNameById[signal.targetName];
|
|
17155
17826
|
if (!peerName) return null;
|
|
17156
|
-
return { targetNodeId: (0,
|
|
17827
|
+
return { targetNodeId: (0, import_types66.serviceId)(peerName), serviceName, edgeType: import_types66.EdgeType.CONNECTS_TO };
|
|
17157
17828
|
}
|
|
17158
17829
|
return null;
|
|
17159
17830
|
};
|
|
@@ -17277,9 +17948,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
17277
17948
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
17278
17949
|
if (secondSep === -1) return null;
|
|
17279
17950
|
const method = rest.slice(0, secondSep);
|
|
17280
|
-
const
|
|
17281
|
-
if (!resourceName || !method || !
|
|
17282
|
-
return { resourceName, method, path:
|
|
17951
|
+
const path76 = rest.slice(secondSep + 1);
|
|
17952
|
+
if (!resourceName || !method || !path76) return null;
|
|
17953
|
+
return { resourceName, method, path: path76 };
|
|
17283
17954
|
}
|
|
17284
17955
|
function resourceNameFor(type, labels) {
|
|
17285
17956
|
if (!labels) return null;
|
|
@@ -17317,14 +17988,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
17317
17988
|
if (!req) return null;
|
|
17318
17989
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
17319
17990
|
const method = req.requestMethod.toUpperCase();
|
|
17320
|
-
const
|
|
17321
|
-
if (
|
|
17991
|
+
const path76 = pathFromRequestUrl(req.requestUrl);
|
|
17992
|
+
if (path76 === null) return null;
|
|
17322
17993
|
const timestamp = entry.timestamp;
|
|
17323
17994
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17324
17995
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
17325
17996
|
return {
|
|
17326
17997
|
targetKind: resourceType,
|
|
17327
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
17998
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path76 }),
|
|
17328
17999
|
callCount: 1,
|
|
17329
18000
|
errorCount: isError ? 1 : 0,
|
|
17330
18001
|
lastObservedIso: timestamp
|
|
@@ -17341,7 +18012,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
17341
18012
|
|
|
17342
18013
|
// src/connectors/firebase/resolve.ts
|
|
17343
18014
|
init_cjs_shims();
|
|
17344
|
-
var
|
|
18015
|
+
var import_types67 = require("@neat.is/types");
|
|
17345
18016
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
17346
18017
|
switch (resourceType) {
|
|
17347
18018
|
case "cloud_function":
|
|
@@ -17356,7 +18027,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
17356
18027
|
const entries = [];
|
|
17357
18028
|
graph.forEachNode((_id, attrs) => {
|
|
17358
18029
|
const node = attrs;
|
|
17359
|
-
if (node.type !==
|
|
18030
|
+
if (node.type !== import_types67.NodeType.RouteNode) return;
|
|
17360
18031
|
const route = attrs;
|
|
17361
18032
|
if (route.service !== serviceName) return;
|
|
17362
18033
|
entries.push({
|
|
@@ -17388,7 +18059,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
17388
18059
|
return {
|
|
17389
18060
|
targetNodeId: match.routeNodeId,
|
|
17390
18061
|
serviceName,
|
|
17391
|
-
edgeType:
|
|
18062
|
+
edgeType: import_types67.EdgeType.CALLS
|
|
17392
18063
|
};
|
|
17393
18064
|
};
|
|
17394
18065
|
}
|
|
@@ -17415,7 +18086,7 @@ init_cjs_shims();
|
|
|
17415
18086
|
|
|
17416
18087
|
// src/connectors/cloudflare/connector.ts
|
|
17417
18088
|
init_cjs_shims();
|
|
17418
|
-
var
|
|
18089
|
+
var import_types69 = require("@neat.is/types");
|
|
17419
18090
|
|
|
17420
18091
|
// src/connectors/cloudflare/client.ts
|
|
17421
18092
|
init_cjs_shims();
|
|
@@ -17531,7 +18202,7 @@ function mapEventToSignal(event) {
|
|
|
17531
18202
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
17532
18203
|
const statusCode = metadata?.statusCode;
|
|
17533
18204
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
17534
|
-
const
|
|
18205
|
+
const path76 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
17535
18206
|
return {
|
|
17536
18207
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
17537
18208
|
targetName: scriptName,
|
|
@@ -17539,7 +18210,7 @@ function mapEventToSignal(event) {
|
|
|
17539
18210
|
errorCount: isError ? 1 : 0,
|
|
17540
18211
|
lastObservedIso: observedAt.toISOString(),
|
|
17541
18212
|
method,
|
|
17542
|
-
...
|
|
18213
|
+
...path76 ? { path: path76 } : {},
|
|
17543
18214
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
17544
18215
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
17545
18216
|
};
|
|
@@ -17579,19 +18250,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
17579
18250
|
graph.forEachNode((id, attrs) => {
|
|
17580
18251
|
if (found) return;
|
|
17581
18252
|
const a = attrs;
|
|
17582
|
-
if (a.type ===
|
|
18253
|
+
if (a.type === import_types69.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
17583
18254
|
found = id;
|
|
17584
18255
|
}
|
|
17585
18256
|
});
|
|
17586
18257
|
return found;
|
|
17587
18258
|
}
|
|
17588
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
17589
|
-
const normalizedPath = normalizePathTemplate(
|
|
18259
|
+
function findMatchingRouteNode(graph, serviceName, method, path76) {
|
|
18260
|
+
const normalizedPath = normalizePathTemplate(path76);
|
|
17590
18261
|
let found = null;
|
|
17591
18262
|
graph.forEachNode((id, attrs) => {
|
|
17592
18263
|
if (found) return;
|
|
17593
18264
|
const a = attrs;
|
|
17594
|
-
if (a.type !==
|
|
18265
|
+
if (a.type !== import_types69.NodeType.RouteNode || a.service !== serviceName) return;
|
|
17595
18266
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
17596
18267
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
17597
18268
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -17603,18 +18274,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17603
18274
|
return (signal) => {
|
|
17604
18275
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
17605
18276
|
const scriptName = signal.targetName;
|
|
17606
|
-
const { method, path:
|
|
18277
|
+
const { method, path: path76 } = signal;
|
|
17607
18278
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
17608
|
-
if (!method || !
|
|
17609
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
18279
|
+
if (!method || !path76) return wholeFileId;
|
|
18280
|
+
return findMatchingRouteNode(graph, serviceName, method, path76) ?? wholeFileId;
|
|
17610
18281
|
};
|
|
17611
18282
|
const mapping = config.workers?.[scriptName];
|
|
17612
18283
|
if (mapping) {
|
|
17613
|
-
const wholeFileId = (0,
|
|
18284
|
+
const wholeFileId = (0, import_types69.fileId)(mapping.service, mapping.entryFile);
|
|
17614
18285
|
return {
|
|
17615
18286
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
17616
18287
|
serviceName: mapping.service,
|
|
17617
|
-
edgeType:
|
|
18288
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17618
18289
|
};
|
|
17619
18290
|
}
|
|
17620
18291
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -17623,13 +18294,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
17623
18294
|
return {
|
|
17624
18295
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
17625
18296
|
serviceName: fileNode.service,
|
|
17626
|
-
edgeType:
|
|
18297
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
17627
18298
|
};
|
|
17628
18299
|
}
|
|
17629
18300
|
return {
|
|
17630
|
-
targetNodeId: (0,
|
|
18301
|
+
targetNodeId: (0, import_types69.infraId)("cloudflare-worker", scriptName),
|
|
17631
18302
|
serviceName: scriptName,
|
|
17632
|
-
edgeType:
|
|
18303
|
+
edgeType: import_types69.EdgeType.CALLS,
|
|
17633
18304
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
17634
18305
|
};
|
|
17635
18306
|
};
|
|
@@ -17825,14 +18496,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
17825
18496
|
|
|
17826
18497
|
// src/connectors/neon/resolve.ts
|
|
17827
18498
|
init_cjs_shims();
|
|
17828
|
-
var
|
|
18499
|
+
var import_types73 = require("@neat.is/types");
|
|
17829
18500
|
function createNeonResolveTarget(config) {
|
|
17830
18501
|
return (signal) => {
|
|
17831
18502
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
17832
18503
|
return {
|
|
17833
|
-
targetNodeId: (0,
|
|
18504
|
+
targetNodeId: (0, import_types73.infraId)("sql-table", signal.targetName),
|
|
17834
18505
|
serviceName: config.serviceName,
|
|
17835
|
-
edgeType:
|
|
18506
|
+
edgeType: import_types73.EdgeType.CALLS,
|
|
17836
18507
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
17837
18508
|
};
|
|
17838
18509
|
};
|
|
@@ -17958,9 +18629,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
17958
18629
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
17959
18630
|
if (secondSep === -1) return null;
|
|
17960
18631
|
const method = rest.slice(0, secondSep);
|
|
17961
|
-
const
|
|
17962
|
-
if (!serviceName || !method || !
|
|
17963
|
-
return { serviceName, method, path:
|
|
18632
|
+
const path76 = rest.slice(secondSep + 1);
|
|
18633
|
+
if (!serviceName || !method || !path76) return null;
|
|
18634
|
+
return { serviceName, method, path: path76 };
|
|
17964
18635
|
}
|
|
17965
18636
|
|
|
17966
18637
|
// src/connectors/cloud-run/map.ts
|
|
@@ -17989,14 +18660,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
17989
18660
|
if (!req) return null;
|
|
17990
18661
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
17991
18662
|
const method = req.requestMethod.toUpperCase();
|
|
17992
|
-
const
|
|
17993
|
-
if (
|
|
18663
|
+
const path76 = pathFromRequestUrl2(req.requestUrl);
|
|
18664
|
+
if (path76 === null) return null;
|
|
17994
18665
|
const timestamp = entry.timestamp;
|
|
17995
18666
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
17996
18667
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
17997
18668
|
return {
|
|
17998
18669
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
17999
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
18670
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path76 }),
|
|
18000
18671
|
callCount: 1,
|
|
18001
18672
|
errorCount: isError ? 1 : 0,
|
|
18002
18673
|
lastObservedIso: timestamp
|
|
@@ -18013,14 +18684,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
18013
18684
|
|
|
18014
18685
|
// src/connectors/cloud-run/resolve.ts
|
|
18015
18686
|
init_cjs_shims();
|
|
18016
|
-
var
|
|
18687
|
+
var import_types77 = require("@neat.is/types");
|
|
18017
18688
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
18018
18689
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
18019
18690
|
let found = null;
|
|
18020
18691
|
graph.forEachNode((_id, attrs) => {
|
|
18021
18692
|
if (found) return;
|
|
18022
18693
|
const node = attrs;
|
|
18023
|
-
if (node.type !==
|
|
18694
|
+
if (node.type !== import_types77.NodeType.RouteNode) return;
|
|
18024
18695
|
const route = attrs;
|
|
18025
18696
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
18026
18697
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -18035,23 +18706,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
18035
18706
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
18036
18707
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
18037
18708
|
if (!identity) return null;
|
|
18038
|
-
const { serviceName: gcpServiceName, method, path:
|
|
18709
|
+
const { serviceName: gcpServiceName, method, path: path76 } = identity;
|
|
18039
18710
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
18040
18711
|
if (mappedService) {
|
|
18041
18712
|
const routeNodeId = findMatchingRouteNode2(
|
|
18042
18713
|
graph,
|
|
18043
18714
|
mappedService,
|
|
18044
18715
|
method,
|
|
18045
|
-
normalizePathTemplate(
|
|
18716
|
+
normalizePathTemplate(path76)
|
|
18046
18717
|
);
|
|
18047
18718
|
if (routeNodeId) {
|
|
18048
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
18719
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types77.EdgeType.CALLS };
|
|
18049
18720
|
}
|
|
18050
18721
|
}
|
|
18051
18722
|
return {
|
|
18052
|
-
targetNodeId: (0,
|
|
18723
|
+
targetNodeId: (0, import_types77.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
18053
18724
|
serviceName: mappedService ?? gcpServiceName,
|
|
18054
|
-
edgeType:
|
|
18725
|
+
edgeType: import_types77.EdgeType.CALLS,
|
|
18055
18726
|
ensureInfraNode: {
|
|
18056
18727
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
18057
18728
|
name: gcpServiceName,
|
|
@@ -18092,7 +18763,7 @@ function createCloudRunConnector(graph, config = {}) {
|
|
|
18092
18763
|
|
|
18093
18764
|
// src/connectors/render/index.ts
|
|
18094
18765
|
init_cjs_shims();
|
|
18095
|
-
var
|
|
18766
|
+
var import_types80 = require("@neat.is/types");
|
|
18096
18767
|
|
|
18097
18768
|
// src/connectors/render/types.ts
|
|
18098
18769
|
init_cjs_shims();
|
|
@@ -18170,7 +18841,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
18170
18841
|
const out = [];
|
|
18171
18842
|
graph.forEachNode((_id, attrs) => {
|
|
18172
18843
|
const node = attrs;
|
|
18173
|
-
if (node.type !==
|
|
18844
|
+
if (node.type !== import_types80.NodeType.RouteNode) return;
|
|
18174
18845
|
const route = attrs;
|
|
18175
18846
|
if (route.service !== serviceName) return;
|
|
18176
18847
|
out.push({
|
|
@@ -18255,7 +18926,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
18255
18926
|
function createRenderResolveTarget(config) {
|
|
18256
18927
|
return (signal) => {
|
|
18257
18928
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
18258
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
18929
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types80.EdgeType.CALLS };
|
|
18259
18930
|
}
|
|
18260
18931
|
return null;
|
|
18261
18932
|
};
|
|
@@ -18393,21 +19064,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
18393
19064
|
|
|
18394
19065
|
// src/connectors/planetscale/resolve.ts
|
|
18395
19066
|
init_cjs_shims();
|
|
18396
|
-
var
|
|
19067
|
+
var import_types84 = require("@neat.is/types");
|
|
18397
19068
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
18398
19069
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
18399
19070
|
const databaseName = `${config.organization}/${config.database}`;
|
|
18400
19071
|
return (signal, _ctx) => {
|
|
18401
19072
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
18402
|
-
const tableId = (0,
|
|
19073
|
+
const tableId = (0, import_types84.infraId)("sql-table", signal.targetName);
|
|
18403
19074
|
if (graph.hasNode(tableId)) {
|
|
18404
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
19075
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types84.EdgeType.CALLS };
|
|
18405
19076
|
}
|
|
18406
|
-
const providerId = (0,
|
|
19077
|
+
const providerId = (0, import_types84.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
18407
19078
|
return {
|
|
18408
19079
|
targetNodeId: providerId,
|
|
18409
19080
|
serviceName: config.serviceName,
|
|
18410
|
-
edgeType:
|
|
19081
|
+
edgeType: import_types84.EdgeType.CALLS,
|
|
18411
19082
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
18412
19083
|
};
|
|
18413
19084
|
};
|
|
@@ -18672,7 +19343,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
18672
19343
|
|
|
18673
19344
|
// src/connectors/eas/resolve.ts
|
|
18674
19345
|
init_cjs_shims();
|
|
18675
|
-
var
|
|
19346
|
+
var import_types89 = require("@neat.is/types");
|
|
18676
19347
|
var NO_ENV2 = "unknown";
|
|
18677
19348
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
18678
19349
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -18688,8 +19359,8 @@ function configBasenamesForPhase(phase) {
|
|
|
18688
19359
|
function configNodeService(graph, configNodeId) {
|
|
18689
19360
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
18690
19361
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18691
|
-
if (edge.type !==
|
|
18692
|
-
const parsed = (0,
|
|
19362
|
+
if (edge.type !== import_types89.EdgeType.CONFIGURED_BY) continue;
|
|
19363
|
+
const parsed = (0, import_types89.parseFileId)(edge.source);
|
|
18693
19364
|
if (parsed) return parsed.service;
|
|
18694
19365
|
}
|
|
18695
19366
|
return null;
|
|
@@ -18700,7 +19371,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
18700
19371
|
graph.forEachNode((id, attrs) => {
|
|
18701
19372
|
if (scoped) return;
|
|
18702
19373
|
const node = attrs;
|
|
18703
|
-
if (node.type !==
|
|
19374
|
+
if (node.type !== import_types89.NodeType.ConfigNode) return;
|
|
18704
19375
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
18705
19376
|
if (anyMatch === null) anyMatch = id;
|
|
18706
19377
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -18717,13 +19388,13 @@ function createEasResolveTarget(graph) {
|
|
|
18717
19388
|
if (basenames.length > 0) {
|
|
18718
19389
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
18719
19390
|
if (configNodeId) {
|
|
18720
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
19391
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types89.EdgeType.CALLS };
|
|
18721
19392
|
}
|
|
18722
19393
|
}
|
|
18723
19394
|
return {
|
|
18724
19395
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
18725
19396
|
serviceName,
|
|
18726
|
-
edgeType:
|
|
19397
|
+
edgeType: import_types89.EdgeType.CALLS
|
|
18727
19398
|
};
|
|
18728
19399
|
};
|
|
18729
19400
|
}
|
|
@@ -19402,11 +20073,11 @@ function registerRoutes(scope, ctx) {
|
|
|
19402
20073
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
19403
20074
|
const parsed = [];
|
|
19404
20075
|
for (const c of candidates) {
|
|
19405
|
-
const r =
|
|
20076
|
+
const r = import_types92.DivergenceTypeSchema.safeParse(c);
|
|
19406
20077
|
if (!r.success) {
|
|
19407
20078
|
return reply.code(400).send({
|
|
19408
20079
|
error: `unknown divergence type "${c}"`,
|
|
19409
|
-
allowed:
|
|
20080
|
+
allowed: import_types92.DivergenceTypeSchema.options
|
|
19410
20081
|
});
|
|
19411
20082
|
}
|
|
19412
20083
|
parsed.push(r.data);
|
|
@@ -19748,7 +20419,7 @@ function registerRoutes(scope, ctx) {
|
|
|
19748
20419
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
19749
20420
|
let violations = await log.readAll();
|
|
19750
20421
|
if (req.query.severity) {
|
|
19751
|
-
const sev =
|
|
20422
|
+
const sev = import_types92.PolicySeveritySchema.safeParse(req.query.severity);
|
|
19752
20423
|
if (!sev.success) {
|
|
19753
20424
|
return reply.code(400).send({
|
|
19754
20425
|
error: "invalid severity",
|
|
@@ -19787,7 +20458,7 @@ function registerRoutes(scope, ctx) {
|
|
|
19787
20458
|
scope.post("/policies/check", async (req, reply) => {
|
|
19788
20459
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
19789
20460
|
if (!proj) return;
|
|
19790
|
-
const parsed =
|
|
20461
|
+
const parsed = import_types92.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
19791
20462
|
if (!parsed.success) {
|
|
19792
20463
|
return reply.code(400).send({
|
|
19793
20464
|
error: "invalid /policies/check body",
|
|
@@ -20108,8 +20779,8 @@ init_otel_grpc();
|
|
|
20108
20779
|
|
|
20109
20780
|
// src/search.ts
|
|
20110
20781
|
init_cjs_shims();
|
|
20111
|
-
var
|
|
20112
|
-
var
|
|
20782
|
+
var import_node_fs39 = require("fs");
|
|
20783
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
20113
20784
|
var import_node_crypto4 = require("crypto");
|
|
20114
20785
|
var DEFAULT_LIMIT = 10;
|
|
20115
20786
|
var NOMIC_DIM = 768;
|
|
@@ -20263,7 +20934,7 @@ async function pickEmbedder() {
|
|
|
20263
20934
|
}
|
|
20264
20935
|
async function readCache(cachePath) {
|
|
20265
20936
|
try {
|
|
20266
|
-
const raw = await
|
|
20937
|
+
const raw = await import_node_fs39.promises.readFile(cachePath, "utf8");
|
|
20267
20938
|
const parsed = JSON.parse(raw);
|
|
20268
20939
|
if (parsed.version !== 1) return null;
|
|
20269
20940
|
return parsed;
|
|
@@ -20272,8 +20943,8 @@ async function readCache(cachePath) {
|
|
|
20272
20943
|
}
|
|
20273
20944
|
}
|
|
20274
20945
|
async function writeCache(cachePath, cache) {
|
|
20275
|
-
await
|
|
20276
|
-
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));
|
|
20277
20948
|
}
|
|
20278
20949
|
var VectorIndex = class {
|
|
20279
20950
|
constructor(embedder, cachePath) {
|
|
@@ -20487,14 +21158,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
20487
21158
|
async function main() {
|
|
20488
21159
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
20489
21160
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
20490
|
-
const baseDir = baseDirEnv ?
|
|
20491
|
-
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");
|
|
20492
21163
|
const registry = new Projects();
|
|
20493
21164
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
20494
21165
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
20495
21166
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
20496
21167
|
const projectScan = process.env[envKey];
|
|
20497
|
-
await bootProject(registry, name, projectScan ?
|
|
21168
|
+
await bootProject(registry, name, projectScan ? import_node_path75.default.resolve(projectScan) : void 0, baseDir);
|
|
20498
21169
|
}
|
|
20499
21170
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
20500
21171
|
const port = Number(process.env.PORT ?? 8080);
|