@neat.is/core 0.9.8-dev.20260829 → 0.9.8
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-KZBFP7L6.js → chunk-G4A6FCKG.js} +187 -13
- package/dist/chunk-G4A6FCKG.js.map +1 -0
- package/dist/{chunk-JSUPWMH3.js → chunk-I2I5MMO5.js} +14 -4
- package/dist/{chunk-JSUPWMH3.js.map → chunk-I2I5MMO5.js.map} +1 -1
- package/dist/cli.cjs +311 -98
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +46 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +262 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +262 -82
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +248 -80
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-KZBFP7L6.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -6366,11 +6366,25 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
6366
6366
|
};
|
|
6367
6367
|
graph.addEdgeWithKey(id, source, target, edge);
|
|
6368
6368
|
}
|
|
6369
|
+
function emitIncidentEvent(project, ev) {
|
|
6370
|
+
emitNeatEvent({
|
|
6371
|
+
type: "incident",
|
|
6372
|
+
project,
|
|
6373
|
+
payload: {
|
|
6374
|
+
incidentId: ev.id,
|
|
6375
|
+
affectedNode: ev.affectedNode,
|
|
6376
|
+
service: ev.service,
|
|
6377
|
+
incidentKind: (0, import_types8.incidentKindOf)(ev),
|
|
6378
|
+
at: ev.timestamp
|
|
6379
|
+
}
|
|
6380
|
+
});
|
|
6381
|
+
}
|
|
6369
6382
|
async function appendErrorEvent(ctx, ev) {
|
|
6370
6383
|
await import_node_fs8.promises.mkdir(import_node_path9.default.dirname(ctx.errorsPath), { recursive: true });
|
|
6371
6384
|
await import_node_fs8.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6385
|
+
emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev);
|
|
6372
6386
|
}
|
|
6373
|
-
async function appendConnectorIncident(errorsPath, input) {
|
|
6387
|
+
async function appendConnectorIncident(errorsPath, input, project) {
|
|
6374
6388
|
const ev = {
|
|
6375
6389
|
id: input.id,
|
|
6376
6390
|
timestamp: input.timestamp,
|
|
@@ -6384,6 +6398,7 @@ async function appendConnectorIncident(errorsPath, input) {
|
|
|
6384
6398
|
};
|
|
6385
6399
|
await import_node_fs8.promises.mkdir(import_node_path9.default.dirname(errorsPath), { recursive: true });
|
|
6386
6400
|
await import_node_fs8.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6401
|
+
if (project) emitIncidentEvent(project, ev);
|
|
6387
6402
|
}
|
|
6388
6403
|
function landIncidentCallSite(span, callSite, trusted, graph) {
|
|
6389
6404
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
@@ -6477,12 +6492,13 @@ function buildErrorEventForReceiver(span, graph, scanPath) {
|
|
|
6477
6492
|
affectedNode: locus.affectedNode
|
|
6478
6493
|
};
|
|
6479
6494
|
}
|
|
6480
|
-
function makeErrorSpanWriter(errorsPath, graph, scanPath) {
|
|
6495
|
+
function makeErrorSpanWriter(errorsPath, graph, scanPath, project = DEFAULT_PROJECT) {
|
|
6481
6496
|
return async (span) => {
|
|
6482
6497
|
const ev = buildErrorEventForReceiver(span, graph, scanPath);
|
|
6483
6498
|
if (!ev) return;
|
|
6484
6499
|
await import_node_fs8.promises.mkdir(import_node_path9.default.dirname(errorsPath), { recursive: true });
|
|
6485
6500
|
await import_node_fs8.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6501
|
+
emitIncidentEvent(project, ev);
|
|
6486
6502
|
};
|
|
6487
6503
|
}
|
|
6488
6504
|
async function recordFailingResponseIncident(ctx, span, affectedNode, timestamp, statusCode, count, firstTimestamp) {
|
|
@@ -16943,7 +16959,7 @@ var import_chokidar = __toESM(require("chokidar"), 1);
|
|
|
16943
16959
|
init_cjs_shims();
|
|
16944
16960
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
16945
16961
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
16946
|
-
var
|
|
16962
|
+
var import_types99 = require("@neat.is/types");
|
|
16947
16963
|
|
|
16948
16964
|
// src/extend/index.ts
|
|
16949
16965
|
init_cjs_shims();
|
|
@@ -17333,9 +17349,128 @@ function queryLogEntries(opts) {
|
|
|
17333
17349
|
return merged;
|
|
17334
17350
|
}
|
|
17335
17351
|
|
|
17336
|
-
// src/
|
|
17352
|
+
// src/goodybag.ts
|
|
17337
17353
|
init_cjs_shims();
|
|
17338
17354
|
var import_types60 = require("@neat.is/types");
|
|
17355
|
+
var CODE_FILEPATH_ATTR2 = "code.filepath";
|
|
17356
|
+
var CODE_LINENO_ATTR2 = "code.lineno";
|
|
17357
|
+
var BLAST_NEAREST_LIMIT = 5;
|
|
17358
|
+
function grainOf2(graph, nodeId) {
|
|
17359
|
+
if (graph.hasNode(nodeId)) {
|
|
17360
|
+
const t = graph.getNodeAttributes(nodeId).type;
|
|
17361
|
+
if (typeof t === "string" && t.length > 0) {
|
|
17362
|
+
return (t.endsWith("Node") ? t.slice(0, -4) : t).toLowerCase();
|
|
17363
|
+
}
|
|
17364
|
+
}
|
|
17365
|
+
const colon = nodeId.indexOf(":");
|
|
17366
|
+
return colon > 0 ? nodeId.slice(0, colon) : "unknown";
|
|
17367
|
+
}
|
|
17368
|
+
function locusOf(graph, ev) {
|
|
17369
|
+
const file = ev.attributes?.[CODE_FILEPATH_ATTR2];
|
|
17370
|
+
if (typeof file !== "string" || file.length === 0) return null;
|
|
17371
|
+
const rawLine = ev.attributes?.[CODE_LINENO_ATTR2];
|
|
17372
|
+
const line = typeof rawLine === "number" ? rawLine : Number(rawLine);
|
|
17373
|
+
const node = graph.hasNode(ev.affectedNode) ? graph.getNodeAttributes(ev.affectedNode) : void 0;
|
|
17374
|
+
return {
|
|
17375
|
+
file,
|
|
17376
|
+
...Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {},
|
|
17377
|
+
...node?.name ? { symbol: node.name } : {},
|
|
17378
|
+
service: node?.service ?? ev.service,
|
|
17379
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17380
|
+
};
|
|
17381
|
+
}
|
|
17382
|
+
function divergenceSummary(d) {
|
|
17383
|
+
const column = "column" in d && d.column ? `.${d.column}` : "";
|
|
17384
|
+
const label = "table" in d && d.table ? `${d.table}${column}` : `${d.source} \u2192 ${d.target}`;
|
|
17385
|
+
return label;
|
|
17386
|
+
}
|
|
17387
|
+
function baseName(p) {
|
|
17388
|
+
const parts = p.split(/[\\/]/);
|
|
17389
|
+
return parts[parts.length - 1] || p;
|
|
17390
|
+
}
|
|
17391
|
+
function shortLabel(graph, nodeId) {
|
|
17392
|
+
if (graph.hasNode(nodeId)) {
|
|
17393
|
+
const name = graph.getNodeAttributes(nodeId).name;
|
|
17394
|
+
if (typeof name === "string" && name.length > 0) return name;
|
|
17395
|
+
}
|
|
17396
|
+
const afterHash = nodeId.includes("#") ? nodeId.slice(nodeId.lastIndexOf("#") + 1) : nodeId;
|
|
17397
|
+
return afterHash.includes(":") ? afterHash.slice(afterHash.lastIndexOf(":") + 1) : afterHash;
|
|
17398
|
+
}
|
|
17399
|
+
function renderHeadline(graph, ev, locus, causeNode) {
|
|
17400
|
+
const what = ev.exceptionType ? `raised ${ev.exceptionType}` : ev.errorMessage || "failed";
|
|
17401
|
+
const cause = causeNode && causeNode !== ev.affectedNode ? ` \u2192 root cause ${shortLabel(graph, causeNode)}` : "";
|
|
17402
|
+
if (locus) {
|
|
17403
|
+
const base = baseName(locus.file);
|
|
17404
|
+
const lines = locus.lineStart != null ? locus.lineEnd && locus.lineEnd !== locus.lineStart ? `LINES ${locus.lineStart}-${locus.lineEnd}` : `LINE ${locus.lineStart}` : "";
|
|
17405
|
+
const symbol = locus.symbol ?? (grainOf2(graph, ev.affectedNode) === "symbol" ? shortLabel(graph, ev.affectedNode) : void 0);
|
|
17406
|
+
const subject = symbol ? `SYMBOL ${symbol}` : `FILE ${base}`;
|
|
17407
|
+
const at = symbol ? `${lines ? `${lines} in ` : ""}${base}` : lines;
|
|
17408
|
+
const where = at ? ` at ${at}` : "";
|
|
17409
|
+
return `${subject}${where} (SERVICE ${ev.service}) ${what} at ${ev.timestamp}${cause}`;
|
|
17410
|
+
}
|
|
17411
|
+
return `SERVICE ${ev.service} ${what} at ${ev.timestamp}${cause}`;
|
|
17412
|
+
}
|
|
17413
|
+
function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
17414
|
+
const affected = errorEvent.affectedNode;
|
|
17415
|
+
const locus = locusOf(graph, errorEvent);
|
|
17416
|
+
const inGraph = graph.hasNode(affected);
|
|
17417
|
+
const rc = inGraph ? getRootCause(graph, affected, errorEvent, incidents) : null;
|
|
17418
|
+
let rootCause = null;
|
|
17419
|
+
if (rc) {
|
|
17420
|
+
const provs = rc.edgeProvenances ?? [];
|
|
17421
|
+
const chain = (rc.traversalPath ?? []).map((node, i) => ({
|
|
17422
|
+
node,
|
|
17423
|
+
grain: grainOf2(graph, node),
|
|
17424
|
+
provenance: provs[i] ?? provs[provs.length - 1] ?? import_types60.Provenance.INFERRED
|
|
17425
|
+
}));
|
|
17426
|
+
rootCause = {
|
|
17427
|
+
node: rc.rootCauseNode,
|
|
17428
|
+
...rc.candidates?.[0]?.classification ? { classification: rc.candidates[0].classification } : {},
|
|
17429
|
+
reason: rc.rootCauseReason,
|
|
17430
|
+
confidence: rc.confidence,
|
|
17431
|
+
fix: rc.fixRecommendation ?? null,
|
|
17432
|
+
chain
|
|
17433
|
+
};
|
|
17434
|
+
}
|
|
17435
|
+
const blast = inGraph ? getBlastRadius(graph, affected) : { origin: affected, affectedNodes: [], totalAffected: 0 };
|
|
17436
|
+
const nearest = [...blast.affectedNodes].sort((a, b) => a.distance - b.distance).slice(0, BLAST_NEAREST_LIMIT).map((n) => ({ node: n.nodeId, distance: n.distance, provenance: n.edgeProvenance }));
|
|
17437
|
+
const applicable = inGraph ? selectApplicablePolicies(graph, policies, affected) : [];
|
|
17438
|
+
const policyCards = applicable.map((p) => ({
|
|
17439
|
+
policyName: p.policyName,
|
|
17440
|
+
severity: p.severity,
|
|
17441
|
+
message: p.reason
|
|
17442
|
+
}));
|
|
17443
|
+
const divergences = inGraph ? computeDivergences(graph, { node: affected, incidents }).divergences.map((d) => ({
|
|
17444
|
+
type: d.type,
|
|
17445
|
+
summary: divergenceSummary(d)
|
|
17446
|
+
})) : [];
|
|
17447
|
+
const card = {
|
|
17448
|
+
kind: "incident",
|
|
17449
|
+
id: errorEvent.id,
|
|
17450
|
+
at: errorEvent.timestamp,
|
|
17451
|
+
incidentKind: (0, import_types60.incidentKindOf)(errorEvent),
|
|
17452
|
+
service: errorEvent.service,
|
|
17453
|
+
affectedNode: affected,
|
|
17454
|
+
message: errorEvent.errorMessage,
|
|
17455
|
+
...errorEvent.exceptionType ? { exceptionType: errorEvent.exceptionType } : {},
|
|
17456
|
+
...errorEvent.httpStatusCode !== void 0 ? { httpStatusCode: errorEvent.httpStatusCode } : {},
|
|
17457
|
+
...errorEvent.incidentCount !== void 0 ? { count: errorEvent.incidentCount } : {},
|
|
17458
|
+
...errorEvent.firstTimestamp && errorEvent.lastTimestamp ? { window: { first: errorEvent.firstTimestamp, last: errorEvent.lastTimestamp } } : {},
|
|
17459
|
+
...errorEvent.traceId ? { traceId: errorEvent.traceId } : {},
|
|
17460
|
+
...errorEvent.spanId ? { spanId: errorEvent.spanId } : {},
|
|
17461
|
+
locus,
|
|
17462
|
+
rootCause,
|
|
17463
|
+
...nearest.length > 0 ? { blastRadius: { totalAffected: blast.totalAffected, nearest } } : {},
|
|
17464
|
+
...policyCards.length > 0 ? { policies: policyCards } : {},
|
|
17465
|
+
...divergences.length > 0 ? { divergence: divergences } : {},
|
|
17466
|
+
headline: renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)
|
|
17467
|
+
};
|
|
17468
|
+
return import_types60.IncidentCardSchema.parse(card);
|
|
17469
|
+
}
|
|
17470
|
+
|
|
17471
|
+
// src/ask.ts
|
|
17472
|
+
init_cjs_shims();
|
|
17473
|
+
var import_types61 = require("@neat.is/types");
|
|
17339
17474
|
var DEFAULT_MAX_NODES = 3;
|
|
17340
17475
|
var MAX_FACTS_PER_SECTION = 6;
|
|
17341
17476
|
var INTENT_RULES = [
|
|
@@ -17563,7 +17698,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17563
17698
|
};
|
|
17564
17699
|
graph.forEachNode((id, attrs) => {
|
|
17565
17700
|
const node = attrs;
|
|
17566
|
-
if (node.type ===
|
|
17701
|
+
if (node.type === import_types61.NodeType.FrontierNode) return;
|
|
17567
17702
|
const name = nodeName(node);
|
|
17568
17703
|
const body = idBody(id);
|
|
17569
17704
|
const labelTokens = /* @__PURE__ */ new Set([...tokens(body), ...tokens(name)]);
|
|
@@ -17582,7 +17717,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17582
17717
|
const res = await searchIndex.search(question, 10);
|
|
17583
17718
|
if (res.provider !== "substring") {
|
|
17584
17719
|
for (const m of res.matches) {
|
|
17585
|
-
if (m.node.type ===
|
|
17720
|
+
if (m.node.type === import_types61.NodeType.FrontierNode) continue;
|
|
17586
17721
|
const already = best.get(m.node.id);
|
|
17587
17722
|
if (!already && m.score < EMBED_MIN_SCORE) continue;
|
|
17588
17723
|
consider({
|
|
@@ -17620,7 +17755,7 @@ function edgeSignalNote(e) {
|
|
|
17620
17755
|
function buildRootCauseSection(graph, node, incidents, now) {
|
|
17621
17756
|
const result = getRootCause(graph, node, void 0, incidents, { now });
|
|
17622
17757
|
if (!result) return null;
|
|
17623
|
-
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ??
|
|
17758
|
+
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types61.Provenance.OBSERVED;
|
|
17624
17759
|
const facts = [
|
|
17625
17760
|
{
|
|
17626
17761
|
text: `Root cause: ${result.rootCauseNode} \u2014 ${result.rootCauseReason}`,
|
|
@@ -17670,7 +17805,7 @@ function buildObservedSection(graph, node) {
|
|
|
17670
17805
|
if (result.observed && result.inboundObservedCount > 0) {
|
|
17671
17806
|
facts.push({
|
|
17672
17807
|
text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 a pure receiver`,
|
|
17673
|
-
provenance:
|
|
17808
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17674
17809
|
});
|
|
17675
17810
|
} else {
|
|
17676
17811
|
return null;
|
|
@@ -17698,7 +17833,7 @@ function buildIncidentsSection(node, incidents) {
|
|
|
17698
17833
|
const facts = ordered.map((ev) => ({
|
|
17699
17834
|
text: `${ev.timestamp} \u2014 ${ev.service}: ${ev.errorMessage}`,
|
|
17700
17835
|
// ErrorEvents are observation records — OBSERVED by definition.
|
|
17701
|
-
provenance:
|
|
17836
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17702
17837
|
}));
|
|
17703
17838
|
return { heading: `Recent incidents (OBSERVED) \u2014 ${relevant.length} recorded`, facts };
|
|
17704
17839
|
}
|
|
@@ -17758,7 +17893,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17758
17893
|
}
|
|
17759
17894
|
const byKey = /* @__PURE__ */ new Map();
|
|
17760
17895
|
for (const ev of incidents) {
|
|
17761
|
-
const key = ev.affectedNode || (0,
|
|
17896
|
+
const key = ev.affectedNode || (0, import_types61.serviceId)(ev.service);
|
|
17762
17897
|
const cur = byKey.get(key);
|
|
17763
17898
|
if (!cur) {
|
|
17764
17899
|
byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
|
|
@@ -17773,7 +17908,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17773
17908
|
const rows = [...byKey.values()].sort((a, b) => b.count - a.count || b.latest.localeCompare(a.latest) || a.key.localeCompare(b.key)).slice(0, MAX_FACTS_PER_SECTION);
|
|
17774
17909
|
const facts = rows.map((r) => ({
|
|
17775
17910
|
text: `${r.key} \u2014 ${r.count} incident${r.count === 1 ? "" : "s"}, latest ${r.latest}: ${r.sampleMsg}`,
|
|
17776
|
-
provenance:
|
|
17911
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17777
17912
|
}));
|
|
17778
17913
|
return {
|
|
17779
17914
|
heading: `Incidents across the system \u2014 ${incidents.length} recorded`,
|
|
@@ -17786,7 +17921,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17786
17921
|
graph.forEachNode((_id, attrs) => {
|
|
17787
17922
|
const node = attrs;
|
|
17788
17923
|
nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1);
|
|
17789
|
-
if (node.type ===
|
|
17924
|
+
if (node.type === import_types61.NodeType.ServiceNode) services.push(node.id);
|
|
17790
17925
|
});
|
|
17791
17926
|
const edgeByProv = /* @__PURE__ */ new Map();
|
|
17792
17927
|
graph.forEachEdge((_id, attrs) => {
|
|
@@ -17798,10 +17933,10 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17798
17933
|
const shapeFacts = [
|
|
17799
17934
|
{ text: `${graph.order} nodes, ${graph.size} edges` },
|
|
17800
17935
|
{
|
|
17801
|
-
text: `${count(
|
|
17936
|
+
text: `${count(import_types61.NodeType.ServiceNode)} services, ${count(import_types61.NodeType.FileNode)} files, ${count(import_types61.NodeType.SymbolNode)} symbols, ${count(import_types61.NodeType.DatabaseNode)} databases`
|
|
17802
17937
|
}
|
|
17803
17938
|
];
|
|
17804
|
-
for (const p of [
|
|
17939
|
+
for (const p of [import_types61.Provenance.EXTRACTED, import_types61.Provenance.OBSERVED, import_types61.Provenance.INFERRED, import_types61.Provenance.STALE]) {
|
|
17805
17940
|
const n = edgeByProv.get(p) ?? 0;
|
|
17806
17941
|
if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? "" : "s"}`, provenance: p });
|
|
17807
17942
|
}
|
|
@@ -17818,7 +17953,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17818
17953
|
if (incidents && incidents.length > 0) {
|
|
17819
17954
|
const incCount = /* @__PURE__ */ new Map();
|
|
17820
17955
|
for (const ev of incidents) {
|
|
17821
|
-
const key = ev.affectedNode || (0,
|
|
17956
|
+
const key = ev.affectedNode || (0, import_types61.serviceId)(ev.service);
|
|
17822
17957
|
incCount.set(key, (incCount.get(key) ?? 0) + 1);
|
|
17823
17958
|
}
|
|
17824
17959
|
const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
|
|
@@ -17826,7 +17961,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17826
17961
|
heading: `Nodes with incidents \u2014 ${incidents.length} recorded`,
|
|
17827
17962
|
facts: top.map(([k, n]) => ({
|
|
17828
17963
|
text: `${k} \u2014 ${n} incident${n === 1 ? "" : "s"}`,
|
|
17829
|
-
provenance:
|
|
17964
|
+
provenance: import_types61.Provenance.OBSERVED
|
|
17830
17965
|
}))
|
|
17831
17966
|
});
|
|
17832
17967
|
}
|
|
@@ -17962,7 +18097,7 @@ async function askGraph(graph, question, opts = {}) {
|
|
|
17962
18097
|
const provSet = /* @__PURE__ */ new Set();
|
|
17963
18098
|
for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance);
|
|
17964
18099
|
const confidence = sections[0]?.facts[0]?.confidence;
|
|
17965
|
-
return
|
|
18100
|
+
return import_types61.AskResultSchema.parse({
|
|
17966
18101
|
question,
|
|
17967
18102
|
intent,
|
|
17968
18103
|
matched,
|
|
@@ -18109,7 +18244,7 @@ init_cjs_shims();
|
|
|
18109
18244
|
var import_node_fs39 = require("fs");
|
|
18110
18245
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
18111
18246
|
var import_node_path74 = __toESM(require("path"), 1);
|
|
18112
|
-
var
|
|
18247
|
+
var import_types62 = require("@neat.is/types");
|
|
18113
18248
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
18114
18249
|
var LOCK_RETRY_MS = 50;
|
|
18115
18250
|
function neatHome() {
|
|
@@ -18363,10 +18498,10 @@ async function readRegistry() {
|
|
|
18363
18498
|
throw err;
|
|
18364
18499
|
}
|
|
18365
18500
|
const parsed = JSON.parse(raw);
|
|
18366
|
-
return
|
|
18501
|
+
return import_types62.RegistryFileSchema.parse(parsed);
|
|
18367
18502
|
}
|
|
18368
18503
|
async function writeRegistry(reg) {
|
|
18369
|
-
const validated =
|
|
18504
|
+
const validated = import_types62.RegistryFileSchema.parse(reg);
|
|
18370
18505
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
18371
18506
|
}
|
|
18372
18507
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -18879,15 +19014,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
18879
19014
|
|
|
18880
19015
|
// src/connectors/index.ts
|
|
18881
19016
|
init_cjs_shims();
|
|
18882
|
-
var
|
|
19017
|
+
var import_types63 = require("@neat.is/types");
|
|
18883
19018
|
var NO_ENV = "unknown";
|
|
18884
19019
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
18885
19020
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18886
19021
|
const sites = [];
|
|
18887
19022
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
18888
19023
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18889
|
-
if (edge.provenance !==
|
|
18890
|
-
const parsed = (0,
|
|
19024
|
+
if (edge.provenance !== import_types63.Provenance.EXTRACTED) continue;
|
|
19025
|
+
const parsed = (0, import_types63.parseFileId)(edge.source);
|
|
18891
19026
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
18892
19027
|
const site = { relPath: edge.evidence.file };
|
|
18893
19028
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -18898,7 +19033,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
18898
19033
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
18899
19034
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18900
19035
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
18901
|
-
if (attrs.type !==
|
|
19036
|
+
if (attrs.type !== import_types63.NodeType.RouteNode || !attrs.path) return void 0;
|
|
18902
19037
|
const site = { relPath: attrs.path };
|
|
18903
19038
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
18904
19039
|
return site;
|
|
@@ -18928,7 +19063,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
18928
19063
|
errorMessage: signal.incident.errorMessage,
|
|
18929
19064
|
...signal.incident.attributes ? { attributes: signal.incident.attributes } : {},
|
|
18930
19065
|
affectedNode: resolved.targetNodeId
|
|
18931
|
-
});
|
|
19066
|
+
}, ctx.project);
|
|
18932
19067
|
continue;
|
|
18933
19068
|
}
|
|
18934
19069
|
if (resolved.ensureInfraNode) {
|
|
@@ -19510,23 +19645,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
19510
19645
|
|
|
19511
19646
|
// src/connectors/supabase/resolve.ts
|
|
19512
19647
|
init_cjs_shims();
|
|
19513
|
-
var
|
|
19648
|
+
var import_types65 = require("@neat.is/types");
|
|
19514
19649
|
function createSupabaseResolveTarget(graph, config) {
|
|
19515
19650
|
return (signal, _ctx) => {
|
|
19516
19651
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
19517
19652
|
return null;
|
|
19518
19653
|
}
|
|
19519
|
-
const subResourceId = (0,
|
|
19654
|
+
const subResourceId = (0, import_types65.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
19520
19655
|
if (graph.hasNode(subResourceId)) {
|
|
19521
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
19656
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types65.EdgeType.CALLS };
|
|
19522
19657
|
}
|
|
19523
|
-
const bareResourceId = (0,
|
|
19658
|
+
const bareResourceId = (0, import_types65.infraId)(signal.targetKind, signal.targetName);
|
|
19524
19659
|
if (graph.hasNode(bareResourceId)) {
|
|
19525
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
19660
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types65.EdgeType.CALLS };
|
|
19526
19661
|
}
|
|
19527
|
-
const projectLevelId = (0,
|
|
19662
|
+
const projectLevelId = (0, import_types65.infraId)("supabase", config.nodeRef);
|
|
19528
19663
|
if (graph.hasNode(projectLevelId)) {
|
|
19529
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
19664
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types65.EdgeType.CALLS };
|
|
19530
19665
|
}
|
|
19531
19666
|
return null;
|
|
19532
19667
|
};
|
|
@@ -19619,7 +19754,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
19619
19754
|
|
|
19620
19755
|
// src/connectors/railway/index.ts
|
|
19621
19756
|
init_cjs_shims();
|
|
19622
|
-
var
|
|
19757
|
+
var import_types69 = require("@neat.is/types");
|
|
19623
19758
|
|
|
19624
19759
|
// src/connectors/railway/client.ts
|
|
19625
19760
|
init_cjs_shims();
|
|
@@ -19770,7 +19905,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
19770
19905
|
const out = [];
|
|
19771
19906
|
graph.forEachNode((_id, attrs) => {
|
|
19772
19907
|
const node = attrs;
|
|
19773
|
-
if (node.type !==
|
|
19908
|
+
if (node.type !== import_types69.NodeType.RouteNode) return;
|
|
19774
19909
|
const route = attrs;
|
|
19775
19910
|
if (route.service !== serviceName) return;
|
|
19776
19911
|
out.push({
|
|
@@ -19874,12 +20009,12 @@ function createRailwayResolveTarget(config) {
|
|
|
19874
20009
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
19875
20010
|
if (!serviceName) return null;
|
|
19876
20011
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
19877
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
20012
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types69.EdgeType.CALLS };
|
|
19878
20013
|
}
|
|
19879
20014
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
19880
20015
|
const peerName = config.serviceNameById[signal.targetName];
|
|
19881
20016
|
if (!peerName) return null;
|
|
19882
|
-
return { targetNodeId: (0,
|
|
20017
|
+
return { targetNodeId: (0, import_types69.serviceId)(peerName), serviceName, edgeType: import_types69.EdgeType.CONNECTS_TO };
|
|
19883
20018
|
}
|
|
19884
20019
|
return null;
|
|
19885
20020
|
};
|
|
@@ -20067,7 +20202,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
20067
20202
|
|
|
20068
20203
|
// src/connectors/firebase/resolve.ts
|
|
20069
20204
|
init_cjs_shims();
|
|
20070
|
-
var
|
|
20205
|
+
var import_types70 = require("@neat.is/types");
|
|
20071
20206
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
20072
20207
|
switch (resourceType) {
|
|
20073
20208
|
case "cloud_function":
|
|
@@ -20082,7 +20217,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
20082
20217
|
const entries = [];
|
|
20083
20218
|
graph.forEachNode((_id, attrs) => {
|
|
20084
20219
|
const node = attrs;
|
|
20085
|
-
if (node.type !==
|
|
20220
|
+
if (node.type !== import_types70.NodeType.RouteNode) return;
|
|
20086
20221
|
const route = attrs;
|
|
20087
20222
|
if (route.service !== serviceName) return;
|
|
20088
20223
|
entries.push({
|
|
@@ -20114,7 +20249,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
20114
20249
|
return {
|
|
20115
20250
|
targetNodeId: match.routeNodeId,
|
|
20116
20251
|
serviceName,
|
|
20117
|
-
edgeType:
|
|
20252
|
+
edgeType: import_types70.EdgeType.CALLS
|
|
20118
20253
|
};
|
|
20119
20254
|
};
|
|
20120
20255
|
}
|
|
@@ -20141,7 +20276,7 @@ init_cjs_shims();
|
|
|
20141
20276
|
|
|
20142
20277
|
// src/connectors/cloudflare/connector.ts
|
|
20143
20278
|
init_cjs_shims();
|
|
20144
|
-
var
|
|
20279
|
+
var import_types72 = require("@neat.is/types");
|
|
20145
20280
|
|
|
20146
20281
|
// src/connectors/cloudflare/client.ts
|
|
20147
20282
|
init_cjs_shims();
|
|
@@ -20305,7 +20440,7 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
20305
20440
|
graph.forEachNode((id, attrs) => {
|
|
20306
20441
|
if (found) return;
|
|
20307
20442
|
const a = attrs;
|
|
20308
|
-
if (a.type ===
|
|
20443
|
+
if (a.type === import_types72.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
20309
20444
|
found = id;
|
|
20310
20445
|
}
|
|
20311
20446
|
});
|
|
@@ -20317,7 +20452,7 @@ function findMatchingRouteNode(graph, serviceName, method, path94) {
|
|
|
20317
20452
|
graph.forEachNode((id, attrs) => {
|
|
20318
20453
|
if (found) return;
|
|
20319
20454
|
const a = attrs;
|
|
20320
|
-
if (a.type !==
|
|
20455
|
+
if (a.type !== import_types72.NodeType.RouteNode || a.service !== serviceName) return;
|
|
20321
20456
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
20322
20457
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
20323
20458
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -20336,11 +20471,11 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20336
20471
|
};
|
|
20337
20472
|
const mapping = config.workers?.[scriptName];
|
|
20338
20473
|
if (mapping) {
|
|
20339
|
-
const wholeFileId = (0,
|
|
20474
|
+
const wholeFileId = (0, import_types72.fileId)(mapping.service, mapping.entryFile);
|
|
20340
20475
|
return {
|
|
20341
20476
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
20342
20477
|
serviceName: mapping.service,
|
|
20343
|
-
edgeType:
|
|
20478
|
+
edgeType: import_types72.EdgeType.CALLS
|
|
20344
20479
|
};
|
|
20345
20480
|
}
|
|
20346
20481
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -20349,13 +20484,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20349
20484
|
return {
|
|
20350
20485
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
20351
20486
|
serviceName: fileNode.service,
|
|
20352
|
-
edgeType:
|
|
20487
|
+
edgeType: import_types72.EdgeType.CALLS
|
|
20353
20488
|
};
|
|
20354
20489
|
}
|
|
20355
20490
|
return {
|
|
20356
|
-
targetNodeId: (0,
|
|
20491
|
+
targetNodeId: (0, import_types72.infraId)("cloudflare-worker", scriptName),
|
|
20357
20492
|
serviceName: scriptName,
|
|
20358
|
-
edgeType:
|
|
20493
|
+
edgeType: import_types72.EdgeType.CALLS,
|
|
20359
20494
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
20360
20495
|
};
|
|
20361
20496
|
};
|
|
@@ -20551,14 +20686,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
20551
20686
|
|
|
20552
20687
|
// src/connectors/neon/resolve.ts
|
|
20553
20688
|
init_cjs_shims();
|
|
20554
|
-
var
|
|
20689
|
+
var import_types76 = require("@neat.is/types");
|
|
20555
20690
|
function createNeonResolveTarget(config) {
|
|
20556
20691
|
return (signal) => {
|
|
20557
20692
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20558
20693
|
return {
|
|
20559
|
-
targetNodeId: (0,
|
|
20694
|
+
targetNodeId: (0, import_types76.infraId)("sql-table", signal.targetName),
|
|
20560
20695
|
serviceName: config.serviceName,
|
|
20561
|
-
edgeType:
|
|
20696
|
+
edgeType: import_types76.EdgeType.CALLS,
|
|
20562
20697
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
20563
20698
|
};
|
|
20564
20699
|
};
|
|
@@ -20739,14 +20874,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
20739
20874
|
|
|
20740
20875
|
// src/connectors/cloud-run/resolve.ts
|
|
20741
20876
|
init_cjs_shims();
|
|
20742
|
-
var
|
|
20877
|
+
var import_types80 = require("@neat.is/types");
|
|
20743
20878
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
20744
20879
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
20745
20880
|
let found = null;
|
|
20746
20881
|
graph.forEachNode((_id, attrs) => {
|
|
20747
20882
|
if (found) return;
|
|
20748
20883
|
const node = attrs;
|
|
20749
|
-
if (node.type !==
|
|
20884
|
+
if (node.type !== import_types80.NodeType.RouteNode) return;
|
|
20750
20885
|
const route = attrs;
|
|
20751
20886
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20752
20887
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20771,13 +20906,13 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
20771
20906
|
normalizePathTemplate(path94)
|
|
20772
20907
|
);
|
|
20773
20908
|
if (routeNodeId) {
|
|
20774
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20909
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types80.EdgeType.CALLS };
|
|
20775
20910
|
}
|
|
20776
20911
|
}
|
|
20777
20912
|
return {
|
|
20778
|
-
targetNodeId: (0,
|
|
20913
|
+
targetNodeId: (0, import_types80.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
20779
20914
|
serviceName: mappedService ?? gcpServiceName,
|
|
20780
|
-
edgeType:
|
|
20915
|
+
edgeType: import_types80.EdgeType.CALLS,
|
|
20781
20916
|
ensureInfraNode: {
|
|
20782
20917
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
20783
20918
|
name: gcpServiceName,
|
|
@@ -20959,14 +21094,14 @@ function mapLogEntriesToSignals3(entries) {
|
|
|
20959
21094
|
|
|
20960
21095
|
// src/connectors/gcp-lb/resolve.ts
|
|
20961
21096
|
init_cjs_shims();
|
|
20962
|
-
var
|
|
21097
|
+
var import_types84 = require("@neat.is/types");
|
|
20963
21098
|
var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
|
|
20964
21099
|
function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
|
|
20965
21100
|
let found = null;
|
|
20966
21101
|
graph.forEachNode((_id, attrs) => {
|
|
20967
21102
|
if (found) return;
|
|
20968
21103
|
const node = attrs;
|
|
20969
|
-
if (node.type !==
|
|
21104
|
+
if (node.type !== import_types84.NodeType.RouteNode) return;
|
|
20970
21105
|
const route = attrs;
|
|
20971
21106
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20972
21107
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20991,13 +21126,13 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
20991
21126
|
normalizePathTemplate(path94)
|
|
20992
21127
|
);
|
|
20993
21128
|
if (routeNodeId) {
|
|
20994
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
21129
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types84.EdgeType.CALLS };
|
|
20995
21130
|
}
|
|
20996
21131
|
}
|
|
20997
21132
|
return {
|
|
20998
|
-
targetNodeId: (0,
|
|
21133
|
+
targetNodeId: (0, import_types84.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
|
|
20999
21134
|
serviceName: mappedService ?? backendServiceName,
|
|
21000
|
-
edgeType:
|
|
21135
|
+
edgeType: import_types84.EdgeType.CALLS,
|
|
21001
21136
|
ensureInfraNode: {
|
|
21002
21137
|
kind: GCP_LB_BACKEND_INFRA_KIND,
|
|
21003
21138
|
name: backendServiceName,
|
|
@@ -21038,7 +21173,7 @@ function createGcpLbConnector(graph, config = {}) {
|
|
|
21038
21173
|
|
|
21039
21174
|
// src/connectors/render/index.ts
|
|
21040
21175
|
init_cjs_shims();
|
|
21041
|
-
var
|
|
21176
|
+
var import_types87 = require("@neat.is/types");
|
|
21042
21177
|
|
|
21043
21178
|
// src/connectors/render/types.ts
|
|
21044
21179
|
init_cjs_shims();
|
|
@@ -21116,7 +21251,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
21116
21251
|
const out = [];
|
|
21117
21252
|
graph.forEachNode((_id, attrs) => {
|
|
21118
21253
|
const node = attrs;
|
|
21119
|
-
if (node.type !==
|
|
21254
|
+
if (node.type !== import_types87.NodeType.RouteNode) return;
|
|
21120
21255
|
const route = attrs;
|
|
21121
21256
|
if (route.service !== serviceName) return;
|
|
21122
21257
|
out.push({
|
|
@@ -21201,7 +21336,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
21201
21336
|
function createRenderResolveTarget(config) {
|
|
21202
21337
|
return (signal) => {
|
|
21203
21338
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
21204
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
21339
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types87.EdgeType.CALLS };
|
|
21205
21340
|
}
|
|
21206
21341
|
return null;
|
|
21207
21342
|
};
|
|
@@ -21339,21 +21474,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
21339
21474
|
|
|
21340
21475
|
// src/connectors/planetscale/resolve.ts
|
|
21341
21476
|
init_cjs_shims();
|
|
21342
|
-
var
|
|
21477
|
+
var import_types91 = require("@neat.is/types");
|
|
21343
21478
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
21344
21479
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
21345
21480
|
const databaseName = `${config.organization}/${config.database}`;
|
|
21346
21481
|
return (signal, _ctx) => {
|
|
21347
21482
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
21348
|
-
const tableId = (0,
|
|
21483
|
+
const tableId = (0, import_types91.infraId)("sql-table", signal.targetName);
|
|
21349
21484
|
if (graph.hasNode(tableId)) {
|
|
21350
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
21485
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types91.EdgeType.CALLS };
|
|
21351
21486
|
}
|
|
21352
|
-
const providerId = (0,
|
|
21487
|
+
const providerId = (0, import_types91.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
21353
21488
|
return {
|
|
21354
21489
|
targetNodeId: providerId,
|
|
21355
21490
|
serviceName: config.serviceName,
|
|
21356
|
-
edgeType:
|
|
21491
|
+
edgeType: import_types91.EdgeType.CALLS,
|
|
21357
21492
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
21358
21493
|
};
|
|
21359
21494
|
};
|
|
@@ -21618,7 +21753,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
21618
21753
|
|
|
21619
21754
|
// src/connectors/eas/resolve.ts
|
|
21620
21755
|
init_cjs_shims();
|
|
21621
|
-
var
|
|
21756
|
+
var import_types96 = require("@neat.is/types");
|
|
21622
21757
|
var NO_ENV2 = "unknown";
|
|
21623
21758
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
21624
21759
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -21634,8 +21769,8 @@ function configBasenamesForPhase(phase) {
|
|
|
21634
21769
|
function configNodeService(graph, configNodeId) {
|
|
21635
21770
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
21636
21771
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
21637
|
-
if (edge.type !==
|
|
21638
|
-
const parsed = (0,
|
|
21772
|
+
if (edge.type !== import_types96.EdgeType.CONFIGURED_BY) continue;
|
|
21773
|
+
const parsed = (0, import_types96.parseFileId)(edge.source);
|
|
21639
21774
|
if (parsed) return parsed.service;
|
|
21640
21775
|
}
|
|
21641
21776
|
return null;
|
|
@@ -21646,7 +21781,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
21646
21781
|
graph.forEachNode((id, attrs) => {
|
|
21647
21782
|
if (scoped) return;
|
|
21648
21783
|
const node = attrs;
|
|
21649
|
-
if (node.type !==
|
|
21784
|
+
if (node.type !== import_types96.NodeType.ConfigNode) return;
|
|
21650
21785
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
21651
21786
|
if (anyMatch === null) anyMatch = id;
|
|
21652
21787
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -21663,13 +21798,13 @@ function createEasResolveTarget(graph) {
|
|
|
21663
21798
|
if (basenames.length > 0) {
|
|
21664
21799
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
21665
21800
|
if (configNodeId) {
|
|
21666
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
21801
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types96.EdgeType.CALLS };
|
|
21667
21802
|
}
|
|
21668
21803
|
}
|
|
21669
21804
|
return {
|
|
21670
21805
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
21671
21806
|
serviceName,
|
|
21672
|
-
edgeType:
|
|
21807
|
+
edgeType: import_types96.EdgeType.CALLS
|
|
21673
21808
|
};
|
|
21674
21809
|
};
|
|
21675
21810
|
}
|
|
@@ -22287,6 +22422,7 @@ async function startConnectorPolling(input) {
|
|
|
22287
22422
|
registration.connector,
|
|
22288
22423
|
{
|
|
22289
22424
|
projectDir: input.projectDir,
|
|
22425
|
+
project: input.project,
|
|
22290
22426
|
credentials: registration.credentials,
|
|
22291
22427
|
...input.errorsPath ? { errorsPath: input.errorsPath } : {}
|
|
22292
22428
|
},
|
|
@@ -22509,11 +22645,11 @@ function registerRoutes(scope, ctx) {
|
|
|
22509
22645
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
22510
22646
|
const parsed = [];
|
|
22511
22647
|
for (const c of candidates) {
|
|
22512
|
-
const r =
|
|
22648
|
+
const r = import_types99.DivergenceTypeSchema.safeParse(c);
|
|
22513
22649
|
if (!r.success) {
|
|
22514
22650
|
return reply.code(400).send({
|
|
22515
22651
|
error: `unknown divergence type "${c}"`,
|
|
22516
|
-
allowed:
|
|
22652
|
+
allowed: import_types99.DivergenceTypeSchema.options
|
|
22517
22653
|
});
|
|
22518
22654
|
}
|
|
22519
22655
|
parsed.push(r.data);
|
|
@@ -22630,6 +22766,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22630
22766
|
reg.connector,
|
|
22631
22767
|
{
|
|
22632
22768
|
projectDir: proj.scanPath ?? "",
|
|
22769
|
+
project: proj.name,
|
|
22633
22770
|
credentials: reg.credentials,
|
|
22634
22771
|
...incidentsPath ? { errorsPath: incidentsPath } : {}
|
|
22635
22772
|
},
|
|
@@ -22693,6 +22830,39 @@ function registerRoutes(scope, ctx) {
|
|
|
22693
22830
|
if (!result) return reply.code(404).send({ error: "no root cause found", id: nodeId });
|
|
22694
22831
|
return result;
|
|
22695
22832
|
});
|
|
22833
|
+
scope.get("/graph/incident-card/:nodeId", async (req, reply) => {
|
|
22834
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22835
|
+
if (!proj) return;
|
|
22836
|
+
const { nodeId } = req.params;
|
|
22837
|
+
if (!proj.graph.hasNode(nodeId)) {
|
|
22838
|
+
return reply.code(404).send({ error: "node not found", id: nodeId });
|
|
22839
|
+
}
|
|
22840
|
+
const epath = errorsPathFor(proj);
|
|
22841
|
+
const incidents = epath ? await readErrorEvents(epath) : [];
|
|
22842
|
+
let errorEvent;
|
|
22843
|
+
if (req.query.errorId) {
|
|
22844
|
+
errorEvent = incidents.find((e) => e.id === req.query.errorId);
|
|
22845
|
+
if (!errorEvent) {
|
|
22846
|
+
return reply.code(404).send({ error: "error event not found", id: req.query.errorId });
|
|
22847
|
+
}
|
|
22848
|
+
} else {
|
|
22849
|
+
const svc = nodeId.replace(/^service:/, "");
|
|
22850
|
+
errorEvent = [...incidents].filter((e) => e.affectedNode === nodeId || e.service === svc).sort((a, b) => (b.timestamp ?? "").localeCompare(a.timestamp ?? ""))[0];
|
|
22851
|
+
if (!errorEvent) {
|
|
22852
|
+
return reply.code(404).send({ error: "no incident found for node", id: nodeId });
|
|
22853
|
+
}
|
|
22854
|
+
}
|
|
22855
|
+
const policyPath = ctx.policyFilePathFor(proj);
|
|
22856
|
+
let policies = [];
|
|
22857
|
+
if (policyPath) {
|
|
22858
|
+
try {
|
|
22859
|
+
policies = await loadPolicyFile(policyPath);
|
|
22860
|
+
} catch {
|
|
22861
|
+
policies = [];
|
|
22862
|
+
}
|
|
22863
|
+
}
|
|
22864
|
+
return buildIncidentCard(proj.graph, errorEvent, incidents, policies);
|
|
22865
|
+
});
|
|
22696
22866
|
scope.get("/graph/blast-radius/:nodeId", async (req, reply) => {
|
|
22697
22867
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22698
22868
|
if (!proj) return;
|
|
@@ -22875,7 +23045,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22875
23045
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
22876
23046
|
let violations = await log.readAll();
|
|
22877
23047
|
if (req.query.severity) {
|
|
22878
|
-
const sev =
|
|
23048
|
+
const sev = import_types99.PolicySeveritySchema.safeParse(req.query.severity);
|
|
22879
23049
|
if (!sev.success) {
|
|
22880
23050
|
return reply.code(400).send({
|
|
22881
23051
|
error: "invalid severity",
|
|
@@ -22914,7 +23084,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22914
23084
|
scope.post("/policies/check", async (req, reply) => {
|
|
22915
23085
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22916
23086
|
if (!proj) return;
|
|
22917
|
-
const parsed =
|
|
23087
|
+
const parsed = import_types99.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
22918
23088
|
if (!parsed.success) {
|
|
22919
23089
|
return reply.code(400).send({
|
|
22920
23090
|
error: "invalid /policies/check body",
|
|
@@ -23247,7 +23417,7 @@ var import_node_fs41 = require("fs");
|
|
|
23247
23417
|
var import_node_path76 = __toESM(require("path"), 1);
|
|
23248
23418
|
|
|
23249
23419
|
// src/daemon.ts
|
|
23250
|
-
var
|
|
23420
|
+
var import_types100 = require("@neat.is/types");
|
|
23251
23421
|
function daemonJsonPath(scanPath) {
|
|
23252
23422
|
return import_node_path77.default.join(scanPath, "neat-out", "daemon.json");
|
|
23253
23423
|
}
|
|
@@ -23957,7 +24127,7 @@ async function startWatch(graph, opts) {
|
|
|
23957
24127
|
writeErrorEventInline: false,
|
|
23958
24128
|
onPolicyTrigger
|
|
23959
24129
|
});
|
|
23960
|
-
const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath, graph, opts.scanPath);
|
|
24130
|
+
const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath, graph, opts.scanPath, projectName);
|
|
23961
24131
|
const otelHttp = await buildOtelReceiver({ onSpan, onErrorSpanSync });
|
|
23962
24132
|
const otelAddress = await listenSteppingOtlp(otelHttp, otelPort, host);
|
|
23963
24133
|
const boundOtelPort = portFromListenAddress(otelAddress, otelPort);
|
|
@@ -28264,7 +28434,7 @@ var import_node_path87 = __toESM(require("path"), 1);
|
|
|
28264
28434
|
|
|
28265
28435
|
// src/cli-client.ts
|
|
28266
28436
|
init_cjs_shims();
|
|
28267
|
-
var
|
|
28437
|
+
var import_types101 = require("@neat.is/types");
|
|
28268
28438
|
var HttpError = class extends Error {
|
|
28269
28439
|
constructor(status2, message, responseBody = "") {
|
|
28270
28440
|
super(message);
|
|
@@ -28406,7 +28576,7 @@ async function runBlastRadius(client, input) {
|
|
|
28406
28576
|
}
|
|
28407
28577
|
}
|
|
28408
28578
|
function formatBlastEntry(n) {
|
|
28409
|
-
const tag = n.edgeProvenance ===
|
|
28579
|
+
const tag = n.edgeProvenance === import_types101.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
28410
28580
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
28411
28581
|
}
|
|
28412
28582
|
async function runDependencies(client, input) {
|
|
@@ -28463,7 +28633,7 @@ async function runObservedDependencies(client, input) {
|
|
|
28463
28633
|
if (result.observed) {
|
|
28464
28634
|
return {
|
|
28465
28635
|
summary: `${input.nodeId} makes no outbound runtime calls, but OTel has observed it receiving traffic on ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 it's a pure receiver.`,
|
|
28466
|
-
provenance:
|
|
28636
|
+
provenance: import_types101.Provenance.OBSERVED
|
|
28467
28637
|
};
|
|
28468
28638
|
}
|
|
28469
28639
|
const note = result.hasExtractedOutbound ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
@@ -28473,7 +28643,7 @@ async function runObservedDependencies(client, input) {
|
|
|
28473
28643
|
return {
|
|
28474
28644
|
summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
28475
28645
|
block: blockLines.join("\n"),
|
|
28476
|
-
provenance:
|
|
28646
|
+
provenance: import_types101.Provenance.OBSERVED
|
|
28477
28647
|
};
|
|
28478
28648
|
} catch (err) {
|
|
28479
28649
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -28527,7 +28697,7 @@ async function runIncidents(client, input) {
|
|
|
28527
28697
|
return {
|
|
28528
28698
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
28529
28699
|
block: blockLines.join("\n"),
|
|
28530
|
-
provenance:
|
|
28700
|
+
provenance: import_types101.Provenance.OBSERVED
|
|
28531
28701
|
};
|
|
28532
28702
|
} catch (err) {
|
|
28533
28703
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -28636,7 +28806,7 @@ async function runStaleEdges(client, input) {
|
|
|
28636
28806
|
return {
|
|
28637
28807
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
28638
28808
|
block: blockLines.join("\n"),
|
|
28639
|
-
provenance:
|
|
28809
|
+
provenance: import_types101.Provenance.STALE
|
|
28640
28810
|
};
|
|
28641
28811
|
}
|
|
28642
28812
|
async function runPolicies(client, input) {
|
|
@@ -29927,12 +30097,12 @@ async function runEditorCommand(clientId, args, projectDir = process.cwd()) {
|
|
|
29927
30097
|
|
|
29928
30098
|
// src/monitor.ts
|
|
29929
30099
|
init_cjs_shims();
|
|
29930
|
-
var
|
|
30100
|
+
var import_types102 = require("@neat.is/types");
|
|
29931
30101
|
var OBSERVED_DEP_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
29932
|
-
|
|
29933
|
-
|
|
29934
|
-
|
|
29935
|
-
|
|
30102
|
+
import_types102.EdgeType.CALLS,
|
|
30103
|
+
import_types102.EdgeType.CONNECTS_TO,
|
|
30104
|
+
import_types102.EdgeType.PUBLISHES_TO,
|
|
30105
|
+
import_types102.EdgeType.CONSUMES_FROM
|
|
29936
30106
|
]);
|
|
29937
30107
|
function divergenceKey(d) {
|
|
29938
30108
|
const column = "column" in d && d.column ? d.column : "";
|
|
@@ -29993,7 +30163,7 @@ function formatDivergenceLine2(d) {
|
|
|
29993
30163
|
}
|
|
29994
30164
|
}
|
|
29995
30165
|
function formatStaleLine(edgeId) {
|
|
29996
|
-
const parsed = (0,
|
|
30166
|
+
const parsed = (0, import_types102.parseEdgeId)(edgeId);
|
|
29997
30167
|
if (parsed) {
|
|
29998
30168
|
return `\u22EF stale ${parsed.source} \u2192 ${parsed.target} (observed edge went quiet)`;
|
|
29999
30169
|
}
|
|
@@ -30006,7 +30176,7 @@ function divergenceJson(d) {
|
|
|
30006
30176
|
return JSON.stringify({ kind: "divergence", ...d });
|
|
30007
30177
|
}
|
|
30008
30178
|
function staleJson(edgeId) {
|
|
30009
|
-
const parsed = (0,
|
|
30179
|
+
const parsed = (0, import_types102.parseEdgeId)(edgeId);
|
|
30010
30180
|
return JSON.stringify({
|
|
30011
30181
|
kind: "stale",
|
|
30012
30182
|
edgeId,
|
|
@@ -30041,6 +30211,19 @@ function formatPolicyLine(v) {
|
|
|
30041
30211
|
function policyJson(v) {
|
|
30042
30212
|
return JSON.stringify({ kind: "policy", ...v });
|
|
30043
30213
|
}
|
|
30214
|
+
function formatIncidentLine(card) {
|
|
30215
|
+
let tag = "";
|
|
30216
|
+
if (card.rootCause) {
|
|
30217
|
+
const rc = card.rootCause;
|
|
30218
|
+
const provs = rc.chain.map((h) => h.provenance).join("\xB7");
|
|
30219
|
+
const cls = rc.classification ? `${rc.classification} ` : "";
|
|
30220
|
+
tag = ` \xB7 ${cls}${rc.confidence.toFixed(2)}${provs ? ` [${provs}]` : ""}`;
|
|
30221
|
+
}
|
|
30222
|
+
return `\u2716 incident [${card.incidentKind}] ${card.headline}${tag}`;
|
|
30223
|
+
}
|
|
30224
|
+
function incidentJson(card) {
|
|
30225
|
+
return JSON.stringify(card);
|
|
30226
|
+
}
|
|
30044
30227
|
var MonitorEmitter = class {
|
|
30045
30228
|
constructor(opts) {
|
|
30046
30229
|
this.opts = opts;
|
|
@@ -30076,7 +30259,7 @@ var MonitorEmitter = class {
|
|
|
30076
30259
|
// ignores non-OBSERVED edges and non-dependency edge types (structural
|
|
30077
30260
|
// ownership), so only real runtime dependencies reach stdout.
|
|
30078
30261
|
emitObservedEdge(edge) {
|
|
30079
|
-
if (edge.provenance !==
|
|
30262
|
+
if (edge.provenance !== import_types102.Provenance.OBSERVED) return false;
|
|
30080
30263
|
if (!OBSERVED_DEP_EDGE_TYPES.has(edge.type)) return false;
|
|
30081
30264
|
const key = `edge|${edge.id}`;
|
|
30082
30265
|
if (this.seen.has(key)) return false;
|
|
@@ -30098,6 +30281,17 @@ var MonitorEmitter = class {
|
|
|
30098
30281
|
}
|
|
30099
30282
|
return emitted;
|
|
30100
30283
|
}
|
|
30284
|
+
// Emit one incident card once, keyed on the incident id. Unlike the other
|
|
30285
|
+
// facts this is event-driven, not a re-read of derivable state, so there is no
|
|
30286
|
+
// baseline dump on connect — only incidents that arrive live after the monitor
|
|
30287
|
+
// is watching reach stdout.
|
|
30288
|
+
emitIncident(card) {
|
|
30289
|
+
const key = `incident|${card.id}`;
|
|
30290
|
+
if (this.seen.has(key)) return false;
|
|
30291
|
+
this.seen.add(key);
|
|
30292
|
+
this.out(this.opts.json ? incidentJson(card) : formatIncidentLine(card));
|
|
30293
|
+
return true;
|
|
30294
|
+
}
|
|
30101
30295
|
};
|
|
30102
30296
|
function parseFrame(raw) {
|
|
30103
30297
|
let event = "message";
|
|
@@ -30219,6 +30413,18 @@ async function runMonitor(opts) {
|
|
|
30219
30413
|
const result = await client.get(policiesPath);
|
|
30220
30414
|
emitter.emitPolicies(result);
|
|
30221
30415
|
}, debounceMs);
|
|
30416
|
+
const readIncidentCard = async (incidentId, affectedNode) => {
|
|
30417
|
+
try {
|
|
30418
|
+
const card = await client.get(
|
|
30419
|
+
projectPath2(
|
|
30420
|
+
opts.project,
|
|
30421
|
+
`/graph/incident-card/${encodeURIComponent(affectedNode)}?errorId=${encodeURIComponent(incidentId)}`
|
|
30422
|
+
)
|
|
30423
|
+
);
|
|
30424
|
+
emitter.emitIncident(card);
|
|
30425
|
+
} catch {
|
|
30426
|
+
}
|
|
30427
|
+
};
|
|
30222
30428
|
const onFrame = (frame) => {
|
|
30223
30429
|
switch (frame.event) {
|
|
30224
30430
|
case "extraction-complete":
|
|
@@ -30234,7 +30440,7 @@ async function runMonitor(opts) {
|
|
|
30234
30440
|
case "edge-added": {
|
|
30235
30441
|
const payload = safeParse(frame.data);
|
|
30236
30442
|
const edge = payload?.edge;
|
|
30237
|
-
if (edge && edge.provenance ===
|
|
30443
|
+
if (edge && edge.provenance === import_types102.Provenance.OBSERVED) {
|
|
30238
30444
|
emitter.emitObservedEdge(edge);
|
|
30239
30445
|
divergences.schedule();
|
|
30240
30446
|
}
|
|
@@ -30243,6 +30449,13 @@ async function runMonitor(opts) {
|
|
|
30243
30449
|
case "policy-violation":
|
|
30244
30450
|
policies.schedule();
|
|
30245
30451
|
break;
|
|
30452
|
+
case "incident": {
|
|
30453
|
+
const payload = safeParse(frame.data);
|
|
30454
|
+
const incidentId = payload && typeof payload.incidentId === "string" ? payload.incidentId : void 0;
|
|
30455
|
+
const affectedNode = payload && typeof payload.affectedNode === "string" ? payload.affectedNode : void 0;
|
|
30456
|
+
if (incidentId && affectedNode) void readIncidentCard(incidentId, affectedNode);
|
|
30457
|
+
break;
|
|
30458
|
+
}
|
|
30246
30459
|
default:
|
|
30247
30460
|
break;
|
|
30248
30461
|
}
|
|
@@ -30477,7 +30690,7 @@ async function runSync(opts) {
|
|
|
30477
30690
|
}
|
|
30478
30691
|
|
|
30479
30692
|
// src/cli.ts
|
|
30480
|
-
var
|
|
30693
|
+
var import_types103 = require("@neat.is/types");
|
|
30481
30694
|
function isNpxInvocation() {
|
|
30482
30695
|
if (process.env.npm_command === "exec") return true;
|
|
30483
30696
|
const execpath = process.env.npm_execpath ?? "";
|
|
@@ -31561,10 +31774,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
31561
31774
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
31562
31775
|
const out = [];
|
|
31563
31776
|
for (const p of parts) {
|
|
31564
|
-
const r =
|
|
31777
|
+
const r = import_types103.DivergenceTypeSchema.safeParse(p);
|
|
31565
31778
|
if (!r.success) {
|
|
31566
31779
|
console.error(
|
|
31567
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
31780
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types103.DivergenceTypeSchema.options.join(", ")}`
|
|
31568
31781
|
);
|
|
31569
31782
|
return 2;
|
|
31570
31783
|
}
|