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