@neat.is/core 0.5.3 → 0.6.0
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-X2AMX3QZ.js → chunk-5PVQJLPR.js} +272 -13
- package/dist/chunk-5PVQJLPR.js.map +1 -0
- package/dist/{chunk-CFDPIMRP.js → chunk-BZ3AJVAC.js} +9 -3
- package/dist/chunk-BZ3AJVAC.js.map +1 -0
- package/dist/{chunk-GJHEZC5K.js → chunk-CS4GHQO3.js} +458 -111
- package/dist/chunk-CS4GHQO3.js.map +1 -0
- package/dist/{chunk-I72HTUOG.js → chunk-MVINCLQM.js} +2 -2
- package/dist/cli.cjs +1190 -458
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +140 -25
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +849 -286
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +858 -295
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-IDMIH6ZY.js → otel-grpc-XS45HBET.js} +3 -3
- package/dist/server.cjs +540 -173
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-CFDPIMRP.js.map +0 -1
- package/dist/chunk-GJHEZC5K.js.map +0 -1
- package/dist/chunk-X2AMX3QZ.js.map +0 -1
- /package/dist/{chunk-I72HTUOG.js.map → chunk-MVINCLQM.js.map} +0 -0
- /package/dist/{otel-grpc-IDMIH6ZY.js.map → otel-grpc-XS45HBET.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 path52 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
63
|
+
if (exactUnauthPaths.has(path52) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path52)) {
|
|
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_path48.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
196
|
+
return import_node_path48.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_path48, 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_path48 = __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);
|
|
@@ -340,6 +340,11 @@ function pickEnv(spanAttrs, resourceAttrs) {
|
|
|
340
340
|
}
|
|
341
341
|
return ENV_FALLBACK;
|
|
342
342
|
}
|
|
343
|
+
function normalizeDbSystem(attrs) {
|
|
344
|
+
const raw = attrs["db.system"];
|
|
345
|
+
if (typeof raw !== "string") return void 0;
|
|
346
|
+
return raw === "mongoose" ? "mongodb" : raw;
|
|
347
|
+
}
|
|
343
348
|
function messagingDestinationOf(attrs) {
|
|
344
349
|
for (const key of ["messaging.destination.name", "messaging.destination"]) {
|
|
345
350
|
const v = attrs[key];
|
|
@@ -360,8 +365,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
360
365
|
const v = attrs[key];
|
|
361
366
|
if (typeof v === "string" && v.length > 0) {
|
|
362
367
|
const q = v.indexOf("?");
|
|
363
|
-
const
|
|
364
|
-
if (
|
|
368
|
+
const path52 = q === -1 ? v : v.slice(0, q);
|
|
369
|
+
if (path52.length > 0) return path52;
|
|
365
370
|
}
|
|
366
371
|
}
|
|
367
372
|
return void 0;
|
|
@@ -394,8 +399,9 @@ function parseOtlpRequest(body) {
|
|
|
394
399
|
durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),
|
|
395
400
|
env: pickEnv(attrs, resourceAttrs),
|
|
396
401
|
attributes: attrs,
|
|
397
|
-
dbSystem:
|
|
402
|
+
dbSystem: normalizeDbSystem(attrs),
|
|
398
403
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
404
|
+
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
399
405
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
400
406
|
messagingDestination: messagingDestinationOf(attrs),
|
|
401
407
|
graphqlOperationName: typeof attrs["graphql.operation.name"] === "string" && attrs["graphql.operation.name"].length > 0 ? attrs["graphql.operation.name"] : void 0,
|
|
@@ -415,10 +421,10 @@ function parseOtlpRequest(body) {
|
|
|
415
421
|
return out;
|
|
416
422
|
}
|
|
417
423
|
function loadProtoRoot() {
|
|
418
|
-
const here =
|
|
419
|
-
const protoRoot =
|
|
424
|
+
const here = import_node_path49.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
425
|
+
const protoRoot = import_node_path49.default.resolve(here, "..", "proto");
|
|
420
426
|
const root = new import_protobufjs.default.Root();
|
|
421
|
-
root.resolvePath = (_origin, target) =>
|
|
427
|
+
root.resolvePath = (_origin, target) => import_node_path49.default.resolve(protoRoot, target);
|
|
422
428
|
root.loadSync(
|
|
423
429
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
424
430
|
{ keepCase: true }
|
|
@@ -630,12 +636,12 @@ async function buildOtelReceiver(opts) {
|
|
|
630
636
|
};
|
|
631
637
|
return decorated;
|
|
632
638
|
}
|
|
633
|
-
var
|
|
639
|
+
var import_node_path49, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
634
640
|
var init_otel = __esm({
|
|
635
641
|
"src/otel.ts"() {
|
|
636
642
|
"use strict";
|
|
637
643
|
init_cjs_shims();
|
|
638
|
-
|
|
644
|
+
import_node_path49 = __toESM(require("path"), 1);
|
|
639
645
|
import_node_url2 = require("url");
|
|
640
646
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
641
647
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -651,7 +657,7 @@ var init_otel = __esm({
|
|
|
651
657
|
|
|
652
658
|
// src/server.ts
|
|
653
659
|
init_cjs_shims();
|
|
654
|
-
var
|
|
660
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
655
661
|
|
|
656
662
|
// src/graph.ts
|
|
657
663
|
init_cjs_shims();
|
|
@@ -675,7 +681,7 @@ function getGraph(project = DEFAULT_PROJECT) {
|
|
|
675
681
|
init_cjs_shims();
|
|
676
682
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
677
683
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
678
|
-
var
|
|
684
|
+
var import_types34 = require("@neat.is/types");
|
|
679
685
|
|
|
680
686
|
// src/extend/index.ts
|
|
681
687
|
init_cjs_shims();
|
|
@@ -1446,19 +1452,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1446
1452
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1447
1453
|
let best = { path: [start], edges: [] };
|
|
1448
1454
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1449
|
-
function step(node,
|
|
1450
|
-
if (
|
|
1451
|
-
best = { path: [...
|
|
1455
|
+
function step(node, path52, edges) {
|
|
1456
|
+
if (path52.length > best.path.length) {
|
|
1457
|
+
best = { path: [...path52], edges: [...edges] };
|
|
1452
1458
|
}
|
|
1453
|
-
if (
|
|
1459
|
+
if (path52.length - 1 >= maxDepth) return;
|
|
1454
1460
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1455
1461
|
for (const [srcId, edge] of incoming) {
|
|
1456
1462
|
if (visited.has(srcId)) continue;
|
|
1457
1463
|
visited.add(srcId);
|
|
1458
|
-
|
|
1464
|
+
path52.push(srcId);
|
|
1459
1465
|
edges.push(edge);
|
|
1460
|
-
step(srcId,
|
|
1461
|
-
|
|
1466
|
+
step(srcId, path52, edges);
|
|
1467
|
+
path52.pop();
|
|
1462
1468
|
edges.pop();
|
|
1463
1469
|
visited.delete(srcId);
|
|
1464
1470
|
}
|
|
@@ -1652,26 +1658,26 @@ function dominantFailingCall(graph, serviceId5, visited) {
|
|
|
1652
1658
|
return best;
|
|
1653
1659
|
}
|
|
1654
1660
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1655
|
-
const
|
|
1661
|
+
const path52 = [originServiceId];
|
|
1656
1662
|
const edges = [];
|
|
1657
1663
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1658
1664
|
let current = originServiceId;
|
|
1659
1665
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1660
1666
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1661
1667
|
if (!hop) break;
|
|
1662
|
-
|
|
1668
|
+
path52.push(hop.nextService);
|
|
1663
1669
|
edges.push(hop.edge);
|
|
1664
1670
|
visited.add(hop.nextService);
|
|
1665
1671
|
current = hop.nextService;
|
|
1666
1672
|
}
|
|
1667
1673
|
if (edges.length === 0) return null;
|
|
1668
|
-
return { path:
|
|
1674
|
+
return { path: path52, edges, culprit: current };
|
|
1669
1675
|
}
|
|
1670
1676
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1671
1677
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1672
1678
|
if (!chain) return null;
|
|
1673
1679
|
const culprit = chain.culprit;
|
|
1674
|
-
const
|
|
1680
|
+
const path52 = [...chain.path];
|
|
1675
1681
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1676
1682
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1677
1683
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1679,14 +1685,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1679
1685
|
if (loc) {
|
|
1680
1686
|
let rootCauseNode = culprit;
|
|
1681
1687
|
if (loc.fileNode) {
|
|
1682
|
-
|
|
1688
|
+
path52.push(loc.fileNode);
|
|
1683
1689
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1684
1690
|
rootCauseNode = loc.fileNode;
|
|
1685
1691
|
}
|
|
1686
1692
|
return import_types.RootCauseResultSchema.parse({
|
|
1687
1693
|
rootCauseNode,
|
|
1688
1694
|
rootCauseReason: loc.rootCauseReason,
|
|
1689
|
-
traversalPath:
|
|
1695
|
+
traversalPath: path52,
|
|
1690
1696
|
edgeProvenances,
|
|
1691
1697
|
confidence,
|
|
1692
1698
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1698,7 +1704,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1698
1704
|
return import_types.RootCauseResultSchema.parse({
|
|
1699
1705
|
rootCauseNode: culprit,
|
|
1700
1706
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1701
|
-
traversalPath:
|
|
1707
|
+
traversalPath: path52,
|
|
1702
1708
|
edgeProvenances,
|
|
1703
1709
|
confidence,
|
|
1704
1710
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -3122,6 +3128,19 @@ function ensureServiceNode(graph, serviceName, env) {
|
|
|
3122
3128
|
graph.addNode(id, node);
|
|
3123
3129
|
return id;
|
|
3124
3130
|
}
|
|
3131
|
+
function ensureInfraNode(graph, kind, name, provider) {
|
|
3132
|
+
const id = (0, import_types4.infraId)(kind, name);
|
|
3133
|
+
if (graph.hasNode(id)) return id;
|
|
3134
|
+
const node = {
|
|
3135
|
+
id,
|
|
3136
|
+
type: import_types4.NodeType.InfraNode,
|
|
3137
|
+
name,
|
|
3138
|
+
provider,
|
|
3139
|
+
kind
|
|
3140
|
+
};
|
|
3141
|
+
graph.addNode(id, node);
|
|
3142
|
+
return id;
|
|
3143
|
+
}
|
|
3125
3144
|
function ensureDatabaseNode(graph, host, engine) {
|
|
3126
3145
|
const id = (0, import_types4.databaseId)(host);
|
|
3127
3146
|
if (graph.hasNode(id)) return id;
|
|
@@ -3434,6 +3453,18 @@ async function handleSpan(ctx, span) {
|
|
|
3434
3453
|
callSiteEvidence
|
|
3435
3454
|
);
|
|
3436
3455
|
if (result) affectedNode = targetId;
|
|
3456
|
+
if (span.dbSystem === "mongodb" && span.dbCollection) {
|
|
3457
|
+
const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
|
|
3458
|
+
upsertObservedEdge(
|
|
3459
|
+
ctx.graph,
|
|
3460
|
+
import_types4.EdgeType.CALLS,
|
|
3461
|
+
observedSource(),
|
|
3462
|
+
collectionId,
|
|
3463
|
+
ts,
|
|
3464
|
+
isError,
|
|
3465
|
+
callSiteEvidence
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3437
3468
|
}
|
|
3438
3469
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
3439
3470
|
const targetId = ensureMessagingDestinationNode(
|
|
@@ -6281,7 +6312,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
6281
6312
|
|
|
6282
6313
|
// src/extract/calls/index.ts
|
|
6283
6314
|
init_cjs_shims();
|
|
6284
|
-
var
|
|
6315
|
+
var import_types22 = require("@neat.is/types");
|
|
6285
6316
|
|
|
6286
6317
|
// src/extract/calls/http.ts
|
|
6287
6318
|
init_cjs_shims();
|
|
@@ -6994,15 +7025,311 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
6994
7025
|
return out;
|
|
6995
7026
|
}
|
|
6996
7027
|
|
|
7028
|
+
// src/extract/calls/mongoose.ts
|
|
7029
|
+
init_cjs_shims();
|
|
7030
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
7031
|
+
var import_types21 = require("@neat.is/types");
|
|
7032
|
+
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
7033
|
+
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
7034
|
+
var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
|
|
7035
|
+
var UNCOUNTABLES = /* @__PURE__ */ new Set([
|
|
7036
|
+
"advice",
|
|
7037
|
+
"energy",
|
|
7038
|
+
"excretion",
|
|
7039
|
+
"digestion",
|
|
7040
|
+
"cooperation",
|
|
7041
|
+
"health",
|
|
7042
|
+
"justice",
|
|
7043
|
+
"labour",
|
|
7044
|
+
"machinery",
|
|
7045
|
+
"equipment",
|
|
7046
|
+
"information",
|
|
7047
|
+
"pollution",
|
|
7048
|
+
"sewage",
|
|
7049
|
+
"paper",
|
|
7050
|
+
"money",
|
|
7051
|
+
"species",
|
|
7052
|
+
"series",
|
|
7053
|
+
"rain",
|
|
7054
|
+
"rice",
|
|
7055
|
+
"fish",
|
|
7056
|
+
"sheep",
|
|
7057
|
+
"moose",
|
|
7058
|
+
"deer",
|
|
7059
|
+
"news",
|
|
7060
|
+
"expertise",
|
|
7061
|
+
"status",
|
|
7062
|
+
"media"
|
|
7063
|
+
]);
|
|
7064
|
+
var PLURALIZE_RULES = [
|
|
7065
|
+
[/human$/gi, "humans"],
|
|
7066
|
+
[/(m)an$/gi, "$1en"],
|
|
7067
|
+
[/(pe)rson$/gi, "$1ople"],
|
|
7068
|
+
[/(child)$/gi, "$1ren"],
|
|
7069
|
+
[/^(ox)$/gi, "$1en"],
|
|
7070
|
+
[/(ax|test)is$/gi, "$1es"],
|
|
7071
|
+
[/(octop|vir)us$/gi, "$1i"],
|
|
7072
|
+
[/(alias|status)$/gi, "$1es"],
|
|
7073
|
+
[/(bu)s$/gi, "$1ses"],
|
|
7074
|
+
[/(buffal|tomat|potat)o$/gi, "$1oes"],
|
|
7075
|
+
[/([ti])um$/gi, "$1a"],
|
|
7076
|
+
[/sis$/gi, "ses"],
|
|
7077
|
+
[/(?:([^f])fe|([lr])f)$/gi, "$1$2ves"],
|
|
7078
|
+
[/(hive)$/gi, "$1s"],
|
|
7079
|
+
[/([^aeiouy]|qu)y$/gi, "$1ies"],
|
|
7080
|
+
[/(x|ch|ss|sh)$/gi, "$1es"],
|
|
7081
|
+
[/(matr|vert|ind)ix|ex$/gi, "$1ices"],
|
|
7082
|
+
[/([m|l])ouse$/gi, "$1ice"],
|
|
7083
|
+
[/(kn|w|l)ife$/gi, "$1ives"],
|
|
7084
|
+
[/(quiz)$/gi, "$1zes"],
|
|
7085
|
+
[/s$/gi, "s"],
|
|
7086
|
+
[/([^a-z])$/, "$1"],
|
|
7087
|
+
[/$/gi, "s"]
|
|
7088
|
+
];
|
|
7089
|
+
function pluralizeCollection(name) {
|
|
7090
|
+
const str = name.toLowerCase();
|
|
7091
|
+
if (UNCOUNTABLES.has(str)) return str;
|
|
7092
|
+
for (const [re, repl] of PLURALIZE_RULES) {
|
|
7093
|
+
if (str.match(re)) return str.replace(re, repl);
|
|
7094
|
+
}
|
|
7095
|
+
return str;
|
|
7096
|
+
}
|
|
7097
|
+
var MODEL_METHODS = [
|
|
7098
|
+
"find",
|
|
7099
|
+
"findOne",
|
|
7100
|
+
"findById",
|
|
7101
|
+
"findByIdAndUpdate",
|
|
7102
|
+
"findByIdAndDelete",
|
|
7103
|
+
"findOneAndUpdate",
|
|
7104
|
+
"findOneAndDelete",
|
|
7105
|
+
"findOneAndReplace",
|
|
7106
|
+
"countDocuments",
|
|
7107
|
+
"estimatedDocumentCount",
|
|
7108
|
+
"distinct",
|
|
7109
|
+
"aggregate",
|
|
7110
|
+
"exists",
|
|
7111
|
+
"where",
|
|
7112
|
+
"populate",
|
|
7113
|
+
"watch",
|
|
7114
|
+
"hydrate",
|
|
7115
|
+
"create",
|
|
7116
|
+
"insertMany",
|
|
7117
|
+
"insertOne",
|
|
7118
|
+
"updateOne",
|
|
7119
|
+
"updateMany",
|
|
7120
|
+
"replaceOne",
|
|
7121
|
+
"deleteOne",
|
|
7122
|
+
"deleteMany",
|
|
7123
|
+
"bulkWrite",
|
|
7124
|
+
"bulkSave",
|
|
7125
|
+
"save",
|
|
7126
|
+
// pre-v7, removed in current mongoose but present in older codebases:
|
|
7127
|
+
"count",
|
|
7128
|
+
"update",
|
|
7129
|
+
"remove",
|
|
7130
|
+
"findOneAndRemove",
|
|
7131
|
+
"findByIdAndRemove"
|
|
7132
|
+
];
|
|
7133
|
+
var MODEL_METHODS_ALT = MODEL_METHODS.join("|");
|
|
7134
|
+
function schemaCollectionVars(content) {
|
|
7135
|
+
const out = /* @__PURE__ */ new Map();
|
|
7136
|
+
const re = /(?:const|let|var)\s+(\w+)\s*=\s*new\s+(?:mongoose\s*\.\s*)?Schema\s*\(/g;
|
|
7137
|
+
let m;
|
|
7138
|
+
while ((m = re.exec(content)) !== null) {
|
|
7139
|
+
const windowText = content.slice(m.index, m.index + 2e3);
|
|
7140
|
+
const opt = /\bcollection\s*:\s*['"`]([\w.-]+)['"`]/.exec(windowText);
|
|
7141
|
+
if (opt) out.set(m[1], opt[1]);
|
|
7142
|
+
}
|
|
7143
|
+
return out;
|
|
7144
|
+
}
|
|
7145
|
+
function resolveModel(modelName, rest, schemaColl, pluralizeOn) {
|
|
7146
|
+
const trimmed = rest.trim();
|
|
7147
|
+
const literalThird = /,\s*['"`]([\w.-]+)['"`]\s*$/.exec(trimmed);
|
|
7148
|
+
if (literalThird) return { name: literalThird[1], kind: "mongodb-collection" };
|
|
7149
|
+
const firstIdent = /^([A-Za-z_$][\w$]*)/.exec(trimmed)?.[1];
|
|
7150
|
+
if (firstIdent && schemaColl.has(firstIdent)) {
|
|
7151
|
+
return { name: schemaColl.get(firstIdent), kind: "mongodb-collection" };
|
|
7152
|
+
}
|
|
7153
|
+
if (/,\s*[A-Za-z_$][\w$]*\s*$/.test(trimmed)) {
|
|
7154
|
+
return { name: modelName, kind: "mongodb-model" };
|
|
7155
|
+
}
|
|
7156
|
+
return { name: pluralizeOn ? pluralizeCollection(modelName) : modelName, kind: "mongodb-collection" };
|
|
7157
|
+
}
|
|
7158
|
+
function collectModelDefs(content, pluralizeOn) {
|
|
7159
|
+
const schemaColl = schemaCollectionVars(content);
|
|
7160
|
+
const out = [];
|
|
7161
|
+
const re = /(?:(?:const|let|var)\s+(\w+)\s*=\s*)?(?:await\s+)?(?:\b\w+\s*\.\s*)?\bmodel\s*\(\s*['"`]([\w$]+)['"`]\s*(?:,\s*([\s\S]{0,300}?))?\)/g;
|
|
7162
|
+
let m;
|
|
7163
|
+
while ((m = re.exec(content)) !== null) {
|
|
7164
|
+
out.push({
|
|
7165
|
+
modelName: m[2],
|
|
7166
|
+
varName: m[1] ?? null,
|
|
7167
|
+
resolved: resolveModel(m[2], m[3] ?? "", schemaColl, pluralizeOn),
|
|
7168
|
+
matchText: m[0]
|
|
7169
|
+
});
|
|
7170
|
+
}
|
|
7171
|
+
return out;
|
|
7172
|
+
}
|
|
7173
|
+
function endpoint(r, file, serviceDir, matchText) {
|
|
7174
|
+
const line = lineOf(file.content, matchText);
|
|
7175
|
+
return {
|
|
7176
|
+
infraId: (0, import_types21.infraId)(r.kind, r.name),
|
|
7177
|
+
name: r.name,
|
|
7178
|
+
kind: r.kind,
|
|
7179
|
+
edgeType: "CALLS",
|
|
7180
|
+
confidenceKind: "verified-call-site",
|
|
7181
|
+
evidence: { file: import_node_path33.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
7182
|
+
};
|
|
7183
|
+
}
|
|
7184
|
+
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
7185
|
+
const hasMongoose = MONGOOSE_IMPORT_RE.test(file.content);
|
|
7186
|
+
const hasMongodb = MONGODB_IMPORT_RE.test(file.content);
|
|
7187
|
+
if (!hasMongoose && !hasMongodb) return [];
|
|
7188
|
+
const content = file.content;
|
|
7189
|
+
const out = [];
|
|
7190
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7191
|
+
const push = (r, matchText) => {
|
|
7192
|
+
const key = `${r.kind}/${r.name}`;
|
|
7193
|
+
if (seen.has(key)) return;
|
|
7194
|
+
seen.add(key);
|
|
7195
|
+
out.push(endpoint(r, file, serviceDir, matchText));
|
|
7196
|
+
};
|
|
7197
|
+
if (hasMongoose) {
|
|
7198
|
+
const pluralizeOn = !PLURALIZE_DISABLED_RE.test(content);
|
|
7199
|
+
for (const def of collectModelDefs(content, pluralizeOn)) push(def.resolved, def.matchText);
|
|
7200
|
+
}
|
|
7201
|
+
const collRe = /\.\s*collection\s*\(\s*['"`]([\w.$-]+)['"`]\s*\)/g;
|
|
7202
|
+
let c;
|
|
7203
|
+
while ((c = collRe.exec(content)) !== null) {
|
|
7204
|
+
push({ name: c[1], kind: "mongodb-collection" }, c[0]);
|
|
7205
|
+
}
|
|
7206
|
+
return out;
|
|
7207
|
+
}
|
|
7208
|
+
function parseDestructure(inner, specifier, out) {
|
|
7209
|
+
for (const raw of inner.split(",")) {
|
|
7210
|
+
const part = raw.trim();
|
|
7211
|
+
if (!part) continue;
|
|
7212
|
+
const asM = /^(\w+)\s+as\s+(\w+)$/.exec(part);
|
|
7213
|
+
const colonM = /^(\w+)\s*:\s*(\w+)$/.exec(part);
|
|
7214
|
+
if (asM) out.push({ local: asM[2], kind: "named", exportName: asM[1], specifier });
|
|
7215
|
+
else if (colonM) out.push({ local: colonM[2], kind: "named", exportName: colonM[1], specifier });
|
|
7216
|
+
else {
|
|
7217
|
+
const id = /^(\w+)$/.exec(part);
|
|
7218
|
+
if (id) out.push({ local: id[1], kind: "named", exportName: id[1], specifier });
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7221
|
+
}
|
|
7222
|
+
function parseImportBindings(content) {
|
|
7223
|
+
const out = [];
|
|
7224
|
+
const esm = /import\s+([^;'"`\n]+?)\s+from\s*['"`]([^'"`]+)['"`]/g;
|
|
7225
|
+
let m;
|
|
7226
|
+
while ((m = esm.exec(content)) !== null) {
|
|
7227
|
+
const clause = m[1].trim();
|
|
7228
|
+
const spec = m[2];
|
|
7229
|
+
const ns = /^\*\s+as\s+(\w+)$/.exec(clause);
|
|
7230
|
+
if (ns) {
|
|
7231
|
+
out.push({ local: ns[1], kind: "namespace", specifier: spec });
|
|
7232
|
+
continue;
|
|
7233
|
+
}
|
|
7234
|
+
const named = /\{([^}]*)\}/.exec(clause);
|
|
7235
|
+
if (named) parseDestructure(named[1], spec, out);
|
|
7236
|
+
const def = /^(\w+)\s*(?:,|$)/.exec(clause);
|
|
7237
|
+
if (def && !clause.startsWith("{")) out.push({ local: def[1], kind: "default", specifier: spec });
|
|
7238
|
+
}
|
|
7239
|
+
const cjs = /(?:const|let|var)\s+(\{[^}]*\}|\w+)\s*=\s*require\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
7240
|
+
while ((m = cjs.exec(content)) !== null) {
|
|
7241
|
+
const lhs = m[1];
|
|
7242
|
+
const spec = m[2];
|
|
7243
|
+
if (lhs.startsWith("{")) parseDestructure(lhs.slice(1, -1), spec, out);
|
|
7244
|
+
else out.push({ local: lhs, kind: "whole", specifier: spec });
|
|
7245
|
+
}
|
|
7246
|
+
return out;
|
|
7247
|
+
}
|
|
7248
|
+
function fileExportsOf(content, pluralizeOn) {
|
|
7249
|
+
const defs = collectModelDefs(content, pluralizeOn).filter((d) => d.resolved.kind === "mongodb-collection");
|
|
7250
|
+
if (defs.length === 0) return null;
|
|
7251
|
+
const byVar = /* @__PURE__ */ new Map();
|
|
7252
|
+
for (const d of defs) if (d.varName) byVar.set(d.varName, d.resolved.name);
|
|
7253
|
+
const byName = new Map(byVar);
|
|
7254
|
+
let def;
|
|
7255
|
+
const named = /(?:module\.exports|export\s+default)\s*=\s*(\w+)\b/.exec(content);
|
|
7256
|
+
if (named && byVar.has(named[1])) def = byVar.get(named[1]);
|
|
7257
|
+
if (!def) {
|
|
7258
|
+
const inline = /(?:module\.exports|export\s+default)\s*=\s*(?:await\s+)?(?:\w+\s*\.\s*)?model\s*\(\s*['"`]([\w$]+)['"`]/.exec(content);
|
|
7259
|
+
if (inline) def = pluralizeOn ? pluralizeCollection(inline[1]) : inline[1];
|
|
7260
|
+
}
|
|
7261
|
+
if (!def && byVar.size === 1) def = [...byVar.values()][0];
|
|
7262
|
+
return { byName, ...def ? { default: def } : {} };
|
|
7263
|
+
}
|
|
7264
|
+
async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
7265
|
+
const mongooseFiles = files.filter((f) => MONGOOSE_IMPORT_RE.test(f.content));
|
|
7266
|
+
if (mongooseFiles.length === 0) return [];
|
|
7267
|
+
const pluralizeOn = !files.some((f) => PLURALIZE_DISABLED_RE.test(f.content));
|
|
7268
|
+
const registry = /* @__PURE__ */ new Map();
|
|
7269
|
+
for (const f of mongooseFiles) {
|
|
7270
|
+
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
7271
|
+
if (fx) registry.set(toPosix2(import_node_path33.default.relative(serviceDir, f.path)), fx);
|
|
7272
|
+
}
|
|
7273
|
+
if (registry.size === 0) return [];
|
|
7274
|
+
const out = [];
|
|
7275
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7276
|
+
for (const f of files) {
|
|
7277
|
+
const bindings = parseImportBindings(f.content);
|
|
7278
|
+
if (bindings.length === 0) continue;
|
|
7279
|
+
const directColl = /* @__PURE__ */ new Map();
|
|
7280
|
+
const nsExports = /* @__PURE__ */ new Map();
|
|
7281
|
+
for (const b of bindings) {
|
|
7282
|
+
const resolvedRel = await resolveJsImport(b.specifier, import_node_path33.default.dirname(f.path), serviceDir, null);
|
|
7283
|
+
if (!resolvedRel) continue;
|
|
7284
|
+
const fx = registry.get(resolvedRel);
|
|
7285
|
+
if (!fx) continue;
|
|
7286
|
+
if (b.kind === "named" && b.exportName) {
|
|
7287
|
+
const coll = fx.byName.get(b.exportName);
|
|
7288
|
+
if (coll) directColl.set(b.local, coll);
|
|
7289
|
+
} else if (b.kind === "default") {
|
|
7290
|
+
if (fx.default) directColl.set(b.local, fx.default);
|
|
7291
|
+
} else {
|
|
7292
|
+
if (fx.default) directColl.set(b.local, fx.default);
|
|
7293
|
+
nsExports.set(b.local, fx);
|
|
7294
|
+
}
|
|
7295
|
+
}
|
|
7296
|
+
if (directColl.size === 0 && nsExports.size === 0) continue;
|
|
7297
|
+
const localDefs = new Set(
|
|
7298
|
+
collectModelDefs(f.content, pluralizeOn).map((d) => d.varName).filter((v) => v !== null)
|
|
7299
|
+
);
|
|
7300
|
+
const emit = (collection, matchText) => {
|
|
7301
|
+
const key = `${f.path}::${collection}`;
|
|
7302
|
+
if (seen.has(key)) return;
|
|
7303
|
+
seen.add(key);
|
|
7304
|
+
out.push(endpoint({ name: collection, kind: "mongodb-collection" }, f, serviceDir, matchText));
|
|
7305
|
+
};
|
|
7306
|
+
for (const [local, collection] of directColl) {
|
|
7307
|
+
if (localDefs.has(local)) continue;
|
|
7308
|
+
const qre = new RegExp(`\\b${local}\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
|
|
7309
|
+
let qm;
|
|
7310
|
+
while ((qm = qre.exec(f.content)) !== null) emit(collection, qm[0]);
|
|
7311
|
+
}
|
|
7312
|
+
for (const [local, fx] of nsExports) {
|
|
7313
|
+
const qre = new RegExp(`\\b${local}\\s*\\.\\s*(\\w+)\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
|
|
7314
|
+
let qm;
|
|
7315
|
+
while ((qm = qre.exec(f.content)) !== null) {
|
|
7316
|
+
const coll = fx.byName.get(qm[1]);
|
|
7317
|
+
if (coll) emit(coll, qm[0]);
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7320
|
+
}
|
|
7321
|
+
return out;
|
|
7322
|
+
}
|
|
7323
|
+
|
|
6997
7324
|
// src/extract/calls/index.ts
|
|
6998
7325
|
function edgeTypeFromEndpoint(ep) {
|
|
6999
7326
|
switch (ep.edgeType) {
|
|
7000
7327
|
case "PUBLISHES_TO":
|
|
7001
|
-
return
|
|
7328
|
+
return import_types22.EdgeType.PUBLISHES_TO;
|
|
7002
7329
|
case "CONSUMES_FROM":
|
|
7003
|
-
return
|
|
7330
|
+
return import_types22.EdgeType.CONSUMES_FROM;
|
|
7004
7331
|
default:
|
|
7005
|
-
return
|
|
7332
|
+
return import_types22.EdgeType.CALLS;
|
|
7006
7333
|
}
|
|
7007
7334
|
}
|
|
7008
7335
|
function isAwsKind(kind) {
|
|
@@ -7014,23 +7341,27 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
7014
7341
|
for (const service of services) {
|
|
7015
7342
|
const files = await loadSourceFiles(service.dir);
|
|
7016
7343
|
const endpoints = [];
|
|
7344
|
+
const maskedFiles = [];
|
|
7017
7345
|
for (const file of files) {
|
|
7018
7346
|
if (isTestPath(file.path)) continue;
|
|
7019
7347
|
const masked = maskCommentsInSource(file.content);
|
|
7020
7348
|
const maskedFile = { path: file.path, content: masked };
|
|
7349
|
+
maskedFiles.push(maskedFile);
|
|
7021
7350
|
endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir));
|
|
7022
7351
|
endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir));
|
|
7023
7352
|
endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir));
|
|
7024
7353
|
endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
|
|
7025
7354
|
endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
|
|
7355
|
+
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
7026
7356
|
}
|
|
7357
|
+
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
7027
7358
|
if (endpoints.length === 0) continue;
|
|
7028
7359
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
7029
7360
|
for (const ep of endpoints) {
|
|
7030
7361
|
if (!graph.hasNode(ep.infraId)) {
|
|
7031
7362
|
const node = {
|
|
7032
7363
|
id: ep.infraId,
|
|
7033
|
-
type:
|
|
7364
|
+
type: import_types22.NodeType.InfraNode,
|
|
7034
7365
|
name: ep.name,
|
|
7035
7366
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
7036
7367
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -7042,7 +7373,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
7042
7373
|
nodesAdded++;
|
|
7043
7374
|
}
|
|
7044
7375
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
7045
|
-
const confidence = (0,
|
|
7376
|
+
const confidence = (0, import_types22.confidenceForExtracted)(ep.confidenceKind);
|
|
7046
7377
|
const relFile = toPosix2(ep.evidence.file);
|
|
7047
7378
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
7048
7379
|
graph,
|
|
@@ -7052,7 +7383,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
7052
7383
|
);
|
|
7053
7384
|
nodesAdded += n;
|
|
7054
7385
|
edgesAdded += e;
|
|
7055
|
-
if (!(0,
|
|
7386
|
+
if (!(0, import_types22.passesExtractedFloor)(confidence)) {
|
|
7056
7387
|
noteExtractedDropped({
|
|
7057
7388
|
source: fileNodeId,
|
|
7058
7389
|
target: ep.infraId,
|
|
@@ -7072,7 +7403,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
7072
7403
|
source: fileNodeId,
|
|
7073
7404
|
target: ep.infraId,
|
|
7074
7405
|
type: edgeType,
|
|
7075
|
-
provenance:
|
|
7406
|
+
provenance: import_types22.Provenance.EXTRACTED,
|
|
7076
7407
|
confidence,
|
|
7077
7408
|
evidence: ep.evidence
|
|
7078
7409
|
};
|
|
@@ -7098,16 +7429,16 @@ init_cjs_shims();
|
|
|
7098
7429
|
|
|
7099
7430
|
// src/extract/infra/docker-compose.ts
|
|
7100
7431
|
init_cjs_shims();
|
|
7101
|
-
var
|
|
7102
|
-
var
|
|
7432
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
7433
|
+
var import_types24 = require("@neat.is/types");
|
|
7103
7434
|
|
|
7104
7435
|
// src/extract/infra/shared.ts
|
|
7105
7436
|
init_cjs_shims();
|
|
7106
|
-
var
|
|
7437
|
+
var import_types23 = require("@neat.is/types");
|
|
7107
7438
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
7108
7439
|
return {
|
|
7109
|
-
id: (0,
|
|
7110
|
-
type:
|
|
7440
|
+
id: (0, import_types23.infraId)(kind, name),
|
|
7441
|
+
type: import_types23.NodeType.InfraNode,
|
|
7111
7442
|
name,
|
|
7112
7443
|
provider,
|
|
7113
7444
|
kind,
|
|
@@ -7151,8 +7482,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
7151
7482
|
source: anchorId,
|
|
7152
7483
|
target: node.id,
|
|
7153
7484
|
type: edgeType,
|
|
7154
|
-
provenance:
|
|
7155
|
-
confidence: (0,
|
|
7485
|
+
provenance: import_types23.Provenance.EXTRACTED,
|
|
7486
|
+
confidence: (0, import_types23.confidenceForExtracted)("structural"),
|
|
7156
7487
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
7157
7488
|
};
|
|
7158
7489
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7169,7 +7500,7 @@ function dependsOnList(value) {
|
|
|
7169
7500
|
}
|
|
7170
7501
|
function serviceNameToServiceNode(name, services) {
|
|
7171
7502
|
for (const s of services) {
|
|
7172
|
-
if (s.node.name === name ||
|
|
7503
|
+
if (s.node.name === name || import_node_path34.default.basename(s.dir) === name) return s.node.id;
|
|
7173
7504
|
}
|
|
7174
7505
|
return null;
|
|
7175
7506
|
}
|
|
@@ -7178,7 +7509,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7178
7509
|
let edgesAdded = 0;
|
|
7179
7510
|
let composePath = null;
|
|
7180
7511
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
7181
|
-
const abs =
|
|
7512
|
+
const abs = import_node_path34.default.join(scanPath, name);
|
|
7182
7513
|
if (await exists2(abs)) {
|
|
7183
7514
|
composePath = abs;
|
|
7184
7515
|
break;
|
|
@@ -7191,13 +7522,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7191
7522
|
} catch (err) {
|
|
7192
7523
|
recordExtractionError(
|
|
7193
7524
|
"infra docker-compose",
|
|
7194
|
-
|
|
7525
|
+
import_node_path34.default.relative(scanPath, composePath),
|
|
7195
7526
|
err
|
|
7196
7527
|
);
|
|
7197
7528
|
return { nodesAdded, edgesAdded };
|
|
7198
7529
|
}
|
|
7199
7530
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
7200
|
-
const evidenceFile =
|
|
7531
|
+
const evidenceFile = import_node_path34.default.relative(scanPath, composePath).split(import_node_path34.default.sep).join("/");
|
|
7201
7532
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
7202
7533
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
7203
7534
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -7219,15 +7550,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7219
7550
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
7220
7551
|
const targetId = composeNameToNodeId.get(dep);
|
|
7221
7552
|
if (!targetId) continue;
|
|
7222
|
-
const edgeId = (0, import_types5.extractedEdgeId)(sourceId, targetId,
|
|
7553
|
+
const edgeId = (0, import_types5.extractedEdgeId)(sourceId, targetId, import_types24.EdgeType.DEPENDS_ON);
|
|
7223
7554
|
if (graph.hasEdge(edgeId)) continue;
|
|
7224
7555
|
const edge = {
|
|
7225
7556
|
id: edgeId,
|
|
7226
7557
|
source: sourceId,
|
|
7227
7558
|
target: targetId,
|
|
7228
|
-
type:
|
|
7229
|
-
provenance:
|
|
7230
|
-
confidence: (0,
|
|
7559
|
+
type: import_types24.EdgeType.DEPENDS_ON,
|
|
7560
|
+
provenance: import_types24.Provenance.EXTRACTED,
|
|
7561
|
+
confidence: (0, import_types24.confidenceForExtracted)("structural"),
|
|
7231
7562
|
evidence: { file: evidenceFile }
|
|
7232
7563
|
};
|
|
7233
7564
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7239,9 +7570,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
7239
7570
|
|
|
7240
7571
|
// src/extract/infra/dockerfile.ts
|
|
7241
7572
|
init_cjs_shims();
|
|
7242
|
-
var
|
|
7573
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
7243
7574
|
var import_node_fs18 = require("fs");
|
|
7244
|
-
var
|
|
7575
|
+
var import_types25 = require("@neat.is/types");
|
|
7245
7576
|
function readDockerfile(content) {
|
|
7246
7577
|
let image = null;
|
|
7247
7578
|
const ports = [];
|
|
@@ -7270,7 +7601,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7270
7601
|
let nodesAdded = 0;
|
|
7271
7602
|
let edgesAdded = 0;
|
|
7272
7603
|
for (const service of services) {
|
|
7273
|
-
const dockerfilePath =
|
|
7604
|
+
const dockerfilePath = import_node_path35.default.join(service.dir, "Dockerfile");
|
|
7274
7605
|
if (!await exists2(dockerfilePath)) continue;
|
|
7275
7606
|
let content;
|
|
7276
7607
|
try {
|
|
@@ -7278,7 +7609,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7278
7609
|
} catch (err) {
|
|
7279
7610
|
recordExtractionError(
|
|
7280
7611
|
"infra dockerfile",
|
|
7281
|
-
|
|
7612
|
+
import_node_path35.default.relative(scanPath, dockerfilePath),
|
|
7282
7613
|
err
|
|
7283
7614
|
);
|
|
7284
7615
|
continue;
|
|
@@ -7290,8 +7621,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7290
7621
|
graph.addNode(node.id, node);
|
|
7291
7622
|
nodesAdded++;
|
|
7292
7623
|
}
|
|
7293
|
-
const relDockerfile = toPosix2(
|
|
7294
|
-
const evidenceFile = toPosix2(
|
|
7624
|
+
const relDockerfile = toPosix2(import_node_path35.default.relative(service.dir, dockerfilePath));
|
|
7625
|
+
const evidenceFile = toPosix2(import_node_path35.default.relative(scanPath, dockerfilePath));
|
|
7295
7626
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7296
7627
|
graph,
|
|
7297
7628
|
service.pkg.name,
|
|
@@ -7300,15 +7631,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7300
7631
|
);
|
|
7301
7632
|
nodesAdded += fn;
|
|
7302
7633
|
edgesAdded += fe;
|
|
7303
|
-
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, node.id,
|
|
7634
|
+
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, node.id, import_types25.EdgeType.RUNS_ON);
|
|
7304
7635
|
if (!graph.hasEdge(edgeId)) {
|
|
7305
7636
|
const edge = {
|
|
7306
7637
|
id: edgeId,
|
|
7307
7638
|
source: fileNodeId,
|
|
7308
7639
|
target: node.id,
|
|
7309
|
-
type:
|
|
7310
|
-
provenance:
|
|
7311
|
-
confidence: (0,
|
|
7640
|
+
type: import_types25.EdgeType.RUNS_ON,
|
|
7641
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7642
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7312
7643
|
evidence: {
|
|
7313
7644
|
file: evidenceFile,
|
|
7314
7645
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -7323,15 +7654,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7323
7654
|
graph.addNode(portNode.id, portNode);
|
|
7324
7655
|
nodesAdded++;
|
|
7325
7656
|
}
|
|
7326
|
-
const portEdgeId = (0, import_types5.extractedEdgeId)(fileNodeId, portNode.id,
|
|
7657
|
+
const portEdgeId = (0, import_types5.extractedEdgeId)(fileNodeId, portNode.id, import_types25.EdgeType.CONNECTS_TO);
|
|
7327
7658
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
7328
7659
|
const portEdge = {
|
|
7329
7660
|
id: portEdgeId,
|
|
7330
7661
|
source: fileNodeId,
|
|
7331
7662
|
target: portNode.id,
|
|
7332
|
-
type:
|
|
7333
|
-
provenance:
|
|
7334
|
-
confidence: (0,
|
|
7663
|
+
type: import_types25.EdgeType.CONNECTS_TO,
|
|
7664
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7665
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7335
7666
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
7336
7667
|
};
|
|
7337
7668
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -7344,8 +7675,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
7344
7675
|
// src/extract/infra/terraform.ts
|
|
7345
7676
|
init_cjs_shims();
|
|
7346
7677
|
var import_node_fs19 = require("fs");
|
|
7347
|
-
var
|
|
7348
|
-
var
|
|
7678
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
7679
|
+
var import_types26 = require("@neat.is/types");
|
|
7349
7680
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
7350
7681
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
7351
7682
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -7355,11 +7686,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
7355
7686
|
for (const entry of entries) {
|
|
7356
7687
|
if (entry.isDirectory()) {
|
|
7357
7688
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
7358
|
-
const child =
|
|
7689
|
+
const child = import_node_path36.default.join(start, entry.name);
|
|
7359
7690
|
if (await isPythonVenvDir(child)) continue;
|
|
7360
7691
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
7361
7692
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
7362
|
-
out.push(
|
|
7693
|
+
out.push(import_node_path36.default.join(start, entry.name));
|
|
7363
7694
|
}
|
|
7364
7695
|
}
|
|
7365
7696
|
return out;
|
|
@@ -7391,7 +7722,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7391
7722
|
const files = await walkTfFiles(scanPath);
|
|
7392
7723
|
for (const file of files) {
|
|
7393
7724
|
const content = await import_node_fs19.promises.readFile(file, "utf8");
|
|
7394
|
-
const evidenceFile = toPosix2(
|
|
7725
|
+
const evidenceFile = toPosix2(import_node_path36.default.relative(scanPath, file));
|
|
7395
7726
|
const resources = [];
|
|
7396
7727
|
const byKey = /* @__PURE__ */ new Map();
|
|
7397
7728
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -7426,16 +7757,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7426
7757
|
if (!target) continue;
|
|
7427
7758
|
if (seen.has(target.nodeId)) continue;
|
|
7428
7759
|
seen.add(target.nodeId);
|
|
7429
|
-
const edgeId = (0, import_types5.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
7760
|
+
const edgeId = (0, import_types5.extractedEdgeId)(resource.nodeId, target.nodeId, import_types26.EdgeType.DEPENDS_ON);
|
|
7430
7761
|
if (graph.hasEdge(edgeId)) continue;
|
|
7431
7762
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
7432
7763
|
const edge = {
|
|
7433
7764
|
id: edgeId,
|
|
7434
7765
|
source: resource.nodeId,
|
|
7435
7766
|
target: target.nodeId,
|
|
7436
|
-
type:
|
|
7437
|
-
provenance:
|
|
7438
|
-
confidence: (0,
|
|
7767
|
+
type: import_types26.EdgeType.DEPENDS_ON,
|
|
7768
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7769
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7439
7770
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
7440
7771
|
};
|
|
7441
7772
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7449,7 +7780,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
7449
7780
|
// src/extract/infra/k8s.ts
|
|
7450
7781
|
init_cjs_shims();
|
|
7451
7782
|
var import_node_fs20 = require("fs");
|
|
7452
|
-
var
|
|
7783
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
7453
7784
|
var import_yaml3 = require("yaml");
|
|
7454
7785
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
7455
7786
|
Service: "k8s-service",
|
|
@@ -7467,11 +7798,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
7467
7798
|
for (const entry of entries) {
|
|
7468
7799
|
if (entry.isDirectory()) {
|
|
7469
7800
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
7470
|
-
const child =
|
|
7801
|
+
const child = import_node_path37.default.join(start, entry.name);
|
|
7471
7802
|
if (await isPythonVenvDir(child)) continue;
|
|
7472
7803
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
7473
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
7474
|
-
out.push(
|
|
7804
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path37.default.extname(entry.name))) {
|
|
7805
|
+
out.push(import_node_path37.default.join(start, entry.name));
|
|
7475
7806
|
}
|
|
7476
7807
|
}
|
|
7477
7808
|
return out;
|
|
@@ -7505,13 +7836,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
7505
7836
|
// src/extract/infra/cloudflare.ts
|
|
7506
7837
|
init_cjs_shims();
|
|
7507
7838
|
var import_node_fs21 = require("fs");
|
|
7508
|
-
var
|
|
7839
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7509
7840
|
var import_smol_toml2 = require("smol-toml");
|
|
7510
|
-
var
|
|
7841
|
+
var import_types27 = require("@neat.is/types");
|
|
7511
7842
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
7512
7843
|
async function readWranglerConfig(dir) {
|
|
7513
7844
|
for (const filename of WRANGLER_FILENAMES) {
|
|
7514
|
-
const abs =
|
|
7845
|
+
const abs = import_node_path38.default.join(dir, filename);
|
|
7515
7846
|
if (!await exists2(abs)) continue;
|
|
7516
7847
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
7517
7848
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7555,8 +7886,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
7555
7886
|
source: anchorId,
|
|
7556
7887
|
target: node.id,
|
|
7557
7888
|
type: edgeType,
|
|
7558
|
-
provenance:
|
|
7559
|
-
confidence: (0,
|
|
7889
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7890
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7560
7891
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
7561
7892
|
};
|
|
7562
7893
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7574,11 +7905,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7574
7905
|
try {
|
|
7575
7906
|
read = await readWranglerConfig(service.dir);
|
|
7576
7907
|
} catch (err) {
|
|
7577
|
-
recordExtractionError("infra cloudflare",
|
|
7908
|
+
recordExtractionError("infra cloudflare", import_node_path38.default.relative(scanPath, service.dir), err);
|
|
7578
7909
|
continue;
|
|
7579
7910
|
}
|
|
7580
7911
|
if (!read || !read.config.name) continue;
|
|
7581
|
-
const evidenceFile = toPosix2(
|
|
7912
|
+
const evidenceFile = toPosix2(import_node_path38.default.relative(scanPath, import_node_path38.default.join(service.dir, read.relFile)));
|
|
7582
7913
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
7583
7914
|
}
|
|
7584
7915
|
for (const worker of discovered) {
|
|
@@ -7590,7 +7921,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7590
7921
|
}
|
|
7591
7922
|
let anchorId = service.node.id;
|
|
7592
7923
|
if (config.main) {
|
|
7593
|
-
const entryRelPath = toPosix2(
|
|
7924
|
+
const entryRelPath = toPosix2(import_node_path38.default.normalize(config.main));
|
|
7594
7925
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7595
7926
|
graph,
|
|
7596
7927
|
service.pkg.name,
|
|
@@ -7617,15 +7948,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7617
7948
|
nodesAdded++;
|
|
7618
7949
|
}
|
|
7619
7950
|
if (runtimeNode.id !== anchorId) {
|
|
7620
|
-
const runsOnId = (0, import_types5.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
7951
|
+
const runsOnId = (0, import_types5.extractedEdgeId)(anchorId, runtimeNode.id, import_types27.EdgeType.RUNS_ON);
|
|
7621
7952
|
if (!graph.hasEdge(runsOnId)) {
|
|
7622
7953
|
const edge = {
|
|
7623
7954
|
id: runsOnId,
|
|
7624
7955
|
source: anchorId,
|
|
7625
7956
|
target: runtimeNode.id,
|
|
7626
|
-
type:
|
|
7627
|
-
provenance:
|
|
7628
|
-
confidence: (0,
|
|
7957
|
+
type: import_types27.EdgeType.RUNS_ON,
|
|
7958
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
7959
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7629
7960
|
evidence: {
|
|
7630
7961
|
file: evidenceFile,
|
|
7631
7962
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -7639,7 +7970,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7639
7970
|
const result = addResourceEdge(
|
|
7640
7971
|
graph,
|
|
7641
7972
|
anchorId,
|
|
7642
|
-
|
|
7973
|
+
import_types27.EdgeType.CONNECTS_TO,
|
|
7643
7974
|
"cloudflare-route",
|
|
7644
7975
|
route,
|
|
7645
7976
|
evidenceFile,
|
|
@@ -7663,7 +7994,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7663
7994
|
const result = addResourceEdge(
|
|
7664
7995
|
graph,
|
|
7665
7996
|
anchorId,
|
|
7666
|
-
|
|
7997
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7667
7998
|
group.kind,
|
|
7668
7999
|
name,
|
|
7669
8000
|
evidenceFile,
|
|
@@ -7677,7 +8008,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7677
8008
|
const result = addResourceEdge(
|
|
7678
8009
|
graph,
|
|
7679
8010
|
anchorId,
|
|
7680
|
-
|
|
8011
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7681
8012
|
"cloudflare-cron",
|
|
7682
8013
|
cron,
|
|
7683
8014
|
evidenceFile,
|
|
@@ -7690,7 +8021,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7690
8021
|
const result = addResourceEdge(
|
|
7691
8022
|
graph,
|
|
7692
8023
|
anchorId,
|
|
7693
|
-
|
|
8024
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7694
8025
|
"cloudflare-env-var",
|
|
7695
8026
|
varName,
|
|
7696
8027
|
evidenceFile,
|
|
@@ -7703,15 +8034,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7703
8034
|
if (!svc.service) continue;
|
|
7704
8035
|
const target = workerIndex.get(svc.service);
|
|
7705
8036
|
if (target && target.anchorId !== anchorId) {
|
|
7706
|
-
const edgeId = (0, import_types5.extractedEdgeId)(anchorId, target.anchorId,
|
|
8037
|
+
const edgeId = (0, import_types5.extractedEdgeId)(anchorId, target.anchorId, import_types27.EdgeType.CALLS);
|
|
7707
8038
|
if (!graph.hasEdge(edgeId)) {
|
|
7708
8039
|
const edge = {
|
|
7709
8040
|
id: edgeId,
|
|
7710
8041
|
source: anchorId,
|
|
7711
8042
|
target: target.anchorId,
|
|
7712
|
-
type:
|
|
7713
|
-
provenance:
|
|
7714
|
-
confidence: (0,
|
|
8043
|
+
type: import_types27.EdgeType.CALLS,
|
|
8044
|
+
provenance: import_types27.Provenance.EXTRACTED,
|
|
8045
|
+
confidence: (0, import_types27.confidenceForExtracted)("structural"),
|
|
7715
8046
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
7716
8047
|
};
|
|
7717
8048
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7722,7 +8053,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7722
8053
|
const result = addResourceEdge(
|
|
7723
8054
|
graph,
|
|
7724
8055
|
anchorId,
|
|
7725
|
-
|
|
8056
|
+
import_types27.EdgeType.DEPENDS_ON,
|
|
7726
8057
|
"cloudflare-service-binding",
|
|
7727
8058
|
svc.service,
|
|
7728
8059
|
evidenceFile,
|
|
@@ -7738,12 +8069,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7738
8069
|
// src/extract/infra/vercel.ts
|
|
7739
8070
|
init_cjs_shims();
|
|
7740
8071
|
var import_node_fs22 = require("fs");
|
|
7741
|
-
var
|
|
7742
|
-
var
|
|
8072
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
8073
|
+
var import_types28 = require("@neat.is/types");
|
|
7743
8074
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
7744
8075
|
async function readVercelConfig(dir) {
|
|
7745
8076
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
7746
|
-
const abs =
|
|
8077
|
+
const abs = import_node_path39.default.join(dir, filename);
|
|
7747
8078
|
if (!await exists2(abs)) continue;
|
|
7748
8079
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
7749
8080
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7752,7 +8083,7 @@ async function readVercelConfig(dir) {
|
|
|
7752
8083
|
return null;
|
|
7753
8084
|
}
|
|
7754
8085
|
async function readLinkedProjectName(dir) {
|
|
7755
|
-
const abs =
|
|
8086
|
+
const abs = import_node_path39.default.join(dir, ".vercel", "project.json");
|
|
7756
8087
|
if (!await exists2(abs)) return void 0;
|
|
7757
8088
|
const parsed = JSON.parse(await import_node_fs22.promises.readFile(abs, "utf8"));
|
|
7758
8089
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -7770,7 +8101,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7770
8101
|
read = await readVercelConfig(service.dir);
|
|
7771
8102
|
projectName = await readLinkedProjectName(service.dir);
|
|
7772
8103
|
} catch (err) {
|
|
7773
|
-
recordExtractionError("infra vercel",
|
|
8104
|
+
recordExtractionError("infra vercel", import_node_path39.default.relative(scanPath, service.dir), err);
|
|
7774
8105
|
continue;
|
|
7775
8106
|
}
|
|
7776
8107
|
if (!read && !projectName) continue;
|
|
@@ -7786,7 +8117,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7786
8117
|
const anchorId = service.node.id;
|
|
7787
8118
|
if (!read) continue;
|
|
7788
8119
|
const { config, relFile, raw } = read;
|
|
7789
|
-
const evidenceFile = toPosix2(
|
|
8120
|
+
const evidenceFile = toPosix2(import_node_path39.default.relative(scanPath, import_node_path39.default.join(service.dir, relFile)));
|
|
7790
8121
|
const add = (edgeType, kind, name) => {
|
|
7791
8122
|
if (!name) return;
|
|
7792
8123
|
const result = emitPlatformResourceEdge(
|
|
@@ -7802,12 +8133,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7802
8133
|
nodesAdded += result.nodesAdded;
|
|
7803
8134
|
edgesAdded += result.edgesAdded;
|
|
7804
8135
|
};
|
|
7805
|
-
add(
|
|
7806
|
-
for (const cron of config.crons ?? []) add(
|
|
7807
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
7808
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
8136
|
+
add(import_types28.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
8137
|
+
for (const cron of config.crons ?? []) add(import_types28.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
8138
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types28.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
8139
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types28.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7809
8140
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
7810
|
-
add(
|
|
8141
|
+
add(import_types28.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
7811
8142
|
}
|
|
7812
8143
|
}
|
|
7813
8144
|
return { nodesAdded, edgesAdded };
|
|
@@ -7816,13 +8147,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7816
8147
|
// src/extract/infra/railway.ts
|
|
7817
8148
|
init_cjs_shims();
|
|
7818
8149
|
var import_node_fs23 = require("fs");
|
|
7819
|
-
var
|
|
8150
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7820
8151
|
var import_smol_toml3 = require("smol-toml");
|
|
7821
|
-
var
|
|
8152
|
+
var import_types29 = require("@neat.is/types");
|
|
7822
8153
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
7823
8154
|
async function readRailwayConfig(dir) {
|
|
7824
8155
|
for (const filename of RAILWAY_FILENAMES) {
|
|
7825
|
-
const abs =
|
|
8156
|
+
const abs = import_node_path40.default.join(dir, filename);
|
|
7826
8157
|
if (!await exists2(abs)) continue;
|
|
7827
8158
|
const raw = await import_node_fs23.promises.readFile(abs, "utf8");
|
|
7828
8159
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7838,7 +8169,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7838
8169
|
try {
|
|
7839
8170
|
read = await readRailwayConfig(service.dir);
|
|
7840
8171
|
} catch (err) {
|
|
7841
|
-
recordExtractionError("infra railway",
|
|
8172
|
+
recordExtractionError("infra railway", import_node_path40.default.relative(scanPath, service.dir), err);
|
|
7842
8173
|
continue;
|
|
7843
8174
|
}
|
|
7844
8175
|
if (!read) continue;
|
|
@@ -7848,7 +8179,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7848
8179
|
}
|
|
7849
8180
|
const anchorId = service.node.id;
|
|
7850
8181
|
const { config, relFile, raw } = read;
|
|
7851
|
-
const evidenceFile = toPosix2(
|
|
8182
|
+
const evidenceFile = toPosix2(import_node_path40.default.relative(scanPath, import_node_path40.default.join(service.dir, relFile)));
|
|
7852
8183
|
const add = (edgeType, kind, name) => {
|
|
7853
8184
|
if (!name) return;
|
|
7854
8185
|
const result = emitPlatformResourceEdge(
|
|
@@ -7864,9 +8195,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7864
8195
|
nodesAdded += result.nodesAdded;
|
|
7865
8196
|
edgesAdded += result.edgesAdded;
|
|
7866
8197
|
};
|
|
7867
|
-
add(
|
|
7868
|
-
add(
|
|
7869
|
-
add(
|
|
8198
|
+
add(import_types29.EdgeType.RUNS_ON, "railway", "railway");
|
|
8199
|
+
add(import_types29.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
8200
|
+
add(import_types29.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
7870
8201
|
}
|
|
7871
8202
|
return { nodesAdded, edgesAdded };
|
|
7872
8203
|
}
|
|
@@ -7874,12 +8205,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7874
8205
|
// src/extract/infra/supabase.ts
|
|
7875
8206
|
init_cjs_shims();
|
|
7876
8207
|
var import_node_fs24 = require("fs");
|
|
7877
|
-
var
|
|
8208
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7878
8209
|
var import_smol_toml4 = require("smol-toml");
|
|
7879
|
-
var
|
|
8210
|
+
var import_types30 = require("@neat.is/types");
|
|
7880
8211
|
async function readSupabaseConfig(dir) {
|
|
7881
|
-
const relFile =
|
|
7882
|
-
const abs =
|
|
8212
|
+
const relFile = import_node_path41.default.join("supabase", "config.toml");
|
|
8213
|
+
const abs = import_node_path41.default.join(dir, relFile);
|
|
7883
8214
|
if (!await exists2(abs)) return null;
|
|
7884
8215
|
const raw = await import_node_fs24.promises.readFile(abs, "utf8");
|
|
7885
8216
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -7893,7 +8224,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7893
8224
|
try {
|
|
7894
8225
|
read = await readSupabaseConfig(service.dir);
|
|
7895
8226
|
} catch (err) {
|
|
7896
|
-
recordExtractionError("infra supabase",
|
|
8227
|
+
recordExtractionError("infra supabase", import_node_path41.default.relative(scanPath, service.dir), err);
|
|
7897
8228
|
continue;
|
|
7898
8229
|
}
|
|
7899
8230
|
if (!read) continue;
|
|
@@ -7908,7 +8239,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7908
8239
|
});
|
|
7909
8240
|
}
|
|
7910
8241
|
const anchorId = service.node.id;
|
|
7911
|
-
const evidenceFile = toPosix2(
|
|
8242
|
+
const evidenceFile = toPosix2(import_node_path41.default.relative(scanPath, import_node_path41.default.join(service.dir, relFile)));
|
|
7912
8243
|
const add = (edgeType, kind, name) => {
|
|
7913
8244
|
if (!name) return;
|
|
7914
8245
|
const result = emitPlatformResourceEdge(
|
|
@@ -7924,10 +8255,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7924
8255
|
nodesAdded += result.nodesAdded;
|
|
7925
8256
|
edgesAdded += result.edgesAdded;
|
|
7926
8257
|
};
|
|
7927
|
-
add(
|
|
7928
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
7929
|
-
if (config.storage) add(
|
|
7930
|
-
if (config.auth) add(
|
|
8258
|
+
add(import_types30.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
8259
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types30.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
8260
|
+
if (config.storage) add(import_types30.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
8261
|
+
if (config.auth) add(import_types30.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
7931
8262
|
}
|
|
7932
8263
|
return { nodesAdded, edgesAdded };
|
|
7933
8264
|
}
|
|
@@ -7949,17 +8280,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
7949
8280
|
}
|
|
7950
8281
|
|
|
7951
8282
|
// src/extract/index.ts
|
|
7952
|
-
var
|
|
8283
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
7953
8284
|
|
|
7954
8285
|
// src/extract/retire.ts
|
|
7955
8286
|
init_cjs_shims();
|
|
7956
8287
|
var import_node_fs25 = require("fs");
|
|
7957
|
-
var
|
|
7958
|
-
var
|
|
8288
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
8289
|
+
var import_types31 = require("@neat.is/types");
|
|
7959
8290
|
function dropOrphanedFileNodes(graph) {
|
|
7960
8291
|
const orphans = [];
|
|
7961
8292
|
graph.forEachNode((id, attrs) => {
|
|
7962
|
-
if (attrs.type !==
|
|
8293
|
+
if (attrs.type !== import_types31.NodeType.FileNode) return;
|
|
7963
8294
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
7964
8295
|
orphans.push(id);
|
|
7965
8296
|
}
|
|
@@ -7972,14 +8303,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
7972
8303
|
const bases = [scanPath, ...serviceDirs];
|
|
7973
8304
|
graph.forEachEdge((id, attrs) => {
|
|
7974
8305
|
const edge = attrs;
|
|
7975
|
-
if (edge.provenance !==
|
|
8306
|
+
if (edge.provenance !== import_types31.Provenance.EXTRACTED) return;
|
|
7976
8307
|
const evidenceFile = edge.evidence?.file;
|
|
7977
8308
|
if (!evidenceFile) return;
|
|
7978
|
-
if (
|
|
8309
|
+
if (import_node_path42.default.isAbsolute(evidenceFile)) {
|
|
7979
8310
|
if (!(0, import_node_fs25.existsSync)(evidenceFile)) toDrop.push(id);
|
|
7980
8311
|
return;
|
|
7981
8312
|
}
|
|
7982
|
-
const found = bases.some((base) => (0, import_node_fs25.existsSync)(
|
|
8313
|
+
const found = bases.some((base) => (0, import_node_fs25.existsSync)(import_node_path42.default.join(base, evidenceFile)));
|
|
7983
8314
|
if (!found) toDrop.push(id);
|
|
7984
8315
|
});
|
|
7985
8316
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -8021,7 +8352,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
8021
8352
|
}
|
|
8022
8353
|
const droppedEntries = drainDroppedExtracted();
|
|
8023
8354
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
8024
|
-
const rejectedPath =
|
|
8355
|
+
const rejectedPath = import_node_path43.default.join(import_node_path43.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
8025
8356
|
try {
|
|
8026
8357
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
8027
8358
|
} catch (err) {
|
|
@@ -8133,8 +8464,8 @@ function canonicalJson(value) {
|
|
|
8133
8464
|
// src/persist.ts
|
|
8134
8465
|
init_cjs_shims();
|
|
8135
8466
|
var import_node_fs27 = require("fs");
|
|
8136
|
-
var
|
|
8137
|
-
var
|
|
8467
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8468
|
+
var import_types32 = require("@neat.is/types");
|
|
8138
8469
|
var SCHEMA_VERSION = 4;
|
|
8139
8470
|
function migrateV1ToV2(payload) {
|
|
8140
8471
|
const nodes = payload.graph.nodes;
|
|
@@ -8156,12 +8487,12 @@ function migrateV2ToV3(payload) {
|
|
|
8156
8487
|
for (const edge of edges) {
|
|
8157
8488
|
const attrs = edge.attributes;
|
|
8158
8489
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
8159
|
-
attrs.provenance =
|
|
8490
|
+
attrs.provenance = import_types32.Provenance.OBSERVED;
|
|
8160
8491
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
8161
8492
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
8162
8493
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
8163
8494
|
if (type && source && target) {
|
|
8164
|
-
const newId = (0,
|
|
8495
|
+
const newId = (0, import_types32.observedEdgeId)(source, target, type);
|
|
8165
8496
|
attrs.id = newId;
|
|
8166
8497
|
if (edge.key) edge.key = newId;
|
|
8167
8498
|
}
|
|
@@ -8170,7 +8501,7 @@ function migrateV2ToV3(payload) {
|
|
|
8170
8501
|
return { ...payload, schemaVersion: 3 };
|
|
8171
8502
|
}
|
|
8172
8503
|
async function ensureDir(filePath) {
|
|
8173
|
-
await import_node_fs27.promises.mkdir(
|
|
8504
|
+
await import_node_fs27.promises.mkdir(import_node_path44.default.dirname(filePath), { recursive: true });
|
|
8174
8505
|
}
|
|
8175
8506
|
async function saveGraphToDisk(graph, outPath) {
|
|
8176
8507
|
await ensureDir(outPath);
|
|
@@ -8251,23 +8582,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
8251
8582
|
|
|
8252
8583
|
// src/projects.ts
|
|
8253
8584
|
init_cjs_shims();
|
|
8254
|
-
var
|
|
8585
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8255
8586
|
function pathsForProject(project, baseDir) {
|
|
8256
8587
|
if (project === DEFAULT_PROJECT) {
|
|
8257
8588
|
return {
|
|
8258
|
-
snapshotPath:
|
|
8259
|
-
errorsPath:
|
|
8260
|
-
staleEventsPath:
|
|
8261
|
-
embeddingsCachePath:
|
|
8262
|
-
policyViolationsPath:
|
|
8589
|
+
snapshotPath: import_node_path45.default.join(baseDir, "graph.json"),
|
|
8590
|
+
errorsPath: import_node_path45.default.join(baseDir, "errors.ndjson"),
|
|
8591
|
+
staleEventsPath: import_node_path45.default.join(baseDir, "stale-events.ndjson"),
|
|
8592
|
+
embeddingsCachePath: import_node_path45.default.join(baseDir, "embeddings.json"),
|
|
8593
|
+
policyViolationsPath: import_node_path45.default.join(baseDir, "policy-violations.ndjson")
|
|
8263
8594
|
};
|
|
8264
8595
|
}
|
|
8265
8596
|
return {
|
|
8266
|
-
snapshotPath:
|
|
8267
|
-
errorsPath:
|
|
8268
|
-
staleEventsPath:
|
|
8269
|
-
embeddingsCachePath:
|
|
8270
|
-
policyViolationsPath:
|
|
8597
|
+
snapshotPath: import_node_path45.default.join(baseDir, `${project}.json`),
|
|
8598
|
+
errorsPath: import_node_path45.default.join(baseDir, `errors.${project}.ndjson`),
|
|
8599
|
+
staleEventsPath: import_node_path45.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
8600
|
+
embeddingsCachePath: import_node_path45.default.join(baseDir, `embeddings.${project}.json`),
|
|
8601
|
+
policyViolationsPath: import_node_path45.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
8271
8602
|
};
|
|
8272
8603
|
}
|
|
8273
8604
|
var Projects = class {
|
|
@@ -8309,15 +8640,15 @@ function parseExtraProjects(raw) {
|
|
|
8309
8640
|
init_cjs_shims();
|
|
8310
8641
|
var import_node_fs28 = require("fs");
|
|
8311
8642
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
8312
|
-
var
|
|
8313
|
-
var
|
|
8643
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8644
|
+
var import_types33 = require("@neat.is/types");
|
|
8314
8645
|
function neatHome() {
|
|
8315
8646
|
const override = process.env.NEAT_HOME;
|
|
8316
|
-
if (override && override.length > 0) return
|
|
8317
|
-
return
|
|
8647
|
+
if (override && override.length > 0) return import_node_path46.default.resolve(override);
|
|
8648
|
+
return import_node_path46.default.join(import_node_os3.default.homedir(), ".neat");
|
|
8318
8649
|
}
|
|
8319
8650
|
function registryPath() {
|
|
8320
|
-
return
|
|
8651
|
+
return import_node_path46.default.join(neatHome(), "projects.json");
|
|
8321
8652
|
}
|
|
8322
8653
|
async function readRegistry() {
|
|
8323
8654
|
const file = registryPath();
|
|
@@ -8331,7 +8662,7 @@ async function readRegistry() {
|
|
|
8331
8662
|
throw err;
|
|
8332
8663
|
}
|
|
8333
8664
|
const parsed = JSON.parse(raw);
|
|
8334
|
-
return
|
|
8665
|
+
return import_types33.RegistryFileSchema.parse(parsed);
|
|
8335
8666
|
}
|
|
8336
8667
|
async function getProject(name) {
|
|
8337
8668
|
const reg = await readRegistry();
|
|
@@ -8406,16 +8737,16 @@ init_auth();
|
|
|
8406
8737
|
// src/connectors-config.ts
|
|
8407
8738
|
init_cjs_shims();
|
|
8408
8739
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
8409
|
-
var
|
|
8740
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
8410
8741
|
var import_node_fs29 = require("fs");
|
|
8411
8742
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
8412
8743
|
function neatHome2() {
|
|
8413
8744
|
const override = process.env.NEAT_HOME;
|
|
8414
|
-
if (override && override.length > 0) return
|
|
8415
|
-
return
|
|
8745
|
+
if (override && override.length > 0) return import_node_path47.default.resolve(override);
|
|
8746
|
+
return import_node_path47.default.join(import_node_os4.default.homedir(), ".neat");
|
|
8416
8747
|
}
|
|
8417
8748
|
function connectorsConfigPath(home = neatHome2()) {
|
|
8418
|
-
return
|
|
8749
|
+
return import_node_path47.default.join(home, "connectors.json");
|
|
8419
8750
|
}
|
|
8420
8751
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
8421
8752
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -8714,11 +9045,11 @@ function registerRoutes(scope, ctx) {
|
|
|
8714
9045
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
8715
9046
|
const parsed = [];
|
|
8716
9047
|
for (const c of candidates) {
|
|
8717
|
-
const r =
|
|
9048
|
+
const r = import_types34.DivergenceTypeSchema.safeParse(c);
|
|
8718
9049
|
if (!r.success) {
|
|
8719
9050
|
return reply.code(400).send({
|
|
8720
9051
|
error: `unknown divergence type "${c}"`,
|
|
8721
|
-
allowed:
|
|
9052
|
+
allowed: import_types34.DivergenceTypeSchema.options
|
|
8722
9053
|
});
|
|
8723
9054
|
}
|
|
8724
9055
|
parsed.push(r.data);
|
|
@@ -8989,7 +9320,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8989
9320
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
8990
9321
|
let violations = await log.readAll();
|
|
8991
9322
|
if (req.query.severity) {
|
|
8992
|
-
const sev =
|
|
9323
|
+
const sev = import_types34.PolicySeveritySchema.safeParse(req.query.severity);
|
|
8993
9324
|
if (!sev.success) {
|
|
8994
9325
|
return reply.code(400).send({
|
|
8995
9326
|
error: "invalid severity",
|
|
@@ -9028,7 +9359,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9028
9359
|
scope.post("/policies/check", async (req, reply) => {
|
|
9029
9360
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
9030
9361
|
if (!proj) return;
|
|
9031
|
-
const parsed =
|
|
9362
|
+
const parsed = import_types34.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
9032
9363
|
if (!parsed.success) {
|
|
9033
9364
|
return reply.code(400).send({
|
|
9034
9365
|
error: "invalid /policies/check body",
|
|
@@ -9100,6 +9431,42 @@ function registerRoutes(scope, ctx) {
|
|
|
9100
9431
|
return reply.code(500).send({ error: err.message });
|
|
9101
9432
|
}
|
|
9102
9433
|
});
|
|
9434
|
+
scope.get("/instrumentation", async (req, reply) => {
|
|
9435
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
9436
|
+
if (!proj) return;
|
|
9437
|
+
if (!proj.scanPath) {
|
|
9438
|
+
return { engaged: null };
|
|
9439
|
+
}
|
|
9440
|
+
try {
|
|
9441
|
+
const state = await describeProjectInstrumentation({ project: proj.name, scanPath: proj.scanPath });
|
|
9442
|
+
const uninstrumented = await listUninstrumented({ project: proj.name, scanPath: proj.scanPath });
|
|
9443
|
+
if (state.hookFiles.length === 0) {
|
|
9444
|
+
return {
|
|
9445
|
+
engaged: false,
|
|
9446
|
+
diagnosis: {
|
|
9447
|
+
reason: "No instrumented entry point found \u2014 NEAT hasn't written an OTel init hook for this project.",
|
|
9448
|
+
fixCommand: "neat init",
|
|
9449
|
+
detail: "Run `neat init` so NEAT writes the instrumentation hook next to your entry point, then run your app."
|
|
9450
|
+
}
|
|
9451
|
+
};
|
|
9452
|
+
}
|
|
9453
|
+
if (uninstrumented.length > 0) {
|
|
9454
|
+
const names = uninstrumented.map((u) => u.library);
|
|
9455
|
+
const more = names.length > 1 ? ` (and ${names.length - 1} more)` : "";
|
|
9456
|
+
return {
|
|
9457
|
+
engaged: false,
|
|
9458
|
+
diagnosis: {
|
|
9459
|
+
reason: `\`${names[0]}\`${more} isn't in the auto-instrumentation set, so spans from it won't reach the graph.`,
|
|
9460
|
+
fixCommand: "neat extend",
|
|
9461
|
+
detail: `Uninstrumented on your hot path: ${names.join(", ")}. Run \`neat extend\` to wire the missing instrumentation.`
|
|
9462
|
+
}
|
|
9463
|
+
};
|
|
9464
|
+
}
|
|
9465
|
+
return { engaged: true };
|
|
9466
|
+
} catch {
|
|
9467
|
+
return { engaged: null };
|
|
9468
|
+
}
|
|
9469
|
+
});
|
|
9103
9470
|
scope.post("/extend/apply", async (req, reply) => {
|
|
9104
9471
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
9105
9472
|
if (!proj) return;
|
|
@@ -9294,7 +9661,7 @@ init_otel_grpc();
|
|
|
9294
9661
|
// src/search.ts
|
|
9295
9662
|
init_cjs_shims();
|
|
9296
9663
|
var import_node_fs30 = require("fs");
|
|
9297
|
-
var
|
|
9664
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
9298
9665
|
var import_node_crypto3 = require("crypto");
|
|
9299
9666
|
var DEFAULT_LIMIT = 10;
|
|
9300
9667
|
var NOMIC_DIM = 768;
|
|
@@ -9457,7 +9824,7 @@ async function readCache(cachePath) {
|
|
|
9457
9824
|
}
|
|
9458
9825
|
}
|
|
9459
9826
|
async function writeCache(cachePath, cache) {
|
|
9460
|
-
await import_node_fs30.promises.mkdir(
|
|
9827
|
+
await import_node_fs30.promises.mkdir(import_node_path50.default.dirname(cachePath), { recursive: true });
|
|
9461
9828
|
await import_node_fs30.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
9462
9829
|
}
|
|
9463
9830
|
var VectorIndex = class {
|
|
@@ -9638,14 +10005,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
9638
10005
|
async function main() {
|
|
9639
10006
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
9640
10007
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
9641
|
-
const baseDir = baseDirEnv ?
|
|
9642
|
-
const defaultScanPath =
|
|
10008
|
+
const baseDir = baseDirEnv ? import_node_path51.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path51.default.resolve(import_node_path51.default.dirname(legacyOutPath)) : import_node_path51.default.resolve("./neat-out");
|
|
10009
|
+
const defaultScanPath = import_node_path51.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
|
|
9643
10010
|
const registry = new Projects();
|
|
9644
10011
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
9645
10012
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
9646
10013
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
9647
10014
|
const projectScan = process.env[envKey];
|
|
9648
|
-
await bootProject(registry, name, projectScan ?
|
|
10015
|
+
await bootProject(registry, name, projectScan ? import_node_path51.default.resolve(projectScan) : void 0, baseDir);
|
|
9649
10016
|
}
|
|
9650
10017
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
9651
10018
|
const port = Number(process.env.PORT ?? 8080);
|