@neat.is/core 0.4.16 → 0.4.17
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-VMLWUK7W.js → chunk-CEDXXMGO.js} +16 -2
- package/dist/chunk-CEDXXMGO.js.map +1 -0
- package/dist/{chunk-XS4CGNRO.js → chunk-LUDSPX5N.js} +293 -71
- package/dist/chunk-LUDSPX5N.js.map +1 -0
- package/dist/cli.cjs +568 -286
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +12 -2
- package/dist/cli.d.ts +12 -2
- package/dist/cli.js +76 -17
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +377 -142
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +384 -149
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +269 -97
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-VMLWUK7W.js.map +0 -1
- package/dist/chunk-XS4CGNRO.js.map +0 -1
package/dist/server.cjs
CHANGED
|
@@ -56,9 +56,9 @@ function mountBearerAuth(app, opts) {
|
|
|
56
56
|
const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...opts.extraUnauthenticatedSuffixes ?? []];
|
|
57
57
|
const publicRead = opts.publicRead === true;
|
|
58
58
|
app.addHook("preHandler", (req, reply, done) => {
|
|
59
|
-
const
|
|
59
|
+
const path43 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
60
60
|
for (const suffix of suffixes) {
|
|
61
|
-
if (
|
|
61
|
+
if (path43 === suffix || path43.endsWith(suffix)) {
|
|
62
62
|
done();
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
@@ -186,8 +186,8 @@ function reshapeGrpcRequest(req) {
|
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
function resolveProtoRoot() {
|
|
189
|
-
const here =
|
|
190
|
-
return
|
|
189
|
+
const here = import_node_path39.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
190
|
+
return import_node_path39.default.resolve(here, "..", "proto");
|
|
191
191
|
}
|
|
192
192
|
function loadTraceService() {
|
|
193
193
|
const protoRoot = resolveProtoRoot();
|
|
@@ -255,13 +255,13 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
255
255
|
})
|
|
256
256
|
};
|
|
257
257
|
}
|
|
258
|
-
var import_node_url,
|
|
258
|
+
var import_node_url, import_node_path39, import_node_crypto2, grpc, protoLoader;
|
|
259
259
|
var init_otel_grpc = __esm({
|
|
260
260
|
"src/otel-grpc.ts"() {
|
|
261
261
|
"use strict";
|
|
262
262
|
init_cjs_shims();
|
|
263
263
|
import_node_url = require("url");
|
|
264
|
-
|
|
264
|
+
import_node_path39 = __toESM(require("path"), 1);
|
|
265
265
|
import_node_crypto2 = require("crypto");
|
|
266
266
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
267
267
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
@@ -371,10 +371,10 @@ function parseOtlpRequest(body) {
|
|
|
371
371
|
return out;
|
|
372
372
|
}
|
|
373
373
|
function loadProtoRoot() {
|
|
374
|
-
const here =
|
|
375
|
-
const protoRoot =
|
|
374
|
+
const here = import_node_path40.default.dirname((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
375
|
+
const protoRoot = import_node_path40.default.resolve(here, "..", "proto");
|
|
376
376
|
const root = new import_protobufjs.default.Root();
|
|
377
|
-
root.resolvePath = (_origin, target) =>
|
|
377
|
+
root.resolvePath = (_origin, target) => import_node_path40.default.resolve(protoRoot, target);
|
|
378
378
|
root.loadSync(
|
|
379
379
|
"opentelemetry/proto/collector/trace/v1/trace_service.proto",
|
|
380
380
|
{ keepCase: true }
|
|
@@ -570,12 +570,12 @@ async function buildOtelReceiver(opts) {
|
|
|
570
570
|
};
|
|
571
571
|
return decorated;
|
|
572
572
|
}
|
|
573
|
-
var
|
|
573
|
+
var import_node_path40, import_node_url2, import_fastify2, import_protobufjs, ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT, ENV_FALLBACK, exportTraceServiceRequestType, exportTraceServiceResponseType, cachedProtobufResponseBody;
|
|
574
574
|
var init_otel = __esm({
|
|
575
575
|
"src/otel.ts"() {
|
|
576
576
|
"use strict";
|
|
577
577
|
init_cjs_shims();
|
|
578
|
-
|
|
578
|
+
import_node_path40 = __toESM(require("path"), 1);
|
|
579
579
|
import_node_url2 = require("url");
|
|
580
580
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
581
581
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
@@ -591,7 +591,7 @@ var init_otel = __esm({
|
|
|
591
591
|
|
|
592
592
|
// src/server.ts
|
|
593
593
|
init_cjs_shims();
|
|
594
|
-
var
|
|
594
|
+
var import_node_path42 = __toESM(require("path"), 1);
|
|
595
595
|
|
|
596
596
|
// src/graph.ts
|
|
597
597
|
init_cjs_shims();
|
|
@@ -615,7 +615,7 @@ function getGraph(project = DEFAULT_PROJECT) {
|
|
|
615
615
|
init_cjs_shims();
|
|
616
616
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
617
617
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
618
|
-
var
|
|
618
|
+
var import_types25 = require("@neat.is/types");
|
|
619
619
|
|
|
620
620
|
// src/extend/index.ts
|
|
621
621
|
init_cjs_shims();
|
|
@@ -1358,19 +1358,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
1358
1358
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
1359
1359
|
let best = { path: [start], edges: [] };
|
|
1360
1360
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
1361
|
-
function step(node,
|
|
1362
|
-
if (
|
|
1363
|
-
best = { path: [...
|
|
1361
|
+
function step(node, path43, edges) {
|
|
1362
|
+
if (path43.length > best.path.length) {
|
|
1363
|
+
best = { path: [...path43], edges: [...edges] };
|
|
1364
1364
|
}
|
|
1365
|
-
if (
|
|
1365
|
+
if (path43.length - 1 >= maxDepth) return;
|
|
1366
1366
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
1367
1367
|
for (const [srcId, edge] of incoming) {
|
|
1368
1368
|
if (visited.has(srcId)) continue;
|
|
1369
1369
|
visited.add(srcId);
|
|
1370
|
-
|
|
1370
|
+
path43.push(srcId);
|
|
1371
1371
|
edges.push(edge);
|
|
1372
|
-
step(srcId,
|
|
1373
|
-
|
|
1372
|
+
step(srcId, path43, edges);
|
|
1373
|
+
path43.pop();
|
|
1374
1374
|
edges.pop();
|
|
1375
1375
|
visited.delete(srcId);
|
|
1376
1376
|
}
|
|
@@ -2174,6 +2174,41 @@ function thresholdForEdgeType(edgeType, overrides) {
|
|
|
2174
2174
|
const map = overrides ?? loadStaleThresholdsFromEnv();
|
|
2175
2175
|
return map[edgeType] ?? FALLBACK_STALE_THRESHOLD_MS;
|
|
2176
2176
|
}
|
|
2177
|
+
var DEFAULT_INCIDENT_THRESHOLDS = {
|
|
2178
|
+
threshold: 5,
|
|
2179
|
+
windowMs: 6e4
|
|
2180
|
+
};
|
|
2181
|
+
function loadIncidentThresholdsFromEnv() {
|
|
2182
|
+
const raw = process.env.NEAT_INCIDENT_THRESHOLDS;
|
|
2183
|
+
if (!raw) return DEFAULT_INCIDENT_THRESHOLDS;
|
|
2184
|
+
try {
|
|
2185
|
+
const overrides = JSON.parse(raw);
|
|
2186
|
+
const merged = { ...DEFAULT_INCIDENT_THRESHOLDS };
|
|
2187
|
+
if (typeof overrides.threshold === "number" && Number.isFinite(overrides.threshold) && overrides.threshold >= 1) {
|
|
2188
|
+
merged.threshold = Math.floor(overrides.threshold);
|
|
2189
|
+
}
|
|
2190
|
+
if (typeof overrides.windowMs === "number" && Number.isFinite(overrides.windowMs) && overrides.windowMs >= 0) {
|
|
2191
|
+
merged.windowMs = overrides.windowMs;
|
|
2192
|
+
}
|
|
2193
|
+
return merged;
|
|
2194
|
+
} catch (err) {
|
|
2195
|
+
console.warn(
|
|
2196
|
+
`[neat] NEAT_INCIDENT_THRESHOLDS could not be parsed (${err.message}); using defaults`
|
|
2197
|
+
);
|
|
2198
|
+
return DEFAULT_INCIDENT_THRESHOLDS;
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
function httpResponseStatus(span) {
|
|
2202
|
+
for (const key of ["http.response.status_code", "http.status_code"]) {
|
|
2203
|
+
const v = span.attributes[key];
|
|
2204
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
2205
|
+
if (typeof v === "string") {
|
|
2206
|
+
const n = Number(v);
|
|
2207
|
+
if (Number.isFinite(n)) return n;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
return void 0;
|
|
2211
|
+
}
|
|
2177
2212
|
function nowIso(ctx) {
|
|
2178
2213
|
return new Date(ctx.now ? ctx.now() : Date.now()).toISOString();
|
|
2179
2214
|
}
|
|
@@ -2562,6 +2597,71 @@ function sanitizeAttributes(attrs) {
|
|
|
2562
2597
|
}
|
|
2563
2598
|
return out;
|
|
2564
2599
|
}
|
|
2600
|
+
async function recordFailingResponseIncident(ctx, span, affectedNode, timestamp, statusCode, count, firstTimestamp) {
|
|
2601
|
+
const attrs = sanitizeAttributes(span.attributes);
|
|
2602
|
+
const first = firstTimestamp ?? timestamp;
|
|
2603
|
+
const peer = pickAddress(span);
|
|
2604
|
+
const message = count > 1 ? `${count} consecutive HTTP ${statusCode} responses` + (peer ? ` to ${peer}` : "") : `HTTP ${statusCode} response` + (peer ? ` from ${peer}` : "");
|
|
2605
|
+
const ev = {
|
|
2606
|
+
id: `${span.traceId}:${span.spanId}`,
|
|
2607
|
+
timestamp,
|
|
2608
|
+
service: span.service,
|
|
2609
|
+
traceId: span.traceId,
|
|
2610
|
+
spanId: span.spanId,
|
|
2611
|
+
errorType: "http-failure",
|
|
2612
|
+
errorMessage: message,
|
|
2613
|
+
...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
|
|
2614
|
+
affectedNode,
|
|
2615
|
+
httpStatusCode: statusCode,
|
|
2616
|
+
incidentCount: count,
|
|
2617
|
+
firstTimestamp: first,
|
|
2618
|
+
lastTimestamp: timestamp
|
|
2619
|
+
};
|
|
2620
|
+
await appendErrorEvent(ctx, ev);
|
|
2621
|
+
}
|
|
2622
|
+
async function advance4xxBurst(ctx, span, affectedNode, ts, nowMs, status2) {
|
|
2623
|
+
const { threshold, windowMs } = loadIncidentThresholdsFromEnv();
|
|
2624
|
+
if (!ctx.burstState) ctx.burstState = /* @__PURE__ */ new Map();
|
|
2625
|
+
const peer = pickAddress(span) ?? span.spanId;
|
|
2626
|
+
const key = `${span.service}->${peer}`;
|
|
2627
|
+
const existing = ctx.burstState.get(key);
|
|
2628
|
+
let state;
|
|
2629
|
+
if (existing && nowMs - existing.lastMs <= windowMs) {
|
|
2630
|
+
existing.count += 1;
|
|
2631
|
+
existing.lastTs = ts;
|
|
2632
|
+
existing.lastMs = nowMs;
|
|
2633
|
+
existing.codes.set(status2, (existing.codes.get(status2) ?? 0) + 1);
|
|
2634
|
+
state = existing;
|
|
2635
|
+
} else {
|
|
2636
|
+
state = {
|
|
2637
|
+
count: 1,
|
|
2638
|
+
firstTs: ts,
|
|
2639
|
+
lastTs: ts,
|
|
2640
|
+
lastMs: nowMs,
|
|
2641
|
+
codes: /* @__PURE__ */ new Map([[status2, 1]])
|
|
2642
|
+
};
|
|
2643
|
+
ctx.burstState.set(key, state);
|
|
2644
|
+
}
|
|
2645
|
+
if (state.count < threshold) return;
|
|
2646
|
+
let dominant = status2;
|
|
2647
|
+
let max = 0;
|
|
2648
|
+
for (const [code, n] of state.codes) {
|
|
2649
|
+
if (n > max) {
|
|
2650
|
+
max = n;
|
|
2651
|
+
dominant = code;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
await recordFailingResponseIncident(
|
|
2655
|
+
ctx,
|
|
2656
|
+
span,
|
|
2657
|
+
affectedNode,
|
|
2658
|
+
state.lastTs,
|
|
2659
|
+
dominant,
|
|
2660
|
+
state.count,
|
|
2661
|
+
state.firstTs
|
|
2662
|
+
);
|
|
2663
|
+
ctx.burstState.delete(key);
|
|
2664
|
+
}
|
|
2565
2665
|
async function handleSpan(ctx, span) {
|
|
2566
2666
|
const ts = span.startTimeIso ?? nowIso(ctx);
|
|
2567
2667
|
const nowMs = ctx.now ? ctx.now() : Date.now();
|
|
@@ -2660,6 +2760,14 @@ async function handleSpan(ctx, span) {
|
|
|
2660
2760
|
await appendErrorEvent(ctx, ev);
|
|
2661
2761
|
}
|
|
2662
2762
|
}
|
|
2763
|
+
if (span.statusCode !== 2) {
|
|
2764
|
+
const status2 = httpResponseStatus(span);
|
|
2765
|
+
if (status2 !== void 0 && status2 >= 500) {
|
|
2766
|
+
await recordFailingResponseIncident(ctx, span, sourceId, ts, status2, 1);
|
|
2767
|
+
} else if (status2 !== void 0 && status2 >= 400 && spanMintsObservedEdge(span.kind)) {
|
|
2768
|
+
await advance4xxBurst(ctx, span, sourceId, ts, nowMs, status2);
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2663
2771
|
void affectedNode;
|
|
2664
2772
|
if (ctx.onPolicyTrigger) await ctx.onPolicyTrigger(ctx.graph);
|
|
2665
2773
|
}
|
|
@@ -4679,7 +4787,7 @@ async function addConfigNodes(graph, services, scanPath) {
|
|
|
4679
4787
|
|
|
4680
4788
|
// src/extract/calls/index.ts
|
|
4681
4789
|
init_cjs_shims();
|
|
4682
|
-
var
|
|
4790
|
+
var import_types18 = require("@neat.is/types");
|
|
4683
4791
|
|
|
4684
4792
|
// src/extract/calls/http.ts
|
|
4685
4793
|
init_cjs_shims();
|
|
@@ -5032,15 +5140,75 @@ function grpcEndpointsFromFile(file, serviceDir) {
|
|
|
5032
5140
|
return out;
|
|
5033
5141
|
}
|
|
5034
5142
|
|
|
5143
|
+
// src/extract/calls/supabase.ts
|
|
5144
|
+
init_cjs_shims();
|
|
5145
|
+
var import_node_path29 = __toESM(require("path"), 1);
|
|
5146
|
+
var import_types17 = require("@neat.is/types");
|
|
5147
|
+
var SUPABASE_JS_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/supabase-js['"`]/;
|
|
5148
|
+
var SUPABASE_SSR_IMPORT_RE = /(?:from\s+['"`]|require\(\s*['"`])@supabase\/ssr['"`]/;
|
|
5149
|
+
var SUPABASE_CLIENT_RE = /\b(createClient|createServerClient|createBrowserClient)\s*\(\s*(?:['"`]([^'"`]*)['"`])?/g;
|
|
5150
|
+
function hostFromLiteral(literal) {
|
|
5151
|
+
if (!literal) return null;
|
|
5152
|
+
const m = /^https?:\/\/([^/:'"`\s]+)/.exec(literal.trim());
|
|
5153
|
+
if (!m) return null;
|
|
5154
|
+
const host = m[1];
|
|
5155
|
+
if (!/\.supabase\.(co|in)$/i.test(host)) return null;
|
|
5156
|
+
return host;
|
|
5157
|
+
}
|
|
5158
|
+
function readImports2(content) {
|
|
5159
|
+
return {
|
|
5160
|
+
hasSupabaseJs: SUPABASE_JS_IMPORT_RE.test(content),
|
|
5161
|
+
hasSupabaseSsr: SUPABASE_SSR_IMPORT_RE.test(content)
|
|
5162
|
+
};
|
|
5163
|
+
}
|
|
5164
|
+
function constructorMatchesImport(name, ctx) {
|
|
5165
|
+
if (name === "createClient") return ctx.hasSupabaseJs;
|
|
5166
|
+
return ctx.hasSupabaseSsr;
|
|
5167
|
+
}
|
|
5168
|
+
function supabaseEndpointsFromFile(file, serviceDir) {
|
|
5169
|
+
const ctx = readImports2(file.content);
|
|
5170
|
+
if (!ctx.hasSupabaseJs && !ctx.hasSupabaseSsr) return [];
|
|
5171
|
+
const out = [];
|
|
5172
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5173
|
+
SUPABASE_CLIENT_RE.lastIndex = 0;
|
|
5174
|
+
let m;
|
|
5175
|
+
while ((m = SUPABASE_CLIENT_RE.exec(file.content)) !== null) {
|
|
5176
|
+
const ctor = m[1];
|
|
5177
|
+
if (!constructorMatchesImport(ctor, ctx)) continue;
|
|
5178
|
+
const host = hostFromLiteral(m[2]);
|
|
5179
|
+
const name = host ?? "env";
|
|
5180
|
+
if (seen.has(name)) continue;
|
|
5181
|
+
seen.add(name);
|
|
5182
|
+
const line = lineOf(file.content, m[0]);
|
|
5183
|
+
out.push({
|
|
5184
|
+
infraId: (0, import_types17.infraId)("supabase", name),
|
|
5185
|
+
name,
|
|
5186
|
+
kind: "supabase",
|
|
5187
|
+
edgeType: "CALLS",
|
|
5188
|
+
// `createClient(...)` from @supabase/supabase-js (or createServerClient /
|
|
5189
|
+
// createBrowserClient from @supabase/ssr) with the import in scope — a
|
|
5190
|
+
// framework-aware recognizer matched the SDK shape. Verified-call-site
|
|
5191
|
+
// tier (ADR-066), the same grade aws.ts / grpc.ts emit at.
|
|
5192
|
+
confidenceKind: "verified-call-site",
|
|
5193
|
+
evidence: {
|
|
5194
|
+
file: import_node_path29.default.relative(serviceDir, file.path),
|
|
5195
|
+
line,
|
|
5196
|
+
snippet: snippet(file.content, line)
|
|
5197
|
+
}
|
|
5198
|
+
});
|
|
5199
|
+
}
|
|
5200
|
+
return out;
|
|
5201
|
+
}
|
|
5202
|
+
|
|
5035
5203
|
// src/extract/calls/index.ts
|
|
5036
5204
|
function edgeTypeFromEndpoint(ep) {
|
|
5037
5205
|
switch (ep.edgeType) {
|
|
5038
5206
|
case "PUBLISHES_TO":
|
|
5039
|
-
return
|
|
5207
|
+
return import_types18.EdgeType.PUBLISHES_TO;
|
|
5040
5208
|
case "CONSUMES_FROM":
|
|
5041
|
-
return
|
|
5209
|
+
return import_types18.EdgeType.CONSUMES_FROM;
|
|
5042
5210
|
default:
|
|
5043
|
-
return
|
|
5211
|
+
return import_types18.EdgeType.CALLS;
|
|
5044
5212
|
}
|
|
5045
5213
|
}
|
|
5046
5214
|
function isAwsKind(kind) {
|
|
@@ -5060,6 +5228,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
5060
5228
|
endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir));
|
|
5061
5229
|
endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir));
|
|
5062
5230
|
endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir));
|
|
5231
|
+
endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir));
|
|
5063
5232
|
}
|
|
5064
5233
|
if (endpoints.length === 0) continue;
|
|
5065
5234
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
@@ -5067,7 +5236,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
5067
5236
|
if (!graph.hasNode(ep.infraId)) {
|
|
5068
5237
|
const node = {
|
|
5069
5238
|
id: ep.infraId,
|
|
5070
|
-
type:
|
|
5239
|
+
type: import_types18.NodeType.InfraNode,
|
|
5071
5240
|
name: ep.name,
|
|
5072
5241
|
// #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,
|
|
5073
5242
|
// aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the
|
|
@@ -5079,7 +5248,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
5079
5248
|
nodesAdded++;
|
|
5080
5249
|
}
|
|
5081
5250
|
const edgeType = edgeTypeFromEndpoint(ep);
|
|
5082
|
-
const confidence = (0,
|
|
5251
|
+
const confidence = (0, import_types18.confidenceForExtracted)(ep.confidenceKind);
|
|
5083
5252
|
const relFile = toPosix2(ep.evidence.file);
|
|
5084
5253
|
const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(
|
|
5085
5254
|
graph,
|
|
@@ -5089,7 +5258,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
5089
5258
|
);
|
|
5090
5259
|
nodesAdded += n;
|
|
5091
5260
|
edgesAdded += e;
|
|
5092
|
-
if (!(0,
|
|
5261
|
+
if (!(0, import_types18.passesExtractedFloor)(confidence)) {
|
|
5093
5262
|
noteExtractedDropped({
|
|
5094
5263
|
source: fileNodeId,
|
|
5095
5264
|
target: ep.infraId,
|
|
@@ -5109,7 +5278,7 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
5109
5278
|
source: fileNodeId,
|
|
5110
5279
|
target: ep.infraId,
|
|
5111
5280
|
type: edgeType,
|
|
5112
|
-
provenance:
|
|
5281
|
+
provenance: import_types18.Provenance.EXTRACTED,
|
|
5113
5282
|
confidence,
|
|
5114
5283
|
evidence: ep.evidence
|
|
5115
5284
|
};
|
|
@@ -5134,16 +5303,16 @@ init_cjs_shims();
|
|
|
5134
5303
|
|
|
5135
5304
|
// src/extract/infra/docker-compose.ts
|
|
5136
5305
|
init_cjs_shims();
|
|
5137
|
-
var
|
|
5138
|
-
var
|
|
5306
|
+
var import_node_path30 = __toESM(require("path"), 1);
|
|
5307
|
+
var import_types20 = require("@neat.is/types");
|
|
5139
5308
|
|
|
5140
5309
|
// src/extract/infra/shared.ts
|
|
5141
5310
|
init_cjs_shims();
|
|
5142
|
-
var
|
|
5311
|
+
var import_types19 = require("@neat.is/types");
|
|
5143
5312
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
5144
5313
|
return {
|
|
5145
|
-
id: (0,
|
|
5146
|
-
type:
|
|
5314
|
+
id: (0, import_types19.infraId)(kind, name),
|
|
5315
|
+
type: import_types19.NodeType.InfraNode,
|
|
5147
5316
|
name,
|
|
5148
5317
|
provider,
|
|
5149
5318
|
kind,
|
|
@@ -5172,7 +5341,7 @@ function dependsOnList(value) {
|
|
|
5172
5341
|
}
|
|
5173
5342
|
function serviceNameToServiceNode(name, services) {
|
|
5174
5343
|
for (const s of services) {
|
|
5175
|
-
if (s.node.name === name ||
|
|
5344
|
+
if (s.node.name === name || import_node_path30.default.basename(s.dir) === name) return s.node.id;
|
|
5176
5345
|
}
|
|
5177
5346
|
return null;
|
|
5178
5347
|
}
|
|
@@ -5181,7 +5350,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
5181
5350
|
let edgesAdded = 0;
|
|
5182
5351
|
let composePath = null;
|
|
5183
5352
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
5184
|
-
const abs =
|
|
5353
|
+
const abs = import_node_path30.default.join(scanPath, name);
|
|
5185
5354
|
if (await exists2(abs)) {
|
|
5186
5355
|
composePath = abs;
|
|
5187
5356
|
break;
|
|
@@ -5194,13 +5363,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
5194
5363
|
} catch (err) {
|
|
5195
5364
|
recordExtractionError(
|
|
5196
5365
|
"infra docker-compose",
|
|
5197
|
-
|
|
5366
|
+
import_node_path30.default.relative(scanPath, composePath),
|
|
5198
5367
|
err
|
|
5199
5368
|
);
|
|
5200
5369
|
return { nodesAdded, edgesAdded };
|
|
5201
5370
|
}
|
|
5202
5371
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
5203
|
-
const evidenceFile =
|
|
5372
|
+
const evidenceFile = import_node_path30.default.relative(scanPath, composePath).split(import_node_path30.default.sep).join("/");
|
|
5204
5373
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
5205
5374
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
5206
5375
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -5222,15 +5391,15 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
5222
5391
|
for (const dep of dependsOnList(svc.depends_on)) {
|
|
5223
5392
|
const targetId = composeNameToNodeId.get(dep);
|
|
5224
5393
|
if (!targetId) continue;
|
|
5225
|
-
const edgeId = (0, import_types5.extractedEdgeId)(sourceId, targetId,
|
|
5394
|
+
const edgeId = (0, import_types5.extractedEdgeId)(sourceId, targetId, import_types20.EdgeType.DEPENDS_ON);
|
|
5226
5395
|
if (graph.hasEdge(edgeId)) continue;
|
|
5227
5396
|
const edge = {
|
|
5228
5397
|
id: edgeId,
|
|
5229
5398
|
source: sourceId,
|
|
5230
5399
|
target: targetId,
|
|
5231
|
-
type:
|
|
5232
|
-
provenance:
|
|
5233
|
-
confidence: (0,
|
|
5400
|
+
type: import_types20.EdgeType.DEPENDS_ON,
|
|
5401
|
+
provenance: import_types20.Provenance.EXTRACTED,
|
|
5402
|
+
confidence: (0, import_types20.confidenceForExtracted)("structural"),
|
|
5234
5403
|
evidence: { file: evidenceFile }
|
|
5235
5404
|
};
|
|
5236
5405
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -5242,9 +5411,9 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
5242
5411
|
|
|
5243
5412
|
// src/extract/infra/dockerfile.ts
|
|
5244
5413
|
init_cjs_shims();
|
|
5245
|
-
var
|
|
5414
|
+
var import_node_path31 = __toESM(require("path"), 1);
|
|
5246
5415
|
var import_node_fs17 = require("fs");
|
|
5247
|
-
var
|
|
5416
|
+
var import_types21 = require("@neat.is/types");
|
|
5248
5417
|
function runtimeImage(content) {
|
|
5249
5418
|
const lines = content.split("\n");
|
|
5250
5419
|
let last = null;
|
|
@@ -5263,7 +5432,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
5263
5432
|
let nodesAdded = 0;
|
|
5264
5433
|
let edgesAdded = 0;
|
|
5265
5434
|
for (const service of services) {
|
|
5266
|
-
const dockerfilePath =
|
|
5435
|
+
const dockerfilePath = import_node_path31.default.join(service.dir, "Dockerfile");
|
|
5267
5436
|
if (!await exists2(dockerfilePath)) continue;
|
|
5268
5437
|
let content;
|
|
5269
5438
|
try {
|
|
@@ -5271,7 +5440,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
5271
5440
|
} catch (err) {
|
|
5272
5441
|
recordExtractionError(
|
|
5273
5442
|
"infra dockerfile",
|
|
5274
|
-
|
|
5443
|
+
import_node_path31.default.relative(scanPath, dockerfilePath),
|
|
5275
5444
|
err
|
|
5276
5445
|
);
|
|
5277
5446
|
continue;
|
|
@@ -5283,7 +5452,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
5283
5452
|
graph.addNode(node.id, node);
|
|
5284
5453
|
nodesAdded++;
|
|
5285
5454
|
}
|
|
5286
|
-
const relDockerfile = toPosix2(
|
|
5455
|
+
const relDockerfile = toPosix2(import_node_path31.default.relative(service.dir, dockerfilePath));
|
|
5287
5456
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
5288
5457
|
graph,
|
|
5289
5458
|
service.pkg.name,
|
|
@@ -5292,17 +5461,17 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
5292
5461
|
);
|
|
5293
5462
|
nodesAdded += fn;
|
|
5294
5463
|
edgesAdded += fe;
|
|
5295
|
-
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, node.id,
|
|
5464
|
+
const edgeId = (0, import_types5.extractedEdgeId)(fileNodeId, node.id, import_types21.EdgeType.RUNS_ON);
|
|
5296
5465
|
if (!graph.hasEdge(edgeId)) {
|
|
5297
5466
|
const edge = {
|
|
5298
5467
|
id: edgeId,
|
|
5299
5468
|
source: fileNodeId,
|
|
5300
5469
|
target: node.id,
|
|
5301
|
-
type:
|
|
5302
|
-
provenance:
|
|
5303
|
-
confidence: (0,
|
|
5470
|
+
type: import_types21.EdgeType.RUNS_ON,
|
|
5471
|
+
provenance: import_types21.Provenance.EXTRACTED,
|
|
5472
|
+
confidence: (0, import_types21.confidenceForExtracted)("structural"),
|
|
5304
5473
|
evidence: {
|
|
5305
|
-
file: toPosix2(
|
|
5474
|
+
file: toPosix2(import_node_path31.default.relative(scanPath, dockerfilePath))
|
|
5306
5475
|
}
|
|
5307
5476
|
};
|
|
5308
5477
|
graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge);
|
|
@@ -5315,7 +5484,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
5315
5484
|
// src/extract/infra/terraform.ts
|
|
5316
5485
|
init_cjs_shims();
|
|
5317
5486
|
var import_node_fs18 = require("fs");
|
|
5318
|
-
var
|
|
5487
|
+
var import_node_path32 = __toESM(require("path"), 1);
|
|
5319
5488
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
5320
5489
|
async function walkTfFiles(start, depth = 0, max = 5) {
|
|
5321
5490
|
if (depth > max) return [];
|
|
@@ -5324,11 +5493,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
5324
5493
|
for (const entry of entries) {
|
|
5325
5494
|
if (entry.isDirectory()) {
|
|
5326
5495
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
5327
|
-
const child =
|
|
5496
|
+
const child = import_node_path32.default.join(start, entry.name);
|
|
5328
5497
|
if (await isPythonVenvDir(child)) continue;
|
|
5329
5498
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
5330
5499
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
5331
|
-
out.push(
|
|
5500
|
+
out.push(import_node_path32.default.join(start, entry.name));
|
|
5332
5501
|
}
|
|
5333
5502
|
}
|
|
5334
5503
|
return out;
|
|
@@ -5356,7 +5525,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
5356
5525
|
// src/extract/infra/k8s.ts
|
|
5357
5526
|
init_cjs_shims();
|
|
5358
5527
|
var import_node_fs19 = require("fs");
|
|
5359
|
-
var
|
|
5528
|
+
var import_node_path33 = __toESM(require("path"), 1);
|
|
5360
5529
|
var import_yaml3 = require("yaml");
|
|
5361
5530
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
5362
5531
|
Service: "k8s-service",
|
|
@@ -5374,11 +5543,11 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
5374
5543
|
for (const entry of entries) {
|
|
5375
5544
|
if (entry.isDirectory()) {
|
|
5376
5545
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5377
|
-
const child =
|
|
5546
|
+
const child = import_node_path33.default.join(start, entry.name);
|
|
5378
5547
|
if (await isPythonVenvDir(child)) continue;
|
|
5379
5548
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
5380
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
5381
|
-
out.push(
|
|
5549
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(import_node_path33.default.extname(entry.name))) {
|
|
5550
|
+
out.push(import_node_path33.default.join(start, entry.name));
|
|
5382
5551
|
}
|
|
5383
5552
|
}
|
|
5384
5553
|
return out;
|
|
@@ -5422,17 +5591,17 @@ async function addInfra(graph, scanPath, services) {
|
|
|
5422
5591
|
}
|
|
5423
5592
|
|
|
5424
5593
|
// src/extract/index.ts
|
|
5425
|
-
var
|
|
5594
|
+
var import_node_path35 = __toESM(require("path"), 1);
|
|
5426
5595
|
|
|
5427
5596
|
// src/extract/retire.ts
|
|
5428
5597
|
init_cjs_shims();
|
|
5429
5598
|
var import_node_fs20 = require("fs");
|
|
5430
|
-
var
|
|
5431
|
-
var
|
|
5599
|
+
var import_node_path34 = __toESM(require("path"), 1);
|
|
5600
|
+
var import_types22 = require("@neat.is/types");
|
|
5432
5601
|
function dropOrphanedFileNodes(graph) {
|
|
5433
5602
|
const orphans = [];
|
|
5434
5603
|
graph.forEachNode((id, attrs) => {
|
|
5435
|
-
if (attrs.type !==
|
|
5604
|
+
if (attrs.type !== import_types22.NodeType.FileNode) return;
|
|
5436
5605
|
if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {
|
|
5437
5606
|
orphans.push(id);
|
|
5438
5607
|
}
|
|
@@ -5445,14 +5614,14 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
5445
5614
|
const bases = [scanPath, ...serviceDirs];
|
|
5446
5615
|
graph.forEachEdge((id, attrs) => {
|
|
5447
5616
|
const edge = attrs;
|
|
5448
|
-
if (edge.provenance !==
|
|
5617
|
+
if (edge.provenance !== import_types22.Provenance.EXTRACTED) return;
|
|
5449
5618
|
const evidenceFile = edge.evidence?.file;
|
|
5450
5619
|
if (!evidenceFile) return;
|
|
5451
|
-
if (
|
|
5620
|
+
if (import_node_path34.default.isAbsolute(evidenceFile)) {
|
|
5452
5621
|
if (!(0, import_node_fs20.existsSync)(evidenceFile)) toDrop.push(id);
|
|
5453
5622
|
return;
|
|
5454
5623
|
}
|
|
5455
|
-
const found = bases.some((base) => (0, import_node_fs20.existsSync)(
|
|
5624
|
+
const found = bases.some((base) => (0, import_node_fs20.existsSync)(import_node_path34.default.join(base, evidenceFile)));
|
|
5456
5625
|
if (!found) toDrop.push(id);
|
|
5457
5626
|
});
|
|
5458
5627
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -5492,7 +5661,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
5492
5661
|
}
|
|
5493
5662
|
const droppedEntries = drainDroppedExtracted();
|
|
5494
5663
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
5495
|
-
const rejectedPath =
|
|
5664
|
+
const rejectedPath = import_node_path35.default.join(import_node_path35.default.dirname(opts.errorsPath), "rejected.ndjson");
|
|
5496
5665
|
try {
|
|
5497
5666
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
5498
5667
|
} catch (err) {
|
|
@@ -5604,8 +5773,8 @@ function canonicalJson(value) {
|
|
|
5604
5773
|
// src/persist.ts
|
|
5605
5774
|
init_cjs_shims();
|
|
5606
5775
|
var import_node_fs22 = require("fs");
|
|
5607
|
-
var
|
|
5608
|
-
var
|
|
5776
|
+
var import_node_path36 = __toESM(require("path"), 1);
|
|
5777
|
+
var import_types23 = require("@neat.is/types");
|
|
5609
5778
|
var SCHEMA_VERSION = 4;
|
|
5610
5779
|
function migrateV1ToV2(payload) {
|
|
5611
5780
|
const nodes = payload.graph.nodes;
|
|
@@ -5627,12 +5796,12 @@ function migrateV2ToV3(payload) {
|
|
|
5627
5796
|
for (const edge of edges) {
|
|
5628
5797
|
const attrs = edge.attributes;
|
|
5629
5798
|
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
5630
|
-
attrs.provenance =
|
|
5799
|
+
attrs.provenance = import_types23.Provenance.OBSERVED;
|
|
5631
5800
|
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
5632
5801
|
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
5633
5802
|
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
5634
5803
|
if (type && source && target) {
|
|
5635
|
-
const newId = (0,
|
|
5804
|
+
const newId = (0, import_types23.observedEdgeId)(source, target, type);
|
|
5636
5805
|
attrs.id = newId;
|
|
5637
5806
|
if (edge.key) edge.key = newId;
|
|
5638
5807
|
}
|
|
@@ -5641,7 +5810,7 @@ function migrateV2ToV3(payload) {
|
|
|
5641
5810
|
return { ...payload, schemaVersion: 3 };
|
|
5642
5811
|
}
|
|
5643
5812
|
async function ensureDir(filePath) {
|
|
5644
|
-
await import_node_fs22.promises.mkdir(
|
|
5813
|
+
await import_node_fs22.promises.mkdir(import_node_path36.default.dirname(filePath), { recursive: true });
|
|
5645
5814
|
}
|
|
5646
5815
|
async function saveGraphToDisk(graph, outPath) {
|
|
5647
5816
|
await ensureDir(outPath);
|
|
@@ -5716,23 +5885,23 @@ function startPersistLoop(graph, outPath, intervalMs = 6e4) {
|
|
|
5716
5885
|
|
|
5717
5886
|
// src/projects.ts
|
|
5718
5887
|
init_cjs_shims();
|
|
5719
|
-
var
|
|
5888
|
+
var import_node_path37 = __toESM(require("path"), 1);
|
|
5720
5889
|
function pathsForProject(project, baseDir) {
|
|
5721
5890
|
if (project === DEFAULT_PROJECT) {
|
|
5722
5891
|
return {
|
|
5723
|
-
snapshotPath:
|
|
5724
|
-
errorsPath:
|
|
5725
|
-
staleEventsPath:
|
|
5726
|
-
embeddingsCachePath:
|
|
5727
|
-
policyViolationsPath:
|
|
5892
|
+
snapshotPath: import_node_path37.default.join(baseDir, "graph.json"),
|
|
5893
|
+
errorsPath: import_node_path37.default.join(baseDir, "errors.ndjson"),
|
|
5894
|
+
staleEventsPath: import_node_path37.default.join(baseDir, "stale-events.ndjson"),
|
|
5895
|
+
embeddingsCachePath: import_node_path37.default.join(baseDir, "embeddings.json"),
|
|
5896
|
+
policyViolationsPath: import_node_path37.default.join(baseDir, "policy-violations.ndjson")
|
|
5728
5897
|
};
|
|
5729
5898
|
}
|
|
5730
5899
|
return {
|
|
5731
|
-
snapshotPath:
|
|
5732
|
-
errorsPath:
|
|
5733
|
-
staleEventsPath:
|
|
5734
|
-
embeddingsCachePath:
|
|
5735
|
-
policyViolationsPath:
|
|
5900
|
+
snapshotPath: import_node_path37.default.join(baseDir, `${project}.json`),
|
|
5901
|
+
errorsPath: import_node_path37.default.join(baseDir, `errors.${project}.ndjson`),
|
|
5902
|
+
staleEventsPath: import_node_path37.default.join(baseDir, `stale-events.${project}.ndjson`),
|
|
5903
|
+
embeddingsCachePath: import_node_path37.default.join(baseDir, `embeddings.${project}.json`),
|
|
5904
|
+
policyViolationsPath: import_node_path37.default.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
5736
5905
|
};
|
|
5737
5906
|
}
|
|
5738
5907
|
var Projects = class {
|
|
@@ -5774,15 +5943,15 @@ function parseExtraProjects(raw) {
|
|
|
5774
5943
|
init_cjs_shims();
|
|
5775
5944
|
var import_node_fs23 = require("fs");
|
|
5776
5945
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
5777
|
-
var
|
|
5778
|
-
var
|
|
5946
|
+
var import_node_path38 = __toESM(require("path"), 1);
|
|
5947
|
+
var import_types24 = require("@neat.is/types");
|
|
5779
5948
|
function neatHome() {
|
|
5780
5949
|
const override = process.env.NEAT_HOME;
|
|
5781
|
-
if (override && override.length > 0) return
|
|
5782
|
-
return
|
|
5950
|
+
if (override && override.length > 0) return import_node_path38.default.resolve(override);
|
|
5951
|
+
return import_node_path38.default.join(import_node_os3.default.homedir(), ".neat");
|
|
5783
5952
|
}
|
|
5784
5953
|
function registryPath() {
|
|
5785
|
-
return
|
|
5954
|
+
return import_node_path38.default.join(neatHome(), "projects.json");
|
|
5786
5955
|
}
|
|
5787
5956
|
async function readRegistry() {
|
|
5788
5957
|
const file = registryPath();
|
|
@@ -5796,7 +5965,7 @@ async function readRegistry() {
|
|
|
5796
5965
|
throw err;
|
|
5797
5966
|
}
|
|
5798
5967
|
const parsed = JSON.parse(raw);
|
|
5799
|
-
return
|
|
5968
|
+
return import_types24.RegistryFileSchema.parse(parsed);
|
|
5800
5969
|
}
|
|
5801
5970
|
async function getProject(name) {
|
|
5802
5971
|
const reg = await readRegistry();
|
|
@@ -5806,6 +5975,8 @@ async function listProjects() {
|
|
|
5806
5975
|
const reg = await readRegistry();
|
|
5807
5976
|
return reg.projects;
|
|
5808
5977
|
}
|
|
5978
|
+
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
5979
|
+
var DEFAULT_PRUNE_TTL_MS = 7 * DAY_MS2;
|
|
5809
5980
|
|
|
5810
5981
|
// src/streaming.ts
|
|
5811
5982
|
init_cjs_shims();
|
|
@@ -5819,6 +5990,7 @@ function handleSse(req, reply, opts) {
|
|
|
5819
5990
|
reply.raw.setHeader("Connection", "keep-alive");
|
|
5820
5991
|
reply.raw.setHeader("X-Accel-Buffering", "no");
|
|
5821
5992
|
reply.raw.flushHeaders?.();
|
|
5993
|
+
reply.raw.write(":open\n\n");
|
|
5822
5994
|
let pending = 0;
|
|
5823
5995
|
let dropped = false;
|
|
5824
5996
|
const closeConnection = () => {
|
|
@@ -5998,11 +6170,11 @@ function registerRoutes(scope, ctx) {
|
|
|
5998
6170
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
5999
6171
|
const parsed = [];
|
|
6000
6172
|
for (const c of candidates) {
|
|
6001
|
-
const r =
|
|
6173
|
+
const r = import_types25.DivergenceTypeSchema.safeParse(c);
|
|
6002
6174
|
if (!r.success) {
|
|
6003
6175
|
return reply.code(400).send({
|
|
6004
6176
|
error: `unknown divergence type "${c}"`,
|
|
6005
|
-
allowed:
|
|
6177
|
+
allowed: import_types25.DivergenceTypeSchema.options
|
|
6006
6178
|
});
|
|
6007
6179
|
}
|
|
6008
6180
|
parsed.push(r.data);
|
|
@@ -6215,7 +6387,7 @@ function registerRoutes(scope, ctx) {
|
|
|
6215
6387
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
6216
6388
|
let violations = await log.readAll();
|
|
6217
6389
|
if (req.query.severity) {
|
|
6218
|
-
const sev =
|
|
6390
|
+
const sev = import_types25.PolicySeveritySchema.safeParse(req.query.severity);
|
|
6219
6391
|
if (!sev.success) {
|
|
6220
6392
|
return reply.code(400).send({
|
|
6221
6393
|
error: "invalid severity",
|
|
@@ -6232,7 +6404,7 @@ function registerRoutes(scope, ctx) {
|
|
|
6232
6404
|
scope.post("/policies/check", async (req, reply) => {
|
|
6233
6405
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap);
|
|
6234
6406
|
if (!proj) return;
|
|
6235
|
-
const parsed =
|
|
6407
|
+
const parsed = import_types25.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
6236
6408
|
if (!parsed.success) {
|
|
6237
6409
|
return reply.code(400).send({
|
|
6238
6410
|
error: "invalid /policies/check body",
|
|
@@ -6475,7 +6647,7 @@ init_otel_grpc();
|
|
|
6475
6647
|
// src/search.ts
|
|
6476
6648
|
init_cjs_shims();
|
|
6477
6649
|
var import_node_fs24 = require("fs");
|
|
6478
|
-
var
|
|
6650
|
+
var import_node_path41 = __toESM(require("path"), 1);
|
|
6479
6651
|
var import_node_crypto3 = require("crypto");
|
|
6480
6652
|
var DEFAULT_LIMIT = 10;
|
|
6481
6653
|
var NOMIC_DIM = 768;
|
|
@@ -6614,7 +6786,7 @@ async function readCache(cachePath) {
|
|
|
6614
6786
|
}
|
|
6615
6787
|
}
|
|
6616
6788
|
async function writeCache(cachePath, cache) {
|
|
6617
|
-
await import_node_fs24.promises.mkdir(
|
|
6789
|
+
await import_node_fs24.promises.mkdir(import_node_path41.default.dirname(cachePath), { recursive: true });
|
|
6618
6790
|
await import_node_fs24.promises.writeFile(cachePath, JSON.stringify(cache));
|
|
6619
6791
|
}
|
|
6620
6792
|
var VectorIndex = class {
|
|
@@ -6795,14 +6967,14 @@ async function bootProject(registry, name, scanPath, baseDir) {
|
|
|
6795
6967
|
async function main() {
|
|
6796
6968
|
const baseDirEnv = process.env.NEAT_OUT_DIR;
|
|
6797
6969
|
const legacyOutPath = process.env.NEAT_OUT_PATH;
|
|
6798
|
-
const baseDir = baseDirEnv ?
|
|
6799
|
-
const defaultScanPath =
|
|
6970
|
+
const baseDir = baseDirEnv ? import_node_path42.default.resolve(baseDirEnv) : legacyOutPath ? import_node_path42.default.resolve(import_node_path42.default.dirname(legacyOutPath)) : import_node_path42.default.resolve("./neat-out");
|
|
6971
|
+
const defaultScanPath = import_node_path42.default.resolve(process.env.NEAT_SCAN_PATH ?? "./demo");
|
|
6800
6972
|
const registry = new Projects();
|
|
6801
6973
|
await bootProject(registry, DEFAULT_PROJECT, defaultScanPath, baseDir);
|
|
6802
6974
|
for (const name of parseExtraProjects(process.env.NEAT_PROJECTS)) {
|
|
6803
6975
|
const envKey = `NEAT_PROJECT_SCAN_PATH_${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`;
|
|
6804
6976
|
const projectScan = process.env[envKey];
|
|
6805
|
-
await bootProject(registry, name, projectScan ?
|
|
6977
|
+
await bootProject(registry, name, projectScan ? import_node_path42.default.resolve(projectScan) : void 0, baseDir);
|
|
6806
6978
|
}
|
|
6807
6979
|
const host = process.env.HOST ?? "0.0.0.0";
|
|
6808
6980
|
const port = Number(process.env.PORT ?? 8080);
|