@neat.is/core 0.4.28-dev.20260708 → 0.4.28-dev.20260710
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/server.cjs
CHANGED
|
@@ -59,8 +59,8 @@ function mountBearerAuth(app, opts) {
|
|
|
59
59
|
]);
|
|
60
60
|
const publicRead = opts.publicRead === true;
|
|
61
61
|
app.addHook("preHandler", (req, reply, done) => {
|
|
62
|
-
const
|
|
63
|
-
if (exactUnauthPaths.has(
|
|
62
|
+
const path47 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
63
|
+
if (exactUnauthPaths.has(path47) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path47)) {
|
|
64
64
|
done();
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -192,8 +192,8 @@ function reshapeGrpcRequest(req) {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
function resolveProtoRoot() {
|
|
195
|
-
const here =
|
|
196
|
-
return
|
|
195
|
+
const here = import_node_path43.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
196
|
+
return import_node_path43.default.resolve(here, "..", "proto");
|
|
197
197
|
}
|
|
198
198
|
function loadTraceService() {
|
|
199
199
|
const protoRoot = resolveProtoRoot();
|
|
@@ -261,13 +261,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
261
261
|
})
|
|
262
262
|
};
|
|
263
263
|
}
|
|
264
|
-
var import_node_url,
|
|
264
|
+
var import_node_url, import_node_path43, import_node_crypto2, grpc, protoLoader;
|
|
265
265
|
var init_otel_grpc = __esm({
|
|
266
266
|
"src/otel-grpc.ts"() {
|
|
267
267
|
"use strict";
|
|
268
268
|
init_cjs_shims();
|
|
269
269
|
import_node_url = require("url");
|
|
270
|
-
|
|
270
|
+
import_node_path43 = __toESM(require("path"), 1);
|
|
271
271
|
import_node_crypto2 = require("crypto");
|
|
272
272
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
273
273
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -360,8 +360,8 @@ function websocketChannelPathOf(attrs) {
|
|
|
360
360
|
const v = attrs[key];
|
|
361
361
|
if (typeof v === "string" && v.length > 0) {
|
|
362
362
|
const q = v.indexOf("?");
|
|
363
|
-
const
|
|
364
|
-
if (
|
|
363
|
+
const path47 = q === -1 ? v : v.slice(0, q);
|
|
364
|
+
if (path47.length > 0) return path47;
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
367
|
return void 0;
|
|
@@ -415,10 +415,10 @@ function parseOtlpRequest(body) {
|
|
|
415
415
|
return out;
|
|
416
416
|
}
|
|
417
417
|
function loadProtoRoot() {
|
|
418
|
-
const here =
|
|
419
|
-
const protoRoot =
|
|
418
|
+
const here = import_node_path44.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
419
|
+
const protoRoot = import_node_path44.default.resolve(here, "..", "proto");
|
|
420
420
|
const root = new import_protobufjs.default.Root();
|
|
421
|
-
root.resolvePath = (_origin, target) =>
|
|
421
|
+
root.resolvePath = (_origin, target) => import_node_path44.default.resolve(protoRoot, target);
|
|
422
422
|
root.loadSync(
|
|
423
423
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
424
424
|
{ keepCase: true }
|
|
@@ -630,12 +630,12 @@ async function buildOtelReceiver(opts) {
|
|
|
630
630
|
};
|
|
631
631
|
return decorated;
|
|
632
632
|
}
|
|
633
|
-
var
|
|
633
|
+
var import_node_path44, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
634
634
|
var init_otel = __esm({
|
|
635
635
|
"src/otel.ts"() {
|
|
636
636
|
"use strict";
|
|
637
637
|
init_cjs_shims();
|
|
638
|
-
|
|
638
|
+
import_node_path44 = __toESM(require("path"), 1);
|
|
639
639
|
import_node_url2 = require("url");
|
|
640
640
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
641
641
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -651,7 +651,7 @@ var init_otel = __esm({
|
|
|
651
651
|
|
|
652
652
|
// src/server.ts
|
|
653
653
|
init_cjs_shims();
|
|
654
|
-
var
|
|
654
|
+
var import_node_path46 = __toESM(require("path"), 1);
|
|
655
655
|
|
|
656
656
|
// src/graph.ts
|
|
657
657
|
init_cjs_shims();
|
|
@@ -675,7 +675,7 @@ function getGraph(project = DEFAULT_PROJECT) {
|
|
|
675
675
|
init_cjs_shims();
|
|
676
676
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
677
677
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
678
|
-
var
|
|
678
|
+
var import_types30 = require("@neat.is/types");
|
|
679
679
|
|
|
680
680
|
// src/extend/index.ts
|
|
681
681
|
init_cjs_shims();
|
|
@@ -1418,19 +1418,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1418
1418
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1419
1419
|
let best = { path: [start], edges: [] };
|
|
1420
1420
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1421
|
-
function step(node,
|
|
1422
|
-
if (
|
|
1423
|
-
best = { path: [...
|
|
1421
|
+
function step(node, path47, edges) {
|
|
1422
|
+
if (path47.length > best.path.length) {
|
|
1423
|
+
best = { path: [...path47], edges: [...edges] };
|
|
1424
1424
|
}
|
|
1425
|
-
if (
|
|
1425
|
+
if (path47.length - 1 >= maxDepth) return;
|
|
1426
1426
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1427
1427
|
for (const [srcId, edge] of incoming) {
|
|
1428
1428
|
if (visited.has(srcId)) continue;
|
|
1429
1429
|
visited.add(srcId);
|
|
1430
|
-
|
|
1430
|
+
path47.push(srcId);
|
|
1431
1431
|
edges.push(edge);
|
|
1432
|
-
step(srcId,
|
|
1433
|
-
|
|
1432
|
+
step(srcId, path47, edges);
|
|
1433
|
+
path47.pop();
|
|
1434
1434
|
edges.pop();
|
|
1435
1435
|
visited.delete(srcId);
|
|
1436
1436
|
}
|
|
@@ -1624,26 +1624,26 @@ function dominantFailingCall(graph, serviceId4, visited) {
|
|
|
1624
1624
|
return best;
|
|
1625
1625
|
}
|
|
1626
1626
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
1627
|
-
const
|
|
1627
|
+
const path47 = [originServiceId];
|
|
1628
1628
|
const edges = [];
|
|
1629
1629
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
1630
1630
|
let current = originServiceId;
|
|
1631
1631
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
1632
1632
|
const hop = dominantFailingCall(graph, current, visited);
|
|
1633
1633
|
if (!hop) break;
|
|
1634
|
-
|
|
1634
|
+
path47.push(hop.nextService);
|
|
1635
1635
|
edges.push(hop.edge);
|
|
1636
1636
|
visited.add(hop.nextService);
|
|
1637
1637
|
current = hop.nextService;
|
|
1638
1638
|
}
|
|
1639
1639
|
if (edges.length === 0) return null;
|
|
1640
|
-
return { path:
|
|
1640
|
+
return { path: path47, edges, culprit: current };
|
|
1641
1641
|
}
|
|
1642
1642
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
1643
1643
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
1644
1644
|
if (!chain) return null;
|
|
1645
1645
|
const culprit = chain.culprit;
|
|
1646
|
-
const
|
|
1646
|
+
const path47 = [...chain.path];
|
|
1647
1647
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
1648
1648
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
1649
1649
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -1651,14 +1651,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1651
1651
|
if (loc) {
|
|
1652
1652
|
let rootCauseNode = culprit;
|
|
1653
1653
|
if (loc.fileNode) {
|
|
1654
|
-
|
|
1654
|
+
path47.push(loc.fileNode);
|
|
1655
1655
|
edgeProvenances.push(import_types.Provenance.OBSERVED);
|
|
1656
1656
|
rootCauseNode = loc.fileNode;
|
|
1657
1657
|
}
|
|
1658
1658
|
return import_types.RootCauseResultSchema.parse({
|
|
1659
1659
|
rootCauseNode,
|
|
1660
1660
|
rootCauseReason: loc.rootCauseReason,
|
|
1661
|
-
traversalPath:
|
|
1661
|
+
traversalPath: path47,
|
|
1662
1662
|
edgeProvenances,
|
|
1663
1663
|
confidence,
|
|
1664
1664
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -1670,7 +1670,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
1670
1670
|
return import_types.RootCauseResultSchema.parse({
|
|
1671
1671
|
rootCauseNode: culprit,
|
|
1672
1672
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
1673
|
-
traversalPath:
|
|
1673
|
+
traversalPath: path47,
|
|
1674
1674
|
edgeProvenances,
|
|
1675
1675
|
confidence,
|
|
1676
1676
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -5818,10 +5818,10 @@ function fastifyRouteMethods(objNode) {
|
|
|
5818
5818
|
}
|
|
5819
5819
|
return [];
|
|
5820
5820
|
}
|
|
5821
|
-
function serverRoutesFromSource(source, parser, hasExpress, hasFastify) {
|
|
5821
|
+
function serverRoutesFromSource(source, parser, hasExpress, hasFastify, hasHono = false) {
|
|
5822
5822
|
const tree = parseSource2(parser, source);
|
|
5823
5823
|
const out = [];
|
|
5824
|
-
const framework = hasExpress ? "express" : "fastify";
|
|
5824
|
+
const framework = hasExpress ? "express" : hasFastify ? "fastify" : hasHono ? "hono" : "unknown";
|
|
5825
5825
|
walk(tree.rootNode, (node) => {
|
|
5826
5826
|
if (node.type !== "call_expression") return;
|
|
5827
5827
|
const fn = node.childForFieldName("function");
|
|
@@ -5971,8 +5971,9 @@ async function addRoutes(graph, services) {
|
|
|
5971
5971
|
};
|
|
5972
5972
|
const hasExpress = deps["express"] !== void 0;
|
|
5973
5973
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5974
|
+
const hasHono = deps["hono"] !== void 0;
|
|
5974
5975
|
const hasNext = deps["next"] !== void 0;
|
|
5975
|
-
if (!hasExpress && !hasFastify && !hasNext) continue;
|
|
5976
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext) continue;
|
|
5976
5977
|
const files = await loadSourceFiles(service.dir);
|
|
5977
5978
|
for (const file of files) {
|
|
5978
5979
|
if (isTestPath(file.path)) continue;
|
|
@@ -5982,8 +5983,8 @@ async function addRoutes(graph, services) {
|
|
|
5982
5983
|
try {
|
|
5983
5984
|
if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5984
5985
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5985
|
-
} else if (hasExpress || hasFastify) {
|
|
5986
|
-
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify);
|
|
5986
|
+
} else if (hasExpress || hasFastify || hasHono) {
|
|
5987
|
+
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
5987
5988
|
} else {
|
|
5988
5989
|
routes = [];
|
|
5989
5990
|
}
|
|
@@ -7307,30 +7308,264 @@ async function addK8sResources(graph, scanPath) {
|
|
|
7307
7308
|
return { nodesAdded, edgesAdded: 0 };
|
|
7308
7309
|
}
|
|
7309
7310
|
|
|
7311
|
+
// src/extract/infra/cloudflare.ts
|
|
7312
|
+
init_cjs_shims();
|
|
7313
|
+
var import_node_fs21 = require("fs");
|
|
7314
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
7315
|
+
var import_smol_toml2 = require("smol-toml");
|
|
7316
|
+
var import_types26 = require("@neat.is/types");
|
|
7317
|
+
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
7318
|
+
async function readWranglerConfig(dir) {
|
|
7319
|
+
for (const filename of WRANGLER_FILENAMES) {
|
|
7320
|
+
const abs = import_node_path37.default.join(dir, filename);
|
|
7321
|
+
if (!await exists2(abs)) continue;
|
|
7322
|
+
const raw = await import_node_fs21.promises.readFile(abs, "utf8");
|
|
7323
|
+
const config = filename === "wrangler.toml" ? (0, import_smol_toml2.parse)(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
7324
|
+
return { config, relFile: filename, raw };
|
|
7325
|
+
}
|
|
7326
|
+
return null;
|
|
7327
|
+
}
|
|
7328
|
+
function lineContaining(raw, needle) {
|
|
7329
|
+
if (!needle) return void 0;
|
|
7330
|
+
const idx = raw.indexOf(needle);
|
|
7331
|
+
if (idx === -1) return void 0;
|
|
7332
|
+
let line = 1;
|
|
7333
|
+
for (let i = 0; i < idx; i++) if (raw[i] === "\n") line++;
|
|
7334
|
+
return line;
|
|
7335
|
+
}
|
|
7336
|
+
function normalizeRoutes(config) {
|
|
7337
|
+
const out = [];
|
|
7338
|
+
const pushOne = (r) => {
|
|
7339
|
+
if (typeof r === "string") out.push(r);
|
|
7340
|
+
else if (r && typeof r === "object" && typeof r.pattern === "string") {
|
|
7341
|
+
out.push(r.pattern);
|
|
7342
|
+
}
|
|
7343
|
+
};
|
|
7344
|
+
if (Array.isArray(config.routes)) config.routes.forEach(pushOne);
|
|
7345
|
+
else if (config.route) pushOne(config.route);
|
|
7346
|
+
return out;
|
|
7347
|
+
}
|
|
7348
|
+
function addResourceEdge(graph, anchorId, edgeType, kind, name, evidenceFile, line) {
|
|
7349
|
+
let nodesAdded = 0;
|
|
7350
|
+
let edgesAdded = 0;
|
|
7351
|
+
const node = makeInfraNode(kind, name, "cloudflare");
|
|
7352
|
+
if (!graph.hasNode(node.id)) {
|
|
7353
|
+
graph.addNode(node.id, node);
|
|
7354
|
+
nodesAdded++;
|
|
7355
|
+
}
|
|
7356
|
+
if (node.id === anchorId) return { nodesAdded, edgesAdded };
|
|
7357
|
+
const edgeId = (0, import_types5.extractedEdgeId)(anchorId, node.id, edgeType);
|
|
7358
|
+
if (!graph.hasEdge(edgeId)) {
|
|
7359
|
+
const edge = {
|
|
7360
|
+
id: edgeId,
|
|
7361
|
+
source: anchorId,
|
|
7362
|
+
target: node.id,
|
|
7363
|
+
type: edgeType,
|
|
7364
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7365
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7366
|
+
evidence: { file: evidenceFile, ...line !== void 0 ? { line } : {} }
|
|
7367
|
+
};
|
|
7368
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
7369
|
+
edgesAdded++;
|
|
7370
|
+
}
|
|
7371
|
+
return { nodesAdded, edgesAdded };
|
|
7372
|
+
}
|
|
7373
|
+
async function addCloudflareWorkers(graph, services, scanPath) {
|
|
7374
|
+
let nodesAdded = 0;
|
|
7375
|
+
let edgesAdded = 0;
|
|
7376
|
+
const discovered = [];
|
|
7377
|
+
const workerIndex = /* @__PURE__ */ new Map();
|
|
7378
|
+
for (const service of services) {
|
|
7379
|
+
let read;
|
|
7380
|
+
try {
|
|
7381
|
+
read = await readWranglerConfig(service.dir);
|
|
7382
|
+
} catch (err) {
|
|
7383
|
+
recordExtractionError("infra cloudflare", import_node_path37.default.relative(scanPath, service.dir), err);
|
|
7384
|
+
continue;
|
|
7385
|
+
}
|
|
7386
|
+
if (!read || !read.config.name) continue;
|
|
7387
|
+
const evidenceFile = toPosix2(import_node_path37.default.relative(scanPath, import_node_path37.default.join(service.dir, read.relFile)));
|
|
7388
|
+
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
7389
|
+
}
|
|
7390
|
+
for (const worker of discovered) {
|
|
7391
|
+
const { service, config } = worker;
|
|
7392
|
+
const serviceNode = graph.getNodeAttributes(service.node.id);
|
|
7393
|
+
if (serviceNode.platform !== "cloudflare") {
|
|
7394
|
+
const updated = { ...serviceNode, platform: "cloudflare" };
|
|
7395
|
+
graph.replaceNodeAttributes(service.node.id, updated);
|
|
7396
|
+
}
|
|
7397
|
+
let anchorId = service.node.id;
|
|
7398
|
+
if (config.main) {
|
|
7399
|
+
const entryRelPath = toPosix2(import_node_path37.default.normalize(config.main));
|
|
7400
|
+
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
7401
|
+
graph,
|
|
7402
|
+
service.pkg.name,
|
|
7403
|
+
service.node.id,
|
|
7404
|
+
entryRelPath
|
|
7405
|
+
);
|
|
7406
|
+
nodesAdded += fn;
|
|
7407
|
+
edgesAdded += fe;
|
|
7408
|
+
const fileNode = graph.getNodeAttributes(fileNodeId);
|
|
7409
|
+
if (fileNode.platform !== "cloudflare" || fileNode.platformName !== config.name) {
|
|
7410
|
+
const updated = { ...fileNode, platform: "cloudflare", platformName: config.name };
|
|
7411
|
+
graph.replaceNodeAttributes(fileNodeId, updated);
|
|
7412
|
+
}
|
|
7413
|
+
anchorId = fileNodeId;
|
|
7414
|
+
}
|
|
7415
|
+
workerIndex.set(config.name, { anchorId });
|
|
7416
|
+
}
|
|
7417
|
+
for (const worker of discovered) {
|
|
7418
|
+
const { config, evidenceFile, raw } = worker;
|
|
7419
|
+
const anchorId = workerIndex.get(config.name).anchorId;
|
|
7420
|
+
const runtimeNode = makeInfraNode("workerd", "cloudflare", "cloudflare");
|
|
7421
|
+
if (!graph.hasNode(runtimeNode.id)) {
|
|
7422
|
+
graph.addNode(runtimeNode.id, runtimeNode);
|
|
7423
|
+
nodesAdded++;
|
|
7424
|
+
}
|
|
7425
|
+
if (runtimeNode.id !== anchorId) {
|
|
7426
|
+
const runsOnId = (0, import_types5.extractedEdgeId)(anchorId, runtimeNode.id, import_types26.EdgeType.RUNS_ON);
|
|
7427
|
+
if (!graph.hasEdge(runsOnId)) {
|
|
7428
|
+
const edge = {
|
|
7429
|
+
id: runsOnId,
|
|
7430
|
+
source: anchorId,
|
|
7431
|
+
target: runtimeNode.id,
|
|
7432
|
+
type: import_types26.EdgeType.RUNS_ON,
|
|
7433
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7434
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7435
|
+
evidence: {
|
|
7436
|
+
file: evidenceFile,
|
|
7437
|
+
...config.compatibility_date ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) } : {}
|
|
7438
|
+
}
|
|
7439
|
+
};
|
|
7440
|
+
graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge);
|
|
7441
|
+
edgesAdded++;
|
|
7442
|
+
}
|
|
7443
|
+
}
|
|
7444
|
+
for (const route of normalizeRoutes(config)) {
|
|
7445
|
+
const result = addResourceEdge(
|
|
7446
|
+
graph,
|
|
7447
|
+
anchorId,
|
|
7448
|
+
import_types26.EdgeType.CONNECTS_TO,
|
|
7449
|
+
"cloudflare-route",
|
|
7450
|
+
route,
|
|
7451
|
+
evidenceFile,
|
|
7452
|
+
lineContaining(raw, route)
|
|
7453
|
+
);
|
|
7454
|
+
nodesAdded += result.nodesAdded;
|
|
7455
|
+
edgesAdded += result.edgesAdded;
|
|
7456
|
+
}
|
|
7457
|
+
const bindingGroups = [
|
|
7458
|
+
{ kind: "cloudflare-kv", entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },
|
|
7459
|
+
{ kind: "cloudflare-d1", entries: config.d1_databases ?? [], nameOf: (b) => b.binding },
|
|
7460
|
+
{ kind: "cloudflare-r2", entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },
|
|
7461
|
+
{ kind: "cloudflare-durable-object", entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },
|
|
7462
|
+
{ kind: "cloudflare-queue", entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },
|
|
7463
|
+
{ kind: "cloudflare-queue", entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue }
|
|
7464
|
+
];
|
|
7465
|
+
for (const group of bindingGroups) {
|
|
7466
|
+
for (const entry of group.entries) {
|
|
7467
|
+
const name = group.nameOf(entry);
|
|
7468
|
+
if (!name) continue;
|
|
7469
|
+
const result = addResourceEdge(
|
|
7470
|
+
graph,
|
|
7471
|
+
anchorId,
|
|
7472
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7473
|
+
group.kind,
|
|
7474
|
+
name,
|
|
7475
|
+
evidenceFile,
|
|
7476
|
+
lineContaining(raw, name)
|
|
7477
|
+
);
|
|
7478
|
+
nodesAdded += result.nodesAdded;
|
|
7479
|
+
edgesAdded += result.edgesAdded;
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
for (const cron of config.triggers?.crons ?? []) {
|
|
7483
|
+
const result = addResourceEdge(
|
|
7484
|
+
graph,
|
|
7485
|
+
anchorId,
|
|
7486
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7487
|
+
"cloudflare-cron",
|
|
7488
|
+
cron,
|
|
7489
|
+
evidenceFile,
|
|
7490
|
+
lineContaining(raw, cron)
|
|
7491
|
+
);
|
|
7492
|
+
nodesAdded += result.nodesAdded;
|
|
7493
|
+
edgesAdded += result.edgesAdded;
|
|
7494
|
+
}
|
|
7495
|
+
for (const varName of Object.keys(config.vars ?? {})) {
|
|
7496
|
+
const result = addResourceEdge(
|
|
7497
|
+
graph,
|
|
7498
|
+
anchorId,
|
|
7499
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7500
|
+
"cloudflare-env-var",
|
|
7501
|
+
varName,
|
|
7502
|
+
evidenceFile,
|
|
7503
|
+
lineContaining(raw, varName)
|
|
7504
|
+
);
|
|
7505
|
+
nodesAdded += result.nodesAdded;
|
|
7506
|
+
edgesAdded += result.edgesAdded;
|
|
7507
|
+
}
|
|
7508
|
+
for (const svc of config.services ?? []) {
|
|
7509
|
+
if (!svc.service) continue;
|
|
7510
|
+
const target = workerIndex.get(svc.service);
|
|
7511
|
+
if (target && target.anchorId !== anchorId) {
|
|
7512
|
+
const edgeId = (0, import_types5.extractedEdgeId)(anchorId, target.anchorId, import_types26.EdgeType.CALLS);
|
|
7513
|
+
if (!graph.hasEdge(edgeId)) {
|
|
7514
|
+
const edge = {
|
|
7515
|
+
id: edgeId,
|
|
7516
|
+
source: anchorId,
|
|
7517
|
+
target: target.anchorId,
|
|
7518
|
+
type: import_types26.EdgeType.CALLS,
|
|
7519
|
+
provenance: import_types26.Provenance.EXTRACTED,
|
|
7520
|
+
confidence: (0, import_types26.confidenceForExtracted)("structural"),
|
|
7521
|
+
evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) }
|
|
7522
|
+
};
|
|
7523
|
+
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
7524
|
+
edgesAdded++;
|
|
7525
|
+
}
|
|
7526
|
+
continue;
|
|
7527
|
+
}
|
|
7528
|
+
const result = addResourceEdge(
|
|
7529
|
+
graph,
|
|
7530
|
+
anchorId,
|
|
7531
|
+
import_types26.EdgeType.DEPENDS_ON,
|
|
7532
|
+
"cloudflare-service-binding",
|
|
7533
|
+
svc.service,
|
|
7534
|
+
evidenceFile,
|
|
7535
|
+
lineContaining(raw, svc.service)
|
|
7536
|
+
);
|
|
7537
|
+
nodesAdded += result.nodesAdded;
|
|
7538
|
+
edgesAdded += result.edgesAdded;
|
|
7539
|
+
}
|
|
7540
|
+
}
|
|
7541
|
+
return { nodesAdded, edgesAdded };
|
|
7542
|
+
}
|
|
7543
|
+
|
|
7310
7544
|
// src/extract/infra/index.ts
|
|
7311
7545
|
async function addInfra(graph, scanPath, services) {
|
|
7312
7546
|
const compose = await addComposeInfra(graph, scanPath, services);
|
|
7313
7547
|
const dockerfile = await addDockerfileRuntimes(graph, services, scanPath);
|
|
7314
7548
|
const terraform = await addTerraformResources(graph, scanPath);
|
|
7315
7549
|
const k8s = await addK8sResources(graph, scanPath);
|
|
7550
|
+
const cloudflare = await addCloudflareWorkers(graph, services, scanPath);
|
|
7316
7551
|
return {
|
|
7317
|
-
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,
|
|
7318
|
-
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded
|
|
7552
|
+
nodesAdded: compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded + cloudflare.nodesAdded,
|
|
7553
|
+
edgesAdded: compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.edgesAdded + cloudflare.edgesAdded
|
|
7319
7554
|
};
|
|
7320
7555
|
}
|
|
7321
7556
|
|
|
7322
7557
|
// src/extract/index.ts
|
|
7323
|
-
var
|
|
7558
|
+
var import_node_path39 = __toESM(require("path"), 1);
|
|
7324
7559
|
|
|
7325
7560
|
// src/extract/retire.ts
|
|
7326
7561
|
init_cjs_shims();
|
|
7327
|
-
var
|
|
7328
|
-
var
|
|
7329
|
-
var
|
|
7562
|
+
var import_node_fs22 = require("fs");
|
|
7563
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
7564
|
+
var import_types27 = require("@neat.is/types");
|
|
7330
7565
|
function dropOrphanedFileNodes(graph) {
|
|
7331
7566
|
const orphans = [];
|
|
7332
7567
|
graph.forEachNode((id, attrs) => {
|
|
7333
|
-
if (attrs.type !==
|
|
7568
|
+
if (attrs.type !== import_types27.NodeType.FileNode) return;
|
|
7334
7569
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
7335
7570
|
orphans.push(id);
|
|
7336
7571
|
}
|
|
@@ -7343,14 +7578,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
7343
7578
|
const bases = [scanPath, ...serviceDirs];
|
|
7344
7579
|
graph.forEachEdge((id, attrs) => {
|
|
7345
7580
|
const edge = attrs;
|
|
7346
|
-
if (edge.provenance !==
|
|
7581
|
+
if (edge.provenance !== import_types27.Provenance.EXTRACTED) return;
|
|
7347
7582
|
const evidenceFile = edge.evidence?.file;
|
|
7348
7583
|
if (!evidenceFile) return;
|
|
7349
|
-
if (
|
|
7350
|
-
if (!(0,
|
|
7584
|
+
if (import_node_path38.default.isAbsolute(evidenceFile)) {
|
|
7585
|
+
if (!(0, import_node_fs22.existsSync)(evidenceFile)) toDrop.push(id);
|
|
7351
7586
|
return;
|
|
7352
7587
|
}
|
|
7353
|
-
const found = bases.some((base) => (0,
|
|
7588
|
+
const found = bases.some((base) => (0, import_node_fs22.existsSync)(import_node_path38.default.join(base, evidenceFile)));
|
|
7354
7589
|
if (!found) toDrop.push(id);
|
|
7355
7590
|
});
|
|
7356
7591
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -7392,7 +7627,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7392
7627
|
}
|
|
7393
7628
|
const droppedEntries = drainDroppedExtracted();
|
|
7394
7629
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
7395
|
-
const rejectedPath =
|
|
7630
|
+
const rejectedPath = import_node_path39.default.join(import_node_path39.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
7396
7631
|
try {
|
|
7397
7632
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
7398
7633
|
} catch (err) {
|
|
@@ -7426,7 +7661,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
7426
7661
|
|
|
7427
7662
|
// src/diff.ts
|
|
7428
7663
|
init_cjs_shims();
|
|
7429
|
-
var
|
|
7664
|
+
var import_node_fs23 = require("fs");
|
|
7430
7665
|
async function loadSnapshotForDiff(target) {
|
|
7431
7666
|
if (/^https?:\/\//i.test(target)) {
|
|
7432
7667
|
const res = await fetch(target);
|
|
@@ -7435,7 +7670,7 @@ async function loadSnapshotForDiff(target) {
|
|
|
7435
7670
|
}
|
|
7436
7671
|
return await res.json();
|
|
7437
7672
|
}
|
|
7438
|
-
const raw = await
|
|
7673
|
+
const raw = await import_node_fs23.promises.readFile(target, "utf8");
|
|
7439
7674
|
return JSON.parse(raw);
|
|
7440
7675
|
}
|
|
7441
7676
|
function indexEntries(entries) {
|
|
@@ -7503,9 +7738,9 @@ function canonicalJson(value) {
|
|
|
7503
7738
|
|
|
7504
7739
|
// src/persist.ts
|
|
7505
7740
|
init_cjs_shims();
|
|
7506
|
-
var
|
|
7507
|
-
var
|
|
7508
|
-
var
|
|
7741
|
+
var import_node_fs24 = require("fs");
|
|
7742
|
+
var import_node_path40 = __toESM(require("path"), 1);
|
|
7743
|
+
var import_types28 = require("@neat.is/types");
|
|
7509
7744
|
var SCHEMA_VERSION = 4;
|
|
7510
7745
|
function migrateV1ToV2(payload) {
|
|
7511
7746
|
const nodes = payload.graph.nodes;
|
|
@@ -7527,12 +7762,12 @@ function migrateV2ToV3(payload) {
|
|
|
7527
7762
|
for (const edge of edges) {
|
|
7528
7763
|
const attrs = edge.attributes;
|
|
7529
7764
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
7530
|
-
attrs.provenance =
|
|
7765
|
+
attrs.provenance = import_types28.Provenance.OBSERVED;
|
|
7531
7766
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
7532
7767
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
7533
7768
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
7534
7769
|
if (type && source && target) {
|
|
7535
|
-
const newId = (0,
|
|
7770
|
+
const newId = (0, import_types28.observedEdgeId)(source, target, type);
|
|
7536
7771
|
attrs.id = newId;
|
|
7537
7772
|
if (edge.key) edge.key = newId;
|
|
7538
7773
|
}
|
|
@@ -7541,7 +7776,7 @@ function migrateV2ToV3(payload) {
|
|
|
7541
7776
|
return { ...payload, schemaVersion: 3 };
|
|
7542
7777
|
}
|
|
7543
7778
|
async function ensureDir(filePath) {
|
|
7544
|
-
await
|
|
7779
|
+
await import_node_fs24.promises.mkdir(import_node_path40.default.dirname(filePath), { recursive: true });
|
|
7545
7780
|
}
|
|
7546
7781
|
async function saveGraphToDisk(graph, outPath) {
|
|
7547
7782
|
await ensureDir(outPath);
|
|
@@ -7551,13 +7786,13 @@ async function saveGraphToDisk(graph, outPath) {
|
|
|
7551
7786
|
graph: graph.export()
|
|
7552
7787
|
};
|
|
7553
7788
|
const tmp = `${outPath}.tmp`;
|
|
7554
|
-
await
|
|
7555
|
-
await
|
|
7789
|
+
await import_node_fs24.promises.writeFile(tmp, JSON.stringify(payload), "utf8");
|
|
7790
|
+
await import_node_fs24.promises.rename(tmp, outPath);
|
|
7556
7791
|
}
|
|
7557
7792
|
async function loadGraphFromDisk(graph, outPath) {
|
|
7558
7793
|
let raw;
|
|
7559
7794
|
try {
|
|
7560
|
-
raw = await
|
|
7795
|
+
raw = await import_node_fs24.promises.readFile(outPath, "utf8");
|
|
7561
7796
|
} catch (err) {
|
|
7562
7797
|
if (err.code === "ENOENT") return;
|
|
7563
7798
|
throw err;
|
|
@@ -7622,23 +7857,23 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
7622
7857
|
|
|
7623
7858
|
// src/projects.ts
|
|
7624
7859
|
init_cjs_shims();
|
|
7625
|
-
var
|
|
7860
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
7626
7861
|
function pathsForProject(project, baseDir) {
|
|
7627
7862
|
if (project === DEFAULT_PROJECT) {
|
|
7628
7863
|
return {
|
|
7629
|
-
snapshotPath:
|
|
7630
|
-
errorsPath:
|
|
7631
|
-
staleEventsPath:
|
|
7632
|
-
embeddingsCachePath:
|
|
7633
|
-
policyViolationsPath:
|
|
7864
|
+
snapshotPath: import_node_path41.default.join(baseDir, "graph.json"),
|
|
7865
|
+
errorsPath: import_node_path41.default.join(baseDir, "errors.ndjson"),
|
|
7866
|
+
staleEventsPath: import_node_path41.default.join(baseDir, "stale-events.ndjson"),
|
|
7867
|
+
embeddingsCachePath: import_node_path41.default.join(baseDir, "embeddings.json"),
|
|
7868
|
+
policyViolationsPath: import_node_path41.default.join(baseDir, "policy-violations.ndjson")
|
|
7634
7869
|
};
|
|
7635
7870
|
}
|
|
7636
7871
|
return {
|
|
7637
|
-
snapshotPath:
|
|
7638
|
-
errorsPath:
|
|
7639
|
-
staleEventsPath:
|
|
7640
|
-
embeddingsCachePath:
|
|
7641
|
-
policyViolationsPath:
|
|
7872
|
+
snapshotPath: import_node_path41.default.join(baseDir, `${project}.json`),
|
|
7873
|
+
errorsPath: import_node_path41.default.join(baseDir, `errors.${project}.ndjson`),
|
|
7874
|
+
staleEventsPath: import_node_path41.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
7875
|
+
embeddingsCachePath: import_node_path41.default.join(baseDir, `embeddings.${project}.json`),
|
|
7876
|
+
policyViolationsPath: import_node_path41.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
7642
7877
|
};
|
|
7643
7878
|
}
|
|
7644
7879
|
var Projects = class {
|
|
@@ -7678,23 +7913,23 @@ function parseExtraProjects(raw) {
|
|
|
7678
7913
|
|
|
7679
7914
|
// src/registry.ts
|
|
7680
7915
|
init_cjs_shims();
|
|
7681
|
-
var
|
|
7916
|
+
var import_node_fs25 = require("fs");
|
|
7682
7917
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
7683
|
-
var
|
|
7684
|
-
var
|
|
7918
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
7919
|
+
var import_types29 = require("@neat.is/types");
|
|
7685
7920
|
function neatHome() {
|
|
7686
7921
|
const override = process.env.NEAT_HOME;
|
|
7687
|
-
if (override && override.length > 0) return
|
|
7688
|
-
return
|
|
7922
|
+
if (override && override.length > 0) return import_node_path42.default.resolve(override);
|
|
7923
|
+
return import_node_path42.default.join(import_node_os3.default.homedir(), ".neat");
|
|
7689
7924
|
}
|
|
7690
7925
|
function registryPath() {
|
|
7691
|
-
return
|
|
7926
|
+
return import_node_path42.default.join(neatHome(), "projects.json");
|
|
7692
7927
|
}
|
|
7693
7928
|
async function readRegistry() {
|
|
7694
7929
|
const file = registryPath();
|
|
7695
7930
|
let raw;
|
|
7696
7931
|
try {
|
|
7697
|
-
raw = await
|
|
7932
|
+
raw = await import_node_fs25.promises.readFile(file, "utf8");
|
|
7698
7933
|
} catch (err) {
|
|
7699
7934
|
if (err.code === "ENOENT") {
|
|
7700
7935
|
return { version: 1, projects: [] };
|
|
@@ -7702,7 +7937,7 @@ async function readRegistry() {
|
|
|
7702
7937
|
throw err;
|
|
7703
7938
|
}
|
|
7704
7939
|
const parsed = JSON.parse(raw);
|
|
7705
|
-
return
|
|
7940
|
+
return import_types29.RegistryFileSchema.parse(parsed);
|
|
7706
7941
|
}
|
|
7707
7942
|
async function getProject(name) {
|
|
7708
7943
|
const reg = await readRegistry();
|
|
@@ -7923,11 +8158,11 @@ function registerRoutes(scope, ctx) {
|
|
|
7923
8158
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
7924
8159
|
const parsed = [];
|
|
7925
8160
|
for (const c of candidates) {
|
|
7926
|
-
const r =
|
|
8161
|
+
const r = import_types30.DivergenceTypeSchema.safeParse(c);
|
|
7927
8162
|
if (!r.success) {
|
|
7928
8163
|
return reply.code(400).send({
|
|
7929
8164
|
error: `unknown divergence type "${c}"`,
|
|
7930
|
-
allowed:
|
|
8165
|
+
allowed: import_types30.DivergenceTypeSchema.options
|
|
7931
8166
|
});
|
|
7932
8167
|
}
|
|
7933
8168
|
parsed.push(r.data);
|
|
@@ -8178,7 +8413,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8178
8413
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
8179
8414
|
let violations = await log.readAll();
|
|
8180
8415
|
if (req.query.severity) {
|
|
8181
|
-
const sev =
|
|
8416
|
+
const sev = import_types30.PolicySeveritySchema.safeParse(req.query.severity);
|
|
8182
8417
|
if (!sev.success) {
|
|
8183
8418
|
return reply.code(400).send({
|
|
8184
8419
|
error: "invalid severity",
|
|
@@ -8217,7 +8452,7 @@ function registerRoutes(scope, ctx) {
|
|
|
8217
8452
|
scope.post("/policies/check", async (req, reply) => {
|
|
8218
8453
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
8219
8454
|
if (!proj) return;
|
|
8220
|
-
const parsed =
|
|
8455
|
+
const parsed = import_types30.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
8221
8456
|
if (!parsed.success) {
|
|
8222
8457
|
return reply.code(400).send({
|
|
8223
8458
|
error: "invalid /policies/check body",
|
|
@@ -8479,8 +8714,8 @@ init_otel_grpc();
|
|
|
8479
8714
|
|
|
8480
8715
|
// src/search.ts
|
|
8481
8716
|
init_cjs_shims();
|
|
8482
|
-
var
|
|
8483
|
-
var
|
|
8717
|
+
var import_node_fs26 = require("fs");
|
|
8718
|
+
var import_node_path45 = __toESM(require("path"), 1);
|
|
8484
8719
|
var import_node_crypto3 = require("crypto");
|
|
8485
8720
|
var DEFAULT_LIMIT = 10;
|
|
8486
8721
|
var NOMIC_DIM = 768;
|
|
@@ -8634,7 +8869,7 @@ async function pickEmbedder() {
|
|
|
8634
8869
|
}
|
|
8635
8870
|
async function readCache(cachePath) {
|
|
8636
8871
|
try {
|
|
8637
|
-
const raw = await
|
|
8872
|
+
const raw = await import_node_fs26.promises.readFile(cachePath, "utf8");
|
|
8638
8873
|
const parsed = JSON.parse(raw);
|
|
8639
8874
|
if (parsed.version !== 1) return null;
|
|
8640
8875
|
return parsed;
|
|
@@ -8643,8 +8878,8 @@ async function readCache(cachePath) {
|
|
|
8643
8878
|
}
|
|
8644
8879
|
}
|
|
8645
8880
|
async function writeCache(cachePath, cache) {
|
|
8646
|
-
await
|
|
8647
|
-
await
|
|
8881
|
+
await import_node_fs26.promises.mkdir(import_node_path45.default.dirname(cachePath), { recursive: true });
|
|
8882
|
+
await import_node_fs26.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
8648
8883
|
}
|
|
8649
8884
|
var VectorIndex = class {
|
|
8650
8885
|
constructor(embedder, cachePath) {
|
|
@@ -8824,14 +9059,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
8824
9059
|
async function main() {
|
|
8825
9060
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
8826
9061
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
8827
|
-
const baseDir = baseDirEnv ?
|
|
8828
|
-
const defaultScanPath =
|
|
9062
|
+
const baseDir = baseDirEnv ? import_node_path46.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path46.default.resolve(import_node_path46.default.dirname(legacyOutPath)) : import_node_path46.default.resolve("./neat-out");
|
|
9063
|
+
const defaultScanPath = import_node_path46.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
|
|
8829
9064
|
const registry = new Projects();
|
|
8830
9065
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
8831
9066
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
8832
9067
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
8833
9068
|
const projectScan = process.env[envKey];
|
|
8834
|
-
await bootProject(registry, name, projectScan ?
|
|
9069
|
+
await bootProject(registry, name, projectScan ? import_node_path46.default.resolve(projectScan) : void 0, baseDir);
|
|
8835
9070
|
}
|
|
8836
9071
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
8837
9072
|
const port = Number(process.env.PORT ?? 8080);
|