@neat.is/core 0.5.2 → 0.5.4-dev.20260721
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-I72HTUOG.js → chunk-4RU3AAOI.js} +2 -2
- package/dist/{chunk-CFDPIMRP.js → chunk-I4NZ7PSN.js} +3 -2
- package/dist/chunk-I4NZ7PSN.js.map +1 -0
- package/dist/{chunk-BI3XKGVG.js → chunk-PEFX3DBR.js} +473 -127
- package/dist/chunk-PEFX3DBR.js.map +1 -0
- package/dist/{chunk-DPEPI2N6.js → chunk-VR73QNJD.js} +293 -22
- package/dist/chunk-VR73QNJD.js.map +1 -0
- package/dist/cli.cjs +1371 -479
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +343 -75
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +879 -310
- 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 +888 -319
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-IDMIH6ZY.js → otel-grpc-TEGOXE6T.js} +3 -3
- package/dist/server.cjs +553 -192
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-BI3XKGVG.js.map +0 -1
- package/dist/chunk-CFDPIMRP.js.map +0 -1
- package/dist/chunk-DPEPI2N6.js.map +0 -1
- /package/dist/{chunk-I72HTUOG.js.map → chunk-4RU3AAOI.js.map} +0 -0
- /package/dist/{otel-grpc-IDMIH6ZY.js.map → otel-grpc-TEGOXE6T.js.map} +0 -0
package/dist/neatd.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req2, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path54 = (req2.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path54) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path54)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -194,8 +194,8 @@ function reshapeGrpcRequest(req2) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
function resolveProtoRoot() {
|
|
197
|
-
const here =
|
|
198
|
-
return
|
|
197
|
+
const here = import_node_path48.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path48.default.resolve(here, "..", "proto");
|
|
199
199
|
}
|
|
200
200
|
function loadTraceService() {
|
|
201
201
|
const protoRoot = resolveProtoRoot();
|
|
@@ -263,13 +263,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
263
263
|
})
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
|
-
var import_node_url,
|
|
266
|
+
var import_node_url, import_node_path48, import_node_crypto2, grpc, protoLoader;
|
|
267
267
|
var init_otel_grpc = __esm({
|
|
268
268
|
"src/otel-grpc.ts"() {
|
|
269
269
|
"use strict";
|
|
270
270
|
init_cjs_shims();
|
|
271
271
|
import_node_url = require("url");
|
|
272
|
-
|
|
272
|
+
import_node_path48 = __toESM(require("path"), 1);
|
|
273
273
|
import_node_crypto2 = require("crypto");
|
|
274
274
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
275
275
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -362,8 +362,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
362
362
|
const v = attrs[key];
|
|
363
363
|
if (typeof v === "string" && v.length > 0) {
|
|
364
364
|
const q = v.indexOf("?");
|
|
365
|
-
const
|
|
366
|
-
if (
|
|
365
|
+
const path54 = q === -1 ? v : v.slice(0, q);
|
|
366
|
+
if (path54.length > 0) return path54;
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
return void 0;
|
|
@@ -398,6 +398,7 @@ function parseOtlpRequest(body) {
|
|
|
398
398
|
attributes: attrs,
|
|
399
399
|
dbSystem: typeof attrs["db.system"] === "string" ? attrs["db.system"] : void 0,
|
|
400
400
|
dbName: typeof attrs["db.name"] === "string" ? attrs["db.name"] : void 0,
|
|
401
|
+
dbCollection: typeof attrs["db.collection.name"] === "string" ? attrs["db.collection.name"] : typeof attrs["db.mongodb.collection"] === "string" ? attrs["db.mongodb.collection"] : void 0,
|
|
401
402
|
messagingSystem: typeof attrs["messaging.system"] === "string" ? attrs["messaging.system"] : void 0,
|
|
402
403
|
messagingDestination: messagingDestinationOf(attrs),
|
|
403
404
|
graphqlOperationName: typeof attrs["graphql.operation.name"] === "string" && attrs["graphql.operation.name"].length > 0 ? attrs["graphql.operation.name"] : void 0,
|
|
@@ -417,10 +418,10 @@ function parseOtlpRequest(body) {
|
|
|
417
418
|
return out;
|
|
418
419
|
}
|
|
419
420
|
function loadProtoRoot() {
|
|
420
|
-
const here =
|
|
421
|
-
const protoRoot =
|
|
421
|
+
const here = import_node_path49.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
422
|
+
const protoRoot = import_node_path49.default.resolve(here, "..", "proto");
|
|
422
423
|
const root = new import_protobufjs.default.Root();
|
|
423
|
-
root.resolvePath = (_origin, target) =>
|
|
424
|
+
root.resolvePath = (_origin, target) => import_node_path49.default.resolve(protoRoot, target);
|
|
424
425
|
root.loadSync(
|
|
425
426
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
426
427
|
{ keepCase: true }
|
|
@@ -648,12 +649,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
648
649
|
}
|
|
649
650
|
}
|
|
650
651
|
}
|
|
651
|
-
var
|
|
652
|
+
var import_node_path49, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
652
653
|
var init_otel = __esm({
|
|
653
654
|
"src/otel.ts"() {
|
|
654
655
|
"use strict";
|
|
655
656
|
init_cjs_shims();
|
|
656
|
-
|
|
657
|
+
import_node_path49 = __toESM(require("path"), 1);
|
|
657
658
|
import_node_url2 = require("url");
|
|
658
659
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
659
660
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -677,13 +678,13 @@ __export(neatd_exports, {
|
|
|
677
678
|
module.exports = __toCommonJS(neatd_exports);
|
|
678
679
|
init_cjs_shims();
|
|
679
680
|
var import_node_fs33 = require("fs");
|
|
680
|
-
var
|
|
681
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
681
682
|
var import_node_module2 = require("module");
|
|
682
683
|
|
|
683
684
|
// src/daemon.ts
|
|
684
685
|
init_cjs_shims();
|
|
685
686
|
var import_node_fs31 = require("fs");
|
|
686
|
-
var
|
|
687
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
687
688
|
var import_node_module = require("module");
|
|
688
689
|
|
|
689
690
|
// src/graph.ts
|
|
@@ -1213,19 +1214,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1213
1214
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1214
1215
|
let best = { path: [start], edges: [] };
|
|
1215
1216
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1216
|
-
function step(node,
|
|
1217
|
-
if (
|
|
1218
|
-
best = { path: [...
|
|
1217
|
+
function step(node, path54, edges) {
|
|
1218
|
+
if (path54.length > best.path.length) {
|
|
1219
|
+
best = { path: [...path54], edges: [...edges] };
|
|
1219
1220
|
}
|
|
1220
|
-
if (
|
|
1221
|
+
if (path54.length - 1 >= maxDepth) return;
|
|
1221
1222
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1222
1223
|
for (const [srcId, edge] of incoming) {
|
|
1223
1224
|
if (visited.has(srcId)) continue;
|
|
1224
1225
|
visited.add(srcId);
|
|
1225
|
-
|
|
1226
|
+
path54.push(srcId);
|
|
1226
1227
|
edges.push(edge);
|
|
1227
|
-
step(srcId,
|
|
1228
|
-
|
|
1228
|
+
step(srcId, path54, edges);
|
|
1229
|
+
path54.pop();
|
|
1229
1230
|
edges.pop();
|
|
1230
1231
|
visited.delete(srcId);
|
|
1231
1232
|
}
|
|
@@ -1419,26 +1420,26 @@ function dominantFailingCall(graph, serviceId6, visited) {
|
|
|
1419
1420
|
return best;
|
|
1420
1421
|
}
|
|
1421
1422
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1422
|
-
const
|
|
1423
|
+
const path54 = [originServiceId];
|
|
1423
1424
|
const edges = [];
|
|
1424
1425
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1425
1426
|
let current = originServiceId;
|
|
1426
1427
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1427
1428
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1428
1429
|
if (!hop) break;
|
|
1429
|
-
|
|
1430
|
+
path54.push(hop.nextService);
|
|
1430
1431
|
edges.push(hop.edge);
|
|
1431
1432
|
visited.add(hop.nextService);
|
|
1432
1433
|
current = hop.nextService;
|
|
1433
1434
|
}
|
|
1434
1435
|
if (edges.length === 0) return null;
|
|
1435
|
-
return { path:
|
|
1436
|
+
return { path: path54, edges, culprit: current };
|
|
1436
1437
|
}
|
|
1437
1438
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1438
1439
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1439
1440
|
if (!chain) return null;
|
|
1440
1441
|
const culprit = chain.culprit;
|
|
1441
|
-
const
|
|
1442
|
+
const path54 = [...chain.path];
|
|
1442
1443
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1443
1444
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1444
1445
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1446,14 +1447,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1446
1447
|
if (loc) {
|
|
1447
1448
|
let rootCauseNode = culprit;
|
|
1448
1449
|
if (loc.fileNode) {
|
|
1449
|
-
|
|
1450
|
+
path54.push(loc.fileNode);
|
|
1450
1451
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1451
1452
|
rootCauseNode = loc.fileNode;
|
|
1452
1453
|
}
|
|
1453
1454
|
return import_types.RootCauseResultSchema.parse({
|
|
1454
1455
|
rootCauseNode,
|
|
1455
1456
|
rootCauseReason: loc.rootCauseReason,
|
|
1456
|
-
traversalPath:
|
|
1457
|
+
traversalPath: path54,
|
|
1457
1458
|
edgeProvenances,
|
|
1458
1459
|
confidence,
|
|
1459
1460
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1465,7 +1466,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1465
1466
|
return import_types.RootCauseResultSchema.parse({
|
|
1466
1467
|
rootCauseNode: culprit,
|
|
1467
1468
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1468
|
-
traversalPath:
|
|
1469
|
+
traversalPath: path54,
|
|
1469
1470
|
edgeProvenances,
|
|
1470
1471
|
confidence,
|
|
1471
1472
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -2892,6 +2893,18 @@ async function handleSpan(ctx, span) {
|
|
|
2892
2893
|
callSiteEvidence
|
|
2893
2894
|
);
|
|
2894
2895
|
if (result) affectedNode = targetId;
|
|
2896
|
+
if (span.dbSystem === "mongodb" && span.dbCollection) {
|
|
2897
|
+
const collectionId = ensureInfraNode(ctx.graph, "mongodb-collection", span.dbCollection, "self");
|
|
2898
|
+
upsertObservedEdge(
|
|
2899
|
+
ctx.graph,
|
|
2900
|
+
import_types3.EdgeType.CALLS,
|
|
2901
|
+
observedSource(),
|
|
2902
|
+
collectionId,
|
|
2903
|
+
ts,
|
|
2904
|
+
isError,
|
|
2905
|
+
callSiteEvidence
|
|
2906
|
+
);
|
|
2907
|
+
}
|
|
2895
2908
|
}
|
|
2896
2909
|
} else if (span.messagingSystem && span.messagingDestination && spanMintsMessagingEdge(span.kind)) {
|
|
2897
2910
|
const targetId = ensureMessagingDestinationNode(
|
|
@@ -4633,14 +4646,21 @@ function engineFromImage(image) {
|
|
|
4633
4646
|
// src/extract/databases/dotenv.ts
|
|
4634
4647
|
var CONNECTION_KEYS = /* @__PURE__ */ new Set([
|
|
4635
4648
|
"DATABASE_URL",
|
|
4649
|
+
"DATABASE_URI",
|
|
4636
4650
|
"DB_URL",
|
|
4651
|
+
"DB_URI",
|
|
4637
4652
|
"POSTGRES_URL",
|
|
4653
|
+
"POSTGRES_URI",
|
|
4638
4654
|
"POSTGRESQL_URL",
|
|
4655
|
+
"POSTGRESQL_URI",
|
|
4639
4656
|
"MYSQL_URL",
|
|
4657
|
+
"MYSQL_URI",
|
|
4658
|
+
"MONGODB_URL",
|
|
4640
4659
|
"MONGODB_URI",
|
|
4641
4660
|
"MONGO_URL",
|
|
4642
4661
|
"MONGO_URI",
|
|
4643
|
-
"REDIS_URL"
|
|
4662
|
+
"REDIS_URL",
|
|
4663
|
+
"REDIS_URI"
|
|
4644
4664
|
]);
|
|
4645
4665
|
function parseDotenvLine(line) {
|
|
4646
4666
|
const trimmed = line.trim();
|
|
@@ -5729,7 +5749,7 @@ async function addGrpcMethods(graph, services) {
|
|
|
5729
5749
|
|
|
5730
5750
|
// src/extract/calls/index.ts
|
|
5731
5751
|
init_cjs_shims();
|
|
5732
|
-
var
|
|
5752
|
+
var import_types21 = require("@neat.is/types");
|
|
5733
5753
|
|
|
5734
5754
|
// src/extract/calls/http.ts
|
|
5735
5755
|
init_cjs_shims();
|
|
@@ -6442,15 +6462,311 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
6442
6462
|
return out;
|
|
6443
6463
|
}
|
|
6444
6464
|
|
|
6465
|
+
// src/extract/calls/mongoose.ts
|
|
6466
|
+
init_cjs_shims();
|
|
6467
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
6468
|
+
var import_types20 = require("@neat.is/types");
|
|
6469
|
+
var MONGOOSE_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongoose['"`]/;
|
|
6470
|
+
var MONGODB_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])mongodb['"`]/;
|
|
6471
|
+
var PLURALIZE_DISABLED_RE = /\bpluralize\s*\(\s*(?:null|false)\s*\)/;
|
|
6472
|
+
var UNCOUNTABLES = /* @__PURE__ */ new Set([
|
|
6473
|
+
"advice",
|
|
6474
|
+
"energy",
|
|
6475
|
+
"excretion",
|
|
6476
|
+
"digestion",
|
|
6477
|
+
"cooperation",
|
|
6478
|
+
"health",
|
|
6479
|
+
"justice",
|
|
6480
|
+
"labour",
|
|
6481
|
+
"machinery",
|
|
6482
|
+
"equipment",
|
|
6483
|
+
"information",
|
|
6484
|
+
"pollution",
|
|
6485
|
+
"sewage",
|
|
6486
|
+
"paper",
|
|
6487
|
+
"money",
|
|
6488
|
+
"species",
|
|
6489
|
+
"series",
|
|
6490
|
+
"rain",
|
|
6491
|
+
"rice",
|
|
6492
|
+
"fish",
|
|
6493
|
+
"sheep",
|
|
6494
|
+
"moose",
|
|
6495
|
+
"deer",
|
|
6496
|
+
"news",
|
|
6497
|
+
"expertise",
|
|
6498
|
+
"status",
|
|
6499
|
+
"media"
|
|
6500
|
+
]);
|
|
6501
|
+
var PLURALIZE_RULES = [
|
|
6502
|
+
[/human$/gi, "humans"],
|
|
6503
|
+
[/(m)an$/gi, "$1en"],
|
|
6504
|
+
[/(pe)rson$/gi, "$1ople"],
|
|
6505
|
+
[/(child)$/gi, "$1ren"],
|
|
6506
|
+
[/^(ox)$/gi, "$1en"],
|
|
6507
|
+
[/(ax|test)is$/gi, "$1es"],
|
|
6508
|
+
[/(octop|vir)us$/gi, "$1i"],
|
|
6509
|
+
[/(alias|status)$/gi, "$1es"],
|
|
6510
|
+
[/(bu)s$/gi, "$1ses"],
|
|
6511
|
+
[/(buffal|tomat|potat)o$/gi, "$1oes"],
|
|
6512
|
+
[/([ti])um$/gi, "$1a"],
|
|
6513
|
+
[/sis$/gi, "ses"],
|
|
6514
|
+
[/(?:([^f])fe|([lr])f)$/gi, "$1$2ves"],
|
|
6515
|
+
[/(hive)$/gi, "$1s"],
|
|
6516
|
+
[/([^aeiouy]|qu)y$/gi, "$1ies"],
|
|
6517
|
+
[/(x|ch|ss|sh)$/gi, "$1es"],
|
|
6518
|
+
[/(matr|vert|ind)ix|ex$/gi, "$1ices"],
|
|
6519
|
+
[/([m|l])ouse$/gi, "$1ice"],
|
|
6520
|
+
[/(kn|w|l)ife$/gi, "$1ives"],
|
|
6521
|
+
[/(quiz)$/gi, "$1zes"],
|
|
6522
|
+
[/s$/gi, "s"],
|
|
6523
|
+
[/([^a-z])$/, "$1"],
|
|
6524
|
+
[/$/gi, "s"]
|
|
6525
|
+
];
|
|
6526
|
+
function pluralizeCollection(name) {
|
|
6527
|
+
const str = name.toLowerCase();
|
|
6528
|
+
if (UNCOUNTABLES.has(str)) return str;
|
|
6529
|
+
for (const [re, repl] of PLURALIZE_RULES) {
|
|
6530
|
+
if (str.match(re)) return str.replace(re, repl);
|
|
6531
|
+
}
|
|
6532
|
+
return str;
|
|
6533
|
+
}
|
|
6534
|
+
var MODEL_METHODS = [
|
|
6535
|
+
"find",
|
|
6536
|
+
"findOne",
|
|
6537
|
+
"findById",
|
|
6538
|
+
"findByIdAndUpdate",
|
|
6539
|
+
"findByIdAndDelete",
|
|
6540
|
+
"findOneAndUpdate",
|
|
6541
|
+
"findOneAndDelete",
|
|
6542
|
+
"findOneAndReplace",
|
|
6543
|
+
"countDocuments",
|
|
6544
|
+
"estimatedDocumentCount",
|
|
6545
|
+
"distinct",
|
|
6546
|
+
"aggregate",
|
|
6547
|
+
"exists",
|
|
6548
|
+
"where",
|
|
6549
|
+
"populate",
|
|
6550
|
+
"watch",
|
|
6551
|
+
"hydrate",
|
|
6552
|
+
"create",
|
|
6553
|
+
"insertMany",
|
|
6554
|
+
"insertOne",
|
|
6555
|
+
"updateOne",
|
|
6556
|
+
"updateMany",
|
|
6557
|
+
"replaceOne",
|
|
6558
|
+
"deleteOne",
|
|
6559
|
+
"deleteMany",
|
|
6560
|
+
"bulkWrite",
|
|
6561
|
+
"bulkSave",
|
|
6562
|
+
"save",
|
|
6563
|
+
// pre-v7, removed in current mongoose but present in older codebases:
|
|
6564
|
+
"count",
|
|
6565
|
+
"update",
|
|
6566
|
+
"remove",
|
|
6567
|
+
"findOneAndRemove",
|
|
6568
|
+
"findByIdAndRemove"
|
|
6569
|
+
];
|
|
6570
|
+
var MODEL_METHODS_ALT = MODEL_METHODS.join("|");
|
|
6571
|
+
function schemaCollectionVars(content) {
|
|
6572
|
+
const out = /* @__PURE__ */ new Map();
|
|
6573
|
+
const re = /(?:const|let|var)\s+(\w+)\s*=\s*new\s+(?:mongoose\s*\.\s*)?Schema\s*\(/g;
|
|
6574
|
+
let m;
|
|
6575
|
+
while ((m = re.exec(content)) !== null) {
|
|
6576
|
+
const windowText = content.slice(m.index, m.index + 2e3);
|
|
6577
|
+
const opt = /\bcollection\s*:\s*['"`]([\w.-]+)['"`]/.exec(windowText);
|
|
6578
|
+
if (opt) out.set(m[1], opt[1]);
|
|
6579
|
+
}
|
|
6580
|
+
return out;
|
|
6581
|
+
}
|
|
6582
|
+
function resolveModel(modelName, rest, schemaColl, pluralizeOn) {
|
|
6583
|
+
const trimmed = rest.trim();
|
|
6584
|
+
const literalThird = /,\s*['"`]([\w.-]+)['"`]\s*$/.exec(trimmed);
|
|
6585
|
+
if (literalThird) return { name: literalThird[1], kind: "mongodb-collection" };
|
|
6586
|
+
const firstIdent = /^([A-Za-z_$][\w$]*)/.exec(trimmed)?.[1];
|
|
6587
|
+
if (firstIdent && schemaColl.has(firstIdent)) {
|
|
6588
|
+
return { name: schemaColl.get(firstIdent), kind: "mongodb-collection" };
|
|
6589
|
+
}
|
|
6590
|
+
if (/,\s*[A-Za-z_$][\w$]*\s*$/.test(trimmed)) {
|
|
6591
|
+
return { name: modelName, kind: "mongodb-model" };
|
|
6592
|
+
}
|
|
6593
|
+
return { name: pluralizeOn ? pluralizeCollection(modelName) : modelName, kind: "mongodb-collection" };
|
|
6594
|
+
}
|
|
6595
|
+
function collectModelDefs(content, pluralizeOn) {
|
|
6596
|
+
const schemaColl = schemaCollectionVars(content);
|
|
6597
|
+
const out = [];
|
|
6598
|
+
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;
|
|
6599
|
+
let m;
|
|
6600
|
+
while ((m = re.exec(content)) !== null) {
|
|
6601
|
+
out.push({
|
|
6602
|
+
modelName: m[2],
|
|
6603
|
+
varName: m[1] ?? null,
|
|
6604
|
+
resolved: resolveModel(m[2], m[3] ?? "", schemaColl, pluralizeOn),
|
|
6605
|
+
matchText: m[0]
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
return out;
|
|
6609
|
+
}
|
|
6610
|
+
function endpoint(r, file, serviceDir, matchText) {
|
|
6611
|
+
const line = lineOf(file.content, matchText);
|
|
6612
|
+
return {
|
|
6613
|
+
infraId: (0, import_types20.infraId)(r.kind, r.name),
|
|
6614
|
+
name: r.name,
|
|
6615
|
+
kind: r.kind,
|
|
6616
|
+
edgeType: "CALLS",
|
|
6617
|
+
confidenceKind: "verified-call-site",
|
|
6618
|
+
evidence: { file: import_node_path31.default.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
6619
|
+
};
|
|
6620
|
+
}
|
|
6621
|
+
function mongooseEndpointsFromFile(file, serviceDir) {
|
|
6622
|
+
const hasMongoose = MONGOOSE_IMPORT_RE.test(file.content);
|
|
6623
|
+
const hasMongodb = MONGODB_IMPORT_RE.test(file.content);
|
|
6624
|
+
if (!hasMongoose && !hasMongodb) return [];
|
|
6625
|
+
const content = file.content;
|
|
6626
|
+
const out = [];
|
|
6627
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6628
|
+
const push = (r, matchText) => {
|
|
6629
|
+
const key = `${r.kind}/${r.name}`;
|
|
6630
|
+
if (seen.has(key)) return;
|
|
6631
|
+
seen.add(key);
|
|
6632
|
+
out.push(endpoint(r, file, serviceDir, matchText));
|
|
6633
|
+
};
|
|
6634
|
+
if (hasMongoose) {
|
|
6635
|
+
const pluralizeOn = !PLURALIZE_DISABLED_RE.test(content);
|
|
6636
|
+
for (const def of collectModelDefs(content, pluralizeOn)) push(def.resolved, def.matchText);
|
|
6637
|
+
}
|
|
6638
|
+
const collRe = /\.\s*collection\s*\(\s*['"`]([\w.$-]+)['"`]\s*\)/g;
|
|
6639
|
+
let c;
|
|
6640
|
+
while ((c = collRe.exec(content)) !== null) {
|
|
6641
|
+
push({ name: c[1], kind: "mongodb-collection" }, c[0]);
|
|
6642
|
+
}
|
|
6643
|
+
return out;
|
|
6644
|
+
}
|
|
6645
|
+
function parseDestructure(inner, specifier, out) {
|
|
6646
|
+
for (const raw of inner.split(",")) {
|
|
6647
|
+
const part = raw.trim();
|
|
6648
|
+
if (!part) continue;
|
|
6649
|
+
const asM = /^(\w+)\s+as\s+(\w+)$/.exec(part);
|
|
6650
|
+
const colonM = /^(\w+)\s*:\s*(\w+)$/.exec(part);
|
|
6651
|
+
if (asM) out.push({ local: asM[2], kind: "named", exportName: asM[1], specifier });
|
|
6652
|
+
else if (colonM) out.push({ local: colonM[2], kind: "named", exportName: colonM[1], specifier });
|
|
6653
|
+
else {
|
|
6654
|
+
const id = /^(\w+)$/.exec(part);
|
|
6655
|
+
if (id) out.push({ local: id[1], kind: "named", exportName: id[1], specifier });
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
}
|
|
6659
|
+
function parseImportBindings(content) {
|
|
6660
|
+
const out = [];
|
|
6661
|
+
const esm = /import\s+([^;'"`\n]+?)\s+from\s*['"`]([^'"`]+)['"`]/g;
|
|
6662
|
+
let m;
|
|
6663
|
+
while ((m = esm.exec(content)) !== null) {
|
|
6664
|
+
const clause = m[1].trim();
|
|
6665
|
+
const spec = m[2];
|
|
6666
|
+
const ns = /^\*\s+as\s+(\w+)$/.exec(clause);
|
|
6667
|
+
if (ns) {
|
|
6668
|
+
out.push({ local: ns[1], kind: "namespace", specifier: spec });
|
|
6669
|
+
continue;
|
|
6670
|
+
}
|
|
6671
|
+
const named = /\{([^}]*)\}/.exec(clause);
|
|
6672
|
+
if (named) parseDestructure(named[1], spec, out);
|
|
6673
|
+
const def = /^(\w+)\s*(?:,|$)/.exec(clause);
|
|
6674
|
+
if (def && !clause.startsWith("{")) out.push({ local: def[1], kind: "default", specifier: spec });
|
|
6675
|
+
}
|
|
6676
|
+
const cjs = /(?:const|let|var)\s+(\{[^}]*\}|\w+)\s*=\s*require\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
6677
|
+
while ((m = cjs.exec(content)) !== null) {
|
|
6678
|
+
const lhs = m[1];
|
|
6679
|
+
const spec = m[2];
|
|
6680
|
+
if (lhs.startsWith("{")) parseDestructure(lhs.slice(1, -1), spec, out);
|
|
6681
|
+
else out.push({ local: lhs, kind: "whole", specifier: spec });
|
|
6682
|
+
}
|
|
6683
|
+
return out;
|
|
6684
|
+
}
|
|
6685
|
+
function fileExportsOf(content, pluralizeOn) {
|
|
6686
|
+
const defs = collectModelDefs(content, pluralizeOn).filter((d) => d.resolved.kind === "mongodb-collection");
|
|
6687
|
+
if (defs.length === 0) return null;
|
|
6688
|
+
const byVar = /* @__PURE__ */ new Map();
|
|
6689
|
+
for (const d of defs) if (d.varName) byVar.set(d.varName, d.resolved.name);
|
|
6690
|
+
const byName = new Map(byVar);
|
|
6691
|
+
let def;
|
|
6692
|
+
const named = /(?:module\.exports|export\s+default)\s*=\s*(\w+)\b/.exec(content);
|
|
6693
|
+
if (named && byVar.has(named[1])) def = byVar.get(named[1]);
|
|
6694
|
+
if (!def) {
|
|
6695
|
+
const inline = /(?:module\.exports|export\s+default)\s*=\s*(?:await\s+)?(?:\w+\s*\.\s*)?model\s*\(\s*['"`]([\w$]+)['"`]/.exec(content);
|
|
6696
|
+
if (inline) def = pluralizeOn ? pluralizeCollection(inline[1]) : inline[1];
|
|
6697
|
+
}
|
|
6698
|
+
if (!def && byVar.size === 1) def = [...byVar.values()][0];
|
|
6699
|
+
return { byName, ...def ? { default: def } : {} };
|
|
6700
|
+
}
|
|
6701
|
+
async function mongooseCrossFileEndpoints(files, serviceDir) {
|
|
6702
|
+
const mongooseFiles = files.filter((f) => MONGOOSE_IMPORT_RE.test(f.content));
|
|
6703
|
+
if (mongooseFiles.length === 0) return [];
|
|
6704
|
+
const pluralizeOn = !files.some((f) => PLURALIZE_DISABLED_RE.test(f.content));
|
|
6705
|
+
const registry = /* @__PURE__ */ new Map();
|
|
6706
|
+
for (const f of mongooseFiles) {
|
|
6707
|
+
const fx = fileExportsOf(f.content, pluralizeOn);
|
|
6708
|
+
if (fx) registry.set(toPosix2(import_node_path31.default.relative(serviceDir, f.path)), fx);
|
|
6709
|
+
}
|
|
6710
|
+
if (registry.size === 0) return [];
|
|
6711
|
+
const out = [];
|
|
6712
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6713
|
+
for (const f of files) {
|
|
6714
|
+
const bindings = parseImportBindings(f.content);
|
|
6715
|
+
if (bindings.length === 0) continue;
|
|
6716
|
+
const directColl = /* @__PURE__ */ new Map();
|
|
6717
|
+
const nsExports = /* @__PURE__ */ new Map();
|
|
6718
|
+
for (const b of bindings) {
|
|
6719
|
+
const resolvedRel = await resolveJsImport(b.specifier, import_node_path31.default.dirname(f.path), serviceDir, null);
|
|
6720
|
+
if (!resolvedRel) continue;
|
|
6721
|
+
const fx = registry.get(resolvedRel);
|
|
6722
|
+
if (!fx) continue;
|
|
6723
|
+
if (b.kind === "named" && b.exportName) {
|
|
6724
|
+
const coll = fx.byName.get(b.exportName);
|
|
6725
|
+
if (coll) directColl.set(b.local, coll);
|
|
6726
|
+
} else if (b.kind === "default") {
|
|
6727
|
+
if (fx.default) directColl.set(b.local, fx.default);
|
|
6728
|
+
} else {
|
|
6729
|
+
if (fx.default) directColl.set(b.local, fx.default);
|
|
6730
|
+
nsExports.set(b.local, fx);
|
|
6731
|
+
}
|
|
6732
|
+
}
|
|
6733
|
+
if (directColl.size === 0 && nsExports.size === 0) continue;
|
|
6734
|
+
const localDefs = new Set(
|
|
6735
|
+
collectModelDefs(f.content, pluralizeOn).map((d) => d.varName).filter((v) => v !== null)
|
|
6736
|
+
);
|
|
6737
|
+
const emit = (collection, matchText) => {
|
|
6738
|
+
const key = `${f.path}::${collection}`;
|
|
6739
|
+
if (seen.has(key)) return;
|
|
6740
|
+
seen.add(key);
|
|
6741
|
+
out.push(endpoint({ name: collection, kind: "mongodb-collection" }, f, serviceDir, matchText));
|
|
6742
|
+
};
|
|
6743
|
+
for (const [local, collection] of directColl) {
|
|
6744
|
+
if (localDefs.has(local)) continue;
|
|
6745
|
+
const qre = new RegExp(`\\b${local}\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
|
|
6746
|
+
let qm;
|
|
6747
|
+
while ((qm = qre.exec(f.content)) !== null) emit(collection, qm[0]);
|
|
6748
|
+
}
|
|
6749
|
+
for (const [local, fx] of nsExports) {
|
|
6750
|
+
const qre = new RegExp(`\\b${local}\\s*\\.\\s*(\\w+)\\s*\\.\\s*(?:${MODEL_METHODS_ALT})\\s*\\(`, "g");
|
|
6751
|
+
let qm;
|
|
6752
|
+
while ((qm = qre.exec(f.content)) !== null) {
|
|
6753
|
+
const coll = fx.byName.get(qm[1]);
|
|
6754
|
+
if (coll) emit(coll, qm[0]);
|
|
6755
|
+
}
|
|
6756
|
+
}
|
|
6757
|
+
}
|
|
6758
|
+
return out;
|
|
6759
|
+
}
|
|
6760
|
+
|
|
6445
6761
|
// src/extract/calls/index.ts
|
|
6446
6762
|
function edgeTypeFromEndpoint(ep) {
|
|
6447
6763
|
switch (ep.edgeType) {
|
|
6448
6764
|
case "PUBLISHES_TO":
|
|
6449
|
-
return
|
|
6765
|
+
return import_types21.EdgeType.PUBLISHES_TO;
|
|
6450
6766
|
case "CONSUMES_FROM":
|
|
6451
|
-
return
|
|
6767
|
+
return import_types21.EdgeType.CONSUMES_FROM;
|
|
6452
6768
|
default:
|
|
6453
|
-
return
|
|
6769
|
+
return import_types21.EdgeType.CALLS;
|
|
6454
6770
|
}
|
|
6455
6771
|
}
|
|
6456
6772
|
function isAwsKind(kind) {
|
|
@@ -6462,23 +6778,27 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6462
6778
|
for (const service of services) {
|
|
6463
6779
|
const files = await loadSourceFiles(service.dir);
|
|
6464
6780
|
const endpoints = [];
|
|
6781
|
+
const maskedFiles = [];
|
|
6465
6782
|
for (const file of files) {
|
|
6466
6783
|
if (isTestPath(file.path)) continue;
|
|
6467
6784
|
const masked = maskCommentsInSource(file.content);
|
|
6468
6785
|
const maskedFile = { path: file.path, content: masked };
|
|
6786
|
+
maskedFiles.push(maskedFile);
|
|
6469
6787
|
endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir));
|
|
6470
6788
|
endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir));
|
|
6471
6789
|
endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir));
|
|
6472
6790
|
endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
|
|
6473
6791
|
endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
|
|
6792
|
+
endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir));
|
|
6474
6793
|
}
|
|
6794
|
+
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
6475
6795
|
if (endpoints.length === 0) continue;
|
|
6476
6796
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
6477
6797
|
for (const ep of endpoints) {
|
|
6478
6798
|
if (!graph.hasNode(ep.infraId)) {
|
|
6479
6799
|
const node = {
|
|
6480
6800
|
id: ep.infraId,
|
|
6481
|
-
type:
|
|
6801
|
+
type: import_types21.NodeType.InfraNode,
|
|
6482
6802
|
name: ep.name,
|
|
6483
6803
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
6484
6804
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -6490,7 +6810,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6490
6810
|
nodesAdded++;
|
|
6491
6811
|
}
|
|
6492
6812
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
6493
|
-
const confidence = (0,
|
|
6813
|
+
const confidence = (0, import_types21.confidenceForExtracted)(ep.confidenceKind);
|
|
6494
6814
|
const relFile = toPosix2(ep.evidence.file);
|
|
6495
6815
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
6496
6816
|
graph,
|
|
@@ -6500,7 +6820,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6500
6820
|
);
|
|
6501
6821
|
nodesAdded += n;
|
|
6502
6822
|
edgesAdded += e;
|
|
6503
|
-
if (!(0,
|
|
6823
|
+
if (!(0, import_types21.passesExtractedFloor)(confidence)) {
|
|
6504
6824
|
noteExtractedDropped({
|
|
6505
6825
|
source: fileNodeId,
|
|
6506
6826
|
target: ep.infraId,
|
|
@@ -6520,7 +6840,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
6520
6840
|
source: fileNodeId,
|
|
6521
6841
|
target: ep.infraId,
|
|
6522
6842
|
type: edgeType,
|
|
6523
|
-
provenance:
|
|
6843
|
+
provenance: import_types21.Provenance.EXTRACTED,
|
|
6524
6844
|
confidence,
|
|
6525
6845
|
evidence: ep.evidence
|
|
6526
6846
|
};
|
|
@@ -6546,16 +6866,16 @@ init_cjs_shims();
|
|
|
6546
6866
|
|
|
6547
6867
|
// src/extract/infra/docker-compose.ts
|
|
6548
6868
|
init_cjs_shims();
|
|
6549
|
-
var
|
|
6550
|
-
var
|
|
6869
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
6870
|
+
var import_types23 = require("@neat.is/types");
|
|
6551
6871
|
|
|
6552
6872
|
// src/extract/infra/shared.ts
|
|
6553
6873
|
init_cjs_shims();
|
|
6554
|
-
var
|
|
6874
|
+
var import_types22 = require("@neat.is/types");
|
|
6555
6875
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
6556
6876
|
return {
|
|
6557
|
-
id: (0,
|
|
6558
|
-
type:
|
|
6877
|
+
id: (0, import_types22.infraId)(kind, name),
|
|
6878
|
+
type: import_types22.NodeType.InfraNode,
|
|
6559
6879
|
name,
|
|
6560
6880
|
provider,
|
|
6561
6881
|
kind,
|
|
@@ -6599,8 +6919,8 @@ function emitPlatformResourceEdge(graph, anchorId, edgeType, kind, name, provide
|
|
|
6599
6919
|
source: anchorId,
|
|
6600
6920
|
target: node.id,
|
|
6601
6921
|
type: edgeType,
|
|
6602
|
-
provenance:
|
|
6603
|
-
confidence: (0,
|
|
6922
|
+
provenance: import_types22.Provenance.EXTRACTED,
|
|
6923
|
+
confidence: (0, import_types22.confidenceForExtracted)("structural"),
|
|
6604
6924
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
6605
6925
|
};
|
|
6606
6926
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -6617,7 +6937,7 @@ function dependsOnList(value) {
|
|
|
6617
6937
|
}
|
|
6618
6938
|
function serviceNameToServiceNode(name, services) {
|
|
6619
6939
|
for (const s of services) {
|
|
6620
|
-
if (s.node.name === name ||
|
|
6940
|
+
if (s.node.name === name || import_node_path32.default.basename(s.dir) === name) return s.node.id;
|
|
6621
6941
|
}
|
|
6622
6942
|
return null;
|
|
6623
6943
|
}
|
|
@@ -6626,7 +6946,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6626
6946
|
let edgesAdded = 0;
|
|
6627
6947
|
let composePath = null;
|
|
6628
6948
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
6629
|
-
const abs =
|
|
6949
|
+
const abs = import_node_path32.default.join(scanPath, name);
|
|
6630
6950
|
if (await exists(abs)) {
|
|
6631
6951
|
composePath = abs;
|
|
6632
6952
|
break;
|
|
@@ -6639,13 +6959,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6639
6959
|
} catch (err) {
|
|
6640
6960
|
recordExtractionError(
|
|
6641
6961
|
"infra docker-compose",
|
|
6642
|
-
|
|
6962
|
+
import_node_path32.default.relative(scanPath, composePath),
|
|
6643
6963
|
err
|
|
6644
6964
|
);
|
|
6645
6965
|
return { nodesAdded, edgesAdded };
|
|
6646
6966
|
}
|
|
6647
6967
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
6648
|
-
const evidenceFile =
|
|
6968
|
+
const evidenceFile = import_node_path32.default.relative(scanPath, composePath).split(import_node_path32.default.sep).join("/");
|
|
6649
6969
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
6650
6970
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
6651
6971
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -6667,15 +6987,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6667
6987
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
6668
6988
|
const targetId = composeNameToNodeId.get(dep);
|
|
6669
6989
|
if (!targetId) continue;
|
|
6670
|
-
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId,
|
|
6990
|
+
const edgeId = (0, import_types4.extractedEdgeId)(sourceId, targetId, import_types23.EdgeType.DEPENDS_ON);
|
|
6671
6991
|
if (graph.hasEdge(edgeId)) continue;
|
|
6672
6992
|
const edge = {
|
|
6673
6993
|
id: edgeId,
|
|
6674
6994
|
source: sourceId,
|
|
6675
6995
|
target: targetId,
|
|
6676
|
-
type:
|
|
6677
|
-
provenance:
|
|
6678
|
-
confidence: (0,
|
|
6996
|
+
type: import_types23.EdgeType.DEPENDS_ON,
|
|
6997
|
+
provenance: import_types23.Provenance.EXTRACTED,
|
|
6998
|
+
confidence: (0, import_types23.confidenceForExtracted)("structural"),
|
|
6679
6999
|
evidence: { file: evidenceFile }
|
|
6680
7000
|
};
|
|
6681
7001
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -6687,9 +7007,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
6687
7007
|
|
|
6688
7008
|
// src/extract/infra/dockerfile.ts
|
|
6689
7009
|
init_cjs_shims();
|
|
6690
|
-
var
|
|
7010
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
6691
7011
|
var import_node_fs16 = require("fs");
|
|
6692
|
-
var
|
|
7012
|
+
var import_types24 = require("@neat.is/types");
|
|
6693
7013
|
function readDockerfile(content) {
|
|
6694
7014
|
let image = null;
|
|
6695
7015
|
const ports = [];
|
|
@@ -6718,7 +7038,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6718
7038
|
let nodesAdded = 0;
|
|
6719
7039
|
let edgesAdded = 0;
|
|
6720
7040
|
for (const service of services) {
|
|
6721
|
-
const dockerfilePath =
|
|
7041
|
+
const dockerfilePath = import_node_path33.default.join(service.dir, "Dockerfile");
|
|
6722
7042
|
if (!await exists(dockerfilePath)) continue;
|
|
6723
7043
|
let content;
|
|
6724
7044
|
try {
|
|
@@ -6726,7 +7046,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6726
7046
|
} catch (err) {
|
|
6727
7047
|
recordExtractionError(
|
|
6728
7048
|
"infra dockerfile",
|
|
6729
|
-
|
|
7049
|
+
import_node_path33.default.relative(scanPath, dockerfilePath),
|
|
6730
7050
|
err
|
|
6731
7051
|
);
|
|
6732
7052
|
continue;
|
|
@@ -6738,8 +7058,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6738
7058
|
graph.addNode(node.id, node);
|
|
6739
7059
|
nodesAdded++;
|
|
6740
7060
|
}
|
|
6741
|
-
const relDockerfile = toPosix2(
|
|
6742
|
-
const evidenceFile = toPosix2(
|
|
7061
|
+
const relDockerfile = toPosix2(import_node_path33.default.relative(service.dir, dockerfilePath));
|
|
7062
|
+
const evidenceFile = toPosix2(import_node_path33.default.relative(scanPath, dockerfilePath));
|
|
6743
7063
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
6744
7064
|
graph,
|
|
6745
7065
|
service.pkg.name,
|
|
@@ -6748,15 +7068,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6748
7068
|
);
|
|
6749
7069
|
nodesAdded += fn;
|
|
6750
7070
|
edgesAdded += fe;
|
|
6751
|
-
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id,
|
|
7071
|
+
const edgeId = (0, import_types4.extractedEdgeId)(fileNodeId, node.id, import_types24.EdgeType.RUNS_ON);
|
|
6752
7072
|
if (!graph.hasEdge(edgeId)) {
|
|
6753
7073
|
const edge = {
|
|
6754
7074
|
id: edgeId,
|
|
6755
7075
|
source: fileNodeId,
|
|
6756
7076
|
target: node.id,
|
|
6757
|
-
type:
|
|
6758
|
-
provenance:
|
|
6759
|
-
confidence: (0,
|
|
7077
|
+
type: import_types24.EdgeType.RUNS_ON,
|
|
7078
|
+
provenance: import_types24.Provenance.EXTRACTED,
|
|
7079
|
+
confidence: (0, import_types24.confidenceForExtracted)("structural"),
|
|
6760
7080
|
evidence: {
|
|
6761
7081
|
file: evidenceFile,
|
|
6762
7082
|
...facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}
|
|
@@ -6771,15 +7091,15 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6771
7091
|
graph.addNode(portNode.id, portNode);
|
|
6772
7092
|
nodesAdded++;
|
|
6773
7093
|
}
|
|
6774
|
-
const portEdgeId = (0, import_types4.extractedEdgeId)(fileNodeId, portNode.id,
|
|
7094
|
+
const portEdgeId = (0, import_types4.extractedEdgeId)(fileNodeId, portNode.id, import_types24.EdgeType.CONNECTS_TO);
|
|
6775
7095
|
if (graph.hasEdge(portEdgeId)) continue;
|
|
6776
7096
|
const portEdge = {
|
|
6777
7097
|
id: portEdgeId,
|
|
6778
7098
|
source: fileNodeId,
|
|
6779
7099
|
target: portNode.id,
|
|
6780
|
-
type:
|
|
6781
|
-
provenance:
|
|
6782
|
-
confidence: (0,
|
|
7100
|
+
type: import_types24.EdgeType.CONNECTS_TO,
|
|
7101
|
+
provenance: import_types24.Provenance.EXTRACTED,
|
|
7102
|
+
confidence: (0, import_types24.confidenceForExtracted)("structural"),
|
|
6783
7103
|
evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` }
|
|
6784
7104
|
};
|
|
6785
7105
|
graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge);
|
|
@@ -6792,8 +7112,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
6792
7112
|
// src/extract/infra/terraform.ts
|
|
6793
7113
|
init_cjs_shims();
|
|
6794
7114
|
var import_node_fs17 = require("fs");
|
|
6795
|
-
var
|
|
6796
|
-
var
|
|
7115
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
7116
|
+
var import_types25 = require("@neat.is/types");
|
|
6797
7117
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
6798
7118
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
6799
7119
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
@@ -6803,11 +7123,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
6803
7123
|
for (const entry2 of entries) {
|
|
6804
7124
|
if (entry2.isDirectory()) {
|
|
6805
7125
|
if (IGNORED_DIRS.has(entry2.name) || entry2.name === ".terraform") continue;
|
|
6806
|
-
const child =
|
|
7126
|
+
const child = import_node_path34.default.join(start, entry2.name);
|
|
6807
7127
|
if (await isPythonVenvDir(child)) continue;
|
|
6808
7128
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
6809
7129
|
} else if (entry2.isFile() && entry2.name.endsWith(".tf")) {
|
|
6810
|
-
out.push(
|
|
7130
|
+
out.push(import_node_path34.default.join(start, entry2.name));
|
|
6811
7131
|
}
|
|
6812
7132
|
}
|
|
6813
7133
|
return out;
|
|
@@ -6839,7 +7159,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
6839
7159
|
const files = await walkTfFiles(scanPath);
|
|
6840
7160
|
for (const file of files) {
|
|
6841
7161
|
const content = await import_node_fs17.promises.readFile(file, "utf8");
|
|
6842
|
-
const evidenceFile = toPosix2(
|
|
7162
|
+
const evidenceFile = toPosix2(import_node_path34.default.relative(scanPath, file));
|
|
6843
7163
|
const resources = [];
|
|
6844
7164
|
const byKey = /* @__PURE__ */ new Map();
|
|
6845
7165
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -6874,16 +7194,16 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
6874
7194
|
if (!target) continue;
|
|
6875
7195
|
if (seen.has(target.nodeId)) continue;
|
|
6876
7196
|
seen.add(target.nodeId);
|
|
6877
|
-
const edgeId = (0, import_types4.extractedEdgeId)(resource.nodeId, target.nodeId,
|
|
7197
|
+
const edgeId = (0, import_types4.extractedEdgeId)(resource.nodeId, target.nodeId, import_types25.EdgeType.DEPENDS_ON);
|
|
6878
7198
|
if (graph.hasEdge(edgeId)) continue;
|
|
6879
7199
|
const line = lineAt2(content, resource.bodyOffset + ref.index);
|
|
6880
7200
|
const edge = {
|
|
6881
7201
|
id: edgeId,
|
|
6882
7202
|
source: resource.nodeId,
|
|
6883
7203
|
target: target.nodeId,
|
|
6884
|
-
type:
|
|
6885
|
-
provenance:
|
|
6886
|
-
confidence: (0,
|
|
7204
|
+
type: import_types25.EdgeType.DEPENDS_ON,
|
|
7205
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7206
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6887
7207
|
evidence: { file: evidenceFile, line, snippet: key }
|
|
6888
7208
|
};
|
|
6889
7209
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -6897,7 +7217,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
6897
7217
|
// src/extract/infra/k8s.ts
|
|
6898
7218
|
init_cjs_shims();
|
|
6899
7219
|
var import_node_fs18 = require("fs");
|
|
6900
|
-
var
|
|
7220
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
6901
7221
|
var import_yaml3 = require("yaml");
|
|
6902
7222
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
6903
7223
|
Service: "k8s-service",
|
|
@@ -6915,11 +7235,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
6915
7235
|
for (const entry2 of entries) {
|
|
6916
7236
|
if (entry2.isDirectory()) {
|
|
6917
7237
|
if (IGNORED_DIRS.has(entry2.name)) continue;
|
|
6918
|
-
const child =
|
|
7238
|
+
const child = import_node_path35.default.join(start, entry2.name);
|
|
6919
7239
|
if (await isPythonVenvDir(child)) continue;
|
|
6920
7240
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
6921
|
-
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
6922
|
-
out.push(
|
|
7241
|
+
} else if (entry2.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path35.default.extname(entry2.name))) {
|
|
7242
|
+
out.push(import_node_path35.default.join(start, entry2.name));
|
|
6923
7243
|
}
|
|
6924
7244
|
}
|
|
6925
7245
|
return out;
|
|
@@ -6953,13 +7273,13 @@ async function addK8sResources(graph, scanPath) {
|
|
|
6953
7273
|
// src/extract/infra/cloudflare.ts
|
|
6954
7274
|
init_cjs_shims();
|
|
6955
7275
|
var import_node_fs19 = require("fs");
|
|
6956
|
-
var
|
|
7276
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
6957
7277
|
var import_smol_toml2 = require("smol-toml");
|
|
6958
|
-
var
|
|
7278
|
+
var import_types26 = require("@neat.is/types");
|
|
6959
7279
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
6960
7280
|
async function readWranglerConfig(dir) {
|
|
6961
7281
|
for (const filename of WRANGLER_FILENAMES) {
|
|
6962
|
-
const abs =
|
|
7282
|
+
const abs = import_node_path36.default.join(dir, filename);
|
|
6963
7283
|
if (!await exists(abs)) continue;
|
|
6964
7284
|
const raw = await import_node_fs19.promises.readFile(abs, "utf8");
|
|
6965
7285
|
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7003,8 +7323,8 @@ function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, li
|
|
|
7003
7323
|
source: anchorId,
|
|
7004
7324
|
target: node.id,
|
|
7005
7325
|
type: edgeType,
|
|
7006
|
-
provenance:
|
|
7007
|
-
confidence: (0,
|
|
7326
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7327
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7008
7328
|
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
7009
7329
|
};
|
|
7010
7330
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7022,11 +7342,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7022
7342
|
try {
|
|
7023
7343
|
read = await readWranglerConfig(service.dir);
|
|
7024
7344
|
} catch (err) {
|
|
7025
|
-
recordExtractionError("infra cloudflare",
|
|
7345
|
+
recordExtractionError("infra cloudflare", import_node_path36.default.relative(scanPath, service.dir), err);
|
|
7026
7346
|
continue;
|
|
7027
7347
|
}
|
|
7028
7348
|
if (!read || !read.config.name) continue;
|
|
7029
|
-
const evidenceFile = toPosix2(
|
|
7349
|
+
const evidenceFile = toPosix2(import_node_path36.default.relative(scanPath, import_node_path36.default.join(service.dir, read.relFile)));
|
|
7030
7350
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
7031
7351
|
}
|
|
7032
7352
|
for (const worker of discovered) {
|
|
@@ -7038,7 +7358,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7038
7358
|
}
|
|
7039
7359
|
let anchorId = service.node.id;
|
|
7040
7360
|
if (config.main) {
|
|
7041
|
-
const entryRelPath = toPosix2(
|
|
7361
|
+
const entryRelPath = toPosix2(import_node_path36.default.normalize(config.main));
|
|
7042
7362
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7043
7363
|
graph,
|
|
7044
7364
|
service.pkg.name,
|
|
@@ -7065,15 +7385,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7065
7385
|
nodesAdded++;
|
|
7066
7386
|
}
|
|
7067
7387
|
if (runtimeNode.id !== anchorId) {
|
|
7068
|
-
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id,
|
|
7388
|
+
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id, import_types26.EdgeType.RUNS_ON);
|
|
7069
7389
|
if (!graph.hasEdge(runsOnId)) {
|
|
7070
7390
|
const edge = {
|
|
7071
7391
|
id: runsOnId,
|
|
7072
7392
|
source: anchorId,
|
|
7073
7393
|
target: runtimeNode.id,
|
|
7074
|
-
type:
|
|
7075
|
-
provenance:
|
|
7076
|
-
confidence: (0,
|
|
7394
|
+
type: import_types26.EdgeType.RUNS_ON,
|
|
7395
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7396
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7077
7397
|
evidence: {
|
|
7078
7398
|
file: evidenceFile,
|
|
7079
7399
|
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
@@ -7087,7 +7407,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7087
7407
|
const result = addResourceEdge(
|
|
7088
7408
|
graph,
|
|
7089
7409
|
anchorId,
|
|
7090
|
-
|
|
7410
|
+
import_types26.EdgeType.CONNECTS_TO,
|
|
7091
7411
|
"cloudflare-route",
|
|
7092
7412
|
route,
|
|
7093
7413
|
evidenceFile,
|
|
@@ -7111,7 +7431,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7111
7431
|
const result = addResourceEdge(
|
|
7112
7432
|
graph,
|
|
7113
7433
|
anchorId,
|
|
7114
|
-
|
|
7434
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7115
7435
|
group.kind,
|
|
7116
7436
|
name,
|
|
7117
7437
|
evidenceFile,
|
|
@@ -7125,7 +7445,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7125
7445
|
const result = addResourceEdge(
|
|
7126
7446
|
graph,
|
|
7127
7447
|
anchorId,
|
|
7128
|
-
|
|
7448
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7129
7449
|
"cloudflare-cron",
|
|
7130
7450
|
cron,
|
|
7131
7451
|
evidenceFile,
|
|
@@ -7138,7 +7458,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7138
7458
|
const result = addResourceEdge(
|
|
7139
7459
|
graph,
|
|
7140
7460
|
anchorId,
|
|
7141
|
-
|
|
7461
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7142
7462
|
"cloudflare-env-var",
|
|
7143
7463
|
varName,
|
|
7144
7464
|
evidenceFile,
|
|
@@ -7151,15 +7471,15 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7151
7471
|
if (!svc.service) continue;
|
|
7152
7472
|
const target = workerIndex.get(svc.service);
|
|
7153
7473
|
if (target && target.anchorId !== anchorId) {
|
|
7154
|
-
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId,
|
|
7474
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId, import_types26.EdgeType.CALLS);
|
|
7155
7475
|
if (!graph.hasEdge(edgeId)) {
|
|
7156
7476
|
const edge = {
|
|
7157
7477
|
id: edgeId,
|
|
7158
7478
|
source: anchorId,
|
|
7159
7479
|
target: target.anchorId,
|
|
7160
|
-
type:
|
|
7161
|
-
provenance:
|
|
7162
|
-
confidence: (0,
|
|
7480
|
+
type: import_types26.EdgeType.CALLS,
|
|
7481
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7482
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7163
7483
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
7164
7484
|
};
|
|
7165
7485
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -7170,7 +7490,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7170
7490
|
const result = addResourceEdge(
|
|
7171
7491
|
graph,
|
|
7172
7492
|
anchorId,
|
|
7173
|
-
|
|
7493
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7174
7494
|
"cloudflare-service-binding",
|
|
7175
7495
|
svc.service,
|
|
7176
7496
|
evidenceFile,
|
|
@@ -7186,12 +7506,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
7186
7506
|
// src/extract/infra/vercel.ts
|
|
7187
7507
|
init_cjs_shims();
|
|
7188
7508
|
var import_node_fs20 = require("fs");
|
|
7189
|
-
var
|
|
7190
|
-
var
|
|
7509
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
7510
|
+
var import_types27 = require("@neat.is/types");
|
|
7191
7511
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
7192
7512
|
async function readVercelConfig(dir) {
|
|
7193
7513
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
7194
|
-
const abs =
|
|
7514
|
+
const abs = import_node_path37.default.join(dir, filename);
|
|
7195
7515
|
if (!await exists(abs)) continue;
|
|
7196
7516
|
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
7197
7517
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7200,7 +7520,7 @@ async function readVercelConfig(dir) {
|
|
|
7200
7520
|
return null;
|
|
7201
7521
|
}
|
|
7202
7522
|
async function readLinkedProjectName(dir) {
|
|
7203
|
-
const abs =
|
|
7523
|
+
const abs = import_node_path37.default.join(dir, ".vercel", "project.json");
|
|
7204
7524
|
if (!await exists(abs)) return void 0;
|
|
7205
7525
|
const parsed = JSON.parse(await import_node_fs20.promises.readFile(abs, "utf8"));
|
|
7206
7526
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -7218,7 +7538,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7218
7538
|
read = await readVercelConfig(service.dir);
|
|
7219
7539
|
projectName = await readLinkedProjectName(service.dir);
|
|
7220
7540
|
} catch (err) {
|
|
7221
|
-
recordExtractionError("infra vercel",
|
|
7541
|
+
recordExtractionError("infra vercel", import_node_path37.default.relative(scanPath, service.dir), err);
|
|
7222
7542
|
continue;
|
|
7223
7543
|
}
|
|
7224
7544
|
if (!read && !projectName) continue;
|
|
@@ -7234,7 +7554,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7234
7554
|
const anchorId = service.node.id;
|
|
7235
7555
|
if (!read) continue;
|
|
7236
7556
|
const { config, relFile, raw } = read;
|
|
7237
|
-
const evidenceFile = toPosix2(
|
|
7557
|
+
const evidenceFile = toPosix2(import_node_path37.default.relative(scanPath, import_node_path37.default.join(service.dir, relFile)));
|
|
7238
7558
|
const add = (edgeType, kind, name) => {
|
|
7239
7559
|
if (!name) return;
|
|
7240
7560
|
const result = emitPlatformResourceEdge(
|
|
@@ -7250,12 +7570,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7250
7570
|
nodesAdded += result.nodesAdded;
|
|
7251
7571
|
edgesAdded += result.edgesAdded;
|
|
7252
7572
|
};
|
|
7253
|
-
add(
|
|
7254
|
-
for (const cron of config.crons ?? []) add(
|
|
7255
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
7256
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
7573
|
+
add(import_types27.EdgeType.RUNS_ON, "vercel", "vercel");
|
|
7574
|
+
for (const cron of config.crons ?? []) add(import_types27.EdgeType.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
7575
|
+
for (const varName of Object.keys(config.env ?? {})) add(import_types27.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7576
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(import_types27.EdgeType.DEPENDS_ON, "vercel-env-var", varName);
|
|
7257
7577
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
7258
|
-
add(
|
|
7578
|
+
add(import_types27.EdgeType.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
7259
7579
|
}
|
|
7260
7580
|
}
|
|
7261
7581
|
return { nodesAdded, edgesAdded };
|
|
@@ -7264,13 +7584,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
7264
7584
|
// src/extract/infra/railway.ts
|
|
7265
7585
|
init_cjs_shims();
|
|
7266
7586
|
var import_node_fs21 = require("fs");
|
|
7267
|
-
var
|
|
7587
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7268
7588
|
var import_smol_toml3 = require("smol-toml");
|
|
7269
|
-
var
|
|
7589
|
+
var import_types28 = require("@neat.is/types");
|
|
7270
7590
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
7271
7591
|
async function readRailwayConfig(dir) {
|
|
7272
7592
|
for (const filename of RAILWAY_FILENAMES) {
|
|
7273
|
-
const abs =
|
|
7593
|
+
const abs = import_node_path38.default.join(dir, filename);
|
|
7274
7594
|
if (!await exists(abs)) continue;
|
|
7275
7595
|
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
7276
7596
|
const config = filename === "railway.toml" ? (0, import_smol_toml3.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -7286,7 +7606,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7286
7606
|
try {
|
|
7287
7607
|
read = await readRailwayConfig(service.dir);
|
|
7288
7608
|
} catch (err) {
|
|
7289
|
-
recordExtractionError("infra railway",
|
|
7609
|
+
recordExtractionError("infra railway", import_node_path38.default.relative(scanPath, service.dir), err);
|
|
7290
7610
|
continue;
|
|
7291
7611
|
}
|
|
7292
7612
|
if (!read) continue;
|
|
@@ -7296,7 +7616,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7296
7616
|
}
|
|
7297
7617
|
const anchorId = service.node.id;
|
|
7298
7618
|
const { config, relFile, raw } = read;
|
|
7299
|
-
const evidenceFile = toPosix2(
|
|
7619
|
+
const evidenceFile = toPosix2(import_node_path38.default.relative(scanPath, import_node_path38.default.join(service.dir, relFile)));
|
|
7300
7620
|
const add = (edgeType, kind, name) => {
|
|
7301
7621
|
if (!name) return;
|
|
7302
7622
|
const result = emitPlatformResourceEdge(
|
|
@@ -7312,9 +7632,9 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7312
7632
|
nodesAdded += result.nodesAdded;
|
|
7313
7633
|
edgesAdded += result.edgesAdded;
|
|
7314
7634
|
};
|
|
7315
|
-
add(
|
|
7316
|
-
add(
|
|
7317
|
-
add(
|
|
7635
|
+
add(import_types28.EdgeType.RUNS_ON, "railway", "railway");
|
|
7636
|
+
add(import_types28.EdgeType.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
7637
|
+
add(import_types28.EdgeType.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
7318
7638
|
}
|
|
7319
7639
|
return { nodesAdded, edgesAdded };
|
|
7320
7640
|
}
|
|
@@ -7322,12 +7642,12 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
7322
7642
|
// src/extract/infra/supabase.ts
|
|
7323
7643
|
init_cjs_shims();
|
|
7324
7644
|
var import_node_fs22 = require("fs");
|
|
7325
|
-
var
|
|
7645
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7326
7646
|
var import_smol_toml4 = require("smol-toml");
|
|
7327
|
-
var
|
|
7647
|
+
var import_types29 = require("@neat.is/types");
|
|
7328
7648
|
async function readSupabaseConfig(dir) {
|
|
7329
|
-
const relFile =
|
|
7330
|
-
const abs =
|
|
7649
|
+
const relFile = import_node_path39.default.join("supabase", "config.toml");
|
|
7650
|
+
const abs = import_node_path39.default.join(dir, relFile);
|
|
7331
7651
|
if (!await exists(abs)) return null;
|
|
7332
7652
|
const raw = await import_node_fs22.promises.readFile(abs, "utf8");
|
|
7333
7653
|
const config = (0, import_smol_toml4.parse)(raw);
|
|
@@ -7341,7 +7661,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7341
7661
|
try {
|
|
7342
7662
|
read = await readSupabaseConfig(service.dir);
|
|
7343
7663
|
} catch (err) {
|
|
7344
|
-
recordExtractionError("infra supabase",
|
|
7664
|
+
recordExtractionError("infra supabase", import_node_path39.default.relative(scanPath, service.dir), err);
|
|
7345
7665
|
continue;
|
|
7346
7666
|
}
|
|
7347
7667
|
if (!read) continue;
|
|
@@ -7356,7 +7676,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7356
7676
|
});
|
|
7357
7677
|
}
|
|
7358
7678
|
const anchorId = service.node.id;
|
|
7359
|
-
const evidenceFile = toPosix2(
|
|
7679
|
+
const evidenceFile = toPosix2(import_node_path39.default.relative(scanPath, import_node_path39.default.join(service.dir, relFile)));
|
|
7360
7680
|
const add = (edgeType, kind, name) => {
|
|
7361
7681
|
if (!name) return;
|
|
7362
7682
|
const result = emitPlatformResourceEdge(
|
|
@@ -7372,10 +7692,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
7372
7692
|
nodesAdded += result.nodesAdded;
|
|
7373
7693
|
edgesAdded += result.edgesAdded;
|
|
7374
7694
|
};
|
|
7375
|
-
add(
|
|
7376
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
7377
|
-
if (config.storage) add(
|
|
7378
|
-
if (config.auth) add(
|
|
7695
|
+
add(import_types29.EdgeType.RUNS_ON, "supabase", "supabase");
|
|
7696
|
+
for (const fn of Object.keys(config.functions ?? {})) add(import_types29.EdgeType.DEPENDS_ON, "supabase-function", fn);
|
|
7697
|
+
if (config.storage) add(import_types29.EdgeType.DEPENDS_ON, "supabase-storage", "storage");
|
|
7698
|
+
if (config.auth) add(import_types29.EdgeType.DEPENDS_ON, "supabase-auth", "auth");
|
|
7379
7699
|
}
|
|
7380
7700
|
return { nodesAdded, edgesAdded };
|
|
7381
7701
|
}
|
|
@@ -7397,17 +7717,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
7397
7717
|
}
|
|
7398
7718
|
|
|
7399
7719
|
// src/extract/index.ts
|
|
7400
|
-
var
|
|
7720
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7401
7721
|
|
|
7402
7722
|
// src/extract/retire.ts
|
|
7403
7723
|
init_cjs_shims();
|
|
7404
7724
|
var import_node_fs23 = require("fs");
|
|
7405
|
-
var
|
|
7406
|
-
var
|
|
7725
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7726
|
+
var import_types30 = require("@neat.is/types");
|
|
7407
7727
|
function dropOrphanedFileNodes(graph) {
|
|
7408
7728
|
const orphans = [];
|
|
7409
7729
|
graph.forEachNode((id, attrs) => {
|
|
7410
|
-
if (attrs.type !==
|
|
7730
|
+
if (attrs.type !== import_types30.NodeType.FileNode) return;
|
|
7411
7731
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
7412
7732
|
orphans.push(id);
|
|
7413
7733
|
}
|
|
@@ -7420,14 +7740,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
7420
7740
|
const bases = [scanPath, ...serviceDirs];
|
|
7421
7741
|
graph.forEachEdge((id, attrs) => {
|
|
7422
7742
|
const edge = attrs;
|
|
7423
|
-
if (edge.provenance !==
|
|
7743
|
+
if (edge.provenance !== import_types30.Provenance.EXTRACTED) return;
|
|
7424
7744
|
const evidenceFile = edge.evidence?.file;
|
|
7425
7745
|
if (!evidenceFile) return;
|
|
7426
|
-
if (
|
|
7746
|
+
if (import_node_path40.default.isAbsolute(evidenceFile)) {
|
|
7427
7747
|
if (!(0, import_node_fs23.existsSync)(evidenceFile)) toDrop.push(id);
|
|
7428
7748
|
return;
|
|
7429
7749
|
}
|
|
7430
|
-
const found = bases.some((base) => (0, import_node_fs23.existsSync)(
|
|
7750
|
+
const found = bases.some((base) => (0, import_node_fs23.existsSync)(import_node_path40.default.join(base, evidenceFile)));
|
|
7431
7751
|
if (!found) toDrop.push(id);
|
|
7432
7752
|
});
|
|
7433
7753
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -7469,7 +7789,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7469
7789
|
}
|
|
7470
7790
|
const droppedEntries = drainDroppedExtracted();
|
|
7471
7791
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
7472
|
-
const rejectedPath =
|
|
7792
|
+
const rejectedPath = import_node_path41.default.join(import_node_path41.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
7473
7793
|
try {
|
|
7474
7794
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
7475
7795
|
} catch (err) {
|
|
@@ -7504,8 +7824,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7504
7824
|
// src/persist.ts
|
|
7505
7825
|
init_cjs_shims();
|
|
7506
7826
|
var import_node_fs24 = require("fs");
|
|
7507
|
-
var
|
|
7508
|
-
var
|
|
7827
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
7828
|
+
var import_types31 = require("@neat.is/types");
|
|
7509
7829
|
var SCHEMA_VERSION = 4;
|
|
7510
7830
|
function migrateV1ToV2(payload) {
|
|
7511
7831
|
const nodes = payload.graph.nodes;
|
|
@@ -7527,12 +7847,12 @@ function migrateV2ToV3(payload) {
|
|
|
7527
7847
|
for (const edge of edges) {
|
|
7528
7848
|
const attrs = edge.attributes;
|
|
7529
7849
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
7530
|
-
attrs.provenance =
|
|
7850
|
+
attrs.provenance = import_types31.Provenance.OBSERVED;
|
|
7531
7851
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
7532
7852
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
7533
7853
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
7534
7854
|
if (type && source && target) {
|
|
7535
|
-
const newId = (0,
|
|
7855
|
+
const newId = (0, import_types31.observedEdgeId)(source, target, type);
|
|
7536
7856
|
attrs.id = newId;
|
|
7537
7857
|
if (edge.key) edge.key = newId;
|
|
7538
7858
|
}
|
|
@@ -7541,7 +7861,7 @@ function migrateV2ToV3(payload) {
|
|
|
7541
7861
|
return { ...payload, schemaVersion: 3 };
|
|
7542
7862
|
}
|
|
7543
7863
|
async function ensureDir(filePath) {
|
|
7544
|
-
await import_node_fs24.promises.mkdir(
|
|
7864
|
+
await import_node_fs24.promises.mkdir(import_node_path42.default.dirname(filePath), { recursive: true });
|
|
7545
7865
|
}
|
|
7546
7866
|
async function saveGraphToDisk(graph, outPath) {
|
|
7547
7867
|
await ensureDir(outPath);
|
|
@@ -7622,23 +7942,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
7622
7942
|
|
|
7623
7943
|
// src/projects.ts
|
|
7624
7944
|
init_cjs_shims();
|
|
7625
|
-
var
|
|
7945
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
7626
7946
|
function pathsForProject(project, baseDir) {
|
|
7627
7947
|
if (project === DEFAULT_PROJECT) {
|
|
7628
7948
|
return {
|
|
7629
|
-
snapshotPath:
|
|
7630
|
-
errorsPath:
|
|
7631
|
-
staleEventsPath:
|
|
7632
|
-
embeddingsCachePath:
|
|
7633
|
-
policyViolationsPath:
|
|
7949
|
+
snapshotPath: import_node_path43.default.join(baseDir, "graph.json"),
|
|
7950
|
+
errorsPath: import_node_path43.default.join(baseDir, "errors.ndjson"),
|
|
7951
|
+
staleEventsPath: import_node_path43.default.join(baseDir, "stale-events.ndjson"),
|
|
7952
|
+
embeddingsCachePath: import_node_path43.default.join(baseDir, "embeddings.json"),
|
|
7953
|
+
policyViolationsPath: import_node_path43.default.join(baseDir, "policy-violations.ndjson")
|
|
7634
7954
|
};
|
|
7635
7955
|
}
|
|
7636
7956
|
return {
|
|
7637
|
-
snapshotPath:
|
|
7638
|
-
errorsPath:
|
|
7639
|
-
staleEventsPath:
|
|
7640
|
-
embeddingsCachePath:
|
|
7641
|
-
policyViolationsPath:
|
|
7957
|
+
snapshotPath: import_node_path43.default.join(baseDir, `${project}.json`),
|
|
7958
|
+
errorsPath: import_node_path43.default.join(baseDir, `errors.${project}.ndjson`),
|
|
7959
|
+
staleEventsPath: import_node_path43.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
7960
|
+
embeddingsCachePath: import_node_path43.default.join(baseDir, `embeddings.${project}.json`),
|
|
7961
|
+
policyViolationsPath: import_node_path43.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
7642
7962
|
};
|
|
7643
7963
|
}
|
|
7644
7964
|
var Projects = class {
|
|
@@ -7676,19 +7996,19 @@ var Projects = class {
|
|
|
7676
7996
|
init_cjs_shims();
|
|
7677
7997
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
7678
7998
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
7679
|
-
var
|
|
7999
|
+
var import_types34 = require("@neat.is/types");
|
|
7680
8000
|
|
|
7681
8001
|
// src/extend/index.ts
|
|
7682
8002
|
init_cjs_shims();
|
|
7683
8003
|
var import_node_fs26 = require("fs");
|
|
7684
|
-
var
|
|
8004
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
7685
8005
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
7686
8006
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
7687
8007
|
|
|
7688
8008
|
// src/installers/package-manager.ts
|
|
7689
8009
|
init_cjs_shims();
|
|
7690
8010
|
var import_node_fs25 = require("fs");
|
|
7691
|
-
var
|
|
8011
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
7692
8012
|
var import_node_child_process = require("child_process");
|
|
7693
8013
|
var LOCKFILE_PRIORITY = [
|
|
7694
8014
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -7710,22 +8030,22 @@ async function exists2(p) {
|
|
|
7710
8030
|
}
|
|
7711
8031
|
}
|
|
7712
8032
|
async function detectPackageManager(serviceDir) {
|
|
7713
|
-
let dir =
|
|
8033
|
+
let dir = import_node_path44.default.resolve(serviceDir);
|
|
7714
8034
|
const stops = /* @__PURE__ */ new Set();
|
|
7715
8035
|
for (let i = 0; i < 64; i++) {
|
|
7716
8036
|
if (stops.has(dir)) break;
|
|
7717
8037
|
stops.add(dir);
|
|
7718
8038
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
7719
|
-
const lockPath =
|
|
8039
|
+
const lockPath = import_node_path44.default.join(dir, candidate.lockfile);
|
|
7720
8040
|
if (await exists2(lockPath)) {
|
|
7721
8041
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
7722
8042
|
}
|
|
7723
8043
|
}
|
|
7724
|
-
const parent =
|
|
8044
|
+
const parent = import_node_path44.default.dirname(dir);
|
|
7725
8045
|
if (parent === dir) break;
|
|
7726
8046
|
dir = parent;
|
|
7727
8047
|
}
|
|
7728
|
-
return { pm: "npm", cwd:
|
|
8048
|
+
return { pm: "npm", cwd: import_node_path44.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
7729
8049
|
}
|
|
7730
8050
|
async function runPackageManagerInstall(cmd) {
|
|
7731
8051
|
return new Promise((resolve) => {
|
|
@@ -7774,22 +8094,53 @@ async function fileExists2(p) {
|
|
|
7774
8094
|
}
|
|
7775
8095
|
}
|
|
7776
8096
|
async function readPackageJson(scanPath) {
|
|
7777
|
-
const pkgPath =
|
|
8097
|
+
const pkgPath = import_node_path45.default.join(scanPath, "package.json");
|
|
7778
8098
|
const raw = await import_node_fs26.promises.readFile(pkgPath, "utf8");
|
|
7779
8099
|
return JSON.parse(raw);
|
|
7780
8100
|
}
|
|
8101
|
+
var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
8102
|
+
"node_modules",
|
|
8103
|
+
"dist",
|
|
8104
|
+
"build",
|
|
8105
|
+
"out",
|
|
8106
|
+
"coverage",
|
|
8107
|
+
"neat-out"
|
|
8108
|
+
]);
|
|
7781
8109
|
async function findHookFiles(scanPath) {
|
|
7782
|
-
const
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
8110
|
+
const found = [];
|
|
8111
|
+
const walk3 = async (dir) => {
|
|
8112
|
+
const entries = await import_node_fs26.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
8113
|
+
for (const entry2 of entries) {
|
|
8114
|
+
if (entry2.isDirectory()) {
|
|
8115
|
+
if (entry2.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry2.name)) continue;
|
|
8116
|
+
await walk3(import_node_path45.default.join(dir, entry2.name));
|
|
8117
|
+
} else if (entry2.isFile()) {
|
|
8118
|
+
if ((entry2.name.startsWith("instrumentation") || entry2.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry2.name)) {
|
|
8119
|
+
const rel = import_node_path45.default.relative(scanPath, import_node_path45.default.join(dir, entry2.name));
|
|
8120
|
+
found.push(rel.split(import_node_path45.default.sep).join("/"));
|
|
8121
|
+
}
|
|
8122
|
+
}
|
|
8123
|
+
}
|
|
8124
|
+
};
|
|
8125
|
+
await walk3(scanPath);
|
|
8126
|
+
return found.sort();
|
|
8127
|
+
}
|
|
8128
|
+
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
8129
|
+
let fallback = null;
|
|
8130
|
+
for (const file of hookFiles) {
|
|
8131
|
+
const content = await import_node_fs26.promises.readFile(import_node_path45.default.join(scanPath, file), "utf8");
|
|
8132
|
+
const patched = splicedContent(content, snippet2);
|
|
8133
|
+
if (patched !== null) return { file, content, patched };
|
|
8134
|
+
if (fallback === null) fallback = { file, content };
|
|
8135
|
+
}
|
|
8136
|
+
return { file: fallback.file, content: fallback.content, patched: null };
|
|
7786
8137
|
}
|
|
7787
8138
|
function extendLogPath() {
|
|
7788
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
8139
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path45.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
7789
8140
|
}
|
|
7790
8141
|
async function appendExtendLog(entry2) {
|
|
7791
8142
|
const logPath = extendLogPath();
|
|
7792
|
-
await import_node_fs26.promises.mkdir(
|
|
8143
|
+
await import_node_fs26.promises.mkdir(import_node_path45.default.dirname(logPath), { recursive: true });
|
|
7793
8144
|
await import_node_fs26.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
7794
8145
|
}
|
|
7795
8146
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -7848,7 +8199,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
7848
8199
|
}
|
|
7849
8200
|
async function describeProjectInstrumentation(ctx) {
|
|
7850
8201
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7851
|
-
const envNeat = await fileExists2(
|
|
8202
|
+
const envNeat = await fileExists2(import_node_path45.default.join(ctx.scanPath, ".env.neat"));
|
|
7852
8203
|
const registryInstrPackages = new Set(
|
|
7853
8204
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
7854
8205
|
);
|
|
@@ -7870,16 +8221,22 @@ async function applyExtension(ctx, args, options) {
|
|
|
7870
8221
|
);
|
|
7871
8222
|
}
|
|
7872
8223
|
for (const file of hookFiles) {
|
|
7873
|
-
const content = await import_node_fs26.promises.readFile(
|
|
8224
|
+
const content = await import_node_fs26.promises.readFile(import_node_path45.default.join(ctx.scanPath, file), "utf8");
|
|
7874
8225
|
if (content.includes(args.registration_snippet)) {
|
|
7875
8226
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
7876
8227
|
}
|
|
7877
8228
|
}
|
|
7878
|
-
const
|
|
7879
|
-
|
|
8229
|
+
const primary = await pickPrimaryHookFile(ctx.scanPath, hookFiles, args.registration_snippet);
|
|
8230
|
+
if (primary.patched === null) {
|
|
8231
|
+
throw new Error(
|
|
8232
|
+
`Could not find instrumentation insertion point in ${hookFiles.join(", ")}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
8233
|
+
);
|
|
8234
|
+
}
|
|
8235
|
+
const primaryFile = primary.file;
|
|
8236
|
+
const primaryPath = import_node_path45.default.join(ctx.scanPath, primaryFile);
|
|
7880
8237
|
const filesTouched = [];
|
|
7881
8238
|
const depsAdded = [];
|
|
7882
|
-
const pkgPath =
|
|
8239
|
+
const pkgPath = import_node_path45.default.join(ctx.scanPath, "package.json");
|
|
7883
8240
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7884
8241
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
7885
8242
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -7887,14 +8244,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
7887
8244
|
filesTouched.push("package.json");
|
|
7888
8245
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
7889
8246
|
}
|
|
7890
|
-
|
|
7891
|
-
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7892
|
-
if (!patched) {
|
|
7893
|
-
throw new Error(
|
|
7894
|
-
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
7895
|
-
);
|
|
7896
|
-
}
|
|
7897
|
-
await import_node_fs26.promises.writeFile(primaryPath, patched, "utf8");
|
|
8247
|
+
await import_node_fs26.promises.writeFile(primaryPath, primary.patched, "utf8");
|
|
7898
8248
|
filesTouched.push(primaryFile);
|
|
7899
8249
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
7900
8250
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -7925,7 +8275,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7925
8275
|
};
|
|
7926
8276
|
}
|
|
7927
8277
|
for (const file of hookFiles) {
|
|
7928
|
-
const content = await import_node_fs26.promises.readFile(
|
|
8278
|
+
const content = await import_node_fs26.promises.readFile(import_node_path45.default.join(ctx.scanPath, file), "utf8");
|
|
7929
8279
|
if (content.includes(args.registration_snippet)) {
|
|
7930
8280
|
return {
|
|
7931
8281
|
library: args.library,
|
|
@@ -7936,7 +8286,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7936
8286
|
};
|
|
7937
8287
|
}
|
|
7938
8288
|
}
|
|
7939
|
-
const
|
|
8289
|
+
const primary = await pickPrimaryHookFile(ctx.scanPath, hookFiles, args.registration_snippet);
|
|
7940
8290
|
const filesTouched = [];
|
|
7941
8291
|
const depsToAdd = [];
|
|
7942
8292
|
let packageJsonPatch = {};
|
|
@@ -7947,10 +8297,8 @@ async function dryRunExtension(ctx, args) {
|
|
|
7947
8297
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
7948
8298
|
filesTouched.push("package.json");
|
|
7949
8299
|
}
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
if (patched) {
|
|
7953
|
-
filesTouched.push(primaryFile);
|
|
8300
|
+
if (primary.patched !== null) {
|
|
8301
|
+
filesTouched.push(primary.file);
|
|
7954
8302
|
templatePatch = `+ ${args.registration_snippet}`;
|
|
7955
8303
|
} else {
|
|
7956
8304
|
templatePatch = "Could not find insertion point in hook file.";
|
|
@@ -7968,7 +8316,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
7968
8316
|
if (!match) {
|
|
7969
8317
|
return { undone: false, message: "no apply found for library" };
|
|
7970
8318
|
}
|
|
7971
|
-
const pkgPath =
|
|
8319
|
+
const pkgPath = import_node_path45.default.join(ctx.scanPath, "package.json");
|
|
7972
8320
|
if (await fileExists2(pkgPath)) {
|
|
7973
8321
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7974
8322
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -7979,7 +8327,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
7979
8327
|
}
|
|
7980
8328
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7981
8329
|
for (const file of hookFiles) {
|
|
7982
|
-
const filePath =
|
|
8330
|
+
const filePath = import_node_path45.default.join(ctx.scanPath, file);
|
|
7983
8331
|
const content = await import_node_fs26.promises.readFile(filePath, "utf8");
|
|
7984
8332
|
if (content.includes(match.registration_snippet)) {
|
|
7985
8333
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -7995,39 +8343,39 @@ async function rollbackExtension(ctx, args) {
|
|
|
7995
8343
|
|
|
7996
8344
|
// src/divergences.ts
|
|
7997
8345
|
init_cjs_shims();
|
|
7998
|
-
var
|
|
8346
|
+
var import_types32 = require("@neat.is/types");
|
|
7999
8347
|
function bucketKey(source, target, type) {
|
|
8000
8348
|
return `${type}|${source}|${target}`;
|
|
8001
8349
|
}
|
|
8002
8350
|
function bucketSourceFor(graph, edge) {
|
|
8003
|
-
if (edge.type !==
|
|
8004
|
-
const parsed = (0,
|
|
8351
|
+
if (edge.type !== import_types32.EdgeType.CONNECTS_TO) return edge.source;
|
|
8352
|
+
const parsed = (0, import_types32.parseFileId)(edge.source);
|
|
8005
8353
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
8006
8354
|
const target = graph.getNodeAttributes(edge.target);
|
|
8007
|
-
if (target.type !==
|
|
8008
|
-
return (0,
|
|
8355
|
+
if (target.type !== import_types32.NodeType.DatabaseNode) return edge.source;
|
|
8356
|
+
return (0, import_types32.serviceId)(parsed.service);
|
|
8009
8357
|
}
|
|
8010
8358
|
function bucketEdges(graph) {
|
|
8011
8359
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
8012
8360
|
graph.forEachEdge((id, attrs) => {
|
|
8013
8361
|
const e = attrs;
|
|
8014
|
-
const parsed = (0,
|
|
8362
|
+
const parsed = (0, import_types32.parseEdgeId)(id);
|
|
8015
8363
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
8016
8364
|
const source = bucketSourceFor(graph, e);
|
|
8017
8365
|
const key = bucketKey(source, e.target, e.type);
|
|
8018
8366
|
const cur = buckets2.get(key) ?? { source, target: e.target, type: e.type };
|
|
8019
8367
|
switch (provenance) {
|
|
8020
|
-
case
|
|
8368
|
+
case import_types32.Provenance.EXTRACTED:
|
|
8021
8369
|
cur.extracted = e;
|
|
8022
8370
|
break;
|
|
8023
|
-
case
|
|
8371
|
+
case import_types32.Provenance.OBSERVED:
|
|
8024
8372
|
cur.observed = e;
|
|
8025
8373
|
break;
|
|
8026
|
-
case
|
|
8374
|
+
case import_types32.Provenance.INFERRED:
|
|
8027
8375
|
cur.inferred = e;
|
|
8028
8376
|
break;
|
|
8029
8377
|
default:
|
|
8030
|
-
if (e.provenance ===
|
|
8378
|
+
if (e.provenance === import_types32.Provenance.STALE) cur.stale = e;
|
|
8031
8379
|
}
|
|
8032
8380
|
buckets2.set(key, cur);
|
|
8033
8381
|
});
|
|
@@ -8036,12 +8384,12 @@ function bucketEdges(graph) {
|
|
|
8036
8384
|
function nodeIsFrontier(graph, nodeId) {
|
|
8037
8385
|
if (!graph.hasNode(nodeId)) return false;
|
|
8038
8386
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
8039
|
-
return attrs.type ===
|
|
8387
|
+
return attrs.type === import_types32.NodeType.FrontierNode;
|
|
8040
8388
|
}
|
|
8041
8389
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
8042
8390
|
if (!graph.hasNode(nodeId)) return false;
|
|
8043
8391
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
8044
|
-
return attrs.type ===
|
|
8392
|
+
return attrs.type === import_types32.NodeType.WebSocketChannelNode;
|
|
8045
8393
|
}
|
|
8046
8394
|
function clampConfidence(n) {
|
|
8047
8395
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -8061,14 +8409,14 @@ function gradedConfidence(edge) {
|
|
|
8061
8409
|
return clampConfidence(confidenceForEdge(edge));
|
|
8062
8410
|
}
|
|
8063
8411
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8412
|
+
import_types32.EdgeType.CALLS,
|
|
8413
|
+
import_types32.EdgeType.CONNECTS_TO,
|
|
8414
|
+
import_types32.EdgeType.PUBLISHES_TO,
|
|
8415
|
+
import_types32.EdgeType.CONSUMES_FROM
|
|
8068
8416
|
]);
|
|
8069
8417
|
function detectMissingDivergences(graph, bucket) {
|
|
8070
8418
|
const out = [];
|
|
8071
|
-
if (bucket.type ===
|
|
8419
|
+
if (bucket.type === import_types32.EdgeType.CONTAINS) return out;
|
|
8072
8420
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
8073
8421
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
8074
8422
|
out.push({
|
|
@@ -8109,7 +8457,7 @@ function declaredHostFor(svc) {
|
|
|
8109
8457
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
8110
8458
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8111
8459
|
const e = graph.getEdgeAttributes(edgeId);
|
|
8112
|
-
if (e.type ===
|
|
8460
|
+
if (e.type === import_types32.EdgeType.CONFIGURED_BY && e.provenance === import_types32.Provenance.EXTRACTED) {
|
|
8113
8461
|
return true;
|
|
8114
8462
|
}
|
|
8115
8463
|
}
|
|
@@ -8122,10 +8470,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
8122
8470
|
const out = [];
|
|
8123
8471
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8124
8472
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
8125
|
-
if (edge.type !==
|
|
8126
|
-
if (edge.provenance !==
|
|
8473
|
+
if (edge.type !== import_types32.EdgeType.CONNECTS_TO) continue;
|
|
8474
|
+
if (edge.provenance !== import_types32.Provenance.OBSERVED) continue;
|
|
8127
8475
|
const target = graph.getNodeAttributes(edge.target);
|
|
8128
|
-
if (target.type !==
|
|
8476
|
+
if (target.type !== import_types32.NodeType.DatabaseNode) continue;
|
|
8129
8477
|
const observedHost = target.host?.trim();
|
|
8130
8478
|
if (!observedHost) continue;
|
|
8131
8479
|
if (observedHost === declaredHost) continue;
|
|
@@ -8147,10 +8495,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
8147
8495
|
const deps = svc.dependencies ?? {};
|
|
8148
8496
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
8149
8497
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
8150
|
-
if (edge.type !==
|
|
8151
|
-
if (edge.provenance !==
|
|
8498
|
+
if (edge.type !== import_types32.EdgeType.CONNECTS_TO) continue;
|
|
8499
|
+
if (edge.provenance !== import_types32.Provenance.OBSERVED) continue;
|
|
8152
8500
|
const target = graph.getNodeAttributes(edge.target);
|
|
8153
|
-
if (target.type !==
|
|
8501
|
+
if (target.type !== import_types32.NodeType.DatabaseNode) continue;
|
|
8154
8502
|
for (const pair of compatPairs()) {
|
|
8155
8503
|
if (pair.engine !== target.engine) continue;
|
|
8156
8504
|
const declared = deps[pair.driver];
|
|
@@ -8209,7 +8557,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
8209
8557
|
for (const d of all) {
|
|
8210
8558
|
if (d.type !== "host-mismatch") continue;
|
|
8211
8559
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
8212
|
-
declaredHalf.add((0,
|
|
8560
|
+
declaredHalf.add((0, import_types32.databaseId)(d.extractedHost));
|
|
8213
8561
|
}
|
|
8214
8562
|
if (observedHalf.size === 0) return all;
|
|
8215
8563
|
return all.filter((d) => {
|
|
@@ -8228,7 +8576,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8228
8576
|
}
|
|
8229
8577
|
graph.forEachNode((nodeId, attrs) => {
|
|
8230
8578
|
const n = attrs;
|
|
8231
|
-
if (n.type !==
|
|
8579
|
+
if (n.type !== import_types32.NodeType.ServiceNode) return;
|
|
8232
8580
|
const svc = n;
|
|
8233
8581
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
8234
8582
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -8262,7 +8610,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
8262
8610
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
8263
8611
|
return a.target.localeCompare(b.target);
|
|
8264
8612
|
});
|
|
8265
|
-
return
|
|
8613
|
+
return import_types32.DivergenceResultSchema.parse({
|
|
8266
8614
|
divergences: filtered,
|
|
8267
8615
|
totalAffected: filtered.length,
|
|
8268
8616
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -8395,23 +8743,23 @@ function canonicalJson(value) {
|
|
|
8395
8743
|
init_cjs_shims();
|
|
8396
8744
|
var import_node_fs28 = require("fs");
|
|
8397
8745
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
8398
|
-
var
|
|
8399
|
-
var
|
|
8746
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
8747
|
+
var import_types33 = require("@neat.is/types");
|
|
8400
8748
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
8401
8749
|
var LOCK_RETRY_MS = 50;
|
|
8402
8750
|
function neatHome() {
|
|
8403
8751
|
const override = process.env.NEAT_HOME;
|
|
8404
|
-
if (override && override.length > 0) return
|
|
8405
|
-
return
|
|
8752
|
+
if (override && override.length > 0) return import_node_path46.default.resolve(override);
|
|
8753
|
+
return import_node_path46.default.join(import_node_os3.default.homedir(), ".neat");
|
|
8406
8754
|
}
|
|
8407
8755
|
function registryPath() {
|
|
8408
|
-
return
|
|
8756
|
+
return import_node_path46.default.join(neatHome(), "projects.json");
|
|
8409
8757
|
}
|
|
8410
8758
|
function registryLockPath() {
|
|
8411
|
-
return
|
|
8759
|
+
return import_node_path46.default.join(neatHome(), "projects.json.lock");
|
|
8412
8760
|
}
|
|
8413
8761
|
function daemonPidPath() {
|
|
8414
|
-
return
|
|
8762
|
+
return import_node_path46.default.join(neatHome(), "neatd.pid");
|
|
8415
8763
|
}
|
|
8416
8764
|
function isPidAliveDefault(pid) {
|
|
8417
8765
|
try {
|
|
@@ -8471,7 +8819,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
8471
8819
|
}
|
|
8472
8820
|
}
|
|
8473
8821
|
async function writeAtomically(target, contents) {
|
|
8474
|
-
await import_node_fs28.promises.mkdir(
|
|
8822
|
+
await import_node_fs28.promises.mkdir(import_node_path46.default.dirname(target), { recursive: true });
|
|
8475
8823
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
8476
8824
|
const fd = await import_node_fs28.promises.open(tmp, "w");
|
|
8477
8825
|
try {
|
|
@@ -8484,7 +8832,7 @@ async function writeAtomically(target, contents) {
|
|
|
8484
8832
|
}
|
|
8485
8833
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
8486
8834
|
const deadline = Date.now() + timeoutMs;
|
|
8487
|
-
await import_node_fs28.promises.mkdir(
|
|
8835
|
+
await import_node_fs28.promises.mkdir(import_node_path46.default.dirname(lockPath), { recursive: true });
|
|
8488
8836
|
let probedHolder = false;
|
|
8489
8837
|
while (true) {
|
|
8490
8838
|
try {
|
|
@@ -8537,10 +8885,10 @@ async function readRegistry() {
|
|
|
8537
8885
|
throw err;
|
|
8538
8886
|
}
|
|
8539
8887
|
const parsed = JSON.parse(raw);
|
|
8540
|
-
return
|
|
8888
|
+
return import_types33.RegistryFileSchema.parse(parsed);
|
|
8541
8889
|
}
|
|
8542
8890
|
async function writeRegistry(reg) {
|
|
8543
|
-
const validated =
|
|
8891
|
+
const validated = import_types33.RegistryFileSchema.parse(reg);
|
|
8544
8892
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
8545
8893
|
}
|
|
8546
8894
|
async function getProject(name) {
|
|
@@ -8685,7 +9033,7 @@ init_auth();
|
|
|
8685
9033
|
// src/connectors-config.ts
|
|
8686
9034
|
init_cjs_shims();
|
|
8687
9035
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
8688
|
-
var
|
|
9036
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
8689
9037
|
var import_node_fs29 = require("fs");
|
|
8690
9038
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
8691
9039
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -8700,11 +9048,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
8700
9048
|
};
|
|
8701
9049
|
function neatHome2() {
|
|
8702
9050
|
const override = process.env.NEAT_HOME;
|
|
8703
|
-
if (override && override.length > 0) return
|
|
8704
|
-
return
|
|
9051
|
+
if (override && override.length > 0) return import_node_path47.default.resolve(override);
|
|
9052
|
+
return import_node_path47.default.join(import_node_os4.default.homedir(), ".neat");
|
|
8705
9053
|
}
|
|
8706
9054
|
function connectorsConfigPath(home = neatHome2()) {
|
|
8707
|
-
return
|
|
9055
|
+
return import_node_path47.default.join(home, "connectors.json");
|
|
8708
9056
|
}
|
|
8709
9057
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
8710
9058
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -9040,11 +9388,11 @@ function registerRoutes(scope, ctx) {
|
|
|
9040
9388
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
9041
9389
|
const parsed = [];
|
|
9042
9390
|
for (const c of candidates) {
|
|
9043
|
-
const r =
|
|
9391
|
+
const r = import_types34.DivergenceTypeSchema.safeParse(c);
|
|
9044
9392
|
if (!r.success) {
|
|
9045
9393
|
return reply.code(400).send({
|
|
9046
9394
|
error: `unknown divergence type "${c}"`,
|
|
9047
|
-
allowed:
|
|
9395
|
+
allowed: import_types34.DivergenceTypeSchema.options
|
|
9048
9396
|
});
|
|
9049
9397
|
}
|
|
9050
9398
|
parsed.push(r.data);
|
|
@@ -9315,7 +9663,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9315
9663
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
9316
9664
|
let violations = await log.readAll();
|
|
9317
9665
|
if (req2.query.severity) {
|
|
9318
|
-
const sev =
|
|
9666
|
+
const sev = import_types34.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
9319
9667
|
if (!sev.success) {
|
|
9320
9668
|
return reply.code(400).send({
|
|
9321
9669
|
error: "invalid severity",
|
|
@@ -9354,7 +9702,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9354
9702
|
scope.post("/policies/check", async (req2, reply) => {
|
|
9355
9703
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
9356
9704
|
if (!proj) return;
|
|
9357
|
-
const parsed =
|
|
9705
|
+
const parsed = import_types34.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
9358
9706
|
if (!parsed.success) {
|
|
9359
9707
|
return reply.code(400).send({
|
|
9360
9708
|
error: "invalid /policies/check body",
|
|
@@ -9488,7 +9836,7 @@ function registerRoutes(scope, ctx) {
|
|
|
9488
9836
|
});
|
|
9489
9837
|
}
|
|
9490
9838
|
async function buildApi(opts) {
|
|
9491
|
-
const app = (0, import_fastify.default)({ logger: false });
|
|
9839
|
+
const app = (0, import_fastify.default)({ logger: false, routerOptions: { maxParamLength: 1024 } });
|
|
9492
9840
|
await app.register(import_cors.default, { origin: true });
|
|
9493
9841
|
const env = readAuthEnv();
|
|
9494
9842
|
const authToken = opts.authToken ?? env.authToken;
|
|
@@ -9618,15 +9966,15 @@ init_otel();
|
|
|
9618
9966
|
|
|
9619
9967
|
// src/connectors/index.ts
|
|
9620
9968
|
init_cjs_shims();
|
|
9621
|
-
var
|
|
9969
|
+
var import_types35 = require("@neat.is/types");
|
|
9622
9970
|
var NO_ENV = "unknown";
|
|
9623
9971
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
9624
9972
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
9625
9973
|
const sites = [];
|
|
9626
9974
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
9627
9975
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
9628
|
-
if (edge.provenance !==
|
|
9629
|
-
const parsed = (0,
|
|
9976
|
+
if (edge.provenance !== import_types35.Provenance.EXTRACTED) continue;
|
|
9977
|
+
const parsed = (0, import_types35.parseFileId)(edge.source);
|
|
9630
9978
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
9631
9979
|
const site = { relPath: edge.evidence.file };
|
|
9632
9980
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -9637,7 +9985,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
9637
9985
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
9638
9986
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
9639
9987
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
9640
|
-
if (attrs.type !==
|
|
9988
|
+
if (attrs.type !== import_types35.NodeType.RouteNode || !attrs.path) return void 0;
|
|
9641
9989
|
const site = { relPath: attrs.path };
|
|
9642
9990
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
9643
9991
|
return site;
|
|
@@ -9665,8 +10013,8 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
9665
10013
|
line: callSite.line
|
|
9666
10014
|
} : void 0;
|
|
9667
10015
|
const calls = Math.trunc(signal.callCount);
|
|
9668
|
-
if (calls < 1) continue;
|
|
9669
|
-
const errors = Math.min(Math.max(Math.trunc(signal.errorCount), 0), calls);
|
|
10016
|
+
if (!Number.isFinite(calls) || calls < 1) continue;
|
|
10017
|
+
const errors = Number.isFinite(signal.errorCount) ? Math.min(Math.max(Math.trunc(signal.errorCount), 0), calls) : 0;
|
|
9670
10018
|
let created = false;
|
|
9671
10019
|
let ok = true;
|
|
9672
10020
|
for (let i = 0; i < calls; i++) {
|
|
@@ -9811,7 +10159,12 @@ var JUNCTION_DEFAULT_RATE_LIMITS = {
|
|
|
9811
10159
|
supabase: { capacity: 30, refillMs: 1e4 },
|
|
9812
10160
|
// Not a documented API limit at all — a self-imposed ceiling on the raw
|
|
9813
10161
|
// pg_stat_statements connection (see module header above).
|
|
9814
|
-
"supabase-postgres": { capacity: 20, refillMs: 3e3 }
|
|
10162
|
+
"supabase-postgres": { capacity: 20, refillMs: 3e3 },
|
|
10163
|
+
// Push provider (ADR-146): the Drains REST API is touched only by `neat
|
|
10164
|
+
// connector add/remove/test` (provision/deprovision/validate), never a poll
|
|
10165
|
+
// loop, so this bucket is exercised a handful of times per command. Kept
|
|
10166
|
+
// conservative pending a documented Drains-API rate limit.
|
|
10167
|
+
vercel: { capacity: 20, refillMs: 5e3 }
|
|
9815
10168
|
};
|
|
9816
10169
|
var JUNCTION_GENERIC_RATE_LIMIT = { capacity: 20, refillMs: 5e3 };
|
|
9817
10170
|
function defaultRateLimitFor(provider) {
|
|
@@ -10103,17 +10456,20 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
10103
10456
|
// src/connectors/supabase/map.ts
|
|
10104
10457
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
10105
10458
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
10106
|
-
function targetFromRestPath(
|
|
10107
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
10459
|
+
function targetFromRestPath(path54) {
|
|
10460
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path54);
|
|
10108
10461
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
10109
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
10462
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path54);
|
|
10110
10463
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
10111
10464
|
return null;
|
|
10112
10465
|
}
|
|
10113
10466
|
var ERROR_STATUS_THRESHOLD = 500;
|
|
10114
10467
|
function mapEdgeLogRowsToSignals(rows) {
|
|
10115
10468
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
10469
|
+
if (!Array.isArray(rows)) return [];
|
|
10116
10470
|
for (const row of rows) {
|
|
10471
|
+
if (!row || typeof row !== "object") continue;
|
|
10472
|
+
if (typeof row.path !== "string" || typeof row.timestamp !== "string") continue;
|
|
10117
10473
|
const target = targetFromRestPath(row.path);
|
|
10118
10474
|
if (!target) continue;
|
|
10119
10475
|
const key = `${target.targetKind}:${target.name}`;
|
|
@@ -10154,9 +10510,12 @@ function tableNameFromQueryText(query) {
|
|
|
10154
10510
|
function diffPgStatStatementsToSignals(rows, previous, nowIso2) {
|
|
10155
10511
|
const signals = [];
|
|
10156
10512
|
const seen = /* @__PURE__ */ new Set();
|
|
10513
|
+
if (!Array.isArray(rows)) return signals;
|
|
10157
10514
|
for (const row of rows) {
|
|
10158
|
-
|
|
10515
|
+
if (!row || typeof row !== "object" || typeof row.queryid !== "string") continue;
|
|
10159
10516
|
const calls = Number(row.calls);
|
|
10517
|
+
if (!Number.isFinite(calls)) continue;
|
|
10518
|
+
seen.add(row.queryid);
|
|
10160
10519
|
const prior = previous.get(row.queryid);
|
|
10161
10520
|
previous.set(row.queryid, { calls });
|
|
10162
10521
|
if (!prior || calls < prior.calls) continue;
|
|
@@ -10209,23 +10568,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
10209
10568
|
|
|
10210
10569
|
// src/connectors/supabase/resolve.ts
|
|
10211
10570
|
init_cjs_shims();
|
|
10212
|
-
var
|
|
10571
|
+
var import_types37 = require("@neat.is/types");
|
|
10213
10572
|
function createSupabaseResolveTarget(graph, config) {
|
|
10214
10573
|
return (signal, _ctx) => {
|
|
10215
10574
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
10216
10575
|
return null;
|
|
10217
10576
|
}
|
|
10218
|
-
const subResourceId = (0,
|
|
10577
|
+
const subResourceId = (0, import_types37.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
10219
10578
|
if (graph.hasNode(subResourceId)) {
|
|
10220
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
10579
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types37.EdgeType.CALLS };
|
|
10221
10580
|
}
|
|
10222
|
-
const bareResourceId = (0,
|
|
10581
|
+
const bareResourceId = (0, import_types37.infraId)(signal.targetKind, signal.targetName);
|
|
10223
10582
|
if (graph.hasNode(bareResourceId)) {
|
|
10224
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
10583
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types37.EdgeType.CALLS };
|
|
10225
10584
|
}
|
|
10226
|
-
const projectLevelId = (0,
|
|
10585
|
+
const projectLevelId = (0, import_types37.infraId)("supabase", config.nodeRef);
|
|
10227
10586
|
if (graph.hasNode(projectLevelId)) {
|
|
10228
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
10587
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types37.EdgeType.CALLS };
|
|
10229
10588
|
}
|
|
10230
10589
|
return null;
|
|
10231
10590
|
};
|
|
@@ -10318,7 +10677,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
10318
10677
|
|
|
10319
10678
|
// src/connectors/railway/index.ts
|
|
10320
10679
|
init_cjs_shims();
|
|
10321
|
-
var
|
|
10680
|
+
var import_types41 = require("@neat.is/types");
|
|
10322
10681
|
|
|
10323
10682
|
// src/connectors/railway/client.ts
|
|
10324
10683
|
init_cjs_shims();
|
|
@@ -10444,7 +10803,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
10444
10803
|
const out = [];
|
|
10445
10804
|
graph.forEachNode((_id, attrs) => {
|
|
10446
10805
|
const node = attrs;
|
|
10447
|
-
if (node.type !==
|
|
10806
|
+
if (node.type !== import_types41.NodeType.RouteNode) return;
|
|
10448
10807
|
const route = attrs;
|
|
10449
10808
|
if (route.service !== serviceName) return;
|
|
10450
10809
|
out.push({
|
|
@@ -10480,7 +10839,12 @@ function upsertBucket(buckets2, key, isError, timestamp, build) {
|
|
|
10480
10839
|
}
|
|
10481
10840
|
function mapRailwayHttpLogsToSignals(entries, routeIndex) {
|
|
10482
10841
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
10842
|
+
if (!Array.isArray(entries)) return [];
|
|
10483
10843
|
for (const entry2 of entries) {
|
|
10844
|
+
if (!entry2 || typeof entry2 !== "object") continue;
|
|
10845
|
+
if (typeof entry2.method !== "string" || typeof entry2.path !== "string" || typeof entry2.timestamp !== "string") {
|
|
10846
|
+
continue;
|
|
10847
|
+
}
|
|
10484
10848
|
const method = entry2.method.toUpperCase();
|
|
10485
10849
|
const normalizedPath = normalizePathTemplate(entry2.path);
|
|
10486
10850
|
const match = findRailwayRoute(routeIndex, method, normalizedPath);
|
|
@@ -10519,8 +10883,11 @@ function mapRailwayHttpLogsToSignals(entries, routeIndex) {
|
|
|
10519
10883
|
}
|
|
10520
10884
|
function mapRailwayNetworkFlowLogsToSignals(entries) {
|
|
10521
10885
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
10886
|
+
if (!Array.isArray(entries)) return [];
|
|
10522
10887
|
for (const entry2 of entries) {
|
|
10523
|
-
if (!entry2
|
|
10888
|
+
if (!entry2 || typeof entry2 !== "object") continue;
|
|
10889
|
+
if (typeof entry2.peerServiceId !== "string" || entry2.peerServiceId.length === 0) continue;
|
|
10890
|
+
if (typeof entry2.timestamp !== "string") continue;
|
|
10524
10891
|
const isError = entry2.dropCause !== null && entry2.dropCause !== "";
|
|
10525
10892
|
upsertBucket(buckets2, entry2.peerServiceId, isError, entry2.timestamp, () => ({
|
|
10526
10893
|
targetKind: PEER_SERVICE_TARGET_KIND,
|
|
@@ -10540,12 +10907,12 @@ function createRailwayResolveTarget(config) {
|
|
|
10540
10907
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
10541
10908
|
if (!serviceName) return null;
|
|
10542
10909
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
10543
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
10910
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types41.EdgeType.CALLS };
|
|
10544
10911
|
}
|
|
10545
10912
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
10546
10913
|
const peerName = config.serviceNameById[signal.targetName];
|
|
10547
10914
|
if (!peerName) return null;
|
|
10548
|
-
return { targetNodeId: (0,
|
|
10915
|
+
return { targetNodeId: (0, import_types41.serviceId)(peerName), serviceName, edgeType: import_types41.EdgeType.CONNECTS_TO };
|
|
10549
10916
|
}
|
|
10550
10917
|
return null;
|
|
10551
10918
|
};
|
|
@@ -10648,7 +11015,7 @@ async function fetchHttpRequestLogEntries(creds, sinceIso) {
|
|
|
10648
11015
|
throw new Error(`Cloud Logging entries.list failed: ${res.status} ${res.statusText}`);
|
|
10649
11016
|
}
|
|
10650
11017
|
const json = await res.json();
|
|
10651
|
-
out.push(...json.entries
|
|
11018
|
+
if (Array.isArray(json.entries)) out.push(...json.entries);
|
|
10652
11019
|
if (!json.nextPageToken) break;
|
|
10653
11020
|
pageToken = json.nextPageToken;
|
|
10654
11021
|
}
|
|
@@ -10669,9 +11036,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
10669
11036
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
10670
11037
|
if (secondSep === -1) return null;
|
|
10671
11038
|
const method = rest.slice(0, secondSep);
|
|
10672
|
-
const
|
|
10673
|
-
if (!resourceName || !method || !
|
|
10674
|
-
return { resourceName, method, path:
|
|
11039
|
+
const path54 = rest.slice(secondSep + 1);
|
|
11040
|
+
if (!resourceName || !method || !path54) return null;
|
|
11041
|
+
return { resourceName, method, path: path54 };
|
|
10675
11042
|
}
|
|
10676
11043
|
function resourceNameFor(type, labels) {
|
|
10677
11044
|
if (!labels) return null;
|
|
@@ -10685,7 +11052,7 @@ function resourceNameFor(type, labels) {
|
|
|
10685
11052
|
}
|
|
10686
11053
|
}
|
|
10687
11054
|
function pathFromRequestUrl(requestUrl) {
|
|
10688
|
-
if (
|
|
11055
|
+
if (typeof requestUrl !== "string" || requestUrl.length === 0) return null;
|
|
10689
11056
|
if (requestUrl.startsWith("/")) {
|
|
10690
11057
|
const withoutQuery = requestUrl.split("?")[0];
|
|
10691
11058
|
return withoutQuery && withoutQuery.length > 0 ? withoutQuery : "/";
|
|
@@ -10700,22 +11067,23 @@ function pathFromRequestUrl(requestUrl) {
|
|
|
10700
11067
|
}
|
|
10701
11068
|
var ERROR_STATUS_THRESHOLD2 = 500;
|
|
10702
11069
|
function mapLogEntryToSignal(entry2) {
|
|
11070
|
+
if (!entry2 || typeof entry2 !== "object") return null;
|
|
10703
11071
|
const resourceType = entry2.resource?.type;
|
|
10704
11072
|
if (!resourceType || !isFirebaseResourceType(resourceType)) return null;
|
|
10705
11073
|
const resourceName = resourceNameFor(resourceType, entry2.resource?.labels);
|
|
10706
11074
|
if (!resourceName) return null;
|
|
10707
11075
|
const req2 = entry2.httpRequest;
|
|
10708
11076
|
if (!req2) return null;
|
|
10709
|
-
if (
|
|
11077
|
+
if (typeof req2.requestMethod !== "string" || req2.requestMethod.length === 0) return null;
|
|
10710
11078
|
const method = req2.requestMethod.toUpperCase();
|
|
10711
|
-
const
|
|
10712
|
-
if (
|
|
11079
|
+
const path54 = pathFromRequestUrl(req2.requestUrl);
|
|
11080
|
+
if (path54 === null) return null;
|
|
10713
11081
|
const timestamp = entry2.timestamp;
|
|
10714
|
-
if (
|
|
11082
|
+
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
10715
11083
|
const isError = typeof req2.status === "number" && req2.status >= ERROR_STATUS_THRESHOLD2;
|
|
10716
11084
|
return {
|
|
10717
11085
|
targetKind: resourceType,
|
|
10718
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
11086
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path54 }),
|
|
10719
11087
|
callCount: 1,
|
|
10720
11088
|
errorCount: isError ? 1 : 0,
|
|
10721
11089
|
lastObservedIso: timestamp
|
|
@@ -10732,7 +11100,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
10732
11100
|
|
|
10733
11101
|
// src/connectors/firebase/resolve.ts
|
|
10734
11102
|
init_cjs_shims();
|
|
10735
|
-
var
|
|
11103
|
+
var import_types42 = require("@neat.is/types");
|
|
10736
11104
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
10737
11105
|
switch (resourceType) {
|
|
10738
11106
|
case "cloud_function":
|
|
@@ -10747,7 +11115,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
10747
11115
|
const entries = [];
|
|
10748
11116
|
graph.forEachNode((_id, attrs) => {
|
|
10749
11117
|
const node = attrs;
|
|
10750
|
-
if (node.type !==
|
|
11118
|
+
if (node.type !== import_types42.NodeType.RouteNode) return;
|
|
10751
11119
|
const route = attrs;
|
|
10752
11120
|
if (route.service !== serviceName) return;
|
|
10753
11121
|
entries.push({
|
|
@@ -10779,7 +11147,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
10779
11147
|
return {
|
|
10780
11148
|
targetNodeId: match.routeNodeId,
|
|
10781
11149
|
serviceName,
|
|
10782
|
-
edgeType:
|
|
11150
|
+
edgeType: import_types42.EdgeType.CALLS
|
|
10783
11151
|
};
|
|
10784
11152
|
};
|
|
10785
11153
|
}
|
|
@@ -10806,7 +11174,7 @@ init_cjs_shims();
|
|
|
10806
11174
|
|
|
10807
11175
|
// src/connectors/cloudflare/connector.ts
|
|
10808
11176
|
init_cjs_shims();
|
|
10809
|
-
var
|
|
11177
|
+
var import_types44 = require("@neat.is/types");
|
|
10810
11178
|
|
|
10811
11179
|
// src/connectors/cloudflare/client.ts
|
|
10812
11180
|
init_cjs_shims();
|
|
@@ -10863,7 +11231,7 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
|
|
|
10863
11231
|
throw new Error(`cloudflare connector: telemetry query returned an error (${message})`);
|
|
10864
11232
|
}
|
|
10865
11233
|
const events = payload.result?.events?.events;
|
|
10866
|
-
if (events
|
|
11234
|
+
if (!Array.isArray(events)) {
|
|
10867
11235
|
console.warn(
|
|
10868
11236
|
"[neat connector] cloudflare: telemetry query returned success:true but no result.events.events array \u2014 the response shape may have changed; treating as zero events this tick"
|
|
10869
11237
|
);
|
|
@@ -10893,7 +11261,7 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
|
10893
11261
|
]);
|
|
10894
11262
|
var LEADING_TOKEN_RE = /^(\S+)\s+\S/;
|
|
10895
11263
|
function parseHttpMethodFromTrigger(trigger) {
|
|
10896
|
-
if (
|
|
11264
|
+
if (typeof trigger !== "string") return null;
|
|
10897
11265
|
const match = LEADING_TOKEN_RE.exec(trigger.trim());
|
|
10898
11266
|
const token = match?.[1];
|
|
10899
11267
|
if (!token) return null;
|
|
@@ -10909,25 +11277,28 @@ function parsePathFromTrigger(trigger) {
|
|
|
10909
11277
|
}
|
|
10910
11278
|
var ERROR_STATUS_THRESHOLD3 = 500;
|
|
10911
11279
|
function mapEventToSignal(event) {
|
|
11280
|
+
if (!event || typeof event !== "object") return null;
|
|
10912
11281
|
const metadata = event.$metadata;
|
|
10913
11282
|
const workers = event.$workers;
|
|
10914
11283
|
const method = parseHttpMethodFromTrigger(metadata?.trigger);
|
|
10915
11284
|
if (!method) return null;
|
|
10916
11285
|
const scriptName = workers?.scriptName ?? metadata?.service;
|
|
10917
|
-
if (
|
|
11286
|
+
if (typeof scriptName !== "string" || scriptName.length === 0) return null;
|
|
10918
11287
|
const timestampMs = event.timestamp ?? metadata?.startTime;
|
|
10919
11288
|
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return null;
|
|
11289
|
+
const observedAt = new Date(timestampMs);
|
|
11290
|
+
if (Number.isNaN(observedAt.getTime())) return null;
|
|
10920
11291
|
const statusCode = metadata?.statusCode;
|
|
10921
11292
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
10922
|
-
const
|
|
11293
|
+
const path54 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
10923
11294
|
return {
|
|
10924
11295
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
10925
11296
|
targetName: scriptName,
|
|
10926
11297
|
callCount: 1,
|
|
10927
11298
|
errorCount: isError ? 1 : 0,
|
|
10928
|
-
lastObservedIso:
|
|
11299
|
+
lastObservedIso: observedAt.toISOString(),
|
|
10929
11300
|
method,
|
|
10930
|
-
...
|
|
11301
|
+
...path54 ? { path: path54 } : {},
|
|
10931
11302
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
10932
11303
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
10933
11304
|
};
|
|
@@ -10967,19 +11338,19 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
10967
11338
|
graph.forEachNode((id, attrs) => {
|
|
10968
11339
|
if (found) return;
|
|
10969
11340
|
const a = attrs;
|
|
10970
|
-
if (a.type ===
|
|
11341
|
+
if (a.type === import_types44.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
10971
11342
|
found = id;
|
|
10972
11343
|
}
|
|
10973
11344
|
});
|
|
10974
11345
|
return found;
|
|
10975
11346
|
}
|
|
10976
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
10977
|
-
const normalizedPath = normalizePathTemplate(
|
|
11347
|
+
function findMatchingRouteNode(graph, serviceName, method, path54) {
|
|
11348
|
+
const normalizedPath = normalizePathTemplate(path54);
|
|
10978
11349
|
let found = null;
|
|
10979
11350
|
graph.forEachNode((id, attrs) => {
|
|
10980
11351
|
if (found) return;
|
|
10981
11352
|
const a = attrs;
|
|
10982
|
-
if (a.type !==
|
|
11353
|
+
if (a.type !== import_types44.NodeType.RouteNode || a.service !== serviceName) return;
|
|
10983
11354
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
10984
11355
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
10985
11356
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -10991,18 +11362,18 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
10991
11362
|
return (signal) => {
|
|
10992
11363
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
10993
11364
|
const scriptName = signal.targetName;
|
|
10994
|
-
const { method, path:
|
|
11365
|
+
const { method, path: path54 } = signal;
|
|
10995
11366
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
10996
|
-
if (!method || !
|
|
10997
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
11367
|
+
if (!method || !path54) return wholeFileId;
|
|
11368
|
+
return findMatchingRouteNode(graph, serviceName, method, path54) ?? wholeFileId;
|
|
10998
11369
|
};
|
|
10999
11370
|
const mapping = config.workers?.[scriptName];
|
|
11000
11371
|
if (mapping) {
|
|
11001
|
-
const wholeFileId = (0,
|
|
11372
|
+
const wholeFileId = (0, import_types44.fileId)(mapping.service, mapping.entryFile);
|
|
11002
11373
|
return {
|
|
11003
11374
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
11004
11375
|
serviceName: mapping.service,
|
|
11005
|
-
edgeType:
|
|
11376
|
+
edgeType: import_types44.EdgeType.CALLS
|
|
11006
11377
|
};
|
|
11007
11378
|
}
|
|
11008
11379
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -11011,18 +11382,124 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
11011
11382
|
return {
|
|
11012
11383
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
11013
11384
|
serviceName: fileNode.service,
|
|
11014
|
-
edgeType:
|
|
11385
|
+
edgeType: import_types44.EdgeType.CALLS
|
|
11015
11386
|
};
|
|
11016
11387
|
}
|
|
11017
11388
|
return {
|
|
11018
|
-
targetNodeId: (0,
|
|
11389
|
+
targetNodeId: (0, import_types44.infraId)("cloudflare-worker", scriptName),
|
|
11019
11390
|
serviceName: scriptName,
|
|
11020
|
-
edgeType:
|
|
11391
|
+
edgeType: import_types44.EdgeType.CALLS,
|
|
11021
11392
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
11022
11393
|
};
|
|
11023
11394
|
};
|
|
11024
11395
|
}
|
|
11025
11396
|
|
|
11397
|
+
// src/connectors/vercel/index.ts
|
|
11398
|
+
init_cjs_shims();
|
|
11399
|
+
|
|
11400
|
+
// src/connectors/vercel/client.ts
|
|
11401
|
+
init_cjs_shims();
|
|
11402
|
+
var DEFAULT_API_BASE_URL = "https://api.vercel.com";
|
|
11403
|
+
var DEFAULT_DRAIN_NAME = "neat-otlp";
|
|
11404
|
+
var TRACE_SCHEMAS = { trace: { version: "v1" } };
|
|
11405
|
+
function apiBase(config) {
|
|
11406
|
+
return config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
|
|
11407
|
+
}
|
|
11408
|
+
function teamQuery(config) {
|
|
11409
|
+
return `?teamId=${encodeURIComponent(config.teamId)}`;
|
|
11410
|
+
}
|
|
11411
|
+
function drainDelivery(config, otelToken) {
|
|
11412
|
+
return {
|
|
11413
|
+
type: "http",
|
|
11414
|
+
endpoint: config.endpoint,
|
|
11415
|
+
encoding: "json",
|
|
11416
|
+
headers: bearerAuthHeader(otelToken),
|
|
11417
|
+
...config.secret ? { secret: config.secret } : {}
|
|
11418
|
+
};
|
|
11419
|
+
}
|
|
11420
|
+
async function describeError(res) {
|
|
11421
|
+
try {
|
|
11422
|
+
const data = await res.json();
|
|
11423
|
+
const message = data?.error?.message;
|
|
11424
|
+
return typeof message === "string" && message.length > 0 ? ` \u2014 ${message}` : "";
|
|
11425
|
+
} catch {
|
|
11426
|
+
return "";
|
|
11427
|
+
}
|
|
11428
|
+
}
|
|
11429
|
+
async function createVercelDrain(config, credentials, fetchImpl = fetch) {
|
|
11430
|
+
const projectIds = config.projectIds ?? [];
|
|
11431
|
+
const body = {
|
|
11432
|
+
name: config.drainName ?? DEFAULT_DRAIN_NAME,
|
|
11433
|
+
projects: projectIds.length > 0 ? "some" : "all",
|
|
11434
|
+
...projectIds.length > 0 ? { projectIds } : {},
|
|
11435
|
+
schemas: TRACE_SCHEMAS,
|
|
11436
|
+
delivery: drainDelivery(config, credentials.otelToken),
|
|
11437
|
+
source: { kind: "self-served" }
|
|
11438
|
+
};
|
|
11439
|
+
const res = await junctionFetch(
|
|
11440
|
+
`${apiBase(config)}/v1/drains${teamQuery(config)}`,
|
|
11441
|
+
{
|
|
11442
|
+
method: "POST",
|
|
11443
|
+
headers: { "Content-Type": "application/json", ...bearerAuthHeader(credentials.token) },
|
|
11444
|
+
body: JSON.stringify(body)
|
|
11445
|
+
},
|
|
11446
|
+
{ provider: "vercel", accountKey: config.teamId, fetchImpl }
|
|
11447
|
+
);
|
|
11448
|
+
if (!res.ok) {
|
|
11449
|
+
throw new Error(
|
|
11450
|
+
`vercel connector: create drain failed (${res.status} ${res.statusText}${await describeError(res)})`
|
|
11451
|
+
);
|
|
11452
|
+
}
|
|
11453
|
+
const payload = await res.json().catch(() => null);
|
|
11454
|
+
if (!payload || typeof payload.id !== "string" || payload.id.length === 0) {
|
|
11455
|
+
throw new Error(
|
|
11456
|
+
"vercel connector: create drain returned no drain id \u2014 the Drains API response shape may have changed"
|
|
11457
|
+
);
|
|
11458
|
+
}
|
|
11459
|
+
return {
|
|
11460
|
+
id: payload.id,
|
|
11461
|
+
...payload.status ? { status: payload.status } : {},
|
|
11462
|
+
...payload.disabledReason ? { disabledReason: payload.disabledReason } : {}
|
|
11463
|
+
};
|
|
11464
|
+
}
|
|
11465
|
+
async function deleteVercelDrain(config, drainId, credentials, fetchImpl = fetch) {
|
|
11466
|
+
const res = await junctionFetch(
|
|
11467
|
+
`${apiBase(config)}/v1/drains/${encodeURIComponent(drainId)}${teamQuery(config)}`,
|
|
11468
|
+
{ method: "DELETE", headers: { ...bearerAuthHeader(credentials.token) } },
|
|
11469
|
+
{ provider: "vercel", accountKey: config.teamId, fetchImpl }
|
|
11470
|
+
);
|
|
11471
|
+
if (res.ok || res.status === 404) return;
|
|
11472
|
+
throw new Error(
|
|
11473
|
+
`vercel connector: delete drain failed (${res.status} ${res.statusText}${await describeError(res)})`
|
|
11474
|
+
);
|
|
11475
|
+
}
|
|
11476
|
+
async function testVercelDrainDelivery(config, credentials, fetchImpl = fetch) {
|
|
11477
|
+
const res = await junctionFetch(
|
|
11478
|
+
`${apiBase(config)}/v1/drains/test${teamQuery(config)}`,
|
|
11479
|
+
{
|
|
11480
|
+
method: "POST",
|
|
11481
|
+
headers: { "Content-Type": "application/json", ...bearerAuthHeader(credentials.token) },
|
|
11482
|
+
body: JSON.stringify({ schemas: TRACE_SCHEMAS, delivery: drainDelivery(config, credentials.otelToken) })
|
|
11483
|
+
},
|
|
11484
|
+
{ provider: "vercel", accountKey: config.teamId, fetchImpl }
|
|
11485
|
+
);
|
|
11486
|
+
if (res.status === 401 || res.status === 403) {
|
|
11487
|
+
return { status: "failure", error: `vercel rejected the API token (HTTP ${res.status})` };
|
|
11488
|
+
}
|
|
11489
|
+
if (!res.ok) {
|
|
11490
|
+
return {
|
|
11491
|
+
status: "failure",
|
|
11492
|
+
error: `vercel drain validation failed (${res.status} ${res.statusText}${await describeError(res)})`
|
|
11493
|
+
};
|
|
11494
|
+
}
|
|
11495
|
+
const payload = await res.json().catch(() => null);
|
|
11496
|
+
return {
|
|
11497
|
+
...payload?.status ? { status: payload.status } : {},
|
|
11498
|
+
...payload?.error ? { error: payload.error } : {},
|
|
11499
|
+
...payload?.endpoint ? { endpoint: payload.endpoint } : {}
|
|
11500
|
+
};
|
|
11501
|
+
}
|
|
11502
|
+
|
|
11026
11503
|
// src/connectors/registry.ts
|
|
11027
11504
|
var CLOUDFLARE_API_BASE_URL = "https://api.cloudflare.com/client/v4";
|
|
11028
11505
|
async function authProbe(input) {
|
|
@@ -11174,6 +11651,91 @@ var PROVIDER_DISPATCH = {
|
|
|
11174
11651
|
}
|
|
11175
11652
|
}
|
|
11176
11653
|
};
|
|
11654
|
+
function vercelCredsFrom(credentials) {
|
|
11655
|
+
return { token: String(credentials.token ?? ""), otelToken: String(credentials.otelToken ?? "") };
|
|
11656
|
+
}
|
|
11657
|
+
function vercelConfigFromOptions(options) {
|
|
11658
|
+
const raw = options.projectIds;
|
|
11659
|
+
let projectIds;
|
|
11660
|
+
if (Array.isArray(raw)) projectIds = raw.filter((p) => typeof p === "string");
|
|
11661
|
+
else if (typeof raw === "string" && raw.trim().length > 0) {
|
|
11662
|
+
projectIds = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
11663
|
+
}
|
|
11664
|
+
return {
|
|
11665
|
+
teamId: String(options.teamId ?? ""),
|
|
11666
|
+
endpoint: String(options.endpoint ?? ""),
|
|
11667
|
+
...projectIds && projectIds.length > 0 ? { projectIds } : {},
|
|
11668
|
+
...typeof options.drainId === "string" ? { drainId: options.drainId } : {},
|
|
11669
|
+
...typeof options.drainName === "string" ? { drainName: options.drainName } : {},
|
|
11670
|
+
...typeof options.apiBaseUrl === "string" ? { apiBaseUrl: options.apiBaseUrl } : {},
|
|
11671
|
+
...typeof options.secret === "string" ? { secret: options.secret } : {}
|
|
11672
|
+
};
|
|
11673
|
+
}
|
|
11674
|
+
var PUSH_PROVIDER_DISPATCH = {
|
|
11675
|
+
vercel: {
|
|
11676
|
+
provider: "vercel",
|
|
11677
|
+
// The Vercel access token is the "primary" secret a single `--token`
|
|
11678
|
+
// populates; `otelToken` (the daemon's OTLP bearer) is the second field.
|
|
11679
|
+
primaryCredentialKey: "token",
|
|
11680
|
+
requiredCredentialFields: ["token", "otelToken"],
|
|
11681
|
+
// teamId scopes every Drains call; endpoint is where the drain delivers.
|
|
11682
|
+
// projectIds is optional (absent → the drain covers the whole team).
|
|
11683
|
+
requiredOptionFields: ["teamId", "endpoint"],
|
|
11684
|
+
// POST /v1/drains/test — authenticates the token and pings the endpoint
|
|
11685
|
+
// with a sample event, so `success` means the credential is live *and* the
|
|
11686
|
+
// daemon's OTLP endpoint is reachable and accepted the drain's bearer.
|
|
11687
|
+
async validate({ credentials, options, fetchImpl }) {
|
|
11688
|
+
const result = await testVercelDrainDelivery(
|
|
11689
|
+
vercelConfigFromOptions(options),
|
|
11690
|
+
vercelCredsFrom(credentials),
|
|
11691
|
+
fetchImpl
|
|
11692
|
+
);
|
|
11693
|
+
if (result.status === "success") return { ok: true };
|
|
11694
|
+
return {
|
|
11695
|
+
ok: false,
|
|
11696
|
+
reason: result.error ?? `vercel drain delivery test returned "${result.status ?? "no status"}"`
|
|
11697
|
+
};
|
|
11698
|
+
},
|
|
11699
|
+
// POST /v1/drains — creates the trace drain, returns its id to store in
|
|
11700
|
+
// `options.drainId`. A created-but-not-enabled drain is surfaced as a note,
|
|
11701
|
+
// not a failure (the entry still points at a real drain).
|
|
11702
|
+
async provision({ credentials, options, fetchImpl }) {
|
|
11703
|
+
try {
|
|
11704
|
+
const created = await createVercelDrain(
|
|
11705
|
+
vercelConfigFromOptions(options),
|
|
11706
|
+
vercelCredsFrom(credentials),
|
|
11707
|
+
fetchImpl
|
|
11708
|
+
);
|
|
11709
|
+
const note = created.status && created.status !== "enabled" ? `the drain was created but its status is "${created.status}"${created.disabledReason ? ` (${created.disabledReason})` : ""} \u2014 check the Vercel dashboard` : void 0;
|
|
11710
|
+
return { ok: true, options: { drainId: created.id }, ...note ? { note } : {} };
|
|
11711
|
+
} catch (err) {
|
|
11712
|
+
return { ok: false, reason: err.message };
|
|
11713
|
+
}
|
|
11714
|
+
},
|
|
11715
|
+
// DELETE /v1/drains/{id} — idempotent (deleteVercelDrain treats 404 as
|
|
11716
|
+
// success). No recorded drainId → nothing to delete, still a success.
|
|
11717
|
+
async deprovision({ credentials, options, fetchImpl }) {
|
|
11718
|
+
const drainId = typeof options.drainId === "string" ? options.drainId : "";
|
|
11719
|
+
if (!drainId) {
|
|
11720
|
+
return { ok: true, note: "no drain id was recorded \u2014 nothing to delete on the Vercel side" };
|
|
11721
|
+
}
|
|
11722
|
+
try {
|
|
11723
|
+
await deleteVercelDrain(
|
|
11724
|
+
vercelConfigFromOptions(options),
|
|
11725
|
+
drainId,
|
|
11726
|
+
vercelCredsFrom(credentials),
|
|
11727
|
+
fetchImpl
|
|
11728
|
+
);
|
|
11729
|
+
return { ok: true };
|
|
11730
|
+
} catch (err) {
|
|
11731
|
+
return { ok: false, reason: err.message };
|
|
11732
|
+
}
|
|
11733
|
+
}
|
|
11734
|
+
}
|
|
11735
|
+
};
|
|
11736
|
+
function isPushProvider(provider) {
|
|
11737
|
+
return provider in PUSH_PROVIDER_DISPATCH;
|
|
11738
|
+
}
|
|
11177
11739
|
function resolveEntryCredentials(dispatch, entry2, env) {
|
|
11178
11740
|
let credentials;
|
|
11179
11741
|
try {
|
|
@@ -11196,6 +11758,13 @@ function resolveEntryCredentials(dispatch, entry2, env) {
|
|
|
11196
11758
|
function buildRegistration(entry2, graph, env = process.env) {
|
|
11197
11759
|
const dispatch = PROVIDER_DISPATCH[entry2.provider];
|
|
11198
11760
|
if (!dispatch) {
|
|
11761
|
+
if (isPushProvider(entry2.provider)) {
|
|
11762
|
+
return {
|
|
11763
|
+
ok: false,
|
|
11764
|
+
push: true,
|
|
11765
|
+
reason: `push provider "${entry2.provider}" ingests via the OTLP receiver \u2014 nothing to poll`
|
|
11766
|
+
};
|
|
11767
|
+
}
|
|
11199
11768
|
return { ok: false, reason: `unknown provider "${entry2.provider}"` };
|
|
11200
11769
|
}
|
|
11201
11770
|
const creds = resolveEntryCredentials(dispatch, entry2, env);
|
|
@@ -11246,7 +11815,7 @@ async function loadConnectorRegistrations(input) {
|
|
|
11246
11815
|
if (!connectorMatchesProject(entry2, project)) continue;
|
|
11247
11816
|
const result = buildRegistration(entry2, graph, env);
|
|
11248
11817
|
if (result.ok) registrations.push(result.registration);
|
|
11249
|
-
else onSkip?.(entry2, result.reason);
|
|
11818
|
+
else if (!result.push) onSkip?.(entry2, result.reason);
|
|
11250
11819
|
}
|
|
11251
11820
|
return registrations;
|
|
11252
11821
|
}
|
|
@@ -11257,7 +11826,7 @@ init_auth();
|
|
|
11257
11826
|
// src/unrouted.ts
|
|
11258
11827
|
init_cjs_shims();
|
|
11259
11828
|
var import_node_fs30 = require("fs");
|
|
11260
|
-
var
|
|
11829
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
11261
11830
|
function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new Date()) {
|
|
11262
11831
|
return {
|
|
11263
11832
|
timestamp: now.toISOString(),
|
|
@@ -11267,34 +11836,34 @@ function buildUnroutedSpanRecord(serviceName, traceId, now = /* @__PURE__ */ new
|
|
|
11267
11836
|
};
|
|
11268
11837
|
}
|
|
11269
11838
|
async function appendUnroutedSpan(neatHome4, record) {
|
|
11270
|
-
const target =
|
|
11839
|
+
const target = import_node_path50.default.join(neatHome4, "errors.ndjson");
|
|
11271
11840
|
await import_node_fs30.promises.mkdir(neatHome4, { recursive: true });
|
|
11272
11841
|
await import_node_fs30.promises.appendFile(target, JSON.stringify(record) + "\n", "utf8");
|
|
11273
11842
|
}
|
|
11274
11843
|
function unroutedErrorsPath(neatHome4) {
|
|
11275
|
-
return
|
|
11844
|
+
return import_node_path50.default.join(neatHome4, "errors.ndjson");
|
|
11276
11845
|
}
|
|
11277
11846
|
|
|
11278
11847
|
// src/daemon.ts
|
|
11279
|
-
var
|
|
11848
|
+
var import_types47 = require("@neat.is/types");
|
|
11280
11849
|
function daemonJsonPath(scanPath) {
|
|
11281
|
-
return
|
|
11850
|
+
return import_node_path51.default.join(scanPath, "neat-out", "daemon.json");
|
|
11282
11851
|
}
|
|
11283
11852
|
function daemonsDiscoveryDir(home) {
|
|
11284
11853
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
11285
|
-
return
|
|
11854
|
+
return import_node_path51.default.join(base, "daemons");
|
|
11286
11855
|
}
|
|
11287
11856
|
function daemonDiscoveryPath(project, home) {
|
|
11288
|
-
return
|
|
11857
|
+
return import_node_path51.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
11289
11858
|
}
|
|
11290
11859
|
function sanitizeDiscoveryName(project) {
|
|
11291
11860
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
11292
11861
|
}
|
|
11293
11862
|
function neatHomeFromEnv() {
|
|
11294
11863
|
const env = process.env.NEAT_HOME;
|
|
11295
|
-
if (env && env.length > 0) return
|
|
11864
|
+
if (env && env.length > 0) return import_node_path51.default.resolve(env);
|
|
11296
11865
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
11297
|
-
return
|
|
11866
|
+
return import_node_path51.default.join(home, ".neat");
|
|
11298
11867
|
}
|
|
11299
11868
|
function resolveNeatVersion() {
|
|
11300
11869
|
if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {
|
|
@@ -11363,11 +11932,11 @@ function teardownSlot(slot) {
|
|
|
11363
11932
|
}
|
|
11364
11933
|
}
|
|
11365
11934
|
function neatHomeFor(opts) {
|
|
11366
|
-
if (opts.neatHome && opts.neatHome.length > 0) return
|
|
11935
|
+
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path51.default.resolve(opts.neatHome);
|
|
11367
11936
|
const env = process.env.NEAT_HOME;
|
|
11368
|
-
if (env && env.length > 0) return
|
|
11937
|
+
if (env && env.length > 0) return import_node_path51.default.resolve(env);
|
|
11369
11938
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
11370
|
-
return
|
|
11939
|
+
return import_node_path51.default.join(home, ".neat");
|
|
11371
11940
|
}
|
|
11372
11941
|
function routeSpanToProject(serviceName, projects) {
|
|
11373
11942
|
if (!serviceName) return DEFAULT_PROJECT;
|
|
@@ -11411,11 +11980,11 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
11411
11980
|
if (!serviceName) return true;
|
|
11412
11981
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
11413
11982
|
return graph.someNode(
|
|
11414
|
-
(_id, attrs) => attrs.type ===
|
|
11983
|
+
(_id, attrs) => attrs.type === import_types47.NodeType.ServiceNode && attrs.name === serviceName
|
|
11415
11984
|
);
|
|
11416
11985
|
}
|
|
11417
11986
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
11418
|
-
const paths = pathsForProject(entry2.name,
|
|
11987
|
+
const paths = pathsForProject(entry2.name, import_node_path51.default.join(entry2.path, "neat-out"));
|
|
11419
11988
|
try {
|
|
11420
11989
|
const stat = await import_node_fs31.promises.stat(entry2.path);
|
|
11421
11990
|
if (!stat.isDirectory()) {
|
|
@@ -11546,7 +12115,7 @@ async function startDaemon(opts = {}) {
|
|
|
11546
12115
|
const projectArg = typeof opts.project === "string" && opts.project.length > 0 ? opts.project : process.env.NEAT_PROJECT && process.env.NEAT_PROJECT.length > 0 ? process.env.NEAT_PROJECT : null;
|
|
11547
12116
|
const projectPathArg = opts.projectPath && opts.projectPath.length > 0 ? opts.projectPath : process.env.NEAT_PROJECT_PATH && process.env.NEAT_PROJECT_PATH.length > 0 ? process.env.NEAT_PROJECT_PATH : null;
|
|
11548
12117
|
const singleProject = projectArg;
|
|
11549
|
-
const singleProjectPath = singleProject && projectPathArg ?
|
|
12118
|
+
const singleProjectPath = singleProject && projectPathArg ? import_node_path51.default.resolve(projectPathArg) : null;
|
|
11550
12119
|
if (singleProject && !singleProjectPath) {
|
|
11551
12120
|
throw new Error(
|
|
11552
12121
|
`neatd: project "${singleProject}" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`
|
|
@@ -11561,7 +12130,7 @@ async function startDaemon(opts = {}) {
|
|
|
11561
12130
|
);
|
|
11562
12131
|
}
|
|
11563
12132
|
}
|
|
11564
|
-
const pidPath =
|
|
12133
|
+
const pidPath = import_node_path51.default.join(home, "neatd.pid");
|
|
11565
12134
|
await writeAtomically(pidPath, `${process.pid}
|
|
11566
12135
|
`);
|
|
11567
12136
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -11968,8 +12537,8 @@ async function startDaemon(opts = {}) {
|
|
|
11968
12537
|
let registryWatcher = null;
|
|
11969
12538
|
let reloadTimer = null;
|
|
11970
12539
|
if (!singleProject) try {
|
|
11971
|
-
const regDir =
|
|
11972
|
-
const regBase =
|
|
12540
|
+
const regDir = import_node_path51.default.dirname(regPath);
|
|
12541
|
+
const regBase = import_node_path51.default.basename(regPath);
|
|
11973
12542
|
registryWatcher = (0, import_node_fs31.watch)(regDir, (_eventType, filename) => {
|
|
11974
12543
|
if (filename !== null && filename !== regBase) return;
|
|
11975
12544
|
if (reloadTimer) clearTimeout(reloadTimer);
|
|
@@ -12044,7 +12613,7 @@ init_cjs_shims();
|
|
|
12044
12613
|
var import_node_child_process2 = require("child_process");
|
|
12045
12614
|
var import_node_fs32 = require("fs");
|
|
12046
12615
|
var import_node_net = __toESM(require("net"), 1);
|
|
12047
|
-
var
|
|
12616
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
12048
12617
|
var DEFAULT_WEB_PORT = 6328;
|
|
12049
12618
|
var DEFAULT_REST_PORT = 8080;
|
|
12050
12619
|
function asValidPort(value) {
|
|
@@ -12053,11 +12622,11 @@ function asValidPort(value) {
|
|
|
12053
12622
|
}
|
|
12054
12623
|
function projectRoot() {
|
|
12055
12624
|
const fromEnv = process.env.NEAT_SCAN_PATH;
|
|
12056
|
-
return
|
|
12625
|
+
return import_node_path52.default.resolve(fromEnv && fromEnv.length > 0 ? fromEnv : process.cwd());
|
|
12057
12626
|
}
|
|
12058
12627
|
async function readDaemonPorts(root) {
|
|
12059
12628
|
try {
|
|
12060
|
-
const raw = await import_node_fs32.promises.readFile(
|
|
12629
|
+
const raw = await import_node_fs32.promises.readFile(import_node_path52.default.join(root, "neat-out", "daemon.json"), "utf8");
|
|
12061
12630
|
const parsed = JSON.parse(raw);
|
|
12062
12631
|
const ports = parsed?.ports ?? {};
|
|
12063
12632
|
return { web: asValidPort(ports.web), rest: asValidPort(ports.rest) };
|
|
@@ -12102,10 +12671,10 @@ function resolveWebPackageDir() {
|
|
|
12102
12671
|
eval("require")
|
|
12103
12672
|
);
|
|
12104
12673
|
const pkgJsonPath = req.resolve("@neat.is/web/package.json");
|
|
12105
|
-
return
|
|
12674
|
+
return import_node_path52.default.dirname(pkgJsonPath);
|
|
12106
12675
|
}
|
|
12107
12676
|
function resolveStandaloneServerEntry(webDir) {
|
|
12108
|
-
return
|
|
12677
|
+
return import_node_path52.default.join(webDir, ".next/standalone/packages/web/server.js");
|
|
12109
12678
|
}
|
|
12110
12679
|
async function pickInternalPort() {
|
|
12111
12680
|
return new Promise((resolve, reject) => {
|
|
@@ -12158,7 +12727,7 @@ async function spawnWebUI(restPort, opts = {}) {
|
|
|
12158
12727
|
NEAT_API_URL: apiUrl
|
|
12159
12728
|
};
|
|
12160
12729
|
child = (0, import_node_child_process2.spawn)(process.execPath, [serverEntry], {
|
|
12161
|
-
cwd:
|
|
12730
|
+
cwd: import_node_path52.default.dirname(serverEntry),
|
|
12162
12731
|
env,
|
|
12163
12732
|
stdio: ["ignore", "inherit", "inherit"],
|
|
12164
12733
|
detached: false
|
|
@@ -12334,14 +12903,14 @@ function localVersion() {
|
|
|
12334
12903
|
}
|
|
12335
12904
|
function neatHome3() {
|
|
12336
12905
|
if (process.env.NEAT_HOME && process.env.NEAT_HOME.length > 0) {
|
|
12337
|
-
return
|
|
12906
|
+
return import_node_path53.default.resolve(process.env.NEAT_HOME);
|
|
12338
12907
|
}
|
|
12339
12908
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
12340
|
-
return
|
|
12909
|
+
return import_node_path53.default.join(home, ".neat");
|
|
12341
12910
|
}
|
|
12342
12911
|
async function readPid() {
|
|
12343
12912
|
try {
|
|
12344
|
-
const raw = await import_node_fs33.promises.readFile(
|
|
12913
|
+
const raw = await import_node_fs33.promises.readFile(import_node_path53.default.join(neatHome3(), "neatd.pid"), "utf8");
|
|
12345
12914
|
const n = Number.parseInt(raw.trim(), 10);
|
|
12346
12915
|
return Number.isFinite(n) ? n : null;
|
|
12347
12916
|
} catch {
|