@neat.is/core 0.9.8-dev.20260828 → 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/neatd.cjs
CHANGED
|
@@ -6309,11 +6309,25 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
6309
6309
|
};
|
|
6310
6310
|
graph.addEdgeWithKey(id, source, target, edge);
|
|
6311
6311
|
}
|
|
6312
|
+
function emitIncidentEvent(project, ev) {
|
|
6313
|
+
emitNeatEvent({
|
|
6314
|
+
type: "incident",
|
|
6315
|
+
project,
|
|
6316
|
+
payload: {
|
|
6317
|
+
incidentId: ev.id,
|
|
6318
|
+
affectedNode: ev.affectedNode,
|
|
6319
|
+
service: ev.service,
|
|
6320
|
+
incidentKind: (0, import_types8.incidentKindOf)(ev),
|
|
6321
|
+
at: ev.timestamp
|
|
6322
|
+
}
|
|
6323
|
+
});
|
|
6324
|
+
}
|
|
6312
6325
|
async function appendErrorEvent(ctx, ev) {
|
|
6313
6326
|
await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(ctx.errorsPath), { recursive: true });
|
|
6314
6327
|
await import_node_fs7.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6328
|
+
emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev);
|
|
6315
6329
|
}
|
|
6316
|
-
async function appendConnectorIncident(errorsPath, input) {
|
|
6330
|
+
async function appendConnectorIncident(errorsPath, input, project) {
|
|
6317
6331
|
const ev = {
|
|
6318
6332
|
id: input.id,
|
|
6319
6333
|
timestamp: input.timestamp,
|
|
@@ -6327,6 +6341,7 @@ async function appendConnectorIncident(errorsPath, input) {
|
|
|
6327
6341
|
};
|
|
6328
6342
|
await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(errorsPath), { recursive: true });
|
|
6329
6343
|
await import_node_fs7.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6344
|
+
if (project) emitIncidentEvent(project, ev);
|
|
6330
6345
|
}
|
|
6331
6346
|
function landIncidentCallSite(span, callSite, trusted, graph) {
|
|
6332
6347
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
@@ -6420,12 +6435,13 @@ function buildErrorEventForReceiver(span, graph, scanPath) {
|
|
|
6420
6435
|
affectedNode: locus.affectedNode
|
|
6421
6436
|
};
|
|
6422
6437
|
}
|
|
6423
|
-
function makeErrorSpanWriter(errorsPath, graph, scanPath) {
|
|
6438
|
+
function makeErrorSpanWriter(errorsPath, graph, scanPath, project = DEFAULT_PROJECT) {
|
|
6424
6439
|
return async (span) => {
|
|
6425
6440
|
const ev = buildErrorEventForReceiver(span, graph, scanPath);
|
|
6426
6441
|
if (!ev) return;
|
|
6427
6442
|
await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(errorsPath), { recursive: true });
|
|
6428
6443
|
await import_node_fs7.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6444
|
+
emitIncidentEvent(project, ev);
|
|
6429
6445
|
};
|
|
6430
6446
|
}
|
|
6431
6447
|
async function recordFailingResponseIncident(ctx, span, affectedNode, timestamp, statusCode, count, firstTimestamp) {
|
|
@@ -16132,7 +16148,7 @@ var Projects = class {
|
|
|
16132
16148
|
init_cjs_shims();
|
|
16133
16149
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
16134
16150
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
16135
|
-
var
|
|
16151
|
+
var import_types98 = require("@neat.is/types");
|
|
16136
16152
|
|
|
16137
16153
|
// src/extend/index.ts
|
|
16138
16154
|
init_cjs_shims();
|
|
@@ -17174,9 +17190,128 @@ function queryLogEntries(opts) {
|
|
|
17174
17190
|
return merged;
|
|
17175
17191
|
}
|
|
17176
17192
|
|
|
17177
|
-
// src/
|
|
17193
|
+
// src/goodybag.ts
|
|
17178
17194
|
init_cjs_shims();
|
|
17179
17195
|
var import_types59 = require("@neat.is/types");
|
|
17196
|
+
var CODE_FILEPATH_ATTR2 = "code.filepath";
|
|
17197
|
+
var CODE_LINENO_ATTR2 = "code.lineno";
|
|
17198
|
+
var BLAST_NEAREST_LIMIT = 5;
|
|
17199
|
+
function grainOf2(graph, nodeId) {
|
|
17200
|
+
if (graph.hasNode(nodeId)) {
|
|
17201
|
+
const t = graph.getNodeAttributes(nodeId).type;
|
|
17202
|
+
if (typeof t === "string" && t.length > 0) {
|
|
17203
|
+
return (t.endsWith("Node") ? t.slice(0, -4) : t).toLowerCase();
|
|
17204
|
+
}
|
|
17205
|
+
}
|
|
17206
|
+
const colon = nodeId.indexOf(":");
|
|
17207
|
+
return colon > 0 ? nodeId.slice(0, colon) : "unknown";
|
|
17208
|
+
}
|
|
17209
|
+
function locusOf(graph, ev) {
|
|
17210
|
+
const file = ev.attributes?.[CODE_FILEPATH_ATTR2];
|
|
17211
|
+
if (typeof file !== "string" || file.length === 0) return null;
|
|
17212
|
+
const rawLine = ev.attributes?.[CODE_LINENO_ATTR2];
|
|
17213
|
+
const line = typeof rawLine === "number" ? rawLine : Number(rawLine);
|
|
17214
|
+
const node = graph.hasNode(ev.affectedNode) ? graph.getNodeAttributes(ev.affectedNode) : void 0;
|
|
17215
|
+
return {
|
|
17216
|
+
file,
|
|
17217
|
+
...Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {},
|
|
17218
|
+
...node?.name ? { symbol: node.name } : {},
|
|
17219
|
+
service: node?.service ?? ev.service,
|
|
17220
|
+
provenance: import_types59.Provenance.OBSERVED
|
|
17221
|
+
};
|
|
17222
|
+
}
|
|
17223
|
+
function divergenceSummary(d) {
|
|
17224
|
+
const column = "column" in d && d.column ? `.${d.column}` : "";
|
|
17225
|
+
const label = "table" in d && d.table ? `${d.table}${column}` : `${d.source} \u2192 ${d.target}`;
|
|
17226
|
+
return label;
|
|
17227
|
+
}
|
|
17228
|
+
function baseName(p) {
|
|
17229
|
+
const parts = p.split(/[\\/]/);
|
|
17230
|
+
return parts[parts.length - 1] || p;
|
|
17231
|
+
}
|
|
17232
|
+
function shortLabel(graph, nodeId) {
|
|
17233
|
+
if (graph.hasNode(nodeId)) {
|
|
17234
|
+
const name = graph.getNodeAttributes(nodeId).name;
|
|
17235
|
+
if (typeof name === "string" && name.length > 0) return name;
|
|
17236
|
+
}
|
|
17237
|
+
const afterHash = nodeId.includes("#") ? nodeId.slice(nodeId.lastIndexOf("#") + 1) : nodeId;
|
|
17238
|
+
return afterHash.includes(":") ? afterHash.slice(afterHash.lastIndexOf(":") + 1) : afterHash;
|
|
17239
|
+
}
|
|
17240
|
+
function renderHeadline(graph, ev, locus, causeNode) {
|
|
17241
|
+
const what = ev.exceptionType ? `raised ${ev.exceptionType}` : ev.errorMessage || "failed";
|
|
17242
|
+
const cause = causeNode && causeNode !== ev.affectedNode ? ` \u2192 root cause ${shortLabel(graph, causeNode)}` : "";
|
|
17243
|
+
if (locus) {
|
|
17244
|
+
const base = baseName(locus.file);
|
|
17245
|
+
const lines = locus.lineStart != null ? locus.lineEnd && locus.lineEnd !== locus.lineStart ? `LINES ${locus.lineStart}-${locus.lineEnd}` : `LINE ${locus.lineStart}` : "";
|
|
17246
|
+
const symbol = locus.symbol ?? (grainOf2(graph, ev.affectedNode) === "symbol" ? shortLabel(graph, ev.affectedNode) : void 0);
|
|
17247
|
+
const subject = symbol ? `SYMBOL ${symbol}` : `FILE ${base}`;
|
|
17248
|
+
const at = symbol ? `${lines ? `${lines} in ` : ""}${base}` : lines;
|
|
17249
|
+
const where = at ? ` at ${at}` : "";
|
|
17250
|
+
return `${subject}${where} (SERVICE ${ev.service}) ${what} at ${ev.timestamp}${cause}`;
|
|
17251
|
+
}
|
|
17252
|
+
return `SERVICE ${ev.service} ${what} at ${ev.timestamp}${cause}`;
|
|
17253
|
+
}
|
|
17254
|
+
function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
17255
|
+
const affected = errorEvent.affectedNode;
|
|
17256
|
+
const locus = locusOf(graph, errorEvent);
|
|
17257
|
+
const inGraph = graph.hasNode(affected);
|
|
17258
|
+
const rc = inGraph ? getRootCause(graph, affected, errorEvent, incidents) : null;
|
|
17259
|
+
let rootCause = null;
|
|
17260
|
+
if (rc) {
|
|
17261
|
+
const provs = rc.edgeProvenances ?? [];
|
|
17262
|
+
const chain = (rc.traversalPath ?? []).map((node, i) => ({
|
|
17263
|
+
node,
|
|
17264
|
+
grain: grainOf2(graph, node),
|
|
17265
|
+
provenance: provs[i] ?? provs[provs.length - 1] ?? import_types59.Provenance.INFERRED
|
|
17266
|
+
}));
|
|
17267
|
+
rootCause = {
|
|
17268
|
+
node: rc.rootCauseNode,
|
|
17269
|
+
...rc.candidates?.[0]?.classification ? { classification: rc.candidates[0].classification } : {},
|
|
17270
|
+
reason: rc.rootCauseReason,
|
|
17271
|
+
confidence: rc.confidence,
|
|
17272
|
+
fix: rc.fixRecommendation ?? null,
|
|
17273
|
+
chain
|
|
17274
|
+
};
|
|
17275
|
+
}
|
|
17276
|
+
const blast = inGraph ? getBlastRadius(graph, affected) : { origin: affected, affectedNodes: [], totalAffected: 0 };
|
|
17277
|
+
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 }));
|
|
17278
|
+
const applicable = inGraph ? selectApplicablePolicies(graph, policies, affected) : [];
|
|
17279
|
+
const policyCards = applicable.map((p) => ({
|
|
17280
|
+
policyName: p.policyName,
|
|
17281
|
+
severity: p.severity,
|
|
17282
|
+
message: p.reason
|
|
17283
|
+
}));
|
|
17284
|
+
const divergences = inGraph ? computeDivergences(graph, { node: affected, incidents }).divergences.map((d) => ({
|
|
17285
|
+
type: d.type,
|
|
17286
|
+
summary: divergenceSummary(d)
|
|
17287
|
+
})) : [];
|
|
17288
|
+
const card = {
|
|
17289
|
+
kind: "incident",
|
|
17290
|
+
id: errorEvent.id,
|
|
17291
|
+
at: errorEvent.timestamp,
|
|
17292
|
+
incidentKind: (0, import_types59.incidentKindOf)(errorEvent),
|
|
17293
|
+
service: errorEvent.service,
|
|
17294
|
+
affectedNode: affected,
|
|
17295
|
+
message: errorEvent.errorMessage,
|
|
17296
|
+
...errorEvent.exceptionType ? { exceptionType: errorEvent.exceptionType } : {},
|
|
17297
|
+
...errorEvent.httpStatusCode !== void 0 ? { httpStatusCode: errorEvent.httpStatusCode } : {},
|
|
17298
|
+
...errorEvent.incidentCount !== void 0 ? { count: errorEvent.incidentCount } : {},
|
|
17299
|
+
...errorEvent.firstTimestamp && errorEvent.lastTimestamp ? { window: { first: errorEvent.firstTimestamp, last: errorEvent.lastTimestamp } } : {},
|
|
17300
|
+
...errorEvent.traceId ? { traceId: errorEvent.traceId } : {},
|
|
17301
|
+
...errorEvent.spanId ? { spanId: errorEvent.spanId } : {},
|
|
17302
|
+
locus,
|
|
17303
|
+
rootCause,
|
|
17304
|
+
...nearest.length > 0 ? { blastRadius: { totalAffected: blast.totalAffected, nearest } } : {},
|
|
17305
|
+
...policyCards.length > 0 ? { policies: policyCards } : {},
|
|
17306
|
+
...divergences.length > 0 ? { divergence: divergences } : {},
|
|
17307
|
+
headline: renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)
|
|
17308
|
+
};
|
|
17309
|
+
return import_types59.IncidentCardSchema.parse(card);
|
|
17310
|
+
}
|
|
17311
|
+
|
|
17312
|
+
// src/ask.ts
|
|
17313
|
+
init_cjs_shims();
|
|
17314
|
+
var import_types60 = require("@neat.is/types");
|
|
17180
17315
|
var DEFAULT_MAX_NODES = 3;
|
|
17181
17316
|
var MAX_FACTS_PER_SECTION = 6;
|
|
17182
17317
|
var INTENT_RULES = [
|
|
@@ -17404,7 +17539,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17404
17539
|
};
|
|
17405
17540
|
graph.forEachNode((id, attrs) => {
|
|
17406
17541
|
const node = attrs;
|
|
17407
|
-
if (node.type ===
|
|
17542
|
+
if (node.type === import_types60.NodeType.FrontierNode) return;
|
|
17408
17543
|
const name = nodeName(node);
|
|
17409
17544
|
const body = idBody(id);
|
|
17410
17545
|
const labelTokens = /* @__PURE__ */ new Set([...tokens(body), ...tokens(name)]);
|
|
@@ -17423,7 +17558,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17423
17558
|
const res = await searchIndex.search(question, 10);
|
|
17424
17559
|
if (res.provider !== "substring") {
|
|
17425
17560
|
for (const m of res.matches) {
|
|
17426
|
-
if (m.node.type ===
|
|
17561
|
+
if (m.node.type === import_types60.NodeType.FrontierNode) continue;
|
|
17427
17562
|
const already = best.get(m.node.id);
|
|
17428
17563
|
if (!already && m.score < EMBED_MIN_SCORE) continue;
|
|
17429
17564
|
consider({
|
|
@@ -17461,7 +17596,7 @@ function edgeSignalNote(e) {
|
|
|
17461
17596
|
function buildRootCauseSection(graph, node, incidents, now) {
|
|
17462
17597
|
const result = getRootCause(graph, node, void 0, incidents, { now });
|
|
17463
17598
|
if (!result) return null;
|
|
17464
|
-
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ??
|
|
17599
|
+
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types60.Provenance.OBSERVED;
|
|
17465
17600
|
const facts = [
|
|
17466
17601
|
{
|
|
17467
17602
|
text: `Root cause: ${result.rootCauseNode} \u2014 ${result.rootCauseReason}`,
|
|
@@ -17511,7 +17646,7 @@ function buildObservedSection(graph, node) {
|
|
|
17511
17646
|
if (result.observed && result.inboundObservedCount > 0) {
|
|
17512
17647
|
facts.push({
|
|
17513
17648
|
text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 a pure receiver`,
|
|
17514
|
-
provenance:
|
|
17649
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17515
17650
|
});
|
|
17516
17651
|
} else {
|
|
17517
17652
|
return null;
|
|
@@ -17539,7 +17674,7 @@ function buildIncidentsSection(node, incidents) {
|
|
|
17539
17674
|
const facts = ordered.map((ev) => ({
|
|
17540
17675
|
text: `${ev.timestamp} \u2014 ${ev.service}: ${ev.errorMessage}`,
|
|
17541
17676
|
// ErrorEvents are observation records — OBSERVED by definition.
|
|
17542
|
-
provenance:
|
|
17677
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17543
17678
|
}));
|
|
17544
17679
|
return { heading: `Recent incidents (OBSERVED) \u2014 ${relevant.length} recorded`, facts };
|
|
17545
17680
|
}
|
|
@@ -17599,7 +17734,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17599
17734
|
}
|
|
17600
17735
|
const byKey = /* @__PURE__ */ new Map();
|
|
17601
17736
|
for (const ev of incidents) {
|
|
17602
|
-
const key = ev.affectedNode || (0,
|
|
17737
|
+
const key = ev.affectedNode || (0, import_types60.serviceId)(ev.service);
|
|
17603
17738
|
const cur = byKey.get(key);
|
|
17604
17739
|
if (!cur) {
|
|
17605
17740
|
byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
|
|
@@ -17614,7 +17749,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17614
17749
|
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);
|
|
17615
17750
|
const facts = rows.map((r) => ({
|
|
17616
17751
|
text: `${r.key} \u2014 ${r.count} incident${r.count === 1 ? "" : "s"}, latest ${r.latest}: ${r.sampleMsg}`,
|
|
17617
|
-
provenance:
|
|
17752
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17618
17753
|
}));
|
|
17619
17754
|
return {
|
|
17620
17755
|
heading: `Incidents across the system \u2014 ${incidents.length} recorded`,
|
|
@@ -17627,7 +17762,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17627
17762
|
graph.forEachNode((_id, attrs) => {
|
|
17628
17763
|
const node = attrs;
|
|
17629
17764
|
nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1);
|
|
17630
|
-
if (node.type ===
|
|
17765
|
+
if (node.type === import_types60.NodeType.ServiceNode) services.push(node.id);
|
|
17631
17766
|
});
|
|
17632
17767
|
const edgeByProv = /* @__PURE__ */ new Map();
|
|
17633
17768
|
graph.forEachEdge((_id, attrs) => {
|
|
@@ -17639,10 +17774,10 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17639
17774
|
const shapeFacts = [
|
|
17640
17775
|
{ text: `${graph.order} nodes, ${graph.size} edges` },
|
|
17641
17776
|
{
|
|
17642
|
-
text: `${count(
|
|
17777
|
+
text: `${count(import_types60.NodeType.ServiceNode)} services, ${count(import_types60.NodeType.FileNode)} files, ${count(import_types60.NodeType.SymbolNode)} symbols, ${count(import_types60.NodeType.DatabaseNode)} databases`
|
|
17643
17778
|
}
|
|
17644
17779
|
];
|
|
17645
|
-
for (const p of [
|
|
17780
|
+
for (const p of [import_types60.Provenance.EXTRACTED, import_types60.Provenance.OBSERVED, import_types60.Provenance.INFERRED, import_types60.Provenance.STALE]) {
|
|
17646
17781
|
const n = edgeByProv.get(p) ?? 0;
|
|
17647
17782
|
if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? "" : "s"}`, provenance: p });
|
|
17648
17783
|
}
|
|
@@ -17659,7 +17794,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17659
17794
|
if (incidents && incidents.length > 0) {
|
|
17660
17795
|
const incCount = /* @__PURE__ */ new Map();
|
|
17661
17796
|
for (const ev of incidents) {
|
|
17662
|
-
const key = ev.affectedNode || (0,
|
|
17797
|
+
const key = ev.affectedNode || (0, import_types60.serviceId)(ev.service);
|
|
17663
17798
|
incCount.set(key, (incCount.get(key) ?? 0) + 1);
|
|
17664
17799
|
}
|
|
17665
17800
|
const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
|
|
@@ -17667,7 +17802,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17667
17802
|
heading: `Nodes with incidents \u2014 ${incidents.length} recorded`,
|
|
17668
17803
|
facts: top.map(([k, n]) => ({
|
|
17669
17804
|
text: `${k} \u2014 ${n} incident${n === 1 ? "" : "s"}`,
|
|
17670
|
-
provenance:
|
|
17805
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17671
17806
|
}))
|
|
17672
17807
|
});
|
|
17673
17808
|
}
|
|
@@ -17803,7 +17938,7 @@ async function askGraph(graph, question, opts = {}) {
|
|
|
17803
17938
|
const provSet = /* @__PURE__ */ new Set();
|
|
17804
17939
|
for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance);
|
|
17805
17940
|
const confidence = sections[0]?.facts[0]?.confidence;
|
|
17806
|
-
return
|
|
17941
|
+
return import_types60.AskResultSchema.parse({
|
|
17807
17942
|
question,
|
|
17808
17943
|
intent,
|
|
17809
17944
|
matched,
|
|
@@ -17898,7 +18033,7 @@ init_cjs_shims();
|
|
|
17898
18033
|
var import_node_fs37 = require("fs");
|
|
17899
18034
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
17900
18035
|
var import_node_path72 = __toESM(require("path"), 1);
|
|
17901
|
-
var
|
|
18036
|
+
var import_types61 = require("@neat.is/types");
|
|
17902
18037
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
17903
18038
|
var LOCK_RETRY_MS = 50;
|
|
17904
18039
|
function neatHome() {
|
|
@@ -18100,10 +18235,10 @@ async function readRegistry() {
|
|
|
18100
18235
|
throw err;
|
|
18101
18236
|
}
|
|
18102
18237
|
const parsed = JSON.parse(raw);
|
|
18103
|
-
return
|
|
18238
|
+
return import_types61.RegistryFileSchema.parse(parsed);
|
|
18104
18239
|
}
|
|
18105
18240
|
async function writeRegistry(reg) {
|
|
18106
|
-
const validated =
|
|
18241
|
+
const validated = import_types61.RegistryFileSchema.parse(reg);
|
|
18107
18242
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
18108
18243
|
}
|
|
18109
18244
|
async function getProject(name) {
|
|
@@ -18454,15 +18589,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
18454
18589
|
|
|
18455
18590
|
// src/connectors/index.ts
|
|
18456
18591
|
init_cjs_shims();
|
|
18457
|
-
var
|
|
18592
|
+
var import_types62 = require("@neat.is/types");
|
|
18458
18593
|
var NO_ENV = "unknown";
|
|
18459
18594
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
18460
18595
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18461
18596
|
const sites = [];
|
|
18462
18597
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
18463
18598
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18464
|
-
if (edge.provenance !==
|
|
18465
|
-
const parsed = (0,
|
|
18599
|
+
if (edge.provenance !== import_types62.Provenance.EXTRACTED) continue;
|
|
18600
|
+
const parsed = (0, import_types62.parseFileId)(edge.source);
|
|
18466
18601
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
18467
18602
|
const site = { relPath: edge.evidence.file };
|
|
18468
18603
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -18473,7 +18608,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
18473
18608
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
18474
18609
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18475
18610
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
18476
|
-
if (attrs.type !==
|
|
18611
|
+
if (attrs.type !== import_types62.NodeType.RouteNode || !attrs.path) return void 0;
|
|
18477
18612
|
const site = { relPath: attrs.path };
|
|
18478
18613
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
18479
18614
|
return site;
|
|
@@ -18503,7 +18638,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
18503
18638
|
errorMessage: signal.incident.errorMessage,
|
|
18504
18639
|
...signal.incident.attributes ? { attributes: signal.incident.attributes } : {},
|
|
18505
18640
|
affectedNode: resolved.targetNodeId
|
|
18506
|
-
});
|
|
18641
|
+
}, ctx.project);
|
|
18507
18642
|
continue;
|
|
18508
18643
|
}
|
|
18509
18644
|
if (resolved.ensureInfraNode) {
|
|
@@ -19085,23 +19220,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
19085
19220
|
|
|
19086
19221
|
// src/connectors/supabase/resolve.ts
|
|
19087
19222
|
init_cjs_shims();
|
|
19088
|
-
var
|
|
19223
|
+
var import_types64 = require("@neat.is/types");
|
|
19089
19224
|
function createSupabaseResolveTarget(graph, config) {
|
|
19090
19225
|
return (signal, _ctx) => {
|
|
19091
19226
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
19092
19227
|
return null;
|
|
19093
19228
|
}
|
|
19094
|
-
const subResourceId = (0,
|
|
19229
|
+
const subResourceId = (0, import_types64.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
19095
19230
|
if (graph.hasNode(subResourceId)) {
|
|
19096
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
19231
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types64.EdgeType.CALLS };
|
|
19097
19232
|
}
|
|
19098
|
-
const bareResourceId = (0,
|
|
19233
|
+
const bareResourceId = (0, import_types64.infraId)(signal.targetKind, signal.targetName);
|
|
19099
19234
|
if (graph.hasNode(bareResourceId)) {
|
|
19100
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
19235
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types64.EdgeType.CALLS };
|
|
19101
19236
|
}
|
|
19102
|
-
const projectLevelId = (0,
|
|
19237
|
+
const projectLevelId = (0, import_types64.infraId)("supabase", config.nodeRef);
|
|
19103
19238
|
if (graph.hasNode(projectLevelId)) {
|
|
19104
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
19239
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types64.EdgeType.CALLS };
|
|
19105
19240
|
}
|
|
19106
19241
|
return null;
|
|
19107
19242
|
};
|
|
@@ -19194,7 +19329,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
19194
19329
|
|
|
19195
19330
|
// src/connectors/railway/index.ts
|
|
19196
19331
|
init_cjs_shims();
|
|
19197
|
-
var
|
|
19332
|
+
var import_types68 = require("@neat.is/types");
|
|
19198
19333
|
|
|
19199
19334
|
// src/connectors/railway/client.ts
|
|
19200
19335
|
init_cjs_shims();
|
|
@@ -19345,7 +19480,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
19345
19480
|
const out = [];
|
|
19346
19481
|
graph.forEachNode((_id, attrs) => {
|
|
19347
19482
|
const node = attrs;
|
|
19348
|
-
if (node.type !==
|
|
19483
|
+
if (node.type !== import_types68.NodeType.RouteNode) return;
|
|
19349
19484
|
const route = attrs;
|
|
19350
19485
|
if (route.service !== serviceName) return;
|
|
19351
19486
|
out.push({
|
|
@@ -19449,12 +19584,12 @@ function createRailwayResolveTarget(config) {
|
|
|
19449
19584
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
19450
19585
|
if (!serviceName) return null;
|
|
19451
19586
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
19452
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
19587
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types68.EdgeType.CALLS };
|
|
19453
19588
|
}
|
|
19454
19589
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
19455
19590
|
const peerName = config.serviceNameById[signal.targetName];
|
|
19456
19591
|
if (!peerName) return null;
|
|
19457
|
-
return { targetNodeId: (0,
|
|
19592
|
+
return { targetNodeId: (0, import_types68.serviceId)(peerName), serviceName, edgeType: import_types68.EdgeType.CONNECTS_TO };
|
|
19458
19593
|
}
|
|
19459
19594
|
return null;
|
|
19460
19595
|
};
|
|
@@ -19642,7 +19777,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
19642
19777
|
|
|
19643
19778
|
// src/connectors/firebase/resolve.ts
|
|
19644
19779
|
init_cjs_shims();
|
|
19645
|
-
var
|
|
19780
|
+
var import_types69 = require("@neat.is/types");
|
|
19646
19781
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
19647
19782
|
switch (resourceType) {
|
|
19648
19783
|
case "cloud_function":
|
|
@@ -19657,7 +19792,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
19657
19792
|
const entries = [];
|
|
19658
19793
|
graph.forEachNode((_id, attrs) => {
|
|
19659
19794
|
const node = attrs;
|
|
19660
|
-
if (node.type !==
|
|
19795
|
+
if (node.type !== import_types69.NodeType.RouteNode) return;
|
|
19661
19796
|
const route = attrs;
|
|
19662
19797
|
if (route.service !== serviceName) return;
|
|
19663
19798
|
entries.push({
|
|
@@ -19689,7 +19824,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
19689
19824
|
return {
|
|
19690
19825
|
targetNodeId: match.routeNodeId,
|
|
19691
19826
|
serviceName,
|
|
19692
|
-
edgeType:
|
|
19827
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
19693
19828
|
};
|
|
19694
19829
|
};
|
|
19695
19830
|
}
|
|
@@ -19716,7 +19851,7 @@ init_cjs_shims();
|
|
|
19716
19851
|
|
|
19717
19852
|
// src/connectors/cloudflare/connector.ts
|
|
19718
19853
|
init_cjs_shims();
|
|
19719
|
-
var
|
|
19854
|
+
var import_types71 = require("@neat.is/types");
|
|
19720
19855
|
|
|
19721
19856
|
// src/connectors/cloudflare/client.ts
|
|
19722
19857
|
init_cjs_shims();
|
|
@@ -19880,7 +20015,7 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
19880
20015
|
graph.forEachNode((id, attrs) => {
|
|
19881
20016
|
if (found) return;
|
|
19882
20017
|
const a = attrs;
|
|
19883
|
-
if (a.type ===
|
|
20018
|
+
if (a.type === import_types71.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
19884
20019
|
found = id;
|
|
19885
20020
|
}
|
|
19886
20021
|
});
|
|
@@ -19892,7 +20027,7 @@ function findMatchingRouteNode(graph, serviceName, method, path78) {
|
|
|
19892
20027
|
graph.forEachNode((id, attrs) => {
|
|
19893
20028
|
if (found) return;
|
|
19894
20029
|
const a = attrs;
|
|
19895
|
-
if (a.type !==
|
|
20030
|
+
if (a.type !== import_types71.NodeType.RouteNode || a.service !== serviceName) return;
|
|
19896
20031
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
19897
20032
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
19898
20033
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -19911,11 +20046,11 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
19911
20046
|
};
|
|
19912
20047
|
const mapping = config.workers?.[scriptName];
|
|
19913
20048
|
if (mapping) {
|
|
19914
|
-
const wholeFileId = (0,
|
|
20049
|
+
const wholeFileId = (0, import_types71.fileId)(mapping.service, mapping.entryFile);
|
|
19915
20050
|
return {
|
|
19916
20051
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
19917
20052
|
serviceName: mapping.service,
|
|
19918
|
-
edgeType:
|
|
20053
|
+
edgeType: import_types71.EdgeType.CALLS
|
|
19919
20054
|
};
|
|
19920
20055
|
}
|
|
19921
20056
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -19924,13 +20059,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
19924
20059
|
return {
|
|
19925
20060
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
19926
20061
|
serviceName: fileNode.service,
|
|
19927
|
-
edgeType:
|
|
20062
|
+
edgeType: import_types71.EdgeType.CALLS
|
|
19928
20063
|
};
|
|
19929
20064
|
}
|
|
19930
20065
|
return {
|
|
19931
|
-
targetNodeId: (0,
|
|
20066
|
+
targetNodeId: (0, import_types71.infraId)("cloudflare-worker", scriptName),
|
|
19932
20067
|
serviceName: scriptName,
|
|
19933
|
-
edgeType:
|
|
20068
|
+
edgeType: import_types71.EdgeType.CALLS,
|
|
19934
20069
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
19935
20070
|
};
|
|
19936
20071
|
};
|
|
@@ -20126,14 +20261,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
20126
20261
|
|
|
20127
20262
|
// src/connectors/neon/resolve.ts
|
|
20128
20263
|
init_cjs_shims();
|
|
20129
|
-
var
|
|
20264
|
+
var import_types75 = require("@neat.is/types");
|
|
20130
20265
|
function createNeonResolveTarget(config) {
|
|
20131
20266
|
return (signal) => {
|
|
20132
20267
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20133
20268
|
return {
|
|
20134
|
-
targetNodeId: (0,
|
|
20269
|
+
targetNodeId: (0, import_types75.infraId)("sql-table", signal.targetName),
|
|
20135
20270
|
serviceName: config.serviceName,
|
|
20136
|
-
edgeType:
|
|
20271
|
+
edgeType: import_types75.EdgeType.CALLS,
|
|
20137
20272
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
20138
20273
|
};
|
|
20139
20274
|
};
|
|
@@ -20314,14 +20449,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
20314
20449
|
|
|
20315
20450
|
// src/connectors/cloud-run/resolve.ts
|
|
20316
20451
|
init_cjs_shims();
|
|
20317
|
-
var
|
|
20452
|
+
var import_types79 = require("@neat.is/types");
|
|
20318
20453
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
20319
20454
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
20320
20455
|
let found = null;
|
|
20321
20456
|
graph.forEachNode((_id, attrs) => {
|
|
20322
20457
|
if (found) return;
|
|
20323
20458
|
const node = attrs;
|
|
20324
|
-
if (node.type !==
|
|
20459
|
+
if (node.type !== import_types79.NodeType.RouteNode) return;
|
|
20325
20460
|
const route = attrs;
|
|
20326
20461
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20327
20462
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20346,13 +20481,13 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
20346
20481
|
normalizePathTemplate(path78)
|
|
20347
20482
|
);
|
|
20348
20483
|
if (routeNodeId) {
|
|
20349
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20484
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types79.EdgeType.CALLS };
|
|
20350
20485
|
}
|
|
20351
20486
|
}
|
|
20352
20487
|
return {
|
|
20353
|
-
targetNodeId: (0,
|
|
20488
|
+
targetNodeId: (0, import_types79.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
20354
20489
|
serviceName: mappedService ?? gcpServiceName,
|
|
20355
|
-
edgeType:
|
|
20490
|
+
edgeType: import_types79.EdgeType.CALLS,
|
|
20356
20491
|
ensureInfraNode: {
|
|
20357
20492
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
20358
20493
|
name: gcpServiceName,
|
|
@@ -20534,14 +20669,14 @@ function mapLogEntriesToSignals3(entries) {
|
|
|
20534
20669
|
|
|
20535
20670
|
// src/connectors/gcp-lb/resolve.ts
|
|
20536
20671
|
init_cjs_shims();
|
|
20537
|
-
var
|
|
20672
|
+
var import_types83 = require("@neat.is/types");
|
|
20538
20673
|
var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
|
|
20539
20674
|
function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
|
|
20540
20675
|
let found = null;
|
|
20541
20676
|
graph.forEachNode((_id, attrs) => {
|
|
20542
20677
|
if (found) return;
|
|
20543
20678
|
const node = attrs;
|
|
20544
|
-
if (node.type !==
|
|
20679
|
+
if (node.type !== import_types83.NodeType.RouteNode) return;
|
|
20545
20680
|
const route = attrs;
|
|
20546
20681
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20547
20682
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20566,13 +20701,13 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
20566
20701
|
normalizePathTemplate(path78)
|
|
20567
20702
|
);
|
|
20568
20703
|
if (routeNodeId) {
|
|
20569
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20704
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types83.EdgeType.CALLS };
|
|
20570
20705
|
}
|
|
20571
20706
|
}
|
|
20572
20707
|
return {
|
|
20573
|
-
targetNodeId: (0,
|
|
20708
|
+
targetNodeId: (0, import_types83.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
|
|
20574
20709
|
serviceName: mappedService ?? backendServiceName,
|
|
20575
|
-
edgeType:
|
|
20710
|
+
edgeType: import_types83.EdgeType.CALLS,
|
|
20576
20711
|
ensureInfraNode: {
|
|
20577
20712
|
kind: GCP_LB_BACKEND_INFRA_KIND,
|
|
20578
20713
|
name: backendServiceName,
|
|
@@ -20613,7 +20748,7 @@ function createGcpLbConnector(graph, config = {}) {
|
|
|
20613
20748
|
|
|
20614
20749
|
// src/connectors/render/index.ts
|
|
20615
20750
|
init_cjs_shims();
|
|
20616
|
-
var
|
|
20751
|
+
var import_types86 = require("@neat.is/types");
|
|
20617
20752
|
|
|
20618
20753
|
// src/connectors/render/types.ts
|
|
20619
20754
|
init_cjs_shims();
|
|
@@ -20691,7 +20826,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
20691
20826
|
const out = [];
|
|
20692
20827
|
graph.forEachNode((_id, attrs) => {
|
|
20693
20828
|
const node = attrs;
|
|
20694
|
-
if (node.type !==
|
|
20829
|
+
if (node.type !== import_types86.NodeType.RouteNode) return;
|
|
20695
20830
|
const route = attrs;
|
|
20696
20831
|
if (route.service !== serviceName) return;
|
|
20697
20832
|
out.push({
|
|
@@ -20776,7 +20911,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
20776
20911
|
function createRenderResolveTarget(config) {
|
|
20777
20912
|
return (signal) => {
|
|
20778
20913
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
20779
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
20914
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types86.EdgeType.CALLS };
|
|
20780
20915
|
}
|
|
20781
20916
|
return null;
|
|
20782
20917
|
};
|
|
@@ -20914,21 +21049,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
20914
21049
|
|
|
20915
21050
|
// src/connectors/planetscale/resolve.ts
|
|
20916
21051
|
init_cjs_shims();
|
|
20917
|
-
var
|
|
21052
|
+
var import_types90 = require("@neat.is/types");
|
|
20918
21053
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
20919
21054
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
20920
21055
|
const databaseName = `${config.organization}/${config.database}`;
|
|
20921
21056
|
return (signal, _ctx) => {
|
|
20922
21057
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20923
|
-
const tableId = (0,
|
|
21058
|
+
const tableId = (0, import_types90.infraId)("sql-table", signal.targetName);
|
|
20924
21059
|
if (graph.hasNode(tableId)) {
|
|
20925
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
21060
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types90.EdgeType.CALLS };
|
|
20926
21061
|
}
|
|
20927
|
-
const providerId = (0,
|
|
21062
|
+
const providerId = (0, import_types90.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
20928
21063
|
return {
|
|
20929
21064
|
targetNodeId: providerId,
|
|
20930
21065
|
serviceName: config.serviceName,
|
|
20931
|
-
edgeType:
|
|
21066
|
+
edgeType: import_types90.EdgeType.CALLS,
|
|
20932
21067
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
20933
21068
|
};
|
|
20934
21069
|
};
|
|
@@ -21193,7 +21328,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
21193
21328
|
|
|
21194
21329
|
// src/connectors/eas/resolve.ts
|
|
21195
21330
|
init_cjs_shims();
|
|
21196
|
-
var
|
|
21331
|
+
var import_types95 = require("@neat.is/types");
|
|
21197
21332
|
var NO_ENV2 = "unknown";
|
|
21198
21333
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
21199
21334
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -21209,8 +21344,8 @@ function configBasenamesForPhase(phase) {
|
|
|
21209
21344
|
function configNodeService(graph, configNodeId) {
|
|
21210
21345
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
21211
21346
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
21212
|
-
if (edge.type !==
|
|
21213
|
-
const parsed = (0,
|
|
21347
|
+
if (edge.type !== import_types95.EdgeType.CONFIGURED_BY) continue;
|
|
21348
|
+
const parsed = (0, import_types95.parseFileId)(edge.source);
|
|
21214
21349
|
if (parsed) return parsed.service;
|
|
21215
21350
|
}
|
|
21216
21351
|
return null;
|
|
@@ -21221,7 +21356,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
21221
21356
|
graph.forEachNode((id, attrs) => {
|
|
21222
21357
|
if (scoped) return;
|
|
21223
21358
|
const node = attrs;
|
|
21224
|
-
if (node.type !==
|
|
21359
|
+
if (node.type !== import_types95.NodeType.ConfigNode) return;
|
|
21225
21360
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
21226
21361
|
if (anyMatch === null) anyMatch = id;
|
|
21227
21362
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -21238,13 +21373,13 @@ function createEasResolveTarget(graph) {
|
|
|
21238
21373
|
if (basenames.length > 0) {
|
|
21239
21374
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
21240
21375
|
if (configNodeId) {
|
|
21241
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
21376
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types95.EdgeType.CALLS };
|
|
21242
21377
|
}
|
|
21243
21378
|
}
|
|
21244
21379
|
return {
|
|
21245
21380
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
21246
21381
|
serviceName,
|
|
21247
|
-
edgeType:
|
|
21382
|
+
edgeType: import_types95.EdgeType.CALLS
|
|
21248
21383
|
};
|
|
21249
21384
|
};
|
|
21250
21385
|
}
|
|
@@ -21831,6 +21966,7 @@ async function startConnectorPolling(input) {
|
|
|
21831
21966
|
registration.connector,
|
|
21832
21967
|
{
|
|
21833
21968
|
projectDir: input.projectDir,
|
|
21969
|
+
project: input.project,
|
|
21834
21970
|
credentials: registration.credentials,
|
|
21835
21971
|
...input.errorsPath ? { errorsPath: input.errorsPath } : {}
|
|
21836
21972
|
},
|
|
@@ -22005,11 +22141,11 @@ function registerRoutes(scope, ctx) {
|
|
|
22005
22141
|
const candidates = req2.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
22006
22142
|
const parsed = [];
|
|
22007
22143
|
for (const c of candidates) {
|
|
22008
|
-
const r =
|
|
22144
|
+
const r = import_types98.DivergenceTypeSchema.safeParse(c);
|
|
22009
22145
|
if (!r.success) {
|
|
22010
22146
|
return reply.code(400).send({
|
|
22011
22147
|
error: `unknown divergence type "${c}"`,
|
|
22012
|
-
allowed:
|
|
22148
|
+
allowed: import_types98.DivergenceTypeSchema.options
|
|
22013
22149
|
});
|
|
22014
22150
|
}
|
|
22015
22151
|
parsed.push(r.data);
|
|
@@ -22126,6 +22262,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22126
22262
|
reg.connector,
|
|
22127
22263
|
{
|
|
22128
22264
|
projectDir: proj.scanPath ?? "",
|
|
22265
|
+
project: proj.name,
|
|
22129
22266
|
credentials: reg.credentials,
|
|
22130
22267
|
...incidentsPath ? { errorsPath: incidentsPath } : {}
|
|
22131
22268
|
},
|
|
@@ -22189,6 +22326,39 @@ function registerRoutes(scope, ctx) {
|
|
|
22189
22326
|
if (!result) return reply.code(404).send({ error: "no root cause found", id: nodeId });
|
|
22190
22327
|
return result;
|
|
22191
22328
|
});
|
|
22329
|
+
scope.get("/graph/incident-card/:nodeId", async (req2, reply) => {
|
|
22330
|
+
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
22331
|
+
if (!proj) return;
|
|
22332
|
+
const { nodeId } = req2.params;
|
|
22333
|
+
if (!proj.graph.hasNode(nodeId)) {
|
|
22334
|
+
return reply.code(404).send({ error: "node not found", id: nodeId });
|
|
22335
|
+
}
|
|
22336
|
+
const epath = errorsPathFor(proj);
|
|
22337
|
+
const incidents = epath ? await readErrorEvents(epath) : [];
|
|
22338
|
+
let errorEvent;
|
|
22339
|
+
if (req2.query.errorId) {
|
|
22340
|
+
errorEvent = incidents.find((e) => e.id === req2.query.errorId);
|
|
22341
|
+
if (!errorEvent) {
|
|
22342
|
+
return reply.code(404).send({ error: "error event not found", id: req2.query.errorId });
|
|
22343
|
+
}
|
|
22344
|
+
} else {
|
|
22345
|
+
const svc = nodeId.replace(/^service:/, "");
|
|
22346
|
+
errorEvent = [...incidents].filter((e) => e.affectedNode === nodeId || e.service === svc).sort((a, b) => (b.timestamp ?? "").localeCompare(a.timestamp ?? ""))[0];
|
|
22347
|
+
if (!errorEvent) {
|
|
22348
|
+
return reply.code(404).send({ error: "no incident found for node", id: nodeId });
|
|
22349
|
+
}
|
|
22350
|
+
}
|
|
22351
|
+
const policyPath = ctx.policyFilePathFor(proj);
|
|
22352
|
+
let policies = [];
|
|
22353
|
+
if (policyPath) {
|
|
22354
|
+
try {
|
|
22355
|
+
policies = await loadPolicyFile(policyPath);
|
|
22356
|
+
} catch {
|
|
22357
|
+
policies = [];
|
|
22358
|
+
}
|
|
22359
|
+
}
|
|
22360
|
+
return buildIncidentCard(proj.graph, errorEvent, incidents, policies);
|
|
22361
|
+
});
|
|
22192
22362
|
scope.get("/graph/blast-radius/:nodeId", async (req2, reply) => {
|
|
22193
22363
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
22194
22364
|
if (!proj) return;
|
|
@@ -22371,7 +22541,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22371
22541
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
22372
22542
|
let violations = await log.readAll();
|
|
22373
22543
|
if (req2.query.severity) {
|
|
22374
|
-
const sev =
|
|
22544
|
+
const sev = import_types98.PolicySeveritySchema.safeParse(req2.query.severity);
|
|
22375
22545
|
if (!sev.success) {
|
|
22376
22546
|
return reply.code(400).send({
|
|
22377
22547
|
error: "invalid severity",
|
|
@@ -22410,7 +22580,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22410
22580
|
scope.post("/policies/check", async (req2, reply) => {
|
|
22411
22581
|
const proj = resolveProject(registry, req2, reply, ctx.bootstrap, ctx.singleProject);
|
|
22412
22582
|
if (!proj) return;
|
|
22413
|
-
const parsed =
|
|
22583
|
+
const parsed = import_types98.PoliciesCheckBodySchema.safeParse(req2.body ?? {});
|
|
22414
22584
|
if (!parsed.success) {
|
|
22415
22585
|
return reply.code(400).send({
|
|
22416
22586
|
error: "invalid /policies/check body",
|
|
@@ -22751,7 +22921,7 @@ function unroutedErrorsPath(neatHome4) {
|
|
|
22751
22921
|
}
|
|
22752
22922
|
|
|
22753
22923
|
// src/daemon.ts
|
|
22754
|
-
var
|
|
22924
|
+
var import_types99 = require("@neat.is/types");
|
|
22755
22925
|
function daemonJsonPath(scanPath) {
|
|
22756
22926
|
return import_node_path75.default.join(scanPath, "neat-out", "daemon.json");
|
|
22757
22927
|
}
|
|
@@ -22890,7 +23060,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
22890
23060
|
if (!serviceName) return true;
|
|
22891
23061
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
22892
23062
|
return graph.someNode(
|
|
22893
|
-
(_id, attrs) => attrs.type ===
|
|
23063
|
+
(_id, attrs) => attrs.type === import_types99.NodeType.ServiceNode && attrs.name === serviceName
|
|
22894
23064
|
);
|
|
22895
23065
|
}
|
|
22896
23066
|
async function bootstrapProject(entry2, connectors = [], neatHome4) {
|
|
@@ -23345,7 +23515,12 @@ async function startDaemon(opts = {}) {
|
|
|
23345
23515
|
onErrorSpanSync: async (span) => {
|
|
23346
23516
|
const slot = await resolveTargetSlot(span.service, span.traceId);
|
|
23347
23517
|
if (!slot) return;
|
|
23348
|
-
await makeErrorSpanWriter(
|
|
23518
|
+
await makeErrorSpanWriter(
|
|
23519
|
+
slot.paths.errorsPath,
|
|
23520
|
+
slot.graph,
|
|
23521
|
+
slot.entry.path,
|
|
23522
|
+
slot.entry.name
|
|
23523
|
+
)(span);
|
|
23349
23524
|
},
|
|
23350
23525
|
// Project-scoped route (issue #367) — the URL already named the
|
|
23351
23526
|
// project. Resolution is a direct slot lookup; service.name resolves
|
|
@@ -23368,7 +23543,12 @@ async function startDaemon(opts = {}) {
|
|
|
23368
23543
|
onProjectErrorSpanSync: async (project, span) => {
|
|
23369
23544
|
const slot = await resolveSlotByName(project, span.service, span.traceId);
|
|
23370
23545
|
if (!slot) return;
|
|
23371
|
-
await makeErrorSpanWriter(
|
|
23546
|
+
await makeErrorSpanWriter(
|
|
23547
|
+
slot.paths.errorsPath,
|
|
23548
|
+
slot.graph,
|
|
23549
|
+
slot.entry.path,
|
|
23550
|
+
slot.entry.name
|
|
23551
|
+
)(span);
|
|
23372
23552
|
},
|
|
23373
23553
|
// #881 — 404 a project-scoped POST for a project this daemon doesn't
|
|
23374
23554
|
// host, rather than accepting it and dropping the batch. `slots` covers
|