@neat.is/core 0.4.28-dev.20260708 → 0.4.28-dev.20260709
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-O4MRDWD7.js → chunk-5T6J3WKC.js} +369 -121
- package/dist/chunk-5T6J3WKC.js.map +1 -0
- package/dist/{chunk-NY5Q6NE2.js → chunk-UJ6WBLIE.js} +88 -15
- package/dist/chunk-UJ6WBLIE.js.map +1 -0
- package/dist/cli.cjs +712 -409
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +536 -216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +549 -229
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +323 -88
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-NY5Q6NE2.js.map +0 -1
- package/dist/chunk-O4MRDWD7.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -61,8 +61,8 @@ function mountBearerAuth(app, opts) {
|
|
|
61
61
|
]);
|
|
62
62
|
const publicRead = opts.publicRead === true;
|
|
63
63
|
app.addHook("preHandler", (req, reply, done) => {
|
|
64
|
-
const
|
|
65
|
-
if (exactUnauthPaths.has(
|
|
64
|
+
const path58 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
65
|
+
if (exactUnauthPaths.has(path58) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path58)) {
|
|
66
66
|
done();
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
@@ -194,8 +194,8 @@ function reshapeGrpcRequest(req) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
function resolveProtoRoot() {
|
|
197
|
-
const here =
|
|
198
|
-
return
|
|
197
|
+
const here = import_node_path45.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
198
|
+
return import_node_path45.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_url2,
|
|
266
|
+
var import_node_url2, import_node_path45, 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_url2 = require("url");
|
|
272
|
-
|
|
272
|
+
import_node_path45 = __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 path58 = q === -1 ? v : v.slice(0, q);
|
|
366
|
+
if (path58.length > 0) return path58;
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
return void 0;
|
|
@@ -417,10 +417,10 @@ function parseOtlpRequest(body) {
|
|
|
417
417
|
return out;
|
|
418
418
|
}
|
|
419
419
|
function loadProtoRoot() {
|
|
420
|
-
const here =
|
|
421
|
-
const protoRoot =
|
|
420
|
+
const here = import_node_path46.default.dirname((0, import_node_url3.fileURLToPath)(importMetaUrl));
|
|
421
|
+
const protoRoot = import_node_path46.default.resolve(here, "..", "proto");
|
|
422
422
|
const root = new import_protobufjs.default.Root();
|
|
423
|
-
root.resolvePath = (_origin, target) =>
|
|
423
|
+
root.resolvePath = (_origin, target) => import_node_path46.default.resolve(protoRoot, target);
|
|
424
424
|
root.loadSync(
|
|
425
425
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
426
426
|
{ keepCase: true }
|
|
@@ -648,12 +648,12 @@ async function listenSteppingOtlp(app, requestedPort, host) {
|
|
|
648
648
|
}
|
|
649
649
|
}
|
|
650
650
|
}
|
|
651
|
-
var
|
|
651
|
+
var import_node_path46, import_node_url3, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody, OTLP_STEP_ATTEMPTS, OTLP_STEP_STRIDE;
|
|
652
652
|
var init_otel = __esm({
|
|
653
653
|
"src/otel.ts"() {
|
|
654
654
|
"use strict";
|
|
655
655
|
init_cjs_shims();
|
|
656
|
-
|
|
656
|
+
import_node_path46 = __toESM(require("path"), 1);
|
|
657
657
|
import_node_url3 = require("url");
|
|
658
658
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
659
659
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -690,8 +690,8 @@ __export(cli_exports, {
|
|
|
690
690
|
});
|
|
691
691
|
module.exports = __toCommonJS(cli_exports);
|
|
692
692
|
init_cjs_shims();
|
|
693
|
-
var
|
|
694
|
-
var
|
|
693
|
+
var import_node_path57 = __toESM(require("path"), 1);
|
|
694
|
+
var import_node_fs37 = require("fs");
|
|
695
695
|
|
|
696
696
|
// src/banner.ts
|
|
697
697
|
init_cjs_shims();
|
|
@@ -1256,19 +1256,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1256
1256
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1257
1257
|
let best = { path: [start], edges: [] };
|
|
1258
1258
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1259
|
-
function step(node,
|
|
1260
|
-
if (
|
|
1261
|
-
best = { path: [...
|
|
1259
|
+
function step(node, path58, edges) {
|
|
1260
|
+
if (path58.length > best.path.length) {
|
|
1261
|
+
best = { path: [...path58], edges: [...edges] };
|
|
1262
1262
|
}
|
|
1263
|
-
if (
|
|
1263
|
+
if (path58.length - 1 >= maxDepth) return;
|
|
1264
1264
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1265
1265
|
for (const [srcId, edge] of incoming) {
|
|
1266
1266
|
if (visited.has(srcId)) continue;
|
|
1267
1267
|
visited.add(srcId);
|
|
1268
|
-
|
|
1268
|
+
path58.push(srcId);
|
|
1269
1269
|
edges.push(edge);
|
|
1270
|
-
step(srcId,
|
|
1271
|
-
|
|
1270
|
+
step(srcId, path58, edges);
|
|
1271
|
+
path58.pop();
|
|
1272
1272
|
edges.pop();
|
|
1273
1273
|
visited.delete(srcId);
|
|
1274
1274
|
}
|
|
@@ -1462,26 +1462,26 @@ function dominantFailingCall(graph, serviceId5, visited) {
|
|
|
1462
1462
|
return best;
|
|
1463
1463
|
}
|
|
1464
1464
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1465
|
-
const
|
|
1465
|
+
const path58 = [originServiceId];
|
|
1466
1466
|
const edges = [];
|
|
1467
1467
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1468
1468
|
let current = originServiceId;
|
|
1469
1469
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1470
1470
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1471
1471
|
if (!hop) break;
|
|
1472
|
-
|
|
1472
|
+
path58.push(hop.nextService);
|
|
1473
1473
|
edges.push(hop.edge);
|
|
1474
1474
|
visited.add(hop.nextService);
|
|
1475
1475
|
current = hop.nextService;
|
|
1476
1476
|
}
|
|
1477
1477
|
if (edges.length === 0) return null;
|
|
1478
|
-
return { path:
|
|
1478
|
+
return { path: path58, edges, culprit: current };
|
|
1479
1479
|
}
|
|
1480
1480
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1481
1481
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1482
1482
|
if (!chain) return null;
|
|
1483
1483
|
const culprit = chain.culprit;
|
|
1484
|
-
const
|
|
1484
|
+
const path58 = [...chain.path];
|
|
1485
1485
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1486
1486
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1487
1487
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1489,14 +1489,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1489
1489
|
if (loc) {
|
|
1490
1490
|
let rootCauseNode = culprit;
|
|
1491
1491
|
if (loc.fileNode) {
|
|
1492
|
-
|
|
1492
|
+
path58.push(loc.fileNode);
|
|
1493
1493
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1494
1494
|
rootCauseNode = loc.fileNode;
|
|
1495
1495
|
}
|
|
1496
1496
|
return import_types.RootCauseResultSchema.parse({
|
|
1497
1497
|
rootCauseNode,
|
|
1498
1498
|
rootCauseReason: loc.rootCauseReason,
|
|
1499
|
-
traversalPath:
|
|
1499
|
+
traversalPath: path58,
|
|
1500
1500
|
edgeProvenances,
|
|
1501
1501
|
confidence,
|
|
1502
1502
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1508,7 +1508,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1508
1508
|
return import_types.RootCauseResultSchema.parse({
|
|
1509
1509
|
rootCauseNode: culprit,
|
|
1510
1510
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1511
|
-
traversalPath:
|
|
1511
|
+
traversalPath: path58,
|
|
1512
1512
|
edgeProvenances,
|
|
1513
1513
|
confidence,
|
|
1514
1514
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -5355,10 +5355,10 @@ function fastifyRouteMethods(objNode) {
|
|
|
5355
5355
|
}
|
|
5356
5356
|
return [];
|
|
5357
5357
|
}
|
|
5358
|
-
function serverRoutesFromSource(source, parser, hasExpress, hasFastify) {
|
|
5358
|
+
function serverRoutesFromSource(source, parser, hasExpress, hasFastify, hasHono = false) {
|
|
5359
5359
|
const tree = parseSource2(parser, source);
|
|
5360
5360
|
const out = [];
|
|
5361
|
-
const framework = hasExpress ? "express" : "fastify";
|
|
5361
|
+
const framework = hasExpress ? "express" : hasFastify ? "fastify" : hasHono ? "hono" : "unknown";
|
|
5362
5362
|
walk(tree.rootNode, (node) => {
|
|
5363
5363
|
if (node.type !== "call_expression") return;
|
|
5364
5364
|
const fn = node.childForFieldName("function");
|
|
@@ -5508,8 +5508,9 @@ async function addRoutes(graph, services) {
|
|
|
5508
5508
|
};
|
|
5509
5509
|
const hasExpress = deps["express"] !== void 0;
|
|
5510
5510
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5511
|
+
const hasHono = deps["hono"] !== void 0;
|
|
5511
5512
|
const hasNext = deps["next"] !== void 0;
|
|
5512
|
-
if (!hasExpress && !hasFastify && !hasNext) continue;
|
|
5513
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext) continue;
|
|
5513
5514
|
const files = await loadSourceFiles(service.dir);
|
|
5514
5515
|
for (const file of files) {
|
|
5515
5516
|
if (isTestPath(file.path)) continue;
|
|
@@ -5519,8 +5520,8 @@ async function addRoutes(graph, services) {
|
|
|
5519
5520
|
try {
|
|
5520
5521
|
if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5521
5522
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5522
|
-
} else if (hasExpress || hasFastify) {
|
|
5523
|
-
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify);
|
|
5523
|
+
} else if (hasExpress || hasFastify || hasHono) {
|
|
5524
|
+
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
5524
5525
|
} else {
|
|
5525
5526
|
routes = [];
|
|
5526
5527
|
}
|
|
@@ -6844,30 +6845,264 @@ async function addK8sResources(graph, scanPath) {
|
|
|
6844
6845
|
return { nodesAdded, edgesAdded: 0 };
|
|
6845
6846
|
}
|
|
6846
6847
|
|
|
6848
|
+
// src/extract/infra/cloudflare.ts
|
|
6849
|
+
init_cjs_shims();
|
|
6850
|
+
var import_node_fs20 = require("fs");
|
|
6851
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
6852
|
+
var import_smol_toml2 = require("smol-toml");
|
|
6853
|
+
var import_types25 = require("@neat.is/types");
|
|
6854
|
+
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
6855
|
+
async function readWranglerConfig(dir) {
|
|
6856
|
+
for (const filename of WRANGLER_FILENAMES) {
|
|
6857
|
+
const abs = import_node_path36.default.join(dir, filename);
|
|
6858
|
+
if (!await exists(abs)) continue;
|
|
6859
|
+
const raw = await import_node_fs20.promises.readFile(abs, "utf8");
|
|
6860
|
+
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
6861
|
+
return { config, relFile: filename, raw };
|
|
6862
|
+
}
|
|
6863
|
+
return null;
|
|
6864
|
+
}
|
|
6865
|
+
function lineContaining(raw, needle) {
|
|
6866
|
+
if (!needle) return void 0;
|
|
6867
|
+
const idx = raw.indexOf(needle);
|
|
6868
|
+
if (idx === -1) return void 0;
|
|
6869
|
+
let line = 1;
|
|
6870
|
+
for (let i = 0; i < idx; i++) if (raw[i] === "\n") line++;
|
|
6871
|
+
return line;
|
|
6872
|
+
}
|
|
6873
|
+
function normalizeRoutes(config) {
|
|
6874
|
+
const out = [];
|
|
6875
|
+
const pushOne = (r) => {
|
|
6876
|
+
if (typeof r === "string") out.push(r);
|
|
6877
|
+
else if (r && typeof r === "object" && typeof r.pattern === "string") {
|
|
6878
|
+
out.push(r.pattern);
|
|
6879
|
+
}
|
|
6880
|
+
};
|
|
6881
|
+
if (Array.isArray(config.routes)) config.routes.forEach(pushOne);
|
|
6882
|
+
else if (config.route) pushOne(config.route);
|
|
6883
|
+
return out;
|
|
6884
|
+
}
|
|
6885
|
+
function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, line) {
|
|
6886
|
+
let nodesAdded = 0;
|
|
6887
|
+
let edgesAdded = 0;
|
|
6888
|
+
const node = makeInfraNode(kind, name, "cloudflare");
|
|
6889
|
+
if (!graph.hasNode(node.id)) {
|
|
6890
|
+
graph.addNode(node.id, node);
|
|
6891
|
+
nodesAdded++;
|
|
6892
|
+
}
|
|
6893
|
+
if (node.id === anchorId) return { nodesAdded, edgesAdded };
|
|
6894
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, node.id, edgeType);
|
|
6895
|
+
if (!graph.hasEdge(edgeId)) {
|
|
6896
|
+
const edge = {
|
|
6897
|
+
id: edgeId,
|
|
6898
|
+
source: anchorId,
|
|
6899
|
+
target: node.id,
|
|
6900
|
+
type: edgeType,
|
|
6901
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
6902
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6903
|
+
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
6904
|
+
};
|
|
6905
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
6906
|
+
edgesAdded++;
|
|
6907
|
+
}
|
|
6908
|
+
return { nodesAdded, edgesAdded };
|
|
6909
|
+
}
|
|
6910
|
+
async function addCloudflareWorkers(graph, services, scanPath) {
|
|
6911
|
+
let nodesAdded = 0;
|
|
6912
|
+
let edgesAdded = 0;
|
|
6913
|
+
const discovered = [];
|
|
6914
|
+
const workerIndex = /* @__PURE__ */ new Map();
|
|
6915
|
+
for (const service of services) {
|
|
6916
|
+
let read;
|
|
6917
|
+
try {
|
|
6918
|
+
read = await readWranglerConfig(service.dir);
|
|
6919
|
+
} catch (err) {
|
|
6920
|
+
recordExtractionError("infra cloudflare", import_node_path36.default.relative(scanPath, service.dir), err);
|
|
6921
|
+
continue;
|
|
6922
|
+
}
|
|
6923
|
+
if (!read || !read.config.name) continue;
|
|
6924
|
+
const evidenceFile = toPosix2(import_node_path36.default.relative(scanPath, import_node_path36.default.join(service.dir, read.relFile)));
|
|
6925
|
+
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
6926
|
+
}
|
|
6927
|
+
for (const worker of discovered) {
|
|
6928
|
+
const { service, config } = worker;
|
|
6929
|
+
const serviceNode = graph.getNodeAttributes(service.node.id);
|
|
6930
|
+
if (serviceNode.platform !== "cloudflare") {
|
|
6931
|
+
const updated = { ...serviceNode, platform: "cloudflare" };
|
|
6932
|
+
graph.replaceNodeAttributes(service.node.id, updated);
|
|
6933
|
+
}
|
|
6934
|
+
let anchorId = service.node.id;
|
|
6935
|
+
if (config.main) {
|
|
6936
|
+
const entryRelPath = toPosix2(import_node_path36.default.normalize(config.main));
|
|
6937
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
6938
|
+
graph,
|
|
6939
|
+
service.pkg.name,
|
|
6940
|
+
service.node.id,
|
|
6941
|
+
entryRelPath
|
|
6942
|
+
);
|
|
6943
|
+
nodesAdded += fn;
|
|
6944
|
+
edgesAdded += fe;
|
|
6945
|
+
const fileNode = graph.getNodeAttributes(fileNodeId);
|
|
6946
|
+
if (fileNode.platform !== "cloudflare" || fileNode.platformName !== config.name) {
|
|
6947
|
+
const updated = { ...fileNode, platform: "cloudflare", platformName: config.name };
|
|
6948
|
+
graph.replaceNodeAttributes(fileNodeId, updated);
|
|
6949
|
+
}
|
|
6950
|
+
anchorId = fileNodeId;
|
|
6951
|
+
}
|
|
6952
|
+
workerIndex.set(config.name, { anchorId });
|
|
6953
|
+
}
|
|
6954
|
+
for (const worker of discovered) {
|
|
6955
|
+
const { config, evidenceFile, raw } = worker;
|
|
6956
|
+
const anchorId = workerIndex.get(config.name).anchorId;
|
|
6957
|
+
const runtimeNode = makeInfraNode("workerd", "cloudflare", "cloudflare");
|
|
6958
|
+
if (!graph.hasNode(runtimeNode.id)) {
|
|
6959
|
+
graph.addNode(runtimeNode.id, runtimeNode);
|
|
6960
|
+
nodesAdded++;
|
|
6961
|
+
}
|
|
6962
|
+
if (runtimeNode.id !== anchorId) {
|
|
6963
|
+
const runsOnId = (0, import_types4.extractedEdgeId)(anchorId, runtimeNode.id, import_types25.EdgeType.RUNS_ON);
|
|
6964
|
+
if (!graph.hasEdge(runsOnId)) {
|
|
6965
|
+
const edge = {
|
|
6966
|
+
id: runsOnId,
|
|
6967
|
+
source: anchorId,
|
|
6968
|
+
target: runtimeNode.id,
|
|
6969
|
+
type: import_types25.EdgeType.RUNS_ON,
|
|
6970
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
6971
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
6972
|
+
evidence: {
|
|
6973
|
+
file: evidenceFile,
|
|
6974
|
+
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
6975
|
+
}
|
|
6976
|
+
};
|
|
6977
|
+
graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge);
|
|
6978
|
+
edgesAdded++;
|
|
6979
|
+
}
|
|
6980
|
+
}
|
|
6981
|
+
for (const route of normalizeRoutes(config)) {
|
|
6982
|
+
const result = addResourceEdge(
|
|
6983
|
+
graph,
|
|
6984
|
+
anchorId,
|
|
6985
|
+
import_types25.EdgeType.CONNECTS_TO,
|
|
6986
|
+
"cloudflare-route",
|
|
6987
|
+
route,
|
|
6988
|
+
evidenceFile,
|
|
6989
|
+
lineContaining(raw, route)
|
|
6990
|
+
);
|
|
6991
|
+
nodesAdded += result.nodesAdded;
|
|
6992
|
+
edgesAdded += result.edgesAdded;
|
|
6993
|
+
}
|
|
6994
|
+
const bindingGroups = [
|
|
6995
|
+
{ kind: "cloudflare-kv", entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },
|
|
6996
|
+
{ kind: "cloudflare-d1", entries: config.d1_databases ?? [], nameOf: (b) => b.binding },
|
|
6997
|
+
{ kind: "cloudflare-r2", entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },
|
|
6998
|
+
{ kind: "cloudflare-durable-object", entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },
|
|
6999
|
+
{ kind: "cloudflare-queue", entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },
|
|
7000
|
+
{ kind: "cloudflare-queue", entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue }
|
|
7001
|
+
];
|
|
7002
|
+
for (const group of bindingGroups) {
|
|
7003
|
+
for (const entry2 of group.entries) {
|
|
7004
|
+
const name = group.nameOf(entry2);
|
|
7005
|
+
if (!name) continue;
|
|
7006
|
+
const result = addResourceEdge(
|
|
7007
|
+
graph,
|
|
7008
|
+
anchorId,
|
|
7009
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7010
|
+
group.kind,
|
|
7011
|
+
name,
|
|
7012
|
+
evidenceFile,
|
|
7013
|
+
lineContaining(raw, name)
|
|
7014
|
+
);
|
|
7015
|
+
nodesAdded += result.nodesAdded;
|
|
7016
|
+
edgesAdded += result.edgesAdded;
|
|
7017
|
+
}
|
|
7018
|
+
}
|
|
7019
|
+
for (const cron of config.triggers?.crons ?? []) {
|
|
7020
|
+
const result = addResourceEdge(
|
|
7021
|
+
graph,
|
|
7022
|
+
anchorId,
|
|
7023
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7024
|
+
"cloudflare-cron",
|
|
7025
|
+
cron,
|
|
7026
|
+
evidenceFile,
|
|
7027
|
+
lineContaining(raw, cron)
|
|
7028
|
+
);
|
|
7029
|
+
nodesAdded += result.nodesAdded;
|
|
7030
|
+
edgesAdded += result.edgesAdded;
|
|
7031
|
+
}
|
|
7032
|
+
for (const varName of Object.keys(config.vars ?? {})) {
|
|
7033
|
+
const result = addResourceEdge(
|
|
7034
|
+
graph,
|
|
7035
|
+
anchorId,
|
|
7036
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7037
|
+
"cloudflare-env-var",
|
|
7038
|
+
varName,
|
|
7039
|
+
evidenceFile,
|
|
7040
|
+
lineContaining(raw, varName)
|
|
7041
|
+
);
|
|
7042
|
+
nodesAdded += result.nodesAdded;
|
|
7043
|
+
edgesAdded += result.edgesAdded;
|
|
7044
|
+
}
|
|
7045
|
+
for (const svc of config.services ?? []) {
|
|
7046
|
+
if (!svc.service) continue;
|
|
7047
|
+
const target = workerIndex.get(svc.service);
|
|
7048
|
+
if (target && target.anchorId !== anchorId) {
|
|
7049
|
+
const edgeId = (0, import_types4.extractedEdgeId)(anchorId, target.anchorId, import_types25.EdgeType.CALLS);
|
|
7050
|
+
if (!graph.hasEdge(edgeId)) {
|
|
7051
|
+
const edge = {
|
|
7052
|
+
id: edgeId,
|
|
7053
|
+
source: anchorId,
|
|
7054
|
+
target: target.anchorId,
|
|
7055
|
+
type: import_types25.EdgeType.CALLS,
|
|
7056
|
+
provenance: import_types25.Provenance.EXTRACTED,
|
|
7057
|
+
confidence: (0, import_types25.confidenceForExtracted)("structural"),
|
|
7058
|
+
evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) }
|
|
7059
|
+
};
|
|
7060
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
7061
|
+
edgesAdded++;
|
|
7062
|
+
}
|
|
7063
|
+
continue;
|
|
7064
|
+
}
|
|
7065
|
+
const result = addResourceEdge(
|
|
7066
|
+
graph,
|
|
7067
|
+
anchorId,
|
|
7068
|
+
import_types25.EdgeType.DEPENDS_ON,
|
|
7069
|
+
"cloudflare-service-binding",
|
|
7070
|
+
svc.service,
|
|
7071
|
+
evidenceFile,
|
|
7072
|
+
lineContaining(raw, svc.service)
|
|
7073
|
+
);
|
|
7074
|
+
nodesAdded += result.nodesAdded;
|
|
7075
|
+
edgesAdded += result.edgesAdded;
|
|
7076
|
+
}
|
|
7077
|
+
}
|
|
7078
|
+
return { nodesAdded, edgesAdded };
|
|
7079
|
+
}
|
|
7080
|
+
|
|
6847
7081
|
// src/extract/infra/index.ts
|
|
6848
7082
|
async function addInfra(graph, scanPath, services) {
|
|
6849
7083
|
const compose = await addComposeInfra(graph, scanPath, services);
|
|
6850
7084
|
const dockerfile = await addDockerfileRuntimes(graph, services, scanPath);
|
|
6851
7085
|
const terraform = await addTerraformResources(graph, scanPath);
|
|
6852
7086
|
const k8s = await addK8sResources(graph, scanPath);
|
|
7087
|
+
const cloudflare = await addCloudflareWorkers(graph, services, scanPath);
|
|
6853
7088
|
return {
|
|
6854
|
-
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,
|
|
6855
|
-
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded
|
|
7089
|
+
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded + cloudflare.nodesAdded,
|
|
7090
|
+
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded + cloudflare.edgesAdded
|
|
6856
7091
|
};
|
|
6857
7092
|
}
|
|
6858
7093
|
|
|
6859
7094
|
// src/extract/index.ts
|
|
6860
|
-
var
|
|
7095
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
6861
7096
|
|
|
6862
7097
|
// src/extract/retire.ts
|
|
6863
7098
|
init_cjs_shims();
|
|
6864
|
-
var
|
|
6865
|
-
var
|
|
6866
|
-
var
|
|
7099
|
+
var import_node_fs21 = require("fs");
|
|
7100
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
7101
|
+
var import_types26 = require("@neat.is/types");
|
|
6867
7102
|
function dropOrphanedFileNodes(graph) {
|
|
6868
7103
|
const orphans = [];
|
|
6869
7104
|
graph.forEachNode((id, attrs) => {
|
|
6870
|
-
if (attrs.type !==
|
|
7105
|
+
if (attrs.type !== import_types26.NodeType.FileNode) return;
|
|
6871
7106
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
6872
7107
|
orphans.push(id);
|
|
6873
7108
|
}
|
|
@@ -6880,7 +7115,7 @@ function retireEdgesByFile(graph, file) {
|
|
|
6880
7115
|
const toDrop = [];
|
|
6881
7116
|
graph.forEachEdge((id, attrs) => {
|
|
6882
7117
|
const edge = attrs;
|
|
6883
|
-
if (edge.provenance !==
|
|
7118
|
+
if (edge.provenance !== import_types26.Provenance.EXTRACTED) return;
|
|
6884
7119
|
if (!edge.evidence?.file) return;
|
|
6885
7120
|
if (edge.evidence.file === normalized) toDrop.push(id);
|
|
6886
7121
|
});
|
|
@@ -6893,14 +7128,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
6893
7128
|
const bases = [scanPath, ...serviceDirs];
|
|
6894
7129
|
graph.forEachEdge((id, attrs) => {
|
|
6895
7130
|
const edge = attrs;
|
|
6896
|
-
if (edge.provenance !==
|
|
7131
|
+
if (edge.provenance !== import_types26.Provenance.EXTRACTED) return;
|
|
6897
7132
|
const evidenceFile = edge.evidence?.file;
|
|
6898
7133
|
if (!evidenceFile) return;
|
|
6899
|
-
if (
|
|
6900
|
-
if (!(0,
|
|
7134
|
+
if (import_node_path37.default.isAbsolute(evidenceFile)) {
|
|
7135
|
+
if (!(0, import_node_fs21.existsSync)(evidenceFile)) toDrop.push(id);
|
|
6901
7136
|
return;
|
|
6902
7137
|
}
|
|
6903
|
-
const found = bases.some((base) => (0,
|
|
7138
|
+
const found = bases.some((base) => (0, import_node_fs21.existsSync)(import_node_path37.default.join(base, evidenceFile)));
|
|
6904
7139
|
if (!found) toDrop.push(id);
|
|
6905
7140
|
});
|
|
6906
7141
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -6942,7 +7177,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6942
7177
|
}
|
|
6943
7178
|
const droppedEntries = drainDroppedExtracted();
|
|
6944
7179
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
6945
|
-
const rejectedPath =
|
|
7180
|
+
const rejectedPath = import_node_path38.default.join(import_node_path38.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
6946
7181
|
try {
|
|
6947
7182
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
6948
7183
|
} catch (err) {
|
|
@@ -6976,7 +7211,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
6976
7211
|
|
|
6977
7212
|
// src/divergences.ts
|
|
6978
7213
|
init_cjs_shims();
|
|
6979
|
-
var
|
|
7214
|
+
var import_types27 = require("@neat.is/types");
|
|
6980
7215
|
function bucketKey(source, target, type) {
|
|
6981
7216
|
return `${type}|${source}|${target}`;
|
|
6982
7217
|
}
|
|
@@ -6984,22 +7219,22 @@ function bucketEdges(graph) {
|
|
|
6984
7219
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
6985
7220
|
graph.forEachEdge((id, attrs) => {
|
|
6986
7221
|
const e = attrs;
|
|
6987
|
-
const parsed = (0,
|
|
7222
|
+
const parsed = (0, import_types27.parseEdgeId)(id);
|
|
6988
7223
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
6989
7224
|
const key = bucketKey(e.source, e.target, e.type);
|
|
6990
7225
|
const cur = buckets2.get(key) ?? { source: e.source, target: e.target, type: e.type };
|
|
6991
7226
|
switch (provenance) {
|
|
6992
|
-
case
|
|
7227
|
+
case import_types27.Provenance.EXTRACTED:
|
|
6993
7228
|
cur.extracted = e;
|
|
6994
7229
|
break;
|
|
6995
|
-
case
|
|
7230
|
+
case import_types27.Provenance.OBSERVED:
|
|
6996
7231
|
cur.observed = e;
|
|
6997
7232
|
break;
|
|
6998
|
-
case
|
|
7233
|
+
case import_types27.Provenance.INFERRED:
|
|
6999
7234
|
cur.inferred = e;
|
|
7000
7235
|
break;
|
|
7001
7236
|
default:
|
|
7002
|
-
if (e.provenance ===
|
|
7237
|
+
if (e.provenance === import_types27.Provenance.STALE) cur.stale = e;
|
|
7003
7238
|
}
|
|
7004
7239
|
buckets2.set(key, cur);
|
|
7005
7240
|
});
|
|
@@ -7008,12 +7243,12 @@ function bucketEdges(graph) {
|
|
|
7008
7243
|
function nodeIsFrontier(graph, nodeId) {
|
|
7009
7244
|
if (!graph.hasNode(nodeId)) return false;
|
|
7010
7245
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7011
|
-
return attrs.type ===
|
|
7246
|
+
return attrs.type === import_types27.NodeType.FrontierNode;
|
|
7012
7247
|
}
|
|
7013
7248
|
function nodeIsWebsocketChannel(graph, nodeId) {
|
|
7014
7249
|
if (!graph.hasNode(nodeId)) return false;
|
|
7015
7250
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
7016
|
-
return attrs.type ===
|
|
7251
|
+
return attrs.type === import_types27.NodeType.WebSocketChannelNode;
|
|
7017
7252
|
}
|
|
7018
7253
|
function clampConfidence(n) {
|
|
7019
7254
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -7033,14 +7268,14 @@ function gradedConfidence(edge) {
|
|
|
7033
7268
|
return clampConfidence(confidenceForEdge(edge));
|
|
7034
7269
|
}
|
|
7035
7270
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7271
|
+
import_types27.EdgeType.CALLS,
|
|
7272
|
+
import_types27.EdgeType.CONNECTS_TO,
|
|
7273
|
+
import_types27.EdgeType.PUBLISHES_TO,
|
|
7274
|
+
import_types27.EdgeType.CONSUMES_FROM
|
|
7040
7275
|
]);
|
|
7041
7276
|
function detectMissingDivergences(graph, bucket) {
|
|
7042
7277
|
const out = [];
|
|
7043
|
-
if (bucket.type ===
|
|
7278
|
+
if (bucket.type === import_types27.EdgeType.CONTAINS) return out;
|
|
7044
7279
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
7045
7280
|
if (!nodeIsFrontier(graph, bucket.target)) {
|
|
7046
7281
|
out.push({
|
|
@@ -7081,7 +7316,7 @@ function declaredHostFor(svc) {
|
|
|
7081
7316
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
7082
7317
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7083
7318
|
const e = graph.getEdgeAttributes(edgeId);
|
|
7084
|
-
if (e.type ===
|
|
7319
|
+
if (e.type === import_types27.EdgeType.CONFIGURED_BY && e.provenance === import_types27.Provenance.EXTRACTED) {
|
|
7085
7320
|
return true;
|
|
7086
7321
|
}
|
|
7087
7322
|
}
|
|
@@ -7094,10 +7329,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
7094
7329
|
const out = [];
|
|
7095
7330
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7096
7331
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
7097
|
-
if (edge.type !==
|
|
7098
|
-
if (edge.provenance !==
|
|
7332
|
+
if (edge.type !== import_types27.EdgeType.CONNECTS_TO) continue;
|
|
7333
|
+
if (edge.provenance !== import_types27.Provenance.OBSERVED) continue;
|
|
7099
7334
|
const target = graph.getNodeAttributes(edge.target);
|
|
7100
|
-
if (target.type !==
|
|
7335
|
+
if (target.type !== import_types27.NodeType.DatabaseNode) continue;
|
|
7101
7336
|
const observedHost = target.host?.trim();
|
|
7102
7337
|
if (!observedHost) continue;
|
|
7103
7338
|
if (observedHost === declaredHost) continue;
|
|
@@ -7119,10 +7354,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
7119
7354
|
const deps = svc.dependencies ?? {};
|
|
7120
7355
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
7121
7356
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
7122
|
-
if (edge.type !==
|
|
7123
|
-
if (edge.provenance !==
|
|
7357
|
+
if (edge.type !== import_types27.EdgeType.CONNECTS_TO) continue;
|
|
7358
|
+
if (edge.provenance !== import_types27.Provenance.OBSERVED) continue;
|
|
7124
7359
|
const target = graph.getNodeAttributes(edge.target);
|
|
7125
|
-
if (target.type !==
|
|
7360
|
+
if (target.type !== import_types27.NodeType.DatabaseNode) continue;
|
|
7126
7361
|
for (const pair of compatPairs()) {
|
|
7127
7362
|
if (pair.engine !== target.engine) continue;
|
|
7128
7363
|
const declared = deps[pair.driver];
|
|
@@ -7181,7 +7416,7 @@ function suppressHostMismatchHalves(all) {
|
|
|
7181
7416
|
for (const d of all) {
|
|
7182
7417
|
if (d.type !== "host-mismatch") continue;
|
|
7183
7418
|
observedHalf.add(`${d.source}->${d.target}`);
|
|
7184
|
-
declaredHalf.add((0,
|
|
7419
|
+
declaredHalf.add((0, import_types27.databaseId)(d.extractedHost));
|
|
7185
7420
|
}
|
|
7186
7421
|
if (observedHalf.size === 0) return all;
|
|
7187
7422
|
return all.filter((d) => {
|
|
@@ -7200,7 +7435,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7200
7435
|
}
|
|
7201
7436
|
graph.forEachNode((nodeId, attrs) => {
|
|
7202
7437
|
const n = attrs;
|
|
7203
|
-
if (n.type !==
|
|
7438
|
+
if (n.type !== import_types27.NodeType.ServiceNode) return;
|
|
7204
7439
|
const svc = n;
|
|
7205
7440
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
7206
7441
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -7234,7 +7469,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7234
7469
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
7235
7470
|
return a.target.localeCompare(b.target);
|
|
7236
7471
|
});
|
|
7237
|
-
return
|
|
7472
|
+
return import_types27.DivergenceResultSchema.parse({
|
|
7238
7473
|
divergences: filtered,
|
|
7239
7474
|
totalAffected: filtered.length,
|
|
7240
7475
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7243,9 +7478,9 @@ function computeDivergences(graph, opts = {}) {
|
|
|
7243
7478
|
|
|
7244
7479
|
// src/persist.ts
|
|
7245
7480
|
init_cjs_shims();
|
|
7246
|
-
var
|
|
7247
|
-
var
|
|
7248
|
-
var
|
|
7481
|
+
var import_node_fs22 = require("fs");
|
|
7482
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7483
|
+
var import_types28 = require("@neat.is/types");
|
|
7249
7484
|
var SCHEMA_VERSION = 4;
|
|
7250
7485
|
function migrateV1ToV2(payload) {
|
|
7251
7486
|
const nodes = payload.graph.nodes;
|
|
@@ -7267,12 +7502,12 @@ function migrateV2ToV3(payload) {
|
|
|
7267
7502
|
for (const edge of edges) {
|
|
7268
7503
|
const attrs = edge.attributes;
|
|
7269
7504
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
7270
|
-
attrs.provenance =
|
|
7505
|
+
attrs.provenance = import_types28.Provenance.OBSERVED;
|
|
7271
7506
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
7272
7507
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
7273
7508
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
7274
7509
|
if (type && source && target) {
|
|
7275
|
-
const newId = (0,
|
|
7510
|
+
const newId = (0, import_types28.observedEdgeId)(source, target, type);
|
|
7276
7511
|
attrs.id = newId;
|
|
7277
7512
|
if (edge.key) edge.key = newId;
|
|
7278
7513
|
}
|
|
@@ -7281,7 +7516,7 @@ function migrateV2ToV3(payload) {
|
|
|
7281
7516
|
return { ...payload, schemaVersion: 3 };
|
|
7282
7517
|
}
|
|
7283
7518
|
async function ensureDir(filePath) {
|
|
7284
|
-
await
|
|
7519
|
+
await import_node_fs22.promises.mkdir(import_node_path39.default.dirname(filePath), { recursive: true });
|
|
7285
7520
|
}
|
|
7286
7521
|
async function saveGraphToDisk(graph, outPath) {
|
|
7287
7522
|
await ensureDir(outPath);
|
|
@@ -7291,13 +7526,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
7291
7526
|
graph: graph.export()
|
|
7292
7527
|
};
|
|
7293
7528
|
const tmp = `${outPath}.tmp`;
|
|
7294
|
-
await
|
|
7295
|
-
await
|
|
7529
|
+
await import_node_fs22.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
7530
|
+
await import_node_fs22.promises.rename(tmp, outPath);
|
|
7296
7531
|
}
|
|
7297
7532
|
async function loadGraphFromDisk(graph, outPath) {
|
|
7298
7533
|
let raw;
|
|
7299
7534
|
try {
|
|
7300
|
-
raw = await
|
|
7535
|
+
raw = await import_node_fs22.promises.readFile(outPath, "utf8");
|
|
7301
7536
|
} catch (err) {
|
|
7302
7537
|
if (err.code === "ENOENT") return;
|
|
7303
7538
|
throw err;
|
|
@@ -7362,8 +7597,8 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
7362
7597
|
|
|
7363
7598
|
// src/gitignore.ts
|
|
7364
7599
|
init_cjs_shims();
|
|
7365
|
-
var
|
|
7366
|
-
var
|
|
7600
|
+
var import_node_fs23 = require("fs");
|
|
7601
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7367
7602
|
var NEAT_OUT_LINE = "neat-out/";
|
|
7368
7603
|
var NEAT_HEADER = "# NEAT \u2014 machine-local snapshots and events";
|
|
7369
7604
|
function isNeatOutLine(line) {
|
|
@@ -7371,15 +7606,15 @@ function isNeatOutLine(line) {
|
|
|
7371
7606
|
return trimmed === "neat-out/" || trimmed === "neat-out";
|
|
7372
7607
|
}
|
|
7373
7608
|
async function ensureNeatOutIgnored(projectDir) {
|
|
7374
|
-
const file =
|
|
7609
|
+
const file = import_node_path40.default.join(projectDir, ".gitignore");
|
|
7375
7610
|
let existing = null;
|
|
7376
7611
|
try {
|
|
7377
|
-
existing = await
|
|
7612
|
+
existing = await import_node_fs23.promises.readFile(file, "utf8");
|
|
7378
7613
|
} catch (err) {
|
|
7379
7614
|
if (err.code !== "ENOENT") throw err;
|
|
7380
7615
|
}
|
|
7381
7616
|
if (existing === null) {
|
|
7382
|
-
await
|
|
7617
|
+
await import_node_fs23.promises.writeFile(file, `${NEAT_HEADER}
|
|
7383
7618
|
${NEAT_OUT_LINE}
|
|
7384
7619
|
`, "utf8");
|
|
7385
7620
|
return { action: "created", file };
|
|
@@ -7392,13 +7627,13 @@ ${NEAT_OUT_LINE}
|
|
|
7392
7627
|
${NEAT_HEADER}
|
|
7393
7628
|
${NEAT_OUT_LINE}
|
|
7394
7629
|
`;
|
|
7395
|
-
await
|
|
7630
|
+
await import_node_fs23.promises.writeFile(file, existing + appended, "utf8");
|
|
7396
7631
|
return { action: "added", file };
|
|
7397
7632
|
}
|
|
7398
7633
|
|
|
7399
7634
|
// src/summary.ts
|
|
7400
7635
|
init_cjs_shims();
|
|
7401
|
-
var
|
|
7636
|
+
var import_types29 = require("@neat.is/types");
|
|
7402
7637
|
function renderOtelEnvBlock() {
|
|
7403
7638
|
return [
|
|
7404
7639
|
"for prod OTel routing, set these in your deploy platform's env:",
|
|
@@ -7408,19 +7643,19 @@ function renderOtelEnvBlock() {
|
|
|
7408
7643
|
}
|
|
7409
7644
|
function findIncompatServices(nodes) {
|
|
7410
7645
|
return nodes.filter(
|
|
7411
|
-
(n) => n.type ===
|
|
7646
|
+
(n) => n.type === import_types29.NodeType.ServiceNode && Array.isArray(n.incompatibilities) && (n.incompatibilities ?? []).length > 0
|
|
7412
7647
|
);
|
|
7413
7648
|
}
|
|
7414
7649
|
function servicesWithoutObserved(nodes, edges) {
|
|
7415
7650
|
const seen = /* @__PURE__ */ new Set();
|
|
7416
7651
|
for (const e of edges) {
|
|
7417
|
-
if (e.provenance ===
|
|
7652
|
+
if (e.provenance === import_types29.Provenance.OBSERVED) {
|
|
7418
7653
|
seen.add(e.source);
|
|
7419
7654
|
seen.add(e.target);
|
|
7420
7655
|
}
|
|
7421
7656
|
}
|
|
7422
7657
|
return nodes.filter(
|
|
7423
|
-
(n) => n.type ===
|
|
7658
|
+
(n) => n.type === import_types29.NodeType.ServiceNode && !seen.has(n.id)
|
|
7424
7659
|
);
|
|
7425
7660
|
}
|
|
7426
7661
|
function formatDivergence(d) {
|
|
@@ -7494,27 +7729,27 @@ function formatIncompat(inc) {
|
|
|
7494
7729
|
|
|
7495
7730
|
// src/watch.ts
|
|
7496
7731
|
init_cjs_shims();
|
|
7497
|
-
var
|
|
7498
|
-
var
|
|
7732
|
+
var import_node_fs32 = __toESM(require("fs"), 1);
|
|
7733
|
+
var import_node_path51 = __toESM(require("path"), 1);
|
|
7499
7734
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
7500
7735
|
|
|
7501
7736
|
// src/api.ts
|
|
7502
7737
|
init_cjs_shims();
|
|
7503
7738
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
7504
7739
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
7505
|
-
var
|
|
7740
|
+
var import_types31 = require("@neat.is/types");
|
|
7506
7741
|
|
|
7507
7742
|
// src/extend/index.ts
|
|
7508
7743
|
init_cjs_shims();
|
|
7509
|
-
var
|
|
7510
|
-
var
|
|
7744
|
+
var import_node_fs25 = require("fs");
|
|
7745
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
7511
7746
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
7512
7747
|
var import_instrumentation_registry = require("@neat.is/instrumentation-registry");
|
|
7513
7748
|
|
|
7514
7749
|
// src/installers/package-manager.ts
|
|
7515
7750
|
init_cjs_shims();
|
|
7516
|
-
var
|
|
7517
|
-
var
|
|
7751
|
+
var import_node_fs24 = require("fs");
|
|
7752
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7518
7753
|
var import_node_child_process = require("child_process");
|
|
7519
7754
|
var LOCKFILE_PRIORITY = [
|
|
7520
7755
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -7529,29 +7764,29 @@ var LOCKFILE_PRIORITY = [
|
|
|
7529
7764
|
var NPM_FALLBACK_ARGS = ["install", "--no-audit", "--no-fund", "--prefer-offline"];
|
|
7530
7765
|
async function exists2(p) {
|
|
7531
7766
|
try {
|
|
7532
|
-
await
|
|
7767
|
+
await import_node_fs24.promises.access(p);
|
|
7533
7768
|
return true;
|
|
7534
7769
|
} catch {
|
|
7535
7770
|
return false;
|
|
7536
7771
|
}
|
|
7537
7772
|
}
|
|
7538
7773
|
async function detectPackageManager(serviceDir) {
|
|
7539
|
-
let dir =
|
|
7774
|
+
let dir = import_node_path41.default.resolve(serviceDir);
|
|
7540
7775
|
const stops = /* @__PURE__ */ new Set();
|
|
7541
7776
|
for (let i = 0; i < 64; i++) {
|
|
7542
7777
|
if (stops.has(dir)) break;
|
|
7543
7778
|
stops.add(dir);
|
|
7544
7779
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
7545
|
-
const lockPath =
|
|
7780
|
+
const lockPath = import_node_path41.default.join(dir, candidate.lockfile);
|
|
7546
7781
|
if (await exists2(lockPath)) {
|
|
7547
7782
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
7548
7783
|
}
|
|
7549
7784
|
}
|
|
7550
|
-
const parent =
|
|
7785
|
+
const parent = import_node_path41.default.dirname(dir);
|
|
7551
7786
|
if (parent === dir) break;
|
|
7552
7787
|
dir = parent;
|
|
7553
7788
|
}
|
|
7554
|
-
return { pm: "npm", cwd:
|
|
7789
|
+
return { pm: "npm", cwd: import_node_path41.default.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
7555
7790
|
}
|
|
7556
7791
|
async function runPackageManagerInstall(cmd) {
|
|
7557
7792
|
return new Promise((resolve) => {
|
|
@@ -7593,30 +7828,30 @@ ${err.message}`
|
|
|
7593
7828
|
// src/extend/index.ts
|
|
7594
7829
|
async function fileExists2(p) {
|
|
7595
7830
|
try {
|
|
7596
|
-
await
|
|
7831
|
+
await import_node_fs25.promises.access(p);
|
|
7597
7832
|
return true;
|
|
7598
7833
|
} catch {
|
|
7599
7834
|
return false;
|
|
7600
7835
|
}
|
|
7601
7836
|
}
|
|
7602
7837
|
async function readPackageJson(scanPath) {
|
|
7603
|
-
const pkgPath =
|
|
7604
|
-
const raw = await
|
|
7838
|
+
const pkgPath = import_node_path42.default.join(scanPath, "package.json");
|
|
7839
|
+
const raw = await import_node_fs25.promises.readFile(pkgPath, "utf8");
|
|
7605
7840
|
return JSON.parse(raw);
|
|
7606
7841
|
}
|
|
7607
7842
|
async function findHookFiles(scanPath) {
|
|
7608
|
-
const entries = await
|
|
7843
|
+
const entries = await import_node_fs25.promises.readdir(scanPath);
|
|
7609
7844
|
return entries.filter(
|
|
7610
7845
|
(e) => (e.startsWith("instrumentation") || e.startsWith("otel-init")) && /\.(ts|js)$/.test(e)
|
|
7611
7846
|
).sort();
|
|
7612
7847
|
}
|
|
7613
7848
|
function extendLogPath() {
|
|
7614
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
7849
|
+
return process.env.NEAT_EXTEND_LOG ?? import_node_path42.default.join(import_node_os2.default.homedir(), ".neat", "extend-log.ndjson");
|
|
7615
7850
|
}
|
|
7616
7851
|
async function appendExtendLog(entry2) {
|
|
7617
7852
|
const logPath = extendLogPath();
|
|
7618
|
-
await
|
|
7619
|
-
await
|
|
7853
|
+
await import_node_fs25.promises.mkdir(import_node_path42.default.dirname(logPath), { recursive: true });
|
|
7854
|
+
await import_node_fs25.promises.appendFile(logPath, JSON.stringify(entry2) + "\n", "utf8");
|
|
7620
7855
|
}
|
|
7621
7856
|
function splicedContent(fileContent, snippet2) {
|
|
7622
7857
|
if (fileContent.includes("__INSTRUMENTATION_BLOCK__")) {
|
|
@@ -7674,7 +7909,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
7674
7909
|
}
|
|
7675
7910
|
async function describeProjectInstrumentation(ctx) {
|
|
7676
7911
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7677
|
-
const envNeat = await fileExists2(
|
|
7912
|
+
const envNeat = await fileExists2(import_node_path42.default.join(ctx.scanPath, ".env.neat"));
|
|
7678
7913
|
const registryInstrPackages = new Set(
|
|
7679
7914
|
(0, import_instrumentation_registry.list)().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
7680
7915
|
);
|
|
@@ -7696,31 +7931,31 @@ async function applyExtension(ctx, args, options) {
|
|
|
7696
7931
|
);
|
|
7697
7932
|
}
|
|
7698
7933
|
for (const file of hookFiles) {
|
|
7699
|
-
const content = await
|
|
7934
|
+
const content = await import_node_fs25.promises.readFile(import_node_path42.default.join(ctx.scanPath, file), "utf8");
|
|
7700
7935
|
if (content.includes(args.registration_snippet)) {
|
|
7701
7936
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
7702
7937
|
}
|
|
7703
7938
|
}
|
|
7704
7939
|
const primaryFile = hookFiles[0];
|
|
7705
|
-
const primaryPath =
|
|
7940
|
+
const primaryPath = import_node_path42.default.join(ctx.scanPath, primaryFile);
|
|
7706
7941
|
const filesTouched = [];
|
|
7707
7942
|
const depsAdded = [];
|
|
7708
|
-
const pkgPath =
|
|
7943
|
+
const pkgPath = import_node_path42.default.join(ctx.scanPath, "package.json");
|
|
7709
7944
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7710
7945
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
7711
7946
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
7712
|
-
await
|
|
7947
|
+
await import_node_fs25.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
7713
7948
|
filesTouched.push("package.json");
|
|
7714
7949
|
depsAdded.push(`${args.instrumentation_package}@${args.version}`);
|
|
7715
7950
|
}
|
|
7716
|
-
const hookContent = await
|
|
7951
|
+
const hookContent = await import_node_fs25.promises.readFile(primaryPath, "utf8");
|
|
7717
7952
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7718
7953
|
if (!patched) {
|
|
7719
7954
|
throw new Error(
|
|
7720
7955
|
`Could not find instrumentation insertion point in ${primaryFile}. Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.`
|
|
7721
7956
|
);
|
|
7722
7957
|
}
|
|
7723
|
-
await
|
|
7958
|
+
await import_node_fs25.promises.writeFile(primaryPath, patched, "utf8");
|
|
7724
7959
|
filesTouched.push(primaryFile);
|
|
7725
7960
|
const cmd = await detectPackageManager(ctx.scanPath);
|
|
7726
7961
|
const installer = options?.runInstall ?? runPackageManagerInstall;
|
|
@@ -7751,7 +7986,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7751
7986
|
};
|
|
7752
7987
|
}
|
|
7753
7988
|
for (const file of hookFiles) {
|
|
7754
|
-
const content = await
|
|
7989
|
+
const content = await import_node_fs25.promises.readFile(import_node_path42.default.join(ctx.scanPath, file), "utf8");
|
|
7755
7990
|
if (content.includes(args.registration_snippet)) {
|
|
7756
7991
|
return {
|
|
7757
7992
|
library: args.library,
|
|
@@ -7773,7 +8008,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
7773
8008
|
depsToAdd.push(`${args.instrumentation_package}@${args.version}`);
|
|
7774
8009
|
filesTouched.push("package.json");
|
|
7775
8010
|
}
|
|
7776
|
-
const hookContent = await
|
|
8011
|
+
const hookContent = await import_node_fs25.promises.readFile(import_node_path42.default.join(ctx.scanPath, primaryFile), "utf8");
|
|
7777
8012
|
const patched = splicedContent(hookContent, args.registration_snippet);
|
|
7778
8013
|
if (patched) {
|
|
7779
8014
|
filesTouched.push(primaryFile);
|
|
@@ -7788,28 +8023,28 @@ async function rollbackExtension(ctx, args) {
|
|
|
7788
8023
|
if (!await fileExists2(logPath)) {
|
|
7789
8024
|
return { undone: false, message: "no apply found for library" };
|
|
7790
8025
|
}
|
|
7791
|
-
const raw = await
|
|
8026
|
+
const raw = await import_node_fs25.promises.readFile(logPath, "utf8");
|
|
7792
8027
|
const entries = raw.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
7793
8028
|
const match = [...entries].reverse().find((e) => e.project === ctx.project && e.library === args.library);
|
|
7794
8029
|
if (!match) {
|
|
7795
8030
|
return { undone: false, message: "no apply found for library" };
|
|
7796
8031
|
}
|
|
7797
|
-
const pkgPath =
|
|
8032
|
+
const pkgPath = import_node_path42.default.join(ctx.scanPath, "package.json");
|
|
7798
8033
|
if (await fileExists2(pkgPath)) {
|
|
7799
8034
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
7800
8035
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
7801
8036
|
const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies;
|
|
7802
8037
|
pkg.dependencies = rest;
|
|
7803
|
-
await
|
|
8038
|
+
await import_node_fs25.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
7804
8039
|
}
|
|
7805
8040
|
}
|
|
7806
8041
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
7807
8042
|
for (const file of hookFiles) {
|
|
7808
|
-
const filePath =
|
|
7809
|
-
const content = await
|
|
8043
|
+
const filePath = import_node_path42.default.join(ctx.scanPath, file);
|
|
8044
|
+
const content = await import_node_fs25.promises.readFile(filePath, "utf8");
|
|
7810
8045
|
if (content.includes(match.registration_snippet)) {
|
|
7811
8046
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
7812
|
-
await
|
|
8047
|
+
await import_node_fs25.promises.writeFile(filePath, filtered, "utf8");
|
|
7813
8048
|
break;
|
|
7814
8049
|
}
|
|
7815
8050
|
}
|
|
@@ -7866,7 +8101,7 @@ function queryLogEntries(opts) {
|
|
|
7866
8101
|
|
|
7867
8102
|
// src/diff.ts
|
|
7868
8103
|
init_cjs_shims();
|
|
7869
|
-
var
|
|
8104
|
+
var import_node_fs26 = require("fs");
|
|
7870
8105
|
async function loadSnapshotForDiff(target) {
|
|
7871
8106
|
if (/^https?:\/\//i.test(target)) {
|
|
7872
8107
|
const res = await fetch(target);
|
|
@@ -7875,7 +8110,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
7875
8110
|
}
|
|
7876
8111
|
return await res.json();
|
|
7877
8112
|
}
|
|
7878
|
-
const raw = await
|
|
8113
|
+
const raw = await import_node_fs26.promises.readFile(target, "utf8");
|
|
7879
8114
|
return JSON.parse(raw);
|
|
7880
8115
|
}
|
|
7881
8116
|
function indexEntries(entries) {
|
|
@@ -7943,23 +8178,23 @@ function canonicalJson(value) {
|
|
|
7943
8178
|
|
|
7944
8179
|
// src/projects.ts
|
|
7945
8180
|
init_cjs_shims();
|
|
7946
|
-
var
|
|
8181
|
+
var import_node_path43 = __toESM(require("path"), 1);
|
|
7947
8182
|
function pathsForProject(project, baseDir) {
|
|
7948
8183
|
if (project === DEFAULT_PROJECT) {
|
|
7949
8184
|
return {
|
|
7950
|
-
snapshotPath:
|
|
7951
|
-
errorsPath:
|
|
7952
|
-
staleEventsPath:
|
|
7953
|
-
embeddingsCachePath:
|
|
7954
|
-
policyViolationsPath:
|
|
8185
|
+
snapshotPath: import_node_path43.default.join(baseDir, "graph.json"),
|
|
8186
|
+
errorsPath: import_node_path43.default.join(baseDir, "errors.ndjson"),
|
|
8187
|
+
staleEventsPath: import_node_path43.default.join(baseDir, "stale-events.ndjson"),
|
|
8188
|
+
embeddingsCachePath: import_node_path43.default.join(baseDir, "embeddings.json"),
|
|
8189
|
+
policyViolationsPath: import_node_path43.default.join(baseDir, "policy-violations.ndjson")
|
|
7955
8190
|
};
|
|
7956
8191
|
}
|
|
7957
8192
|
return {
|
|
7958
|
-
snapshotPath:
|
|
7959
|
-
errorsPath:
|
|
7960
|
-
staleEventsPath:
|
|
7961
|
-
embeddingsCachePath:
|
|
7962
|
-
policyViolationsPath:
|
|
8193
|
+
snapshotPath: import_node_path43.default.join(baseDir, `${project}.json`),
|
|
8194
|
+
errorsPath: import_node_path43.default.join(baseDir, `errors.${project}.ndjson`),
|
|
8195
|
+
staleEventsPath: import_node_path43.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
8196
|
+
embeddingsCachePath: import_node_path43.default.join(baseDir, `embeddings.${project}.json`),
|
|
8197
|
+
policyViolationsPath: import_node_path43.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
7963
8198
|
};
|
|
7964
8199
|
}
|
|
7965
8200
|
var Projects = class {
|
|
@@ -7995,28 +8230,28 @@ var Projects = class {
|
|
|
7995
8230
|
|
|
7996
8231
|
// src/registry.ts
|
|
7997
8232
|
init_cjs_shims();
|
|
7998
|
-
var
|
|
8233
|
+
var import_node_fs27 = require("fs");
|
|
7999
8234
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
8000
|
-
var
|
|
8001
|
-
var
|
|
8235
|
+
var import_node_path44 = __toESM(require("path"), 1);
|
|
8236
|
+
var import_types30 = require("@neat.is/types");
|
|
8002
8237
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
8003
8238
|
var LOCK_RETRY_MS = 50;
|
|
8004
8239
|
function neatHome() {
|
|
8005
8240
|
const override = process.env.NEAT_HOME;
|
|
8006
|
-
if (override && override.length > 0) return
|
|
8007
|
-
return
|
|
8241
|
+
if (override && override.length > 0) return import_node_path44.default.resolve(override);
|
|
8242
|
+
return import_node_path44.default.join(import_node_os3.default.homedir(), ".neat");
|
|
8008
8243
|
}
|
|
8009
8244
|
function registryPath() {
|
|
8010
|
-
return
|
|
8245
|
+
return import_node_path44.default.join(neatHome(), "projects.json");
|
|
8011
8246
|
}
|
|
8012
8247
|
function registryLockPath() {
|
|
8013
|
-
return
|
|
8248
|
+
return import_node_path44.default.join(neatHome(), "projects.json.lock");
|
|
8014
8249
|
}
|
|
8015
8250
|
function daemonPidPath() {
|
|
8016
|
-
return
|
|
8251
|
+
return import_node_path44.default.join(neatHome(), "neatd.pid");
|
|
8017
8252
|
}
|
|
8018
8253
|
function daemonsDir() {
|
|
8019
|
-
return
|
|
8254
|
+
return import_node_path44.default.join(neatHome(), "daemons");
|
|
8020
8255
|
}
|
|
8021
8256
|
function isFiniteInt(v) {
|
|
8022
8257
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -8049,7 +8284,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
8049
8284
|
const dir = daemonsDir();
|
|
8050
8285
|
let names;
|
|
8051
8286
|
try {
|
|
8052
|
-
names = await
|
|
8287
|
+
names = await import_node_fs27.promises.readdir(dir);
|
|
8053
8288
|
} catch (err) {
|
|
8054
8289
|
if (err.code === "ENOENT") return [];
|
|
8055
8290
|
throw err;
|
|
@@ -8057,10 +8292,10 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
8057
8292
|
const out = [];
|
|
8058
8293
|
for (const name of names) {
|
|
8059
8294
|
if (!name.endsWith(".json")) continue;
|
|
8060
|
-
const file =
|
|
8295
|
+
const file = import_node_path44.default.join(dir, name);
|
|
8061
8296
|
let raw;
|
|
8062
8297
|
try {
|
|
8063
|
-
raw = await
|
|
8298
|
+
raw = await import_node_fs27.promises.readFile(file, "utf8");
|
|
8064
8299
|
} catch {
|
|
8065
8300
|
continue;
|
|
8066
8301
|
}
|
|
@@ -8073,7 +8308,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
8073
8308
|
return out;
|
|
8074
8309
|
}
|
|
8075
8310
|
async function removeDaemonRecord(source) {
|
|
8076
|
-
await
|
|
8311
|
+
await import_node_fs27.promises.unlink(source).catch(() => {
|
|
8077
8312
|
});
|
|
8078
8313
|
}
|
|
8079
8314
|
async function listMachineProjects(probe = defaultDiscoveryProbe) {
|
|
@@ -8130,7 +8365,7 @@ function isPidAliveDefault(pid) {
|
|
|
8130
8365
|
}
|
|
8131
8366
|
async function readPidFile(file) {
|
|
8132
8367
|
try {
|
|
8133
|
-
const raw = await
|
|
8368
|
+
const raw = await import_node_fs27.promises.readFile(file, "utf8");
|
|
8134
8369
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
8135
8370
|
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
8136
8371
|
} catch {
|
|
@@ -8178,32 +8413,32 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
8178
8413
|
}
|
|
8179
8414
|
}
|
|
8180
8415
|
async function normalizeProjectPath(input) {
|
|
8181
|
-
const resolved =
|
|
8416
|
+
const resolved = import_node_path44.default.resolve(input);
|
|
8182
8417
|
try {
|
|
8183
|
-
return await
|
|
8418
|
+
return await import_node_fs27.promises.realpath(resolved);
|
|
8184
8419
|
} catch {
|
|
8185
8420
|
return resolved;
|
|
8186
8421
|
}
|
|
8187
8422
|
}
|
|
8188
8423
|
async function writeAtomically(target, contents) {
|
|
8189
|
-
await
|
|
8424
|
+
await import_node_fs27.promises.mkdir(import_node_path44.default.dirname(target), { recursive: true });
|
|
8190
8425
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
8191
|
-
const fd = await
|
|
8426
|
+
const fd = await import_node_fs27.promises.open(tmp, "w");
|
|
8192
8427
|
try {
|
|
8193
8428
|
await fd.writeFile(contents, "utf8");
|
|
8194
8429
|
await fd.sync();
|
|
8195
8430
|
} finally {
|
|
8196
8431
|
await fd.close();
|
|
8197
8432
|
}
|
|
8198
|
-
await
|
|
8433
|
+
await import_node_fs27.promises.rename(tmp, target);
|
|
8199
8434
|
}
|
|
8200
8435
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
8201
8436
|
const deadline = Date.now() + timeoutMs;
|
|
8202
|
-
await
|
|
8437
|
+
await import_node_fs27.promises.mkdir(import_node_path44.default.dirname(lockPath), { recursive: true });
|
|
8203
8438
|
let probedHolder = false;
|
|
8204
8439
|
while (true) {
|
|
8205
8440
|
try {
|
|
8206
|
-
const fd = await
|
|
8441
|
+
const fd = await import_node_fs27.promises.open(lockPath, "wx");
|
|
8207
8442
|
try {
|
|
8208
8443
|
await fd.writeFile(`${process.pid}
|
|
8209
8444
|
`, "utf8");
|
|
@@ -8228,7 +8463,7 @@ async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaul
|
|
|
8228
8463
|
}
|
|
8229
8464
|
}
|
|
8230
8465
|
async function releaseLock(lockPath) {
|
|
8231
|
-
await
|
|
8466
|
+
await import_node_fs27.promises.unlink(lockPath).catch(() => {
|
|
8232
8467
|
});
|
|
8233
8468
|
}
|
|
8234
8469
|
async function withLock(fn) {
|
|
@@ -8244,7 +8479,7 @@ async function readRegistry() {
|
|
|
8244
8479
|
const file = registryPath();
|
|
8245
8480
|
let raw;
|
|
8246
8481
|
try {
|
|
8247
|
-
raw = await
|
|
8482
|
+
raw = await import_node_fs27.promises.readFile(file, "utf8");
|
|
8248
8483
|
} catch (err) {
|
|
8249
8484
|
if (err.code === "ENOENT") {
|
|
8250
8485
|
return { version: 1, projects: [] };
|
|
@@ -8252,10 +8487,10 @@ async function readRegistry() {
|
|
|
8252
8487
|
throw err;
|
|
8253
8488
|
}
|
|
8254
8489
|
const parsed = JSON.parse(raw);
|
|
8255
|
-
return
|
|
8490
|
+
return import_types30.RegistryFileSchema.parse(parsed);
|
|
8256
8491
|
}
|
|
8257
8492
|
async function writeRegistry(reg) {
|
|
8258
|
-
const validated =
|
|
8493
|
+
const validated = import_types30.RegistryFileSchema.parse(reg);
|
|
8259
8494
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
8260
8495
|
}
|
|
8261
8496
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -8340,7 +8575,7 @@ function pruneTtlMs() {
|
|
|
8340
8575
|
}
|
|
8341
8576
|
async function statPathStatus(p) {
|
|
8342
8577
|
try {
|
|
8343
|
-
const stat = await
|
|
8578
|
+
const stat = await import_node_fs27.promises.stat(p);
|
|
8344
8579
|
return stat.isDirectory() ? "present" : "unknown";
|
|
8345
8580
|
} catch (err) {
|
|
8346
8581
|
return err.code === "ENOENT" ? "gone" : "unknown";
|
|
@@ -8587,11 +8822,11 @@ function registerRoutes(scope, ctx) {
|
|
|
8587
8822
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
8588
8823
|
const parsed = [];
|
|
8589
8824
|
for (const c of candidates) {
|
|
8590
|
-
const r =
|
|
8825
|
+
const r = import_types31.DivergenceTypeSchema.safeParse(c);
|
|
8591
8826
|
if (!r.success) {
|
|
8592
8827
|
return reply.code(400).send({
|
|
8593
8828
|
error: `unknown divergence type "${c}"`,
|
|
8594
|
-
allowed:
|
|
8829
|
+
allowed: import_types31.DivergenceTypeSchema.options
|
|
8595
8830
|
});
|
|
8596
8831
|
}
|
|
8597
8832
|
parsed.push(r.data);
|
|
@@ -8842,7 +9077,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8842
9077
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
8843
9078
|
let violations = await log.readAll();
|
|
8844
9079
|
if (req.query.severity) {
|
|
8845
|
-
const sev =
|
|
9080
|
+
const sev = import_types31.PolicySeveritySchema.safeParse(req.query.severity);
|
|
8846
9081
|
if (!sev.success) {
|
|
8847
9082
|
return reply.code(400).send({
|
|
8848
9083
|
error: "invalid severity",
|
|
@@ -8881,7 +9116,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8881
9116
|
scope.post("/policies/check", async (req, reply) => {
|
|
8882
9117
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
8883
9118
|
if (!proj) return;
|
|
8884
|
-
const parsed =
|
|
9119
|
+
const parsed = import_types31.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
8885
9120
|
if (!parsed.success) {
|
|
8886
9121
|
return reply.code(400).send({
|
|
8887
9122
|
error: "invalid /policies/check body",
|
|
@@ -9143,8 +9378,8 @@ init_otel();
|
|
|
9143
9378
|
|
|
9144
9379
|
// src/daemon.ts
|
|
9145
9380
|
init_cjs_shims();
|
|
9146
|
-
var
|
|
9147
|
-
var
|
|
9381
|
+
var import_node_fs30 = require("fs");
|
|
9382
|
+
var import_node_path49 = __toESM(require("path"), 1);
|
|
9148
9383
|
var import_node_module = require("module");
|
|
9149
9384
|
init_otel();
|
|
9150
9385
|
|
|
@@ -9489,10 +9724,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
9489
9724
|
// src/connectors/supabase/map.ts
|
|
9490
9725
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
9491
9726
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
9492
|
-
function targetFromRestPath(
|
|
9493
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
9727
|
+
function targetFromRestPath(path58) {
|
|
9728
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path58);
|
|
9494
9729
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
9495
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
9730
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path58);
|
|
9496
9731
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
9497
9732
|
return null;
|
|
9498
9733
|
}
|
|
@@ -9595,19 +9830,19 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
9595
9830
|
|
|
9596
9831
|
// src/connectors/supabase/resolve.ts
|
|
9597
9832
|
init_cjs_shims();
|
|
9598
|
-
var
|
|
9833
|
+
var import_types33 = require("@neat.is/types");
|
|
9599
9834
|
function createSupabaseResolveTarget(graph, config) {
|
|
9600
9835
|
return (signal, _ctx) => {
|
|
9601
9836
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
9602
9837
|
return null;
|
|
9603
9838
|
}
|
|
9604
|
-
const subResourceId = (0,
|
|
9839
|
+
const subResourceId = (0, import_types33.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
9605
9840
|
if (graph.hasNode(subResourceId)) {
|
|
9606
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
9841
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types33.EdgeType.CALLS };
|
|
9607
9842
|
}
|
|
9608
|
-
const projectLevelId = (0,
|
|
9843
|
+
const projectLevelId = (0, import_types33.infraId)("supabase", config.nodeRef);
|
|
9609
9844
|
if (graph.hasNode(projectLevelId)) {
|
|
9610
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
9845
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types33.EdgeType.CALLS };
|
|
9611
9846
|
}
|
|
9612
9847
|
return null;
|
|
9613
9848
|
};
|
|
@@ -9665,7 +9900,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
9665
9900
|
|
|
9666
9901
|
// src/connectors/railway/index.ts
|
|
9667
9902
|
init_cjs_shims();
|
|
9668
|
-
var
|
|
9903
|
+
var import_types37 = require("@neat.is/types");
|
|
9669
9904
|
|
|
9670
9905
|
// src/connectors/railway/client.ts
|
|
9671
9906
|
init_cjs_shims();
|
|
@@ -9810,7 +10045,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
9810
10045
|
const out = [];
|
|
9811
10046
|
graph.forEachNode((_id, attrs) => {
|
|
9812
10047
|
const node = attrs;
|
|
9813
|
-
if (node.type !==
|
|
10048
|
+
if (node.type !== import_types37.NodeType.RouteNode) return;
|
|
9814
10049
|
const route = attrs;
|
|
9815
10050
|
if (route.service !== serviceName) return;
|
|
9816
10051
|
out.push({
|
|
@@ -9906,12 +10141,12 @@ function createRailwayResolveTarget(config) {
|
|
|
9906
10141
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
9907
10142
|
if (!serviceName) return null;
|
|
9908
10143
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
9909
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
10144
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types37.EdgeType.CALLS };
|
|
9910
10145
|
}
|
|
9911
10146
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
9912
10147
|
const peerName = config.serviceNameById[signal.targetName];
|
|
9913
10148
|
if (!peerName) return null;
|
|
9914
|
-
return { targetNodeId: (0,
|
|
10149
|
+
return { targetNodeId: (0, import_types37.serviceId)(peerName), serviceName, edgeType: import_types37.EdgeType.CONNECTS_TO };
|
|
9915
10150
|
}
|
|
9916
10151
|
return null;
|
|
9917
10152
|
};
|
|
@@ -10026,9 +10261,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
10026
10261
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
10027
10262
|
if (secondSep === -1) return null;
|
|
10028
10263
|
const method = rest.slice(0, secondSep);
|
|
10029
|
-
const
|
|
10030
|
-
if (!resourceName || !method || !
|
|
10031
|
-
return { resourceName, method, path:
|
|
10264
|
+
const path58 = rest.slice(secondSep + 1);
|
|
10265
|
+
if (!resourceName || !method || !path58) return null;
|
|
10266
|
+
return { resourceName, method, path: path58 };
|
|
10032
10267
|
}
|
|
10033
10268
|
function resourceNameFor(type, labels) {
|
|
10034
10269
|
if (!labels) return null;
|
|
@@ -10065,14 +10300,14 @@ function mapLogEntryToSignal(entry2) {
|
|
|
10065
10300
|
if (!req) return null;
|
|
10066
10301
|
if (!req.requestMethod) return null;
|
|
10067
10302
|
const method = req.requestMethod.toUpperCase();
|
|
10068
|
-
const
|
|
10069
|
-
if (
|
|
10303
|
+
const path58 = pathFromRequestUrl(req.requestUrl);
|
|
10304
|
+
if (path58 === null) return null;
|
|
10070
10305
|
const timestamp = entry2.timestamp;
|
|
10071
10306
|
if (!timestamp) return null;
|
|
10072
10307
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
10073
10308
|
return {
|
|
10074
10309
|
targetKind: resourceType,
|
|
10075
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
10310
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path58 }),
|
|
10076
10311
|
callCount: 1,
|
|
10077
10312
|
errorCount: isError ? 1 : 0,
|
|
10078
10313
|
lastObservedIso: timestamp
|
|
@@ -10089,7 +10324,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
10089
10324
|
|
|
10090
10325
|
// src/connectors/firebase/resolve.ts
|
|
10091
10326
|
init_cjs_shims();
|
|
10092
|
-
var
|
|
10327
|
+
var import_types38 = require("@neat.is/types");
|
|
10093
10328
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
10094
10329
|
switch (resourceType) {
|
|
10095
10330
|
case "cloud_function":
|
|
@@ -10104,7 +10339,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
10104
10339
|
const entries = [];
|
|
10105
10340
|
graph.forEachNode((_id, attrs) => {
|
|
10106
10341
|
const node = attrs;
|
|
10107
|
-
if (node.type !==
|
|
10342
|
+
if (node.type !== import_types38.NodeType.RouteNode) return;
|
|
10108
10343
|
const route = attrs;
|
|
10109
10344
|
if (route.service !== serviceName) return;
|
|
10110
10345
|
entries.push({
|
|
@@ -10136,7 +10371,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
10136
10371
|
return {
|
|
10137
10372
|
targetNodeId: match.routeNodeId,
|
|
10138
10373
|
serviceName,
|
|
10139
|
-
edgeType:
|
|
10374
|
+
edgeType: import_types38.EdgeType.CALLS
|
|
10140
10375
|
};
|
|
10141
10376
|
};
|
|
10142
10377
|
}
|
|
@@ -10163,7 +10398,7 @@ init_cjs_shims();
|
|
|
10163
10398
|
|
|
10164
10399
|
// src/connectors/cloudflare/connector.ts
|
|
10165
10400
|
init_cjs_shims();
|
|
10166
|
-
var
|
|
10401
|
+
var import_types40 = require("@neat.is/types");
|
|
10167
10402
|
|
|
10168
10403
|
// src/connectors/cloudflare/client.ts
|
|
10169
10404
|
init_cjs_shims();
|
|
@@ -10213,7 +10448,14 @@ async function queryWorkerInvocations(ctx, config, window, fetchImpl = fetch) {
|
|
|
10213
10448
|
const message = payload.errors?.map((e) => e.message).join("; ") || "unknown error";
|
|
10214
10449
|
throw new Error(`cloudflare connector: telemetry query returned an error (${message})`);
|
|
10215
10450
|
}
|
|
10216
|
-
|
|
10451
|
+
const events = payload.result?.events?.events;
|
|
10452
|
+
if (events === void 0) {
|
|
10453
|
+
console.warn(
|
|
10454
|
+
"[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"
|
|
10455
|
+
);
|
|
10456
|
+
return [];
|
|
10457
|
+
}
|
|
10458
|
+
return events;
|
|
10217
10459
|
}
|
|
10218
10460
|
|
|
10219
10461
|
// src/connectors/cloudflare/map.ts
|
|
@@ -10244,6 +10486,13 @@ function parseHttpMethodFromTrigger(trigger) {
|
|
|
10244
10486
|
const method = token.toUpperCase();
|
|
10245
10487
|
return HTTP_METHODS.has(method) ? method : null;
|
|
10246
10488
|
}
|
|
10489
|
+
function parsePathFromTrigger(trigger) {
|
|
10490
|
+
const trimmed = trigger.trim();
|
|
10491
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
10492
|
+
if (spaceIdx === -1) return void 0;
|
|
10493
|
+
const rest = trimmed.slice(spaceIdx + 1).trim();
|
|
10494
|
+
return rest.length > 0 ? rest : void 0;
|
|
10495
|
+
}
|
|
10247
10496
|
var ERROR_STATUS_THRESHOLD3 = 500;
|
|
10248
10497
|
function mapEventToSignal(event) {
|
|
10249
10498
|
const metadata = event.$metadata;
|
|
@@ -10256,6 +10505,7 @@ function mapEventToSignal(event) {
|
|
|
10256
10505
|
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return null;
|
|
10257
10506
|
const statusCode = metadata?.statusCode;
|
|
10258
10507
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
10508
|
+
const path58 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
10259
10509
|
return {
|
|
10260
10510
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
10261
10511
|
targetName: scriptName,
|
|
@@ -10263,6 +10513,7 @@ function mapEventToSignal(event) {
|
|
|
10263
10513
|
errorCount: isError ? 1 : 0,
|
|
10264
10514
|
lastObservedIso: new Date(timestampMs).toISOString(),
|
|
10265
10515
|
method,
|
|
10516
|
+
...path58 ? { path: path58 } : {},
|
|
10266
10517
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
10267
10518
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
10268
10519
|
};
|
|
@@ -10297,15 +10548,63 @@ var CloudflareConnector = class {
|
|
|
10297
10548
|
return signals;
|
|
10298
10549
|
}
|
|
10299
10550
|
};
|
|
10300
|
-
function
|
|
10551
|
+
function findTaggedWorkerFileNode(graph, workerName) {
|
|
10552
|
+
let found = null;
|
|
10553
|
+
graph.forEachNode((id, attrs) => {
|
|
10554
|
+
if (found) return;
|
|
10555
|
+
const a = attrs;
|
|
10556
|
+
if (a.type === import_types40.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
10557
|
+
found = id;
|
|
10558
|
+
}
|
|
10559
|
+
});
|
|
10560
|
+
return found;
|
|
10561
|
+
}
|
|
10562
|
+
function findMatchingRouteNode(graph, serviceName, method, path58) {
|
|
10563
|
+
const normalizedPath = normalizePathTemplate(path58);
|
|
10564
|
+
let found = null;
|
|
10565
|
+
graph.forEachNode((id, attrs) => {
|
|
10566
|
+
if (found) return;
|
|
10567
|
+
const a = attrs;
|
|
10568
|
+
if (a.type !== import_types40.NodeType.RouteNode || a.service !== serviceName) return;
|
|
10569
|
+
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
10570
|
+
const routeMethod = (a.method ?? "").toUpperCase();
|
|
10571
|
+
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
10572
|
+
found = id;
|
|
10573
|
+
});
|
|
10574
|
+
return found;
|
|
10575
|
+
}
|
|
10576
|
+
function createCloudflareResolveTarget(config, graph) {
|
|
10301
10577
|
return (signal) => {
|
|
10302
10578
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
10303
|
-
const
|
|
10304
|
-
|
|
10579
|
+
const scriptName = signal.targetName;
|
|
10580
|
+
const { method, path: path58 } = signal;
|
|
10581
|
+
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
10582
|
+
if (!method || !path58) return wholeFileId;
|
|
10583
|
+
return findMatchingRouteNode(graph, serviceName, method, path58) ?? wholeFileId;
|
|
10584
|
+
};
|
|
10585
|
+
const mapping = config.workers?.[scriptName];
|
|
10586
|
+
if (mapping) {
|
|
10587
|
+
const wholeFileId = (0, import_types40.fileId)(mapping.service, mapping.entryFile);
|
|
10588
|
+
return {
|
|
10589
|
+
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
10590
|
+
serviceName: mapping.service,
|
|
10591
|
+
edgeType: import_types40.EdgeType.CALLS
|
|
10592
|
+
};
|
|
10593
|
+
}
|
|
10594
|
+
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
10595
|
+
if (taggedFileId) {
|
|
10596
|
+
const fileNode = graph.getNodeAttributes(taggedFileId);
|
|
10597
|
+
return {
|
|
10598
|
+
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
10599
|
+
serviceName: fileNode.service,
|
|
10600
|
+
edgeType: import_types40.EdgeType.CALLS
|
|
10601
|
+
};
|
|
10602
|
+
}
|
|
10305
10603
|
return {
|
|
10306
|
-
targetNodeId: (0,
|
|
10307
|
-
serviceName:
|
|
10308
|
-
edgeType:
|
|
10604
|
+
targetNodeId: (0, import_types40.infraId)("cloudflare-worker", scriptName),
|
|
10605
|
+
serviceName: scriptName,
|
|
10606
|
+
edgeType: import_types40.EdgeType.CALLS,
|
|
10607
|
+
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
10309
10608
|
};
|
|
10310
10609
|
};
|
|
10311
10610
|
}
|
|
@@ -10313,8 +10612,8 @@ function createCloudflareResolveTarget(config) {
|
|
|
10313
10612
|
// src/connectors-config.ts
|
|
10314
10613
|
init_cjs_shims();
|
|
10315
10614
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10316
|
-
var
|
|
10317
|
-
var
|
|
10615
|
+
var import_node_path47 = __toESM(require("path"), 1);
|
|
10616
|
+
var import_node_fs28 = require("fs");
|
|
10318
10617
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
10319
10618
|
var EnvRefUnsetError = class extends Error {
|
|
10320
10619
|
ref;
|
|
@@ -10328,17 +10627,17 @@ var EnvRefUnsetError = class extends Error {
|
|
|
10328
10627
|
};
|
|
10329
10628
|
function neatHome2() {
|
|
10330
10629
|
const override = process.env.NEAT_HOME;
|
|
10331
|
-
if (override && override.length > 0) return
|
|
10332
|
-
return
|
|
10630
|
+
if (override && override.length > 0) return import_node_path47.default.resolve(override);
|
|
10631
|
+
return import_node_path47.default.join(import_node_os4.default.homedir(), ".neat");
|
|
10333
10632
|
}
|
|
10334
10633
|
function connectorsConfigPath(home = neatHome2()) {
|
|
10335
|
-
return
|
|
10634
|
+
return import_node_path47.default.join(home, "connectors.json");
|
|
10336
10635
|
}
|
|
10337
10636
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
10338
10637
|
async function warnIfModeLooserThan0600(file) {
|
|
10339
10638
|
if (process.platform === "win32") return;
|
|
10340
10639
|
try {
|
|
10341
|
-
const stat = await
|
|
10640
|
+
const stat = await import_node_fs28.promises.stat(file);
|
|
10342
10641
|
if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {
|
|
10343
10642
|
const mode = (stat.mode & 511).toString(8).padStart(3, "0");
|
|
10344
10643
|
console.warn(
|
|
@@ -10352,7 +10651,7 @@ async function readConnectorsConfig(home = neatHome2()) {
|
|
|
10352
10651
|
const file = connectorsConfigPath(home);
|
|
10353
10652
|
let raw;
|
|
10354
10653
|
try {
|
|
10355
|
-
raw = await
|
|
10654
|
+
raw = await import_node_fs28.promises.readFile(file, "utf8");
|
|
10356
10655
|
} catch (err) {
|
|
10357
10656
|
if (err.code === "ENOENT") {
|
|
10358
10657
|
return { version: CONNECTORS_CONFIG_VERSION, connectors: [] };
|
|
@@ -10460,15 +10759,15 @@ function resolveRef(value, env) {
|
|
|
10460
10759
|
var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
|
|
10461
10760
|
var CONNECTORS_LOCK_RETRY_MS = 50;
|
|
10462
10761
|
function connectorsConfigLockPath(home = neatHome2()) {
|
|
10463
|
-
return
|
|
10762
|
+
return import_node_path47.default.join(home, "connectors.json.lock");
|
|
10464
10763
|
}
|
|
10465
10764
|
function isEnvRef(value) {
|
|
10466
10765
|
return value.length > 1 && value.startsWith("$");
|
|
10467
10766
|
}
|
|
10468
10767
|
async function writeConfigAtomically0600(file, contents) {
|
|
10469
|
-
await
|
|
10768
|
+
await import_node_fs28.promises.mkdir(import_node_path47.default.dirname(file), { recursive: true });
|
|
10470
10769
|
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
10471
|
-
const fd = await
|
|
10770
|
+
const fd = await import_node_fs28.promises.open(tmp, "w", 384);
|
|
10472
10771
|
try {
|
|
10473
10772
|
await fd.writeFile(contents, "utf8");
|
|
10474
10773
|
await fd.chmod(384);
|
|
@@ -10476,14 +10775,14 @@ async function writeConfigAtomically0600(file, contents) {
|
|
|
10476
10775
|
} finally {
|
|
10477
10776
|
await fd.close();
|
|
10478
10777
|
}
|
|
10479
|
-
await
|
|
10778
|
+
await import_node_fs28.promises.rename(tmp, file);
|
|
10480
10779
|
}
|
|
10481
10780
|
async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
|
|
10482
10781
|
const deadline = Date.now() + timeoutMs;
|
|
10483
|
-
await
|
|
10782
|
+
await import_node_fs28.promises.mkdir(import_node_path47.default.dirname(lockPath), { recursive: true });
|
|
10484
10783
|
for (; ; ) {
|
|
10485
10784
|
try {
|
|
10486
|
-
const fd = await
|
|
10785
|
+
const fd = await import_node_fs28.promises.open(lockPath, "wx");
|
|
10487
10786
|
try {
|
|
10488
10787
|
await fd.writeFile(`${process.pid}
|
|
10489
10788
|
`, "utf8");
|
|
@@ -10503,7 +10802,7 @@ async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEO
|
|
|
10503
10802
|
}
|
|
10504
10803
|
}
|
|
10505
10804
|
async function releaseConnectorsLock(lockPath) {
|
|
10506
|
-
await
|
|
10805
|
+
await import_node_fs28.promises.unlink(lockPath).catch(() => {
|
|
10507
10806
|
});
|
|
10508
10807
|
}
|
|
10509
10808
|
async function withConnectorsLock(home, fn) {
|
|
@@ -10695,12 +10994,16 @@ var PROVIDER_DISPATCH = {
|
|
|
10695
10994
|
provider: "cloudflare",
|
|
10696
10995
|
primaryCredentialKey: "apiToken",
|
|
10697
10996
|
requiredCredentialFields: ["apiToken"],
|
|
10698
|
-
|
|
10699
|
-
|
|
10997
|
+
// `workers` dropped as a required field (ADR-133) — the mapping is now
|
|
10998
|
+
// derived from the extracted graph's platform tag; an `options.workers`
|
|
10999
|
+
// entry still works as an explicit override
|
|
11000
|
+
// (CloudflareConnectorConfig.workers).
|
|
11001
|
+
requiredOptionFields: ["accountId"],
|
|
11002
|
+
build(graph, options) {
|
|
10700
11003
|
const config = options;
|
|
10701
11004
|
return {
|
|
10702
11005
|
connector: new CloudflareConnector(config),
|
|
10703
|
-
resolveTarget: createCloudflareResolveTarget(config)
|
|
11006
|
+
resolveTarget: createCloudflareResolveTarget(config, graph)
|
|
10704
11007
|
};
|
|
10705
11008
|
},
|
|
10706
11009
|
// GET /user/tokens/verify — Cloudflare's own purpose-built "is this API
|
|
@@ -10771,33 +11074,33 @@ init_auth();
|
|
|
10771
11074
|
|
|
10772
11075
|
// src/unrouted.ts
|
|
10773
11076
|
init_cjs_shims();
|
|
10774
|
-
var
|
|
10775
|
-
var
|
|
11077
|
+
var import_node_fs29 = require("fs");
|
|
11078
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
10776
11079
|
|
|
10777
11080
|
// src/daemon.ts
|
|
10778
|
-
var
|
|
11081
|
+
var import_types43 = require("@neat.is/types");
|
|
10779
11082
|
function daemonJsonPath(scanPath) {
|
|
10780
|
-
return
|
|
11083
|
+
return import_node_path49.default.join(scanPath, "neat-out", "daemon.json");
|
|
10781
11084
|
}
|
|
10782
11085
|
function daemonsDiscoveryDir(home) {
|
|
10783
11086
|
const base = home && home.length > 0 ? home : neatHomeFromEnv();
|
|
10784
|
-
return
|
|
11087
|
+
return import_node_path49.default.join(base, "daemons");
|
|
10785
11088
|
}
|
|
10786
11089
|
function daemonDiscoveryPath(project, home) {
|
|
10787
|
-
return
|
|
11090
|
+
return import_node_path49.default.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`);
|
|
10788
11091
|
}
|
|
10789
11092
|
function sanitizeDiscoveryName(project) {
|
|
10790
11093
|
return project.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
10791
11094
|
}
|
|
10792
11095
|
function neatHomeFromEnv() {
|
|
10793
11096
|
const env = process.env.NEAT_HOME;
|
|
10794
|
-
if (env && env.length > 0) return
|
|
11097
|
+
if (env && env.length > 0) return import_node_path49.default.resolve(env);
|
|
10795
11098
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
10796
|
-
return
|
|
11099
|
+
return import_node_path49.default.join(home, ".neat");
|
|
10797
11100
|
}
|
|
10798
11101
|
async function readDaemonRecord(scanPath) {
|
|
10799
11102
|
try {
|
|
10800
|
-
const raw = await
|
|
11103
|
+
const raw = await import_node_fs30.promises.readFile(daemonJsonPath(scanPath), "utf8");
|
|
10801
11104
|
const parsed = JSON.parse(raw);
|
|
10802
11105
|
if (typeof parsed.project === "string" && parsed.ports && typeof parsed.ports.rest === "number" && typeof parsed.ports.otlp === "number" && typeof parsed.ports.web === "number") {
|
|
10803
11106
|
return parsed;
|
|
@@ -10837,7 +11140,7 @@ async function clearDaemonRecord(record, home) {
|
|
|
10837
11140
|
} catch {
|
|
10838
11141
|
}
|
|
10839
11142
|
try {
|
|
10840
|
-
await
|
|
11143
|
+
await import_node_fs30.promises.unlink(daemonDiscoveryPath(record.project, home));
|
|
10841
11144
|
} catch {
|
|
10842
11145
|
}
|
|
10843
11146
|
}
|
|
@@ -10863,8 +11166,8 @@ init_otel_grpc();
|
|
|
10863
11166
|
|
|
10864
11167
|
// src/search.ts
|
|
10865
11168
|
init_cjs_shims();
|
|
10866
|
-
var
|
|
10867
|
-
var
|
|
11169
|
+
var import_node_fs31 = require("fs");
|
|
11170
|
+
var import_node_path50 = __toESM(require("path"), 1);
|
|
10868
11171
|
var import_node_crypto4 = require("crypto");
|
|
10869
11172
|
var DEFAULT_LIMIT = 10;
|
|
10870
11173
|
var NOMIC_DIM = 768;
|
|
@@ -11018,7 +11321,7 @@ async function pickEmbedder() {
|
|
|
11018
11321
|
}
|
|
11019
11322
|
async function readCache(cachePath) {
|
|
11020
11323
|
try {
|
|
11021
|
-
const raw = await
|
|
11324
|
+
const raw = await import_node_fs31.promises.readFile(cachePath, "utf8");
|
|
11022
11325
|
const parsed = JSON.parse(raw);
|
|
11023
11326
|
if (parsed.version !== 1) return null;
|
|
11024
11327
|
return parsed;
|
|
@@ -11027,8 +11330,8 @@ async function readCache(cachePath) {
|
|
|
11027
11330
|
}
|
|
11028
11331
|
}
|
|
11029
11332
|
async function writeCache(cachePath, cache) {
|
|
11030
|
-
await
|
|
11031
|
-
await
|
|
11333
|
+
await import_node_fs31.promises.mkdir(import_node_path50.default.dirname(cachePath), { recursive: true });
|
|
11334
|
+
await import_node_fs31.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
11032
11335
|
}
|
|
11033
11336
|
var VectorIndex = class {
|
|
11034
11337
|
constructor(embedder, cachePath) {
|
|
@@ -11185,8 +11488,8 @@ var ALL_PHASES = [
|
|
|
11185
11488
|
];
|
|
11186
11489
|
function classifyChange(relPath) {
|
|
11187
11490
|
const phases = /* @__PURE__ */ new Set();
|
|
11188
|
-
const base =
|
|
11189
|
-
const segments = relPath.split(
|
|
11491
|
+
const base = import_node_path51.default.basename(relPath).toLowerCase();
|
|
11492
|
+
const segments = relPath.split(import_node_path51.default.sep).map((s) => s.toLowerCase());
|
|
11190
11493
|
if (base === "package.json" || base === "requirements.txt" || base === "pyproject.toml" || base === "setup.py") {
|
|
11191
11494
|
phases.add("services");
|
|
11192
11495
|
phases.add("aliases");
|
|
@@ -11307,16 +11610,16 @@ function countWatchableDirs(scanPath, limit) {
|
|
|
11307
11610
|
if (count >= limit) return;
|
|
11308
11611
|
let entries;
|
|
11309
11612
|
try {
|
|
11310
|
-
entries =
|
|
11613
|
+
entries = import_node_fs32.default.readdirSync(dir, { withFileTypes: true });
|
|
11311
11614
|
} catch {
|
|
11312
11615
|
return;
|
|
11313
11616
|
}
|
|
11314
11617
|
for (const e of entries) {
|
|
11315
11618
|
if (count >= limit) return;
|
|
11316
11619
|
if (!e.isDirectory()) continue;
|
|
11317
|
-
if (IGNORED_WATCH_PATHS.some((re) => re.test(
|
|
11620
|
+
if (IGNORED_WATCH_PATHS.some((re) => re.test(import_node_path51.default.join(dir, e.name) + import_node_path51.default.sep))) continue;
|
|
11318
11621
|
count++;
|
|
11319
|
-
if (depth < 2) visit(
|
|
11622
|
+
if (depth < 2) visit(import_node_path51.default.join(dir, e.name), depth + 1);
|
|
11320
11623
|
}
|
|
11321
11624
|
};
|
|
11322
11625
|
visit(scanPath, 0);
|
|
@@ -11334,8 +11637,8 @@ async function startWatch(graph, opts) {
|
|
|
11334
11637
|
const projectName = opts.project ?? DEFAULT_PROJECT;
|
|
11335
11638
|
await loadGraphFromDisk(graph, opts.outPath);
|
|
11336
11639
|
const detachEventBus = attachGraphToEventBus(graph, { project: projectName });
|
|
11337
|
-
const policyFilePath =
|
|
11338
|
-
const policyViolationsPath =
|
|
11640
|
+
const policyFilePath = import_node_path51.default.join(opts.scanPath, "policy.json");
|
|
11641
|
+
const policyViolationsPath = import_node_path51.default.join(import_node_path51.default.dirname(opts.outPath), "policy-violations.ndjson");
|
|
11339
11642
|
let policies = [];
|
|
11340
11643
|
try {
|
|
11341
11644
|
policies = await loadPolicyFile(policyFilePath);
|
|
@@ -11386,7 +11689,7 @@ async function startWatch(graph, opts) {
|
|
|
11386
11689
|
assertBindAuthority(host, auth.authToken);
|
|
11387
11690
|
const port = opts.port ?? 8080;
|
|
11388
11691
|
const otelPort = opts.otelPort ?? 4318;
|
|
11389
|
-
const cachePath = opts.embeddingsCachePath ??
|
|
11692
|
+
const cachePath = opts.embeddingsCachePath ?? import_node_path51.default.join(import_node_path51.default.dirname(opts.outPath), "embeddings.json");
|
|
11390
11693
|
let searchIndex;
|
|
11391
11694
|
try {
|
|
11392
11695
|
searchIndex = await buildSearchIndex(graph, { cachePath });
|
|
@@ -11404,7 +11707,7 @@ async function startWatch(graph, opts) {
|
|
|
11404
11707
|
// Paths are derived from the explicit options the watch caller passes
|
|
11405
11708
|
// — pathsForProject is only used to fill in the embeddings/snapshot
|
|
11406
11709
|
// fields so the registry shape is complete.
|
|
11407
|
-
...pathsForProject(projectName,
|
|
11710
|
+
...pathsForProject(projectName, import_node_path51.default.dirname(opts.outPath)),
|
|
11408
11711
|
snapshotPath: opts.outPath,
|
|
11409
11712
|
errorsPath: opts.errorsPath,
|
|
11410
11713
|
staleEventsPath: opts.staleEventsPath
|
|
@@ -11522,9 +11825,9 @@ async function startWatch(graph, opts) {
|
|
|
11522
11825
|
};
|
|
11523
11826
|
const onPath = (absPath) => {
|
|
11524
11827
|
if (shouldIgnore(absPath)) return;
|
|
11525
|
-
const rel =
|
|
11828
|
+
const rel = import_node_path51.default.relative(opts.scanPath, absPath);
|
|
11526
11829
|
if (!rel || rel.startsWith("..")) return;
|
|
11527
|
-
pendingPaths.add(rel.split(
|
|
11830
|
+
pendingPaths.add(rel.split(import_node_path51.default.sep).join("/"));
|
|
11528
11831
|
const phases = classifyChange(rel);
|
|
11529
11832
|
if (phases.size === 0) {
|
|
11530
11833
|
for (const p of ALL_PHASES) pending.add(p);
|
|
@@ -11580,8 +11883,8 @@ async function startWatch(graph, opts) {
|
|
|
11580
11883
|
|
|
11581
11884
|
// src/deploy/detect.ts
|
|
11582
11885
|
init_cjs_shims();
|
|
11583
|
-
var
|
|
11584
|
-
var
|
|
11886
|
+
var import_node_fs33 = require("fs");
|
|
11887
|
+
var import_node_path52 = __toESM(require("path"), 1);
|
|
11585
11888
|
var import_node_child_process2 = require("child_process");
|
|
11586
11889
|
var import_node_crypto5 = require("crypto");
|
|
11587
11890
|
function generateToken() {
|
|
@@ -11681,21 +11984,21 @@ async function runDeploy(opts = {}) {
|
|
|
11681
11984
|
const token = generateToken();
|
|
11682
11985
|
switch (substrate) {
|
|
11683
11986
|
case "docker-compose": {
|
|
11684
|
-
const artifactPath =
|
|
11987
|
+
const artifactPath = import_node_path52.default.join(cwd, "docker-compose.neat.yml");
|
|
11685
11988
|
const contents = emitDockerCompose(cwd);
|
|
11686
|
-
await
|
|
11989
|
+
await import_node_fs33.promises.writeFile(artifactPath, contents, "utf8");
|
|
11687
11990
|
return {
|
|
11688
11991
|
substrate,
|
|
11689
11992
|
artifactPath,
|
|
11690
11993
|
token,
|
|
11691
11994
|
contents,
|
|
11692
|
-
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${
|
|
11995
|
+
startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${import_node_path52.default.basename(artifactPath)} up -d`
|
|
11693
11996
|
};
|
|
11694
11997
|
}
|
|
11695
11998
|
case "systemd": {
|
|
11696
|
-
const artifactPath =
|
|
11999
|
+
const artifactPath = import_node_path52.default.join(cwd, "neat.service");
|
|
11697
12000
|
const contents = emitSystemdUnit(cwd);
|
|
11698
|
-
await
|
|
12001
|
+
await import_node_fs33.promises.writeFile(artifactPath, contents, "utf8");
|
|
11699
12002
|
return {
|
|
11700
12003
|
substrate,
|
|
11701
12004
|
artifactPath,
|
|
@@ -11728,8 +12031,8 @@ init_cjs_shims();
|
|
|
11728
12031
|
|
|
11729
12032
|
// src/installers/javascript.ts
|
|
11730
12033
|
init_cjs_shims();
|
|
11731
|
-
var
|
|
11732
|
-
var
|
|
12034
|
+
var import_node_fs34 = require("fs");
|
|
12035
|
+
var import_node_path53 = __toESM(require("path"), 1);
|
|
11733
12036
|
var import_semver2 = __toESM(require("semver"), 1);
|
|
11734
12037
|
|
|
11735
12038
|
// src/installers/templates.ts
|
|
@@ -12344,15 +12647,15 @@ var OTEL_ENV = {
|
|
|
12344
12647
|
value: "http://localhost:4318/projects/<project>/v1/traces"
|
|
12345
12648
|
};
|
|
12346
12649
|
function serviceNodeName(pkg, serviceDir) {
|
|
12347
|
-
return pkg.name ??
|
|
12650
|
+
return pkg.name ?? import_node_path53.default.basename(serviceDir);
|
|
12348
12651
|
}
|
|
12349
12652
|
function projectToken(pkg, serviceDir, project) {
|
|
12350
12653
|
if (project && project.length > 0) return project;
|
|
12351
|
-
return pkg.name ??
|
|
12654
|
+
return pkg.name ?? import_node_path53.default.basename(serviceDir);
|
|
12352
12655
|
}
|
|
12353
12656
|
async function readJsonFile(p) {
|
|
12354
12657
|
try {
|
|
12355
|
-
const raw = await
|
|
12658
|
+
const raw = await import_node_fs34.promises.readFile(p, "utf8");
|
|
12356
12659
|
return JSON.parse(raw);
|
|
12357
12660
|
} catch {
|
|
12358
12661
|
return null;
|
|
@@ -12361,16 +12664,16 @@ async function readJsonFile(p) {
|
|
|
12361
12664
|
async function detectRuntimeKind(pkgRoot, pkg) {
|
|
12362
12665
|
const deps = allDeps(pkg);
|
|
12363
12666
|
if ("react-native" in deps || "expo" in deps) return "react-native";
|
|
12364
|
-
const appJson = await readJsonFile(
|
|
12667
|
+
const appJson = await readJsonFile(import_node_path53.default.join(pkgRoot, "app.json"));
|
|
12365
12668
|
if (appJson && typeof appJson === "object" && "expo" in appJson) {
|
|
12366
12669
|
return "react-native";
|
|
12367
12670
|
}
|
|
12368
|
-
if (await exists3(
|
|
12671
|
+
if (await exists3(import_node_path53.default.join(pkgRoot, "vite.config.js")) || await exists3(import_node_path53.default.join(pkgRoot, "vite.config.ts")) || await exists3(import_node_path53.default.join(pkgRoot, "vite.config.mjs")) || "vite" in deps) {
|
|
12369
12672
|
return "browser-bundle";
|
|
12370
12673
|
}
|
|
12371
|
-
if (await exists3(
|
|
12372
|
-
if (await exists3(
|
|
12373
|
-
if (await exists3(
|
|
12674
|
+
if (await exists3(import_node_path53.default.join(pkgRoot, "wrangler.toml"))) return "cloudflare-workers";
|
|
12675
|
+
if (await exists3(import_node_path53.default.join(pkgRoot, "bun.lockb"))) return "bun";
|
|
12676
|
+
if (await exists3(import_node_path53.default.join(pkgRoot, "deno.json")) || await exists3(import_node_path53.default.join(pkgRoot, "deno.lock"))) {
|
|
12374
12677
|
return "deno";
|
|
12375
12678
|
}
|
|
12376
12679
|
const engines = pkg.engines ?? {};
|
|
@@ -12379,7 +12682,7 @@ async function detectRuntimeKind(pkgRoot, pkg) {
|
|
|
12379
12682
|
}
|
|
12380
12683
|
async function readPackageJson2(serviceDir) {
|
|
12381
12684
|
try {
|
|
12382
|
-
const raw = await
|
|
12685
|
+
const raw = await import_node_fs34.promises.readFile(import_node_path53.default.join(serviceDir, "package.json"), "utf8");
|
|
12383
12686
|
return JSON.parse(raw);
|
|
12384
12687
|
} catch {
|
|
12385
12688
|
return null;
|
|
@@ -12387,7 +12690,7 @@ async function readPackageJson2(serviceDir) {
|
|
|
12387
12690
|
}
|
|
12388
12691
|
async function exists3(p) {
|
|
12389
12692
|
try {
|
|
12390
|
-
await
|
|
12693
|
+
await import_node_fs34.promises.stat(p);
|
|
12391
12694
|
return true;
|
|
12392
12695
|
} catch {
|
|
12393
12696
|
return false;
|
|
@@ -12395,7 +12698,7 @@ async function exists3(p) {
|
|
|
12395
12698
|
}
|
|
12396
12699
|
async function readFileMaybe(p) {
|
|
12397
12700
|
try {
|
|
12398
|
-
return await
|
|
12701
|
+
return await import_node_fs34.promises.readFile(p, "utf8");
|
|
12399
12702
|
} catch {
|
|
12400
12703
|
return null;
|
|
12401
12704
|
}
|
|
@@ -12423,7 +12726,7 @@ function needsVersionUpgrade(installed, expected) {
|
|
|
12423
12726
|
var NEXT_CONFIG_CANDIDATES = ["next.config.js", "next.config.ts", "next.config.mjs"];
|
|
12424
12727
|
async function findNextConfig(serviceDir) {
|
|
12425
12728
|
for (const name of NEXT_CONFIG_CANDIDATES) {
|
|
12426
|
-
const candidate =
|
|
12729
|
+
const candidate = import_node_path53.default.join(serviceDir, name);
|
|
12427
12730
|
if (await exists3(candidate)) return candidate;
|
|
12428
12731
|
}
|
|
12429
12732
|
return null;
|
|
@@ -12492,7 +12795,7 @@ function hasRemixDependency(pkg) {
|
|
|
12492
12795
|
}
|
|
12493
12796
|
async function findRemixEntry(serviceDir) {
|
|
12494
12797
|
for (const rel of REMIX_ENTRY_CANDIDATES) {
|
|
12495
|
-
const candidate =
|
|
12798
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
12496
12799
|
if (await exists3(candidate)) return candidate;
|
|
12497
12800
|
}
|
|
12498
12801
|
return null;
|
|
@@ -12504,14 +12807,14 @@ function hasSvelteKitDependency(pkg) {
|
|
|
12504
12807
|
}
|
|
12505
12808
|
async function findSvelteKitHooks(serviceDir) {
|
|
12506
12809
|
for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {
|
|
12507
|
-
const candidate =
|
|
12810
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
12508
12811
|
if (await exists3(candidate)) return candidate;
|
|
12509
12812
|
}
|
|
12510
12813
|
return null;
|
|
12511
12814
|
}
|
|
12512
12815
|
async function findSvelteKitConfig(serviceDir) {
|
|
12513
12816
|
for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {
|
|
12514
|
-
const candidate =
|
|
12817
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
12515
12818
|
if (await exists3(candidate)) return candidate;
|
|
12516
12819
|
}
|
|
12517
12820
|
return null;
|
|
@@ -12522,7 +12825,7 @@ function hasNuxtDependency(pkg) {
|
|
|
12522
12825
|
}
|
|
12523
12826
|
async function findNuxtConfig(serviceDir) {
|
|
12524
12827
|
for (const name of NUXT_CONFIG_CANDIDATES) {
|
|
12525
|
-
const candidate =
|
|
12828
|
+
const candidate = import_node_path53.default.join(serviceDir, name);
|
|
12526
12829
|
if (await exists3(candidate)) return candidate;
|
|
12527
12830
|
}
|
|
12528
12831
|
return null;
|
|
@@ -12533,7 +12836,7 @@ function hasAstroDependency(pkg) {
|
|
|
12533
12836
|
}
|
|
12534
12837
|
async function findAstroConfig(serviceDir) {
|
|
12535
12838
|
for (const name of ASTRO_CONFIG_CANDIDATES) {
|
|
12536
|
-
const candidate =
|
|
12839
|
+
const candidate = import_node_path53.default.join(serviceDir, name);
|
|
12537
12840
|
if (await exists3(candidate)) return candidate;
|
|
12538
12841
|
}
|
|
12539
12842
|
return null;
|
|
@@ -12547,7 +12850,7 @@ function parseNextMajor(range) {
|
|
|
12547
12850
|
return Number.isFinite(n) ? n : null;
|
|
12548
12851
|
}
|
|
12549
12852
|
async function isTypeScriptProject(serviceDir) {
|
|
12550
|
-
return exists3(
|
|
12853
|
+
return exists3(import_node_path53.default.join(serviceDir, "tsconfig.json"));
|
|
12551
12854
|
}
|
|
12552
12855
|
var INDEX_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs", ".cjs"];
|
|
12553
12856
|
var INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`);
|
|
@@ -12596,7 +12899,7 @@ function entryFromScript(script) {
|
|
|
12596
12899
|
}
|
|
12597
12900
|
async function resolveEntry(serviceDir, pkg) {
|
|
12598
12901
|
if (typeof pkg.main === "string" && pkg.main.length > 0) {
|
|
12599
|
-
const candidate =
|
|
12902
|
+
const candidate = import_node_path53.default.resolve(serviceDir, pkg.main);
|
|
12600
12903
|
if (await exists3(candidate)) return candidate;
|
|
12601
12904
|
}
|
|
12602
12905
|
if (pkg.bin) {
|
|
@@ -12610,40 +12913,40 @@ async function resolveEntry(serviceDir, pkg) {
|
|
|
12610
12913
|
if (typeof first === "string") binEntry = first;
|
|
12611
12914
|
}
|
|
12612
12915
|
if (binEntry) {
|
|
12613
|
-
const candidate =
|
|
12916
|
+
const candidate = import_node_path53.default.resolve(serviceDir, binEntry);
|
|
12614
12917
|
if (await exists3(candidate)) return candidate;
|
|
12615
12918
|
}
|
|
12616
12919
|
}
|
|
12617
12920
|
const startEntry = entryFromScript(pkg.scripts?.start);
|
|
12618
12921
|
if (startEntry) {
|
|
12619
|
-
const candidate =
|
|
12922
|
+
const candidate = import_node_path53.default.resolve(serviceDir, startEntry);
|
|
12620
12923
|
if (await exists3(candidate)) return candidate;
|
|
12621
12924
|
}
|
|
12622
12925
|
const devEntry = entryFromScript(pkg.scripts?.dev);
|
|
12623
12926
|
if (devEntry) {
|
|
12624
|
-
const candidate =
|
|
12927
|
+
const candidate = import_node_path53.default.resolve(serviceDir, devEntry);
|
|
12625
12928
|
if (await exists3(candidate)) return candidate;
|
|
12626
12929
|
}
|
|
12627
12930
|
for (const rel of SRC_INDEX_CANDIDATES) {
|
|
12628
|
-
const candidate =
|
|
12931
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
12629
12932
|
if (await exists3(candidate)) return candidate;
|
|
12630
12933
|
}
|
|
12631
12934
|
for (const rel of SRC_NAMED_CANDIDATES) {
|
|
12632
|
-
const candidate =
|
|
12935
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
12633
12936
|
if (await exists3(candidate)) return candidate;
|
|
12634
12937
|
}
|
|
12635
12938
|
for (const rel of ROOT_NAMED_CANDIDATES) {
|
|
12636
|
-
const candidate =
|
|
12939
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
12637
12940
|
if (await exists3(candidate)) return candidate;
|
|
12638
12941
|
}
|
|
12639
12942
|
for (const name of INDEX_CANDIDATES) {
|
|
12640
|
-
const candidate =
|
|
12943
|
+
const candidate = import_node_path53.default.join(serviceDir, name);
|
|
12641
12944
|
if (await exists3(candidate)) return candidate;
|
|
12642
12945
|
}
|
|
12643
12946
|
return null;
|
|
12644
12947
|
}
|
|
12645
12948
|
function dispatchEntry(entryFile, pkg) {
|
|
12646
|
-
const ext =
|
|
12949
|
+
const ext = import_node_path53.default.extname(entryFile).toLowerCase();
|
|
12647
12950
|
if (ext === ".ts" || ext === ".tsx") return "ts";
|
|
12648
12951
|
if (ext === ".mjs") return "esm";
|
|
12649
12952
|
if (ext === ".cjs") return "cjs";
|
|
@@ -12660,9 +12963,9 @@ function otelInitContents(flavor) {
|
|
|
12660
12963
|
return OTEL_INIT_CJS;
|
|
12661
12964
|
}
|
|
12662
12965
|
function injectionLine(flavor, entryFile, otelInitFile) {
|
|
12663
|
-
let rel =
|
|
12966
|
+
let rel = import_node_path53.default.relative(import_node_path53.default.dirname(entryFile), otelInitFile);
|
|
12664
12967
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
12665
|
-
rel = rel.split(
|
|
12968
|
+
rel = rel.split(import_node_path53.default.sep).join("/");
|
|
12666
12969
|
if (flavor === "cjs") return `require('${rel}')`;
|
|
12667
12970
|
if (flavor === "esm") return `import '${rel}'`;
|
|
12668
12971
|
const tsRel = rel.replace(/\.ts$/, "");
|
|
@@ -12675,27 +12978,27 @@ function lineIsOtelInjection(line) {
|
|
|
12675
12978
|
}
|
|
12676
12979
|
async function detectsSrcLayout(serviceDir) {
|
|
12677
12980
|
const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([
|
|
12678
|
-
exists3(
|
|
12679
|
-
exists3(
|
|
12680
|
-
exists3(
|
|
12681
|
-
exists3(
|
|
12981
|
+
exists3(import_node_path53.default.join(serviceDir, "src", "app")),
|
|
12982
|
+
exists3(import_node_path53.default.join(serviceDir, "src", "pages")),
|
|
12983
|
+
exists3(import_node_path53.default.join(serviceDir, "app")),
|
|
12984
|
+
exists3(import_node_path53.default.join(serviceDir, "pages"))
|
|
12682
12985
|
]);
|
|
12683
12986
|
return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages;
|
|
12684
12987
|
}
|
|
12685
12988
|
async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project) {
|
|
12686
12989
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
12687
12990
|
const srcLayout = await detectsSrcLayout(serviceDir);
|
|
12688
|
-
const baseDir = srcLayout ?
|
|
12689
|
-
const instrumentationFile =
|
|
12690
|
-
const instrumentationNodeFile =
|
|
12991
|
+
const baseDir = srcLayout ? import_node_path53.default.join(serviceDir, "src") : serviceDir;
|
|
12992
|
+
const instrumentationFile = import_node_path53.default.join(baseDir, useTs ? "instrumentation.ts" : "instrumentation.js");
|
|
12993
|
+
const instrumentationNodeFile = import_node_path53.default.join(
|
|
12691
12994
|
baseDir,
|
|
12692
12995
|
useTs ? "instrumentation.node.ts" : "instrumentation.node.js"
|
|
12693
12996
|
);
|
|
12694
|
-
const instrumentationEdgeFile =
|
|
12997
|
+
const instrumentationEdgeFile = import_node_path53.default.join(
|
|
12695
12998
|
baseDir,
|
|
12696
12999
|
useTs ? "instrumentation.edge.ts" : "instrumentation.edge.js"
|
|
12697
13000
|
);
|
|
12698
|
-
const envNeatFile =
|
|
13001
|
+
const envNeatFile = import_node_path53.default.join(baseDir, ".env.neat");
|
|
12699
13002
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
12700
13003
|
const dependencyEdits = [];
|
|
12701
13004
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -12772,7 +13075,7 @@ async function planNext(serviceDir, pkg, manifestPath, nextConfigPath, project)
|
|
|
12772
13075
|
const nextMajor = parseNextMajor(nextRange);
|
|
12773
13076
|
if (nextMajor !== null && nextMajor < 15) {
|
|
12774
13077
|
try {
|
|
12775
|
-
const raw = await
|
|
13078
|
+
const raw = await import_node_fs34.promises.readFile(nextConfigPath, "utf8");
|
|
12776
13079
|
if (!raw.includes("instrumentationHook")) {
|
|
12777
13080
|
nextConfigEdit = {
|
|
12778
13081
|
file: nextConfigPath,
|
|
@@ -12820,7 +13123,7 @@ function buildDependencyEdits(pkg, manifestPath) {
|
|
|
12820
13123
|
return edits;
|
|
12821
13124
|
}
|
|
12822
13125
|
async function queueEnvNeat(serviceDir, pkg, project, generatedFiles) {
|
|
12823
|
-
const envNeatFile =
|
|
13126
|
+
const envNeatFile = import_node_path53.default.join(serviceDir, ".env.neat");
|
|
12824
13127
|
if (!await exists3(envNeatFile)) {
|
|
12825
13128
|
generatedFiles.push({
|
|
12826
13129
|
file: envNeatFile,
|
|
@@ -12855,7 +13158,7 @@ function fileImportsOtelHook(raw, specifiers) {
|
|
|
12855
13158
|
}
|
|
12856
13159
|
async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
12857
13160
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
12858
|
-
const otelServerFile =
|
|
13161
|
+
const otelServerFile = import_node_path53.default.join(
|
|
12859
13162
|
serviceDir,
|
|
12860
13163
|
useTs ? "app/otel.server.ts" : "app/otel.server.js"
|
|
12861
13164
|
);
|
|
@@ -12876,7 +13179,7 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
12876
13179
|
await queueEnvNeat(serviceDir, pkg, project, generatedFiles);
|
|
12877
13180
|
const entrypointEdits = [];
|
|
12878
13181
|
try {
|
|
12879
|
-
const raw = await
|
|
13182
|
+
const raw = await import_node_fs34.promises.readFile(entryFile, "utf8");
|
|
12880
13183
|
if (!fileImportsOtelHook(raw, ["./otel.server"])) {
|
|
12881
13184
|
const lines = raw.split(/\r?\n/);
|
|
12882
13185
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -12912,11 +13215,11 @@ async function planRemix(serviceDir, pkg, manifestPath, entryFile, project) {
|
|
|
12912
13215
|
}
|
|
12913
13216
|
async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project) {
|
|
12914
13217
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
12915
|
-
const otelInitFile =
|
|
13218
|
+
const otelInitFile = import_node_path53.default.join(
|
|
12916
13219
|
serviceDir,
|
|
12917
13220
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
12918
13221
|
);
|
|
12919
|
-
const resolvedHooksFile = hooksFile ??
|
|
13222
|
+
const resolvedHooksFile = hooksFile ?? import_node_path53.default.join(serviceDir, useTs ? "src/hooks.server.ts" : "src/hooks.server.js");
|
|
12920
13223
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
12921
13224
|
const generatedFiles = [];
|
|
12922
13225
|
const entrypointEdits = [];
|
|
@@ -12941,7 +13244,7 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
12941
13244
|
});
|
|
12942
13245
|
} else {
|
|
12943
13246
|
try {
|
|
12944
|
-
const raw = await
|
|
13247
|
+
const raw = await import_node_fs34.promises.readFile(hooksFile, "utf8");
|
|
12945
13248
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
12946
13249
|
const lines = raw.split(/\r?\n/);
|
|
12947
13250
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -12978,11 +13281,11 @@ async function planSvelteKit(serviceDir, pkg, manifestPath, hooksFile, project)
|
|
|
12978
13281
|
}
|
|
12979
13282
|
async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
12980
13283
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
12981
|
-
const otelPluginFile =
|
|
13284
|
+
const otelPluginFile = import_node_path53.default.join(
|
|
12982
13285
|
serviceDir,
|
|
12983
13286
|
useTs ? "server/plugins/otel.ts" : "server/plugins/otel.js"
|
|
12984
13287
|
);
|
|
12985
|
-
const otelInitFile =
|
|
13288
|
+
const otelInitFile = import_node_path53.default.join(
|
|
12986
13289
|
serviceDir,
|
|
12987
13290
|
useTs ? "server/plugins/otel-init.ts" : "server/plugins/otel-init.js"
|
|
12988
13291
|
);
|
|
@@ -13033,19 +13336,19 @@ async function planNuxt(serviceDir, pkg, manifestPath, project) {
|
|
|
13033
13336
|
var ASTRO_MIDDLEWARE_CANDIDATES = ["src/middleware.ts", "src/middleware.js"];
|
|
13034
13337
|
async function findAstroMiddleware(serviceDir) {
|
|
13035
13338
|
for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {
|
|
13036
|
-
const candidate =
|
|
13339
|
+
const candidate = import_node_path53.default.join(serviceDir, rel);
|
|
13037
13340
|
if (await exists3(candidate)) return candidate;
|
|
13038
13341
|
}
|
|
13039
13342
|
return null;
|
|
13040
13343
|
}
|
|
13041
13344
|
async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
13042
13345
|
const useTs = await isTypeScriptProject(serviceDir);
|
|
13043
|
-
const otelInitFile =
|
|
13346
|
+
const otelInitFile = import_node_path53.default.join(
|
|
13044
13347
|
serviceDir,
|
|
13045
13348
|
useTs ? "src/otel-init.ts" : "src/otel-init.js"
|
|
13046
13349
|
);
|
|
13047
13350
|
const existingMiddleware = await findAstroMiddleware(serviceDir);
|
|
13048
|
-
const middlewareFile = existingMiddleware ??
|
|
13351
|
+
const middlewareFile = existingMiddleware ?? import_node_path53.default.join(serviceDir, useTs ? "src/middleware.ts" : "src/middleware.js");
|
|
13049
13352
|
const dependencyEdits = buildDependencyEdits(pkg, manifestPath);
|
|
13050
13353
|
const generatedFiles = [];
|
|
13051
13354
|
const entrypointEdits = [];
|
|
@@ -13070,7 +13373,7 @@ async function planAstro(serviceDir, pkg, manifestPath, project) {
|
|
|
13070
13373
|
});
|
|
13071
13374
|
} else {
|
|
13072
13375
|
try {
|
|
13073
|
-
const raw = await
|
|
13376
|
+
const raw = await import_node_fs34.promises.readFile(existingMiddleware, "utf8");
|
|
13074
13377
|
if (!fileImportsOtelHook(raw, ["./otel-init"])) {
|
|
13075
13378
|
const lines = raw.split(/\r?\n/);
|
|
13076
13379
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
@@ -13141,7 +13444,7 @@ async function findFrameworkDispatch(serviceDir, pkg, manifestPath, project) {
|
|
|
13141
13444
|
}
|
|
13142
13445
|
async function plan(serviceDir, opts) {
|
|
13143
13446
|
const pkg = await readPackageJson2(serviceDir);
|
|
13144
|
-
const manifestPath =
|
|
13447
|
+
const manifestPath = import_node_path53.default.join(serviceDir, "package.json");
|
|
13145
13448
|
const project = opts?.project;
|
|
13146
13449
|
const empty = {
|
|
13147
13450
|
language: "javascript",
|
|
@@ -13176,8 +13479,8 @@ async function plan(serviceDir, opts) {
|
|
|
13176
13479
|
return { ...empty, libOnly: true };
|
|
13177
13480
|
}
|
|
13178
13481
|
const flavor = dispatchEntry(entryFile, pkg);
|
|
13179
|
-
const otelInitFile =
|
|
13180
|
-
const envNeatFile =
|
|
13482
|
+
const otelInitFile = import_node_path53.default.join(import_node_path53.default.dirname(entryFile), otelInitFilename(flavor));
|
|
13483
|
+
const envNeatFile = import_node_path53.default.join(serviceDir, ".env.neat");
|
|
13181
13484
|
const existingDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
13182
13485
|
const dependencyEdits = [];
|
|
13183
13486
|
for (const sdk of SDK_PACKAGES) {
|
|
@@ -13201,7 +13504,7 @@ async function plan(serviceDir, opts) {
|
|
|
13201
13504
|
}
|
|
13202
13505
|
const entrypointEdits = [];
|
|
13203
13506
|
try {
|
|
13204
|
-
const raw = await
|
|
13507
|
+
const raw = await import_node_fs34.promises.readFile(entryFile, "utf8");
|
|
13205
13508
|
const lines = raw.split(/\r?\n/);
|
|
13206
13509
|
const firstReal = lines[0]?.startsWith("#!") ? lines[1] ?? "" : lines[0] ?? "";
|
|
13207
13510
|
if (!lineIsOtelInjection(firstReal)) {
|
|
@@ -13246,13 +13549,13 @@ async function plan(serviceDir, opts) {
|
|
|
13246
13549
|
};
|
|
13247
13550
|
}
|
|
13248
13551
|
function isAllowedWritePath(serviceDir, target) {
|
|
13249
|
-
const rel =
|
|
13552
|
+
const rel = import_node_path53.default.relative(serviceDir, target);
|
|
13250
13553
|
if (rel.startsWith("..")) return false;
|
|
13251
|
-
const base =
|
|
13554
|
+
const base = import_node_path53.default.basename(target);
|
|
13252
13555
|
if (base === "package.json") return true;
|
|
13253
13556
|
if (base === ".env.neat") return true;
|
|
13254
13557
|
if (/^otel-init\.(?:js|cjs|mjs|ts)$/.test(base)) return true;
|
|
13255
|
-
const relPosix = rel.split(
|
|
13558
|
+
const relPosix = rel.split(import_node_path53.default.sep).join("/");
|
|
13256
13559
|
if (/^instrumentation(?:\.(?:node|edge))?\.(?:js|cjs|mjs|ts)$/.test(base)) {
|
|
13257
13560
|
if (relPosix === base) return true;
|
|
13258
13561
|
if (relPosix === `src/${base}`) return true;
|
|
@@ -13269,10 +13572,10 @@ function isAllowedWritePath(serviceDir, target) {
|
|
|
13269
13572
|
return false;
|
|
13270
13573
|
}
|
|
13271
13574
|
async function writeAtomic(file, contents) {
|
|
13272
|
-
await
|
|
13575
|
+
await import_node_fs34.promises.mkdir(import_node_path53.default.dirname(file), { recursive: true });
|
|
13273
13576
|
const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
13274
|
-
await
|
|
13275
|
-
await
|
|
13577
|
+
await import_node_fs34.promises.writeFile(tmp, contents, "utf8");
|
|
13578
|
+
await import_node_fs34.promises.rename(tmp, file);
|
|
13276
13579
|
}
|
|
13277
13580
|
async function apply(installPlan) {
|
|
13278
13581
|
const { serviceDir } = installPlan;
|
|
@@ -13348,7 +13651,7 @@ async function apply(installPlan) {
|
|
|
13348
13651
|
for (const target of allTargets) {
|
|
13349
13652
|
if (await exists3(target)) {
|
|
13350
13653
|
try {
|
|
13351
|
-
originals.set(target, await
|
|
13654
|
+
originals.set(target, await import_node_fs34.promises.readFile(target, "utf8"));
|
|
13352
13655
|
} catch {
|
|
13353
13656
|
}
|
|
13354
13657
|
}
|
|
@@ -13431,14 +13734,14 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
13431
13734
|
const removed = [];
|
|
13432
13735
|
for (const [file, raw] of originals.entries()) {
|
|
13433
13736
|
try {
|
|
13434
|
-
await
|
|
13737
|
+
await import_node_fs34.promises.writeFile(file, raw, "utf8");
|
|
13435
13738
|
restored.push(file);
|
|
13436
13739
|
} catch {
|
|
13437
13740
|
}
|
|
13438
13741
|
}
|
|
13439
13742
|
for (const file of createdFiles) {
|
|
13440
13743
|
try {
|
|
13441
|
-
await
|
|
13744
|
+
await import_node_fs34.promises.unlink(file);
|
|
13442
13745
|
removed.push(file);
|
|
13443
13746
|
} catch {
|
|
13444
13747
|
}
|
|
@@ -13453,8 +13756,8 @@ async function rollback(installPlan, originals, createdFiles) {
|
|
|
13453
13756
|
...removed.map((f) => `removed: ${f}`),
|
|
13454
13757
|
""
|
|
13455
13758
|
];
|
|
13456
|
-
const rollbackPath =
|
|
13457
|
-
await
|
|
13759
|
+
const rollbackPath = import_node_path53.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
13760
|
+
await import_node_fs34.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
13458
13761
|
}
|
|
13459
13762
|
function injectInstrumentationHook(raw) {
|
|
13460
13763
|
if (raw.includes("instrumentationHook")) return raw;
|
|
@@ -13483,8 +13786,8 @@ var javascriptInstaller = {
|
|
|
13483
13786
|
|
|
13484
13787
|
// src/installers/python.ts
|
|
13485
13788
|
init_cjs_shims();
|
|
13486
|
-
var
|
|
13487
|
-
var
|
|
13789
|
+
var import_node_fs35 = require("fs");
|
|
13790
|
+
var import_node_path54 = __toESM(require("path"), 1);
|
|
13488
13791
|
var SDK_PACKAGES2 = [
|
|
13489
13792
|
{ name: "opentelemetry-distro", version: ">=0.49b0" },
|
|
13490
13793
|
{ name: "opentelemetry-exporter-otlp", version: ">=1.28.0" }
|
|
@@ -13496,7 +13799,7 @@ var OTEL_ENV2 = {
|
|
|
13496
13799
|
};
|
|
13497
13800
|
async function exists4(p) {
|
|
13498
13801
|
try {
|
|
13499
|
-
await
|
|
13802
|
+
await import_node_fs35.promises.stat(p);
|
|
13500
13803
|
return true;
|
|
13501
13804
|
} catch {
|
|
13502
13805
|
return false;
|
|
@@ -13505,7 +13808,7 @@ async function exists4(p) {
|
|
|
13505
13808
|
async function detect2(serviceDir) {
|
|
13506
13809
|
const markers = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
13507
13810
|
for (const m of markers) {
|
|
13508
|
-
if (await exists4(
|
|
13811
|
+
if (await exists4(import_node_path54.default.join(serviceDir, m))) return true;
|
|
13509
13812
|
}
|
|
13510
13813
|
return false;
|
|
13511
13814
|
}
|
|
@@ -13515,9 +13818,9 @@ function reqPackageName(line) {
|
|
|
13515
13818
|
return head.replace(/[<>=!~].*$/, "").toLowerCase();
|
|
13516
13819
|
}
|
|
13517
13820
|
async function planRequirementsTxtEdits(serviceDir) {
|
|
13518
|
-
const file =
|
|
13821
|
+
const file = import_node_path54.default.join(serviceDir, "requirements.txt");
|
|
13519
13822
|
if (!await exists4(file)) return null;
|
|
13520
|
-
const raw = await
|
|
13823
|
+
const raw = await import_node_fs35.promises.readFile(file, "utf8");
|
|
13521
13824
|
const presentNames = new Set(
|
|
13522
13825
|
raw.split(/\r?\n/).map(reqPackageName).filter((n) => n.length > 0)
|
|
13523
13826
|
);
|
|
@@ -13525,9 +13828,9 @@ async function planRequirementsTxtEdits(serviceDir) {
|
|
|
13525
13828
|
return { manifest: file, missing: [...missing] };
|
|
13526
13829
|
}
|
|
13527
13830
|
async function planProcfileEdits(serviceDir) {
|
|
13528
|
-
const procfile =
|
|
13831
|
+
const procfile = import_node_path54.default.join(serviceDir, "Procfile");
|
|
13529
13832
|
if (!await exists4(procfile)) return [];
|
|
13530
|
-
const raw = await
|
|
13833
|
+
const raw = await import_node_fs35.promises.readFile(procfile, "utf8");
|
|
13531
13834
|
const edits = [];
|
|
13532
13835
|
for (const line of raw.split(/\r?\n/)) {
|
|
13533
13836
|
if (line.length === 0) continue;
|
|
@@ -13579,8 +13882,8 @@ async function applyRequirementsTxt(manifest, edits, original) {
|
|
|
13579
13882
|
const next = `${original}${trailing}${newlines.join("\n")}
|
|
13580
13883
|
`;
|
|
13581
13884
|
const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`;
|
|
13582
|
-
await
|
|
13583
|
-
await
|
|
13885
|
+
await import_node_fs35.promises.writeFile(tmp, next, "utf8");
|
|
13886
|
+
await import_node_fs35.promises.rename(tmp, manifest);
|
|
13584
13887
|
}
|
|
13585
13888
|
async function applyProcfile(procfile, edits, original) {
|
|
13586
13889
|
let next = original;
|
|
@@ -13589,8 +13892,8 @@ async function applyProcfile(procfile, edits, original) {
|
|
|
13589
13892
|
next = next.replace(e.before, e.after);
|
|
13590
13893
|
}
|
|
13591
13894
|
const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`;
|
|
13592
|
-
await
|
|
13593
|
-
await
|
|
13895
|
+
await import_node_fs35.promises.writeFile(tmp, next, "utf8");
|
|
13896
|
+
await import_node_fs35.promises.rename(tmp, procfile);
|
|
13594
13897
|
}
|
|
13595
13898
|
async function apply2(installPlan) {
|
|
13596
13899
|
const { serviceDir } = installPlan;
|
|
@@ -13603,7 +13906,7 @@ async function apply2(installPlan) {
|
|
|
13603
13906
|
const originals = /* @__PURE__ */ new Map();
|
|
13604
13907
|
for (const file of touched) {
|
|
13605
13908
|
try {
|
|
13606
|
-
originals.set(file, await
|
|
13909
|
+
originals.set(file, await import_node_fs35.promises.readFile(file, "utf8"));
|
|
13607
13910
|
} catch {
|
|
13608
13911
|
}
|
|
13609
13912
|
}
|
|
@@ -13614,7 +13917,7 @@ async function apply2(installPlan) {
|
|
|
13614
13917
|
if (raw === void 0) {
|
|
13615
13918
|
throw new Error(`python installer: cannot read ${file} during apply`);
|
|
13616
13919
|
}
|
|
13617
|
-
const base =
|
|
13920
|
+
const base = import_node_path54.default.basename(file);
|
|
13618
13921
|
if (base === "requirements.txt") {
|
|
13619
13922
|
const edits = installPlan.dependencyEdits.filter((e) => e.file === file);
|
|
13620
13923
|
if (edits.length > 0) {
|
|
@@ -13639,7 +13942,7 @@ async function rollback2(installPlan, originals) {
|
|
|
13639
13942
|
const restored = [];
|
|
13640
13943
|
for (const [file, raw] of originals.entries()) {
|
|
13641
13944
|
try {
|
|
13642
|
-
await
|
|
13945
|
+
await import_node_fs35.promises.writeFile(file, raw, "utf8");
|
|
13643
13946
|
restored.push(file);
|
|
13644
13947
|
} catch {
|
|
13645
13948
|
}
|
|
@@ -13653,8 +13956,8 @@ async function rollback2(installPlan, originals) {
|
|
|
13653
13956
|
...restored.map((f) => `restored: ${f}`),
|
|
13654
13957
|
""
|
|
13655
13958
|
];
|
|
13656
|
-
const rollbackPath =
|
|
13657
|
-
await
|
|
13959
|
+
const rollbackPath = import_node_path54.default.join(installPlan.serviceDir, "neat-rollback.patch");
|
|
13960
|
+
await import_node_fs35.promises.writeFile(rollbackPath, lines.join("\n"), "utf8");
|
|
13658
13961
|
}
|
|
13659
13962
|
var pythonInstaller = {
|
|
13660
13963
|
name: "python",
|
|
@@ -13777,10 +14080,10 @@ function renderPatch(sections) {
|
|
|
13777
14080
|
|
|
13778
14081
|
// src/orchestrator.ts
|
|
13779
14082
|
init_cjs_shims();
|
|
13780
|
-
var
|
|
14083
|
+
var import_node_fs36 = require("fs");
|
|
13781
14084
|
var import_node_http = __toESM(require("http"), 1);
|
|
13782
14085
|
var import_node_net = __toESM(require("net"), 1);
|
|
13783
|
-
var
|
|
14086
|
+
var import_node_path55 = __toESM(require("path"), 1);
|
|
13784
14087
|
var import_node_child_process3 = require("child_process");
|
|
13785
14088
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
13786
14089
|
async function extractAndPersist(opts) {
|
|
@@ -13789,7 +14092,7 @@ async function extractAndPersist(opts) {
|
|
|
13789
14092
|
const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT;
|
|
13790
14093
|
resetGraph(graphKey);
|
|
13791
14094
|
const graph = getGraph(graphKey);
|
|
13792
|
-
const projectPaths = pathsForProject(graphKey,
|
|
14095
|
+
const projectPaths = pathsForProject(graphKey, import_node_path55.default.join(opts.scanPath, "neat-out"));
|
|
13793
14096
|
const extraction = await extractFromDirectory(graph, opts.scanPath, {
|
|
13794
14097
|
errorsPath: projectPaths.errorsPath
|
|
13795
14098
|
});
|
|
@@ -13841,7 +14144,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13841
14144
|
libOnly++;
|
|
13842
14145
|
const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : [];
|
|
13843
14146
|
if (appDeps.length > 0) {
|
|
13844
|
-
const svcName =
|
|
14147
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13845
14148
|
const list = appDeps.join(", ");
|
|
13846
14149
|
console.warn(
|
|
13847
14150
|
`neat: runtime layer won't engage for ${svcName}: no entry point found.
|
|
@@ -13854,7 +14157,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13854
14157
|
console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`);
|
|
13855
14158
|
} else if (outcome.outcome === "react-native") {
|
|
13856
14159
|
reactNative++;
|
|
13857
|
-
const svcName =
|
|
14160
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13858
14161
|
console.log(
|
|
13859
14162
|
`neat: ${svc.dir} detected as React Native / Expo
|
|
13860
14163
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -13865,7 +14168,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13865
14168
|
);
|
|
13866
14169
|
} else if (outcome.outcome === "bun") {
|
|
13867
14170
|
bun++;
|
|
13868
|
-
const svcName =
|
|
14171
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13869
14172
|
console.log(
|
|
13870
14173
|
`neat: ${svc.dir} detected as Bun
|
|
13871
14174
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -13876,7 +14179,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13876
14179
|
);
|
|
13877
14180
|
} else if (outcome.outcome === "deno") {
|
|
13878
14181
|
deno++;
|
|
13879
|
-
const svcName =
|
|
14182
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13880
14183
|
console.log(
|
|
13881
14184
|
`neat: ${svc.dir} detected as Deno
|
|
13882
14185
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -13887,7 +14190,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13887
14190
|
);
|
|
13888
14191
|
} else if (outcome.outcome === "cloudflare-workers") {
|
|
13889
14192
|
cloudflareWorkers++;
|
|
13890
|
-
const svcName =
|
|
14193
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13891
14194
|
console.log(
|
|
13892
14195
|
`neat: ${svc.dir} detected as Cloudflare Workers
|
|
13893
14196
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -13898,7 +14201,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13898
14201
|
);
|
|
13899
14202
|
} else if (outcome.outcome === "electron") {
|
|
13900
14203
|
electron++;
|
|
13901
|
-
const svcName =
|
|
14204
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13902
14205
|
console.log(
|
|
13903
14206
|
`neat: ${svc.dir} detected as Electron
|
|
13904
14207
|
The installer doesn't cover this runtime deterministically.
|
|
@@ -13911,7 +14214,7 @@ async function applyInstallersOver(services, project, options = {}) {
|
|
|
13911
14214
|
if (svc.pkg && (outcome.outcome === "instrumented" || outcome.outcome === "already-instrumented")) {
|
|
13912
14215
|
const gaps = uninstrumentedLibraries(svc.pkg);
|
|
13913
14216
|
if (gaps.length > 0) {
|
|
13914
|
-
const svcName =
|
|
14217
|
+
const svcName = import_node_path55.default.basename(svc.dir);
|
|
13915
14218
|
const list = gaps.join(", ");
|
|
13916
14219
|
const subject = gaps.length === 1 ? "this library" : "these libraries";
|
|
13917
14220
|
const aux = gaps.length === 1 ? "isn't" : "aren't";
|
|
@@ -14117,24 +14420,24 @@ async function persistedPortsFor(scanPath) {
|
|
|
14117
14420
|
return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web };
|
|
14118
14421
|
}
|
|
14119
14422
|
async function acquireSpawnLock(scanPath) {
|
|
14120
|
-
const lockPath =
|
|
14121
|
-
await
|
|
14423
|
+
const lockPath = import_node_path55.default.join(scanPath, "neat-out", "daemon.spawn.lock");
|
|
14424
|
+
await import_node_fs36.promises.mkdir(import_node_path55.default.dirname(lockPath), { recursive: true });
|
|
14122
14425
|
const STALE_LOCK_MS = 6e4;
|
|
14123
14426
|
try {
|
|
14124
|
-
const fd = await
|
|
14427
|
+
const fd = await import_node_fs36.promises.open(lockPath, "wx");
|
|
14125
14428
|
await fd.writeFile(`${process.pid}
|
|
14126
14429
|
`, "utf8");
|
|
14127
14430
|
await fd.close();
|
|
14128
14431
|
return async () => {
|
|
14129
|
-
await
|
|
14432
|
+
await import_node_fs36.promises.unlink(lockPath).catch(() => {
|
|
14130
14433
|
});
|
|
14131
14434
|
};
|
|
14132
14435
|
} catch (err) {
|
|
14133
14436
|
if (err.code !== "EEXIST") return null;
|
|
14134
14437
|
try {
|
|
14135
|
-
const stat = await
|
|
14438
|
+
const stat = await import_node_fs36.promises.stat(lockPath);
|
|
14136
14439
|
if (Date.now() - stat.mtimeMs > STALE_LOCK_MS) {
|
|
14137
|
-
await
|
|
14440
|
+
await import_node_fs36.promises.unlink(lockPath).catch(() => {
|
|
14138
14441
|
});
|
|
14139
14442
|
return acquireSpawnLock(scanPath);
|
|
14140
14443
|
}
|
|
@@ -14163,13 +14466,13 @@ async function healthIsForProject(restPort, project) {
|
|
|
14163
14466
|
return false;
|
|
14164
14467
|
}
|
|
14165
14468
|
function daemonLogPath(projectPath2) {
|
|
14166
|
-
return
|
|
14469
|
+
return import_node_path55.default.join(projectPath2, "neat-out", "daemon.log");
|
|
14167
14470
|
}
|
|
14168
14471
|
function spawnDaemonDetached(spec) {
|
|
14169
|
-
const here =
|
|
14472
|
+
const here = import_node_path55.default.dirname(new URL(importMetaUrl).pathname);
|
|
14170
14473
|
const candidates = [
|
|
14171
|
-
|
|
14172
|
-
|
|
14474
|
+
import_node_path55.default.join(here, "neatd.cjs"),
|
|
14475
|
+
import_node_path55.default.join(here, "neatd.js")
|
|
14173
14476
|
];
|
|
14174
14477
|
let entry2 = null;
|
|
14175
14478
|
const fsSync = require("fs");
|
|
@@ -14199,7 +14502,7 @@ function spawnDaemonDetached(spec) {
|
|
|
14199
14502
|
let logFd = null;
|
|
14200
14503
|
if (spec) {
|
|
14201
14504
|
const logPath = daemonLogPath(spec.projectPath);
|
|
14202
|
-
fsSync.mkdirSync(
|
|
14505
|
+
fsSync.mkdirSync(import_node_path55.default.dirname(logPath), { recursive: true });
|
|
14203
14506
|
logFd = fsSync.openSync(logPath, "a");
|
|
14204
14507
|
}
|
|
14205
14508
|
const child = (0, import_node_child_process3.spawn)(process.execPath, [entry2, "start"], {
|
|
@@ -14238,7 +14541,7 @@ async function runOrchestrator(opts) {
|
|
|
14238
14541
|
browser: "skipped"
|
|
14239
14542
|
}
|
|
14240
14543
|
};
|
|
14241
|
-
const stat = await
|
|
14544
|
+
const stat = await import_node_fs36.promises.stat(opts.scanPath).catch(() => null);
|
|
14242
14545
|
if (!stat || !stat.isDirectory()) {
|
|
14243
14546
|
console.error(`neat: ${opts.scanPath} is not a directory`);
|
|
14244
14547
|
result.exitCode = 2;
|
|
@@ -14398,7 +14701,7 @@ async function runOrchestrator(opts) {
|
|
|
14398
14701
|
result.steps.browser = openBrowser(dashboardUrl);
|
|
14399
14702
|
}
|
|
14400
14703
|
const daemonRunning = result.steps.daemon === "spawned" || result.steps.daemon === "already-running";
|
|
14401
|
-
const daemonLog = daemonRunning ?
|
|
14704
|
+
const daemonLog = daemonRunning ? import_node_path55.default.relative(opts.scanPath, daemonLogPath(opts.scanPath)) : null;
|
|
14402
14705
|
printSummary(result, graph, dashboardUrl, daemonLog);
|
|
14403
14706
|
return result;
|
|
14404
14707
|
}
|
|
@@ -14766,11 +15069,11 @@ async function runConnectorCommand(rawArgs, deps = {}) {
|
|
|
14766
15069
|
|
|
14767
15070
|
// src/cli-verbs.ts
|
|
14768
15071
|
init_cjs_shims();
|
|
14769
|
-
var
|
|
15072
|
+
var import_node_path56 = __toESM(require("path"), 1);
|
|
14770
15073
|
|
|
14771
15074
|
// src/cli-client.ts
|
|
14772
15075
|
init_cjs_shims();
|
|
14773
|
-
var
|
|
15076
|
+
var import_types44 = require("@neat.is/types");
|
|
14774
15077
|
var HttpError = class extends Error {
|
|
14775
15078
|
constructor(status2, message, responseBody = "") {
|
|
14776
15079
|
super(message);
|
|
@@ -14795,10 +15098,10 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
14795
15098
|
const root = baseUrl.replace(/\/$/, "");
|
|
14796
15099
|
const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
|
|
14797
15100
|
return {
|
|
14798
|
-
async get(
|
|
15101
|
+
async get(path58) {
|
|
14799
15102
|
let res;
|
|
14800
15103
|
try {
|
|
14801
|
-
res = await fetch(`${root}${
|
|
15104
|
+
res = await fetch(`${root}${path58}`, {
|
|
14802
15105
|
headers: { ...authHeader }
|
|
14803
15106
|
});
|
|
14804
15107
|
} catch (err) {
|
|
@@ -14810,16 +15113,16 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
14810
15113
|
const body = await res.text().catch(() => "");
|
|
14811
15114
|
throw new HttpError(
|
|
14812
15115
|
res.status,
|
|
14813
|
-
`${res.status} ${res.statusText} on GET ${
|
|
15116
|
+
`${res.status} ${res.statusText} on GET ${path58}: ${body}`,
|
|
14814
15117
|
body
|
|
14815
15118
|
);
|
|
14816
15119
|
}
|
|
14817
15120
|
return await res.json();
|
|
14818
15121
|
},
|
|
14819
|
-
async post(
|
|
15122
|
+
async post(path58, body) {
|
|
14820
15123
|
let res;
|
|
14821
15124
|
try {
|
|
14822
|
-
res = await fetch(`${root}${
|
|
15125
|
+
res = await fetch(`${root}${path58}`, {
|
|
14823
15126
|
method: "POST",
|
|
14824
15127
|
headers: { "content-type": "application/json", ...authHeader },
|
|
14825
15128
|
body: JSON.stringify(body)
|
|
@@ -14833,7 +15136,7 @@ function createHttpClient(baseUrl, bearerToken) {
|
|
|
14833
15136
|
const text = await res.text().catch(() => "");
|
|
14834
15137
|
throw new HttpError(
|
|
14835
15138
|
res.status,
|
|
14836
|
-
`${res.status} ${res.statusText} on POST ${
|
|
15139
|
+
`${res.status} ${res.statusText} on POST ${path58}: ${text}`,
|
|
14837
15140
|
text
|
|
14838
15141
|
);
|
|
14839
15142
|
}
|
|
@@ -14847,12 +15150,12 @@ function projectPath(project, suffix) {
|
|
|
14847
15150
|
}
|
|
14848
15151
|
async function runRootCause(client, input) {
|
|
14849
15152
|
const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
|
|
14850
|
-
const
|
|
15153
|
+
const path58 = projectPath(
|
|
14851
15154
|
input.project,
|
|
14852
15155
|
`/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
|
|
14853
15156
|
);
|
|
14854
15157
|
try {
|
|
14855
|
-
const result = await client.get(
|
|
15158
|
+
const result = await client.get(path58);
|
|
14856
15159
|
const arrowPath = result.traversalPath.join(" \u2190 ");
|
|
14857
15160
|
const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
|
|
14858
15161
|
const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
|
|
@@ -14878,12 +15181,12 @@ async function runRootCause(client, input) {
|
|
|
14878
15181
|
}
|
|
14879
15182
|
async function runBlastRadius(client, input) {
|
|
14880
15183
|
const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
|
|
14881
|
-
const
|
|
15184
|
+
const path58 = projectPath(
|
|
14882
15185
|
input.project,
|
|
14883
15186
|
`/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
|
|
14884
15187
|
);
|
|
14885
15188
|
try {
|
|
14886
|
-
const result = await client.get(
|
|
15189
|
+
const result = await client.get(path58);
|
|
14887
15190
|
if (result.totalAffected === 0) {
|
|
14888
15191
|
return {
|
|
14889
15192
|
summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
|
|
@@ -14912,17 +15215,17 @@ async function runBlastRadius(client, input) {
|
|
|
14912
15215
|
}
|
|
14913
15216
|
}
|
|
14914
15217
|
function formatBlastEntry(n) {
|
|
14915
|
-
const tag = n.edgeProvenance ===
|
|
15218
|
+
const tag = n.edgeProvenance === import_types44.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
14916
15219
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
14917
15220
|
}
|
|
14918
15221
|
async function runDependencies(client, input) {
|
|
14919
15222
|
const depth = input.depth ?? 3;
|
|
14920
|
-
const
|
|
15223
|
+
const path58 = projectPath(
|
|
14921
15224
|
input.project,
|
|
14922
15225
|
`/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
|
|
14923
15226
|
);
|
|
14924
15227
|
try {
|
|
14925
|
-
const result = await client.get(
|
|
15228
|
+
const result = await client.get(path58);
|
|
14926
15229
|
if (result.total === 0) {
|
|
14927
15230
|
return {
|
|
14928
15231
|
summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
|
|
@@ -14969,7 +15272,7 @@ async function runObservedDependencies(client, input) {
|
|
|
14969
15272
|
if (result.observed) {
|
|
14970
15273
|
return {
|
|
14971
15274
|
summary: `${input.nodeId} makes no outbound runtime calls, but OTel has observed it receiving traffic on ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 it's a pure receiver.`,
|
|
14972
|
-
provenance:
|
|
15275
|
+
provenance: import_types44.Provenance.OBSERVED
|
|
14973
15276
|
};
|
|
14974
15277
|
}
|
|
14975
15278
|
const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
@@ -14979,7 +15282,7 @@ async function runObservedDependencies(client, input) {
|
|
|
14979
15282
|
return {
|
|
14980
15283
|
summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
14981
15284
|
block: blockLines.join("\n"),
|
|
14982
|
-
provenance:
|
|
15285
|
+
provenance: import_types44.Provenance.OBSERVED
|
|
14983
15286
|
};
|
|
14984
15287
|
} catch (err) {
|
|
14985
15288
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -15014,9 +15317,9 @@ function formatDuration(ms) {
|
|
|
15014
15317
|
return `${Math.round(h / 24)}d`;
|
|
15015
15318
|
}
|
|
15016
15319
|
async function runIncidents(client, input) {
|
|
15017
|
-
const
|
|
15320
|
+
const path58 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
|
|
15018
15321
|
try {
|
|
15019
|
-
const body = await client.get(
|
|
15322
|
+
const body = await client.get(path58);
|
|
15020
15323
|
const events = body.events;
|
|
15021
15324
|
if (events.length === 0) {
|
|
15022
15325
|
return {
|
|
@@ -15033,7 +15336,7 @@ async function runIncidents(client, input) {
|
|
|
15033
15336
|
return {
|
|
15034
15337
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
15035
15338
|
block: blockLines.join("\n"),
|
|
15036
|
-
provenance:
|
|
15339
|
+
provenance: import_types44.Provenance.OBSERVED
|
|
15037
15340
|
};
|
|
15038
15341
|
} catch (err) {
|
|
15039
15342
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -15142,7 +15445,7 @@ async function runStaleEdges(client, input) {
|
|
|
15142
15445
|
return {
|
|
15143
15446
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
15144
15447
|
block: blockLines.join("\n"),
|
|
15145
|
-
provenance:
|
|
15448
|
+
provenance: import_types44.Provenance.STALE
|
|
15146
15449
|
};
|
|
15147
15450
|
}
|
|
15148
15451
|
async function runPolicies(client, input) {
|
|
@@ -15306,7 +15609,7 @@ async function resolveProjectEntry(opts) {
|
|
|
15306
15609
|
const cwd = opts.cwd ?? process.cwd();
|
|
15307
15610
|
const resolvedCwd = await normalizeProjectPath(cwd);
|
|
15308
15611
|
for (const entry2 of entries) {
|
|
15309
|
-
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${
|
|
15612
|
+
if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${import_node_path56.default.sep}`)) {
|
|
15310
15613
|
return entry2;
|
|
15311
15614
|
}
|
|
15312
15615
|
}
|
|
@@ -15459,7 +15762,7 @@ async function runSync(opts) {
|
|
|
15459
15762
|
}
|
|
15460
15763
|
|
|
15461
15764
|
// src/cli.ts
|
|
15462
|
-
var
|
|
15765
|
+
var import_types45 = require("@neat.is/types");
|
|
15463
15766
|
function isNpxInvocation() {
|
|
15464
15767
|
if (process.env.npm_command === "exec") return true;
|
|
15465
15768
|
const execpath = process.env.npm_execpath ?? "";
|
|
@@ -15752,7 +16055,7 @@ async function buildPatchSections(services, project) {
|
|
|
15752
16055
|
}
|
|
15753
16056
|
async function runInit(opts) {
|
|
15754
16057
|
const written = [];
|
|
15755
|
-
const stat = await
|
|
16058
|
+
const stat = await import_node_fs37.promises.stat(opts.scanPath).catch(() => null);
|
|
15756
16059
|
if (!stat || !stat.isDirectory()) {
|
|
15757
16060
|
console.error(`neat init: ${opts.scanPath} is not a directory`);
|
|
15758
16061
|
return { exitCode: 2, writtenFiles: written };
|
|
@@ -15761,13 +16064,13 @@ async function runInit(opts) {
|
|
|
15761
16064
|
printDiscoveryReport(opts, services);
|
|
15762
16065
|
const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
|
|
15763
16066
|
const patch = renderPatch(sections);
|
|
15764
|
-
const patchPath =
|
|
16067
|
+
const patchPath = import_node_path57.default.join(opts.scanPath, "neat.patch");
|
|
15765
16068
|
if (opts.dryRun) {
|
|
15766
|
-
await
|
|
16069
|
+
await import_node_fs37.promises.writeFile(patchPath, patch, "utf8");
|
|
15767
16070
|
written.push(patchPath);
|
|
15768
16071
|
console.log(`dry-run: patch written to ${patchPath}`);
|
|
15769
|
-
const gitignorePath =
|
|
15770
|
-
const gitignoreExists = await
|
|
16072
|
+
const gitignorePath = import_node_path57.default.join(opts.scanPath, ".gitignore");
|
|
16073
|
+
const gitignoreExists = await import_node_fs37.promises.stat(gitignorePath).then(() => true).catch(() => false);
|
|
15771
16074
|
const verb = gitignoreExists ? "append" : "create";
|
|
15772
16075
|
console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
|
|
15773
16076
|
console.log("rerun without --dry-run to register and snapshot.");
|
|
@@ -15778,9 +16081,9 @@ async function runInit(opts) {
|
|
|
15778
16081
|
const graph = getGraph(graphKey);
|
|
15779
16082
|
const projectPaths = pathsForProject(
|
|
15780
16083
|
graphKey,
|
|
15781
|
-
|
|
16084
|
+
import_node_path57.default.join(opts.scanPath, "neat-out")
|
|
15782
16085
|
);
|
|
15783
|
-
const errorsPath =
|
|
16086
|
+
const errorsPath = import_node_path57.default.join(import_node_path57.default.dirname(opts.outPath), import_node_path57.default.basename(projectPaths.errorsPath));
|
|
15784
16087
|
const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
|
|
15785
16088
|
await saveGraphToDisk(graph, opts.outPath);
|
|
15786
16089
|
written.push(opts.outPath);
|
|
@@ -15859,7 +16162,7 @@ async function runInit(opts) {
|
|
|
15859
16162
|
console.log("Run `npm install` (or your language equivalent) to refresh lockfiles.");
|
|
15860
16163
|
}
|
|
15861
16164
|
} else {
|
|
15862
|
-
await
|
|
16165
|
+
await import_node_fs37.promises.writeFile(patchPath, patch, "utf8");
|
|
15863
16166
|
written.push(patchPath);
|
|
15864
16167
|
}
|
|
15865
16168
|
}
|
|
@@ -15899,9 +16202,9 @@ var CLAUDE_SKILL_CONFIG = {
|
|
|
15899
16202
|
};
|
|
15900
16203
|
function claudeConfigPath() {
|
|
15901
16204
|
const override = process.env.NEAT_CLAUDE_CONFIG;
|
|
15902
|
-
if (override && override.length > 0) return
|
|
16205
|
+
if (override && override.length > 0) return import_node_path57.default.resolve(override);
|
|
15903
16206
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
15904
|
-
return
|
|
16207
|
+
return import_node_path57.default.join(home, ".claude.json");
|
|
15905
16208
|
}
|
|
15906
16209
|
async function runSkill(opts) {
|
|
15907
16210
|
const snippet2 = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
|
|
@@ -15913,7 +16216,7 @@ async function runSkill(opts) {
|
|
|
15913
16216
|
const target = claudeConfigPath();
|
|
15914
16217
|
let existing = {};
|
|
15915
16218
|
try {
|
|
15916
|
-
existing = JSON.parse(await
|
|
16219
|
+
existing = JSON.parse(await import_node_fs37.promises.readFile(target, "utf8"));
|
|
15917
16220
|
} catch (err) {
|
|
15918
16221
|
if (err.code !== "ENOENT") {
|
|
15919
16222
|
console.error(`neat skill: failed to read ${target} \u2014 ${err.message}`);
|
|
@@ -15925,8 +16228,8 @@ async function runSkill(opts) {
|
|
|
15925
16228
|
...existing,
|
|
15926
16229
|
mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
|
|
15927
16230
|
};
|
|
15928
|
-
await
|
|
15929
|
-
await
|
|
16231
|
+
await import_node_fs37.promises.mkdir(import_node_path57.default.dirname(target), { recursive: true });
|
|
16232
|
+
await import_node_fs37.promises.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
15930
16233
|
console.log(`neat skill: wrote mcpServers.neat to ${target}`);
|
|
15931
16234
|
console.log("restart Claude Code to pick up the new MCP server.");
|
|
15932
16235
|
return { exitCode: 0 };
|
|
@@ -15980,12 +16283,12 @@ async function main() {
|
|
|
15980
16283
|
console.error("neat init: --apply and --dry-run are mutually exclusive");
|
|
15981
16284
|
process.exit(2);
|
|
15982
16285
|
}
|
|
15983
|
-
const scanPath =
|
|
16286
|
+
const scanPath = import_node_path57.default.resolve(target);
|
|
15984
16287
|
const projectExplicit = parsed.project !== null;
|
|
15985
|
-
const projectName = projectExplicit ? project :
|
|
16288
|
+
const projectName = projectExplicit ? project : import_node_path57.default.basename(scanPath);
|
|
15986
16289
|
const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
|
|
15987
|
-
const fallback = pathsForProject(projectKey,
|
|
15988
|
-
const outPath =
|
|
16290
|
+
const fallback = pathsForProject(projectKey, import_node_path57.default.join(scanPath, "neat-out")).snapshotPath;
|
|
16291
|
+
const outPath = import_node_path57.default.resolve(process.env.NEAT_OUT_PATH ?? fallback);
|
|
15989
16292
|
const result = await runInit({
|
|
15990
16293
|
scanPath,
|
|
15991
16294
|
outPath,
|
|
@@ -16006,21 +16309,21 @@ async function main() {
|
|
|
16006
16309
|
usage();
|
|
16007
16310
|
process.exit(2);
|
|
16008
16311
|
}
|
|
16009
|
-
const scanPath =
|
|
16010
|
-
const stat = await
|
|
16312
|
+
const scanPath = import_node_path57.default.resolve(target);
|
|
16313
|
+
const stat = await import_node_fs37.promises.stat(scanPath).catch(() => null);
|
|
16011
16314
|
if (!stat || !stat.isDirectory()) {
|
|
16012
16315
|
console.error(`neat watch: ${scanPath} is not a directory`);
|
|
16013
16316
|
process.exit(2);
|
|
16014
16317
|
}
|
|
16015
|
-
const projectPaths = pathsForProject(project,
|
|
16016
|
-
const outPath =
|
|
16017
|
-
const errorsPath =
|
|
16018
|
-
process.env.NEAT_ERRORS_PATH ??
|
|
16318
|
+
const projectPaths = pathsForProject(project, import_node_path57.default.join(scanPath, "neat-out"));
|
|
16319
|
+
const outPath = import_node_path57.default.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
|
|
16320
|
+
const errorsPath = import_node_path57.default.resolve(
|
|
16321
|
+
process.env.NEAT_ERRORS_PATH ?? import_node_path57.default.join(import_node_path57.default.dirname(outPath), import_node_path57.default.basename(projectPaths.errorsPath))
|
|
16019
16322
|
);
|
|
16020
|
-
const staleEventsPath =
|
|
16021
|
-
process.env.NEAT_STALE_EVENTS_PATH ??
|
|
16323
|
+
const staleEventsPath = import_node_path57.default.resolve(
|
|
16324
|
+
process.env.NEAT_STALE_EVENTS_PATH ?? import_node_path57.default.join(import_node_path57.default.dirname(outPath), import_node_path57.default.basename(projectPaths.staleEventsPath))
|
|
16022
16325
|
);
|
|
16023
|
-
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ?
|
|
16326
|
+
const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? import_node_path57.default.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
|
|
16024
16327
|
const handle = await startWatch(getGraph(project), {
|
|
16025
16328
|
scanPath,
|
|
16026
16329
|
outPath,
|
|
@@ -16203,11 +16506,11 @@ async function main() {
|
|
|
16203
16506
|
process.exit(1);
|
|
16204
16507
|
}
|
|
16205
16508
|
async function tryOrchestrator(cmd, parsed) {
|
|
16206
|
-
const scanPath =
|
|
16207
|
-
const stat = await
|
|
16509
|
+
const scanPath = import_node_path57.default.resolve(cmd);
|
|
16510
|
+
const stat = await import_node_fs37.promises.stat(scanPath).catch(() => null);
|
|
16208
16511
|
if (!stat || !stat.isDirectory()) return null;
|
|
16209
16512
|
const projectExplicit = parsed.project !== null;
|
|
16210
|
-
const projectName = projectExplicit ? parsed.project :
|
|
16513
|
+
const projectName = projectExplicit ? parsed.project : import_node_path57.default.basename(scanPath);
|
|
16211
16514
|
const result = await runOrchestrator({
|
|
16212
16515
|
scanPath,
|
|
16213
16516
|
project: projectName,
|
|
@@ -16396,10 +16699,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
16396
16699
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
16397
16700
|
const out = [];
|
|
16398
16701
|
for (const p of parts) {
|
|
16399
|
-
const r =
|
|
16702
|
+
const r = import_types45.DivergenceTypeSchema.safeParse(p);
|
|
16400
16703
|
if (!r.success) {
|
|
16401
16704
|
console.error(
|
|
16402
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
16705
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types45.DivergenceTypeSchema.options.join(", ")}`
|
|
16403
16706
|
);
|
|
16404
16707
|
return 2;
|
|
16405
16708
|
}
|