@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/index.cjs
CHANGED
|
@@ -6346,11 +6346,25 @@ function upsertInferredEdge(graph, type, source, target, ts) {
|
|
|
6346
6346
|
};
|
|
6347
6347
|
graph.addEdgeWithKey(id, source, target, edge);
|
|
6348
6348
|
}
|
|
6349
|
+
function emitIncidentEvent(project, ev) {
|
|
6350
|
+
emitNeatEvent({
|
|
6351
|
+
type: "incident",
|
|
6352
|
+
project,
|
|
6353
|
+
payload: {
|
|
6354
|
+
incidentId: ev.id,
|
|
6355
|
+
affectedNode: ev.affectedNode,
|
|
6356
|
+
service: ev.service,
|
|
6357
|
+
incidentKind: (0, import_types8.incidentKindOf)(ev),
|
|
6358
|
+
at: ev.timestamp
|
|
6359
|
+
}
|
|
6360
|
+
});
|
|
6361
|
+
}
|
|
6349
6362
|
async function appendErrorEvent(ctx, ev) {
|
|
6350
6363
|
await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(ctx.errorsPath), { recursive: true });
|
|
6351
6364
|
await import_node_fs7.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6365
|
+
emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev);
|
|
6352
6366
|
}
|
|
6353
|
-
async function appendConnectorIncident(errorsPath, input) {
|
|
6367
|
+
async function appendConnectorIncident(errorsPath, input, project) {
|
|
6354
6368
|
const ev = {
|
|
6355
6369
|
id: input.id,
|
|
6356
6370
|
timestamp: input.timestamp,
|
|
@@ -6364,6 +6378,7 @@ async function appendConnectorIncident(errorsPath, input) {
|
|
|
6364
6378
|
};
|
|
6365
6379
|
await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(errorsPath), { recursive: true });
|
|
6366
6380
|
await import_node_fs7.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6381
|
+
if (project) emitIncidentEvent(project, ev);
|
|
6367
6382
|
}
|
|
6368
6383
|
function landIncidentCallSite(span, callSite, trusted, graph) {
|
|
6369
6384
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
@@ -6457,12 +6472,13 @@ function buildErrorEventForReceiver(span, graph, scanPath) {
|
|
|
6457
6472
|
affectedNode: locus.affectedNode
|
|
6458
6473
|
};
|
|
6459
6474
|
}
|
|
6460
|
-
function makeErrorSpanWriter(errorsPath, graph, scanPath) {
|
|
6475
|
+
function makeErrorSpanWriter(errorsPath, graph, scanPath, project = DEFAULT_PROJECT) {
|
|
6461
6476
|
return async (span) => {
|
|
6462
6477
|
const ev = buildErrorEventForReceiver(span, graph, scanPath);
|
|
6463
6478
|
if (!ev) return;
|
|
6464
6479
|
await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(errorsPath), { recursive: true });
|
|
6465
6480
|
await import_node_fs7.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
6481
|
+
emitIncidentEvent(project, ev);
|
|
6466
6482
|
};
|
|
6467
6483
|
}
|
|
6468
6484
|
async function recordFailingResponseIncident(ctx, span, affectedNode, timestamp, statusCode, count, firstTimestamp) {
|
|
@@ -16120,7 +16136,7 @@ function startPersistLoop(graph, outPath, opts = {}) {
|
|
|
16120
16136
|
init_cjs_shims();
|
|
16121
16137
|
var import_fastify2 = __toESM(require("fastify"), 1);
|
|
16122
16138
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
16123
|
-
var
|
|
16139
|
+
var import_types98 = require("@neat.is/types");
|
|
16124
16140
|
|
|
16125
16141
|
// src/extend/index.ts
|
|
16126
16142
|
init_cjs_shims();
|
|
@@ -17162,9 +17178,128 @@ function queryLogEntries(opts) {
|
|
|
17162
17178
|
return merged;
|
|
17163
17179
|
}
|
|
17164
17180
|
|
|
17165
|
-
// src/
|
|
17181
|
+
// src/goodybag.ts
|
|
17166
17182
|
init_cjs_shims();
|
|
17167
17183
|
var import_types59 = require("@neat.is/types");
|
|
17184
|
+
var CODE_FILEPATH_ATTR2 = "code.filepath";
|
|
17185
|
+
var CODE_LINENO_ATTR2 = "code.lineno";
|
|
17186
|
+
var BLAST_NEAREST_LIMIT = 5;
|
|
17187
|
+
function grainOf2(graph, nodeId) {
|
|
17188
|
+
if (graph.hasNode(nodeId)) {
|
|
17189
|
+
const t = graph.getNodeAttributes(nodeId).type;
|
|
17190
|
+
if (typeof t === "string" && t.length > 0) {
|
|
17191
|
+
return (t.endsWith("Node") ? t.slice(0, -4) : t).toLowerCase();
|
|
17192
|
+
}
|
|
17193
|
+
}
|
|
17194
|
+
const colon = nodeId.indexOf(":");
|
|
17195
|
+
return colon > 0 ? nodeId.slice(0, colon) : "unknown";
|
|
17196
|
+
}
|
|
17197
|
+
function locusOf(graph, ev) {
|
|
17198
|
+
const file = ev.attributes?.[CODE_FILEPATH_ATTR2];
|
|
17199
|
+
if (typeof file !== "string" || file.length === 0) return null;
|
|
17200
|
+
const rawLine = ev.attributes?.[CODE_LINENO_ATTR2];
|
|
17201
|
+
const line = typeof rawLine === "number" ? rawLine : Number(rawLine);
|
|
17202
|
+
const node = graph.hasNode(ev.affectedNode) ? graph.getNodeAttributes(ev.affectedNode) : void 0;
|
|
17203
|
+
return {
|
|
17204
|
+
file,
|
|
17205
|
+
...Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {},
|
|
17206
|
+
...node?.name ? { symbol: node.name } : {},
|
|
17207
|
+
service: node?.service ?? ev.service,
|
|
17208
|
+
provenance: import_types59.Provenance.OBSERVED
|
|
17209
|
+
};
|
|
17210
|
+
}
|
|
17211
|
+
function divergenceSummary(d) {
|
|
17212
|
+
const column = "column" in d && d.column ? `.${d.column}` : "";
|
|
17213
|
+
const label = "table" in d && d.table ? `${d.table}${column}` : `${d.source} \u2192 ${d.target}`;
|
|
17214
|
+
return label;
|
|
17215
|
+
}
|
|
17216
|
+
function baseName(p) {
|
|
17217
|
+
const parts = p.split(/[\\/]/);
|
|
17218
|
+
return parts[parts.length - 1] || p;
|
|
17219
|
+
}
|
|
17220
|
+
function shortLabel(graph, nodeId) {
|
|
17221
|
+
if (graph.hasNode(nodeId)) {
|
|
17222
|
+
const name = graph.getNodeAttributes(nodeId).name;
|
|
17223
|
+
if (typeof name === "string" && name.length > 0) return name;
|
|
17224
|
+
}
|
|
17225
|
+
const afterHash = nodeId.includes("#") ? nodeId.slice(nodeId.lastIndexOf("#") + 1) : nodeId;
|
|
17226
|
+
return afterHash.includes(":") ? afterHash.slice(afterHash.lastIndexOf(":") + 1) : afterHash;
|
|
17227
|
+
}
|
|
17228
|
+
function renderHeadline(graph, ev, locus, causeNode) {
|
|
17229
|
+
const what = ev.exceptionType ? `raised ${ev.exceptionType}` : ev.errorMessage || "failed";
|
|
17230
|
+
const cause = causeNode && causeNode !== ev.affectedNode ? ` \u2192 root cause ${shortLabel(graph, causeNode)}` : "";
|
|
17231
|
+
if (locus) {
|
|
17232
|
+
const base = baseName(locus.file);
|
|
17233
|
+
const lines = locus.lineStart != null ? locus.lineEnd && locus.lineEnd !== locus.lineStart ? `LINES ${locus.lineStart}-${locus.lineEnd}` : `LINE ${locus.lineStart}` : "";
|
|
17234
|
+
const symbol = locus.symbol ?? (grainOf2(graph, ev.affectedNode) === "symbol" ? shortLabel(graph, ev.affectedNode) : void 0);
|
|
17235
|
+
const subject = symbol ? `SYMBOL ${symbol}` : `FILE ${base}`;
|
|
17236
|
+
const at = symbol ? `${lines ? `${lines} in ` : ""}${base}` : lines;
|
|
17237
|
+
const where = at ? ` at ${at}` : "";
|
|
17238
|
+
return `${subject}${where} (SERVICE ${ev.service}) ${what} at ${ev.timestamp}${cause}`;
|
|
17239
|
+
}
|
|
17240
|
+
return `SERVICE ${ev.service} ${what} at ${ev.timestamp}${cause}`;
|
|
17241
|
+
}
|
|
17242
|
+
function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
17243
|
+
const affected = errorEvent.affectedNode;
|
|
17244
|
+
const locus = locusOf(graph, errorEvent);
|
|
17245
|
+
const inGraph = graph.hasNode(affected);
|
|
17246
|
+
const rc = inGraph ? getRootCause(graph, affected, errorEvent, incidents) : null;
|
|
17247
|
+
let rootCause = null;
|
|
17248
|
+
if (rc) {
|
|
17249
|
+
const provs = rc.edgeProvenances ?? [];
|
|
17250
|
+
const chain = (rc.traversalPath ?? []).map((node, i) => ({
|
|
17251
|
+
node,
|
|
17252
|
+
grain: grainOf2(graph, node),
|
|
17253
|
+
provenance: provs[i] ?? provs[provs.length - 1] ?? import_types59.Provenance.INFERRED
|
|
17254
|
+
}));
|
|
17255
|
+
rootCause = {
|
|
17256
|
+
node: rc.rootCauseNode,
|
|
17257
|
+
...rc.candidates?.[0]?.classification ? { classification: rc.candidates[0].classification } : {},
|
|
17258
|
+
reason: rc.rootCauseReason,
|
|
17259
|
+
confidence: rc.confidence,
|
|
17260
|
+
fix: rc.fixRecommendation ?? null,
|
|
17261
|
+
chain
|
|
17262
|
+
};
|
|
17263
|
+
}
|
|
17264
|
+
const blast = inGraph ? getBlastRadius(graph, affected) : { origin: affected, affectedNodes: [], totalAffected: 0 };
|
|
17265
|
+
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 }));
|
|
17266
|
+
const applicable = inGraph ? selectApplicablePolicies(graph, policies, affected) : [];
|
|
17267
|
+
const policyCards = applicable.map((p) => ({
|
|
17268
|
+
policyName: p.policyName,
|
|
17269
|
+
severity: p.severity,
|
|
17270
|
+
message: p.reason
|
|
17271
|
+
}));
|
|
17272
|
+
const divergences = inGraph ? computeDivergences(graph, { node: affected, incidents }).divergences.map((d) => ({
|
|
17273
|
+
type: d.type,
|
|
17274
|
+
summary: divergenceSummary(d)
|
|
17275
|
+
})) : [];
|
|
17276
|
+
const card = {
|
|
17277
|
+
kind: "incident",
|
|
17278
|
+
id: errorEvent.id,
|
|
17279
|
+
at: errorEvent.timestamp,
|
|
17280
|
+
incidentKind: (0, import_types59.incidentKindOf)(errorEvent),
|
|
17281
|
+
service: errorEvent.service,
|
|
17282
|
+
affectedNode: affected,
|
|
17283
|
+
message: errorEvent.errorMessage,
|
|
17284
|
+
...errorEvent.exceptionType ? { exceptionType: errorEvent.exceptionType } : {},
|
|
17285
|
+
...errorEvent.httpStatusCode !== void 0 ? { httpStatusCode: errorEvent.httpStatusCode } : {},
|
|
17286
|
+
...errorEvent.incidentCount !== void 0 ? { count: errorEvent.incidentCount } : {},
|
|
17287
|
+
...errorEvent.firstTimestamp && errorEvent.lastTimestamp ? { window: { first: errorEvent.firstTimestamp, last: errorEvent.lastTimestamp } } : {},
|
|
17288
|
+
...errorEvent.traceId ? { traceId: errorEvent.traceId } : {},
|
|
17289
|
+
...errorEvent.spanId ? { spanId: errorEvent.spanId } : {},
|
|
17290
|
+
locus,
|
|
17291
|
+
rootCause,
|
|
17292
|
+
...nearest.length > 0 ? { blastRadius: { totalAffected: blast.totalAffected, nearest } } : {},
|
|
17293
|
+
...policyCards.length > 0 ? { policies: policyCards } : {},
|
|
17294
|
+
...divergences.length > 0 ? { divergence: divergences } : {},
|
|
17295
|
+
headline: renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)
|
|
17296
|
+
};
|
|
17297
|
+
return import_types59.IncidentCardSchema.parse(card);
|
|
17298
|
+
}
|
|
17299
|
+
|
|
17300
|
+
// src/ask.ts
|
|
17301
|
+
init_cjs_shims();
|
|
17302
|
+
var import_types60 = require("@neat.is/types");
|
|
17168
17303
|
var DEFAULT_MAX_NODES = 3;
|
|
17169
17304
|
var MAX_FACTS_PER_SECTION = 6;
|
|
17170
17305
|
var INTENT_RULES = [
|
|
@@ -17392,7 +17527,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17392
17527
|
};
|
|
17393
17528
|
graph.forEachNode((id, attrs) => {
|
|
17394
17529
|
const node = attrs;
|
|
17395
|
-
if (node.type ===
|
|
17530
|
+
if (node.type === import_types60.NodeType.FrontierNode) return;
|
|
17396
17531
|
const name = nodeName(node);
|
|
17397
17532
|
const body = idBody(id);
|
|
17398
17533
|
const labelTokens = /* @__PURE__ */ new Set([...tokens(body), ...tokens(name)]);
|
|
@@ -17411,7 +17546,7 @@ async function resolveEntities(graph, question, searchIndex, maxNodes) {
|
|
|
17411
17546
|
const res = await searchIndex.search(question, 10);
|
|
17412
17547
|
if (res.provider !== "substring") {
|
|
17413
17548
|
for (const m of res.matches) {
|
|
17414
|
-
if (m.node.type ===
|
|
17549
|
+
if (m.node.type === import_types60.NodeType.FrontierNode) continue;
|
|
17415
17550
|
const already = best.get(m.node.id);
|
|
17416
17551
|
if (!already && m.score < EMBED_MIN_SCORE) continue;
|
|
17417
17552
|
consider({
|
|
@@ -17449,7 +17584,7 @@ function edgeSignalNote(e) {
|
|
|
17449
17584
|
function buildRootCauseSection(graph, node, incidents, now) {
|
|
17450
17585
|
const result = getRootCause(graph, node, void 0, incidents, { now });
|
|
17451
17586
|
if (!result) return null;
|
|
17452
|
-
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ??
|
|
17587
|
+
const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? import_types60.Provenance.OBSERVED;
|
|
17453
17588
|
const facts = [
|
|
17454
17589
|
{
|
|
17455
17590
|
text: `Root cause: ${result.rootCauseNode} \u2014 ${result.rootCauseReason}`,
|
|
@@ -17499,7 +17634,7 @@ function buildObservedSection(graph, node) {
|
|
|
17499
17634
|
if (result.observed && result.inboundObservedCount > 0) {
|
|
17500
17635
|
facts.push({
|
|
17501
17636
|
text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? "" : "s"} \u2014 a pure receiver`,
|
|
17502
|
-
provenance:
|
|
17637
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17503
17638
|
});
|
|
17504
17639
|
} else {
|
|
17505
17640
|
return null;
|
|
@@ -17527,7 +17662,7 @@ function buildIncidentsSection(node, incidents) {
|
|
|
17527
17662
|
const facts = ordered.map((ev) => ({
|
|
17528
17663
|
text: `${ev.timestamp} \u2014 ${ev.service}: ${ev.errorMessage}`,
|
|
17529
17664
|
// ErrorEvents are observation records — OBSERVED by definition.
|
|
17530
|
-
provenance:
|
|
17665
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17531
17666
|
}));
|
|
17532
17667
|
return { heading: `Recent incidents (OBSERVED) \u2014 ${relevant.length} recorded`, facts };
|
|
17533
17668
|
}
|
|
@@ -17587,7 +17722,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17587
17722
|
}
|
|
17588
17723
|
const byKey = /* @__PURE__ */ new Map();
|
|
17589
17724
|
for (const ev of incidents) {
|
|
17590
|
-
const key = ev.affectedNode || (0,
|
|
17725
|
+
const key = ev.affectedNode || (0, import_types60.serviceId)(ev.service);
|
|
17591
17726
|
const cur = byKey.get(key);
|
|
17592
17727
|
if (!cur) {
|
|
17593
17728
|
byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
|
|
@@ -17602,7 +17737,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17602
17737
|
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);
|
|
17603
17738
|
const facts = rows.map((r) => ({
|
|
17604
17739
|
text: `${r.key} \u2014 ${r.count} incident${r.count === 1 ? "" : "s"}, latest ${r.latest}: ${r.sampleMsg}`,
|
|
17605
|
-
provenance:
|
|
17740
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17606
17741
|
}));
|
|
17607
17742
|
return {
|
|
17608
17743
|
heading: `Incidents across the system \u2014 ${incidents.length} recorded`,
|
|
@@ -17615,7 +17750,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17615
17750
|
graph.forEachNode((_id, attrs) => {
|
|
17616
17751
|
const node = attrs;
|
|
17617
17752
|
nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1);
|
|
17618
|
-
if (node.type ===
|
|
17753
|
+
if (node.type === import_types60.NodeType.ServiceNode) services.push(node.id);
|
|
17619
17754
|
});
|
|
17620
17755
|
const edgeByProv = /* @__PURE__ */ new Map();
|
|
17621
17756
|
graph.forEachEdge((_id, attrs) => {
|
|
@@ -17627,10 +17762,10 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17627
17762
|
const shapeFacts = [
|
|
17628
17763
|
{ text: `${graph.order} nodes, ${graph.size} edges` },
|
|
17629
17764
|
{
|
|
17630
|
-
text: `${count(
|
|
17765
|
+
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`
|
|
17631
17766
|
}
|
|
17632
17767
|
];
|
|
17633
|
-
for (const p of [
|
|
17768
|
+
for (const p of [import_types60.Provenance.EXTRACTED, import_types60.Provenance.OBSERVED, import_types60.Provenance.INFERRED, import_types60.Provenance.STALE]) {
|
|
17634
17769
|
const n = edgeByProv.get(p) ?? 0;
|
|
17635
17770
|
if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? "" : "s"}`, provenance: p });
|
|
17636
17771
|
}
|
|
@@ -17647,7 +17782,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17647
17782
|
if (incidents && incidents.length > 0) {
|
|
17648
17783
|
const incCount = /* @__PURE__ */ new Map();
|
|
17649
17784
|
for (const ev of incidents) {
|
|
17650
|
-
const key = ev.affectedNode || (0,
|
|
17785
|
+
const key = ev.affectedNode || (0, import_types60.serviceId)(ev.service);
|
|
17651
17786
|
incCount.set(key, (incCount.get(key) ?? 0) + 1);
|
|
17652
17787
|
}
|
|
17653
17788
|
const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
|
|
@@ -17655,7 +17790,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17655
17790
|
heading: `Nodes with incidents \u2014 ${incidents.length} recorded`,
|
|
17656
17791
|
facts: top.map(([k, n]) => ({
|
|
17657
17792
|
text: `${k} \u2014 ${n} incident${n === 1 ? "" : "s"}`,
|
|
17658
|
-
provenance:
|
|
17793
|
+
provenance: import_types60.Provenance.OBSERVED
|
|
17659
17794
|
}))
|
|
17660
17795
|
});
|
|
17661
17796
|
}
|
|
@@ -17791,7 +17926,7 @@ async function askGraph(graph, question, opts = {}) {
|
|
|
17791
17926
|
const provSet = /* @__PURE__ */ new Set();
|
|
17792
17927
|
for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance);
|
|
17793
17928
|
const confidence = sections[0]?.facts[0]?.confidence;
|
|
17794
|
-
return
|
|
17929
|
+
return import_types60.AskResultSchema.parse({
|
|
17795
17930
|
question,
|
|
17796
17931
|
intent,
|
|
17797
17932
|
matched,
|
|
@@ -17938,7 +18073,7 @@ init_cjs_shims();
|
|
|
17938
18073
|
var import_node_fs37 = require("fs");
|
|
17939
18074
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
17940
18075
|
var import_node_path72 = __toESM(require("path"), 1);
|
|
17941
|
-
var
|
|
18076
|
+
var import_types61 = require("@neat.is/types");
|
|
17942
18077
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
17943
18078
|
var LOCK_RETRY_MS = 50;
|
|
17944
18079
|
function neatHome() {
|
|
@@ -18148,10 +18283,10 @@ async function readRegistry() {
|
|
|
18148
18283
|
throw err;
|
|
18149
18284
|
}
|
|
18150
18285
|
const parsed = JSON.parse(raw);
|
|
18151
|
-
return
|
|
18286
|
+
return import_types61.RegistryFileSchema.parse(parsed);
|
|
18152
18287
|
}
|
|
18153
18288
|
async function writeRegistry(reg) {
|
|
18154
|
-
const validated =
|
|
18289
|
+
const validated = import_types61.RegistryFileSchema.parse(reg);
|
|
18155
18290
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
18156
18291
|
}
|
|
18157
18292
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -18552,15 +18687,15 @@ function getConnectorStatus(id, now = Date.now(), thresholdMs = CONNECTOR_STALE_
|
|
|
18552
18687
|
|
|
18553
18688
|
// src/connectors/index.ts
|
|
18554
18689
|
init_cjs_shims();
|
|
18555
|
-
var
|
|
18690
|
+
var import_types62 = require("@neat.is/types");
|
|
18556
18691
|
var NO_ENV = "unknown";
|
|
18557
18692
|
function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
18558
18693
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18559
18694
|
const sites = [];
|
|
18560
18695
|
for (const edgeId of graph.inboundEdges(targetNodeId)) {
|
|
18561
18696
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
18562
|
-
if (edge.provenance !==
|
|
18563
|
-
const parsed = (0,
|
|
18697
|
+
if (edge.provenance !== import_types62.Provenance.EXTRACTED) continue;
|
|
18698
|
+
const parsed = (0, import_types62.parseFileId)(edge.source);
|
|
18564
18699
|
if (!parsed || parsed.service !== serviceName || !edge.evidence) continue;
|
|
18565
18700
|
const site = { relPath: edge.evidence.file };
|
|
18566
18701
|
if (edge.evidence.line !== void 0) site.line = edge.evidence.line;
|
|
@@ -18571,7 +18706,7 @@ function staticCallSiteFor(graph, serviceName, targetNodeId) {
|
|
|
18571
18706
|
function routeCallSiteFor(graph, targetNodeId) {
|
|
18572
18707
|
if (!graph.hasNode(targetNodeId)) return void 0;
|
|
18573
18708
|
const attrs = graph.getNodeAttributes(targetNodeId);
|
|
18574
|
-
if (attrs.type !==
|
|
18709
|
+
if (attrs.type !== import_types62.NodeType.RouteNode || !attrs.path) return void 0;
|
|
18575
18710
|
const site = { relPath: attrs.path };
|
|
18576
18711
|
if (attrs.line !== void 0) site.line = attrs.line;
|
|
18577
18712
|
return site;
|
|
@@ -18601,7 +18736,7 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
|
|
|
18601
18736
|
errorMessage: signal.incident.errorMessage,
|
|
18602
18737
|
...signal.incident.attributes ? { attributes: signal.incident.attributes } : {},
|
|
18603
18738
|
affectedNode: resolved.targetNodeId
|
|
18604
|
-
});
|
|
18739
|
+
}, ctx.project);
|
|
18605
18740
|
continue;
|
|
18606
18741
|
}
|
|
18607
18742
|
if (resolved.ensureInfraNode) {
|
|
@@ -19183,23 +19318,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
19183
19318
|
|
|
19184
19319
|
// src/connectors/supabase/resolve.ts
|
|
19185
19320
|
init_cjs_shims();
|
|
19186
|
-
var
|
|
19321
|
+
var import_types64 = require("@neat.is/types");
|
|
19187
19322
|
function createSupabaseResolveTarget(graph, config) {
|
|
19188
19323
|
return (signal, _ctx) => {
|
|
19189
19324
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
19190
19325
|
return null;
|
|
19191
19326
|
}
|
|
19192
|
-
const subResourceId = (0,
|
|
19327
|
+
const subResourceId = (0, import_types64.infraId)(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
19193
19328
|
if (graph.hasNode(subResourceId)) {
|
|
19194
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
19329
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: import_types64.EdgeType.CALLS };
|
|
19195
19330
|
}
|
|
19196
|
-
const bareResourceId = (0,
|
|
19331
|
+
const bareResourceId = (0, import_types64.infraId)(signal.targetKind, signal.targetName);
|
|
19197
19332
|
if (graph.hasNode(bareResourceId)) {
|
|
19198
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
19333
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: import_types64.EdgeType.CALLS };
|
|
19199
19334
|
}
|
|
19200
|
-
const projectLevelId = (0,
|
|
19335
|
+
const projectLevelId = (0, import_types64.infraId)("supabase", config.nodeRef);
|
|
19201
19336
|
if (graph.hasNode(projectLevelId)) {
|
|
19202
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
19337
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: import_types64.EdgeType.CALLS };
|
|
19203
19338
|
}
|
|
19204
19339
|
return null;
|
|
19205
19340
|
};
|
|
@@ -19292,7 +19427,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
19292
19427
|
|
|
19293
19428
|
// src/connectors/railway/index.ts
|
|
19294
19429
|
init_cjs_shims();
|
|
19295
|
-
var
|
|
19430
|
+
var import_types68 = require("@neat.is/types");
|
|
19296
19431
|
|
|
19297
19432
|
// src/connectors/railway/client.ts
|
|
19298
19433
|
init_cjs_shims();
|
|
@@ -19443,7 +19578,7 @@ function buildRailwayRouteIndex(graph, serviceName) {
|
|
|
19443
19578
|
const out = [];
|
|
19444
19579
|
graph.forEachNode((_id, attrs) => {
|
|
19445
19580
|
const node = attrs;
|
|
19446
|
-
if (node.type !==
|
|
19581
|
+
if (node.type !== import_types68.NodeType.RouteNode) return;
|
|
19447
19582
|
const route = attrs;
|
|
19448
19583
|
if (route.service !== serviceName) return;
|
|
19449
19584
|
out.push({
|
|
@@ -19547,12 +19682,12 @@ function createRailwayResolveTarget(config) {
|
|
|
19547
19682
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
19548
19683
|
if (!serviceName) return null;
|
|
19549
19684
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
19550
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
19685
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: import_types68.EdgeType.CALLS };
|
|
19551
19686
|
}
|
|
19552
19687
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
19553
19688
|
const peerName = config.serviceNameById[signal.targetName];
|
|
19554
19689
|
if (!peerName) return null;
|
|
19555
|
-
return { targetNodeId: (0,
|
|
19690
|
+
return { targetNodeId: (0, import_types68.serviceId)(peerName), serviceName, edgeType: import_types68.EdgeType.CONNECTS_TO };
|
|
19556
19691
|
}
|
|
19557
19692
|
return null;
|
|
19558
19693
|
};
|
|
@@ -19740,7 +19875,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
19740
19875
|
|
|
19741
19876
|
// src/connectors/firebase/resolve.ts
|
|
19742
19877
|
init_cjs_shims();
|
|
19743
|
-
var
|
|
19878
|
+
var import_types69 = require("@neat.is/types");
|
|
19744
19879
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
19745
19880
|
switch (resourceType) {
|
|
19746
19881
|
case "cloud_function":
|
|
@@ -19755,7 +19890,7 @@ function routeEntriesFor(graph, serviceName) {
|
|
|
19755
19890
|
const entries = [];
|
|
19756
19891
|
graph.forEachNode((_id, attrs) => {
|
|
19757
19892
|
const node = attrs;
|
|
19758
|
-
if (node.type !==
|
|
19893
|
+
if (node.type !== import_types69.NodeType.RouteNode) return;
|
|
19759
19894
|
const route = attrs;
|
|
19760
19895
|
if (route.service !== serviceName) return;
|
|
19761
19896
|
entries.push({
|
|
@@ -19787,7 +19922,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
19787
19922
|
return {
|
|
19788
19923
|
targetNodeId: match.routeNodeId,
|
|
19789
19924
|
serviceName,
|
|
19790
|
-
edgeType:
|
|
19925
|
+
edgeType: import_types69.EdgeType.CALLS
|
|
19791
19926
|
};
|
|
19792
19927
|
};
|
|
19793
19928
|
}
|
|
@@ -19814,7 +19949,7 @@ init_cjs_shims();
|
|
|
19814
19949
|
|
|
19815
19950
|
// src/connectors/cloudflare/connector.ts
|
|
19816
19951
|
init_cjs_shims();
|
|
19817
|
-
var
|
|
19952
|
+
var import_types71 = require("@neat.is/types");
|
|
19818
19953
|
|
|
19819
19954
|
// src/connectors/cloudflare/client.ts
|
|
19820
19955
|
init_cjs_shims();
|
|
@@ -19978,7 +20113,7 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
19978
20113
|
graph.forEachNode((id, attrs) => {
|
|
19979
20114
|
if (found) return;
|
|
19980
20115
|
const a = attrs;
|
|
19981
|
-
if (a.type ===
|
|
20116
|
+
if (a.type === import_types71.NodeType.FileNode && a.platform === "cloudflare" && a.platformName === workerName) {
|
|
19982
20117
|
found = id;
|
|
19983
20118
|
}
|
|
19984
20119
|
});
|
|
@@ -19990,7 +20125,7 @@ function findMatchingRouteNode(graph, serviceName, method, path76) {
|
|
|
19990
20125
|
graph.forEachNode((id, attrs) => {
|
|
19991
20126
|
if (found) return;
|
|
19992
20127
|
const a = attrs;
|
|
19993
|
-
if (a.type !==
|
|
20128
|
+
if (a.type !== import_types71.NodeType.RouteNode || a.service !== serviceName) return;
|
|
19994
20129
|
if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return;
|
|
19995
20130
|
const routeMethod = (a.method ?? "").toUpperCase();
|
|
19996
20131
|
if (routeMethod !== "ALL" && routeMethod !== method) return;
|
|
@@ -20009,11 +20144,11 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20009
20144
|
};
|
|
20010
20145
|
const mapping = config.workers?.[scriptName];
|
|
20011
20146
|
if (mapping) {
|
|
20012
|
-
const wholeFileId = (0,
|
|
20147
|
+
const wholeFileId = (0, import_types71.fileId)(mapping.service, mapping.entryFile);
|
|
20013
20148
|
return {
|
|
20014
20149
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
20015
20150
|
serviceName: mapping.service,
|
|
20016
|
-
edgeType:
|
|
20151
|
+
edgeType: import_types71.EdgeType.CALLS
|
|
20017
20152
|
};
|
|
20018
20153
|
}
|
|
20019
20154
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -20022,13 +20157,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
20022
20157
|
return {
|
|
20023
20158
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
20024
20159
|
serviceName: fileNode.service,
|
|
20025
|
-
edgeType:
|
|
20160
|
+
edgeType: import_types71.EdgeType.CALLS
|
|
20026
20161
|
};
|
|
20027
20162
|
}
|
|
20028
20163
|
return {
|
|
20029
|
-
targetNodeId: (0,
|
|
20164
|
+
targetNodeId: (0, import_types71.infraId)("cloudflare-worker", scriptName),
|
|
20030
20165
|
serviceName: scriptName,
|
|
20031
|
-
edgeType:
|
|
20166
|
+
edgeType: import_types71.EdgeType.CALLS,
|
|
20032
20167
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
20033
20168
|
};
|
|
20034
20169
|
};
|
|
@@ -20224,14 +20359,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
20224
20359
|
|
|
20225
20360
|
// src/connectors/neon/resolve.ts
|
|
20226
20361
|
init_cjs_shims();
|
|
20227
|
-
var
|
|
20362
|
+
var import_types75 = require("@neat.is/types");
|
|
20228
20363
|
function createNeonResolveTarget(config) {
|
|
20229
20364
|
return (signal) => {
|
|
20230
20365
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20231
20366
|
return {
|
|
20232
|
-
targetNodeId: (0,
|
|
20367
|
+
targetNodeId: (0, import_types75.infraId)("sql-table", signal.targetName),
|
|
20233
20368
|
serviceName: config.serviceName,
|
|
20234
|
-
edgeType:
|
|
20369
|
+
edgeType: import_types75.EdgeType.CALLS,
|
|
20235
20370
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
20236
20371
|
};
|
|
20237
20372
|
};
|
|
@@ -20412,14 +20547,14 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
20412
20547
|
|
|
20413
20548
|
// src/connectors/cloud-run/resolve.ts
|
|
20414
20549
|
init_cjs_shims();
|
|
20415
|
-
var
|
|
20550
|
+
var import_types79 = require("@neat.is/types");
|
|
20416
20551
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
20417
20552
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
20418
20553
|
let found = null;
|
|
20419
20554
|
graph.forEachNode((_id, attrs) => {
|
|
20420
20555
|
if (found) return;
|
|
20421
20556
|
const node = attrs;
|
|
20422
|
-
if (node.type !==
|
|
20557
|
+
if (node.type !== import_types79.NodeType.RouteNode) return;
|
|
20423
20558
|
const route = attrs;
|
|
20424
20559
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20425
20560
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20444,13 +20579,13 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
20444
20579
|
normalizePathTemplate(path76)
|
|
20445
20580
|
);
|
|
20446
20581
|
if (routeNodeId) {
|
|
20447
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20582
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types79.EdgeType.CALLS };
|
|
20448
20583
|
}
|
|
20449
20584
|
}
|
|
20450
20585
|
return {
|
|
20451
|
-
targetNodeId: (0,
|
|
20586
|
+
targetNodeId: (0, import_types79.infraId)(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
20452
20587
|
serviceName: mappedService ?? gcpServiceName,
|
|
20453
|
-
edgeType:
|
|
20588
|
+
edgeType: import_types79.EdgeType.CALLS,
|
|
20454
20589
|
ensureInfraNode: {
|
|
20455
20590
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
20456
20591
|
name: gcpServiceName,
|
|
@@ -20632,14 +20767,14 @@ function mapLogEntriesToSignals3(entries) {
|
|
|
20632
20767
|
|
|
20633
20768
|
// src/connectors/gcp-lb/resolve.ts
|
|
20634
20769
|
init_cjs_shims();
|
|
20635
|
-
var
|
|
20770
|
+
var import_types83 = require("@neat.is/types");
|
|
20636
20771
|
var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
|
|
20637
20772
|
function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
|
|
20638
20773
|
let found = null;
|
|
20639
20774
|
graph.forEachNode((_id, attrs) => {
|
|
20640
20775
|
if (found) return;
|
|
20641
20776
|
const node = attrs;
|
|
20642
|
-
if (node.type !==
|
|
20777
|
+
if (node.type !== import_types83.NodeType.RouteNode) return;
|
|
20643
20778
|
const route = attrs;
|
|
20644
20779
|
if (route.service !== serviceName || !route.pathTemplate) return;
|
|
20645
20780
|
if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return;
|
|
@@ -20664,13 +20799,13 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
20664
20799
|
normalizePathTemplate(path76)
|
|
20665
20800
|
);
|
|
20666
20801
|
if (routeNodeId) {
|
|
20667
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20802
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: import_types83.EdgeType.CALLS };
|
|
20668
20803
|
}
|
|
20669
20804
|
}
|
|
20670
20805
|
return {
|
|
20671
|
-
targetNodeId: (0,
|
|
20806
|
+
targetNodeId: (0, import_types83.infraId)(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
|
|
20672
20807
|
serviceName: mappedService ?? backendServiceName,
|
|
20673
|
-
edgeType:
|
|
20808
|
+
edgeType: import_types83.EdgeType.CALLS,
|
|
20674
20809
|
ensureInfraNode: {
|
|
20675
20810
|
kind: GCP_LB_BACKEND_INFRA_KIND,
|
|
20676
20811
|
name: backendServiceName,
|
|
@@ -20711,7 +20846,7 @@ function createGcpLbConnector(graph, config = {}) {
|
|
|
20711
20846
|
|
|
20712
20847
|
// src/connectors/render/index.ts
|
|
20713
20848
|
init_cjs_shims();
|
|
20714
|
-
var
|
|
20849
|
+
var import_types86 = require("@neat.is/types");
|
|
20715
20850
|
|
|
20716
20851
|
// src/connectors/render/types.ts
|
|
20717
20852
|
init_cjs_shims();
|
|
@@ -20789,7 +20924,7 @@ function buildRenderRouteIndex(graph, serviceName) {
|
|
|
20789
20924
|
const out = [];
|
|
20790
20925
|
graph.forEachNode((_id, attrs) => {
|
|
20791
20926
|
const node = attrs;
|
|
20792
|
-
if (node.type !==
|
|
20927
|
+
if (node.type !== import_types86.NodeType.RouteNode) return;
|
|
20793
20928
|
const route = attrs;
|
|
20794
20929
|
if (route.service !== serviceName) return;
|
|
20795
20930
|
out.push({
|
|
@@ -20874,7 +21009,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
20874
21009
|
function createRenderResolveTarget(config) {
|
|
20875
21010
|
return (signal) => {
|
|
20876
21011
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
20877
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
21012
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: import_types86.EdgeType.CALLS };
|
|
20878
21013
|
}
|
|
20879
21014
|
return null;
|
|
20880
21015
|
};
|
|
@@ -21012,21 +21147,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
21012
21147
|
|
|
21013
21148
|
// src/connectors/planetscale/resolve.ts
|
|
21014
21149
|
init_cjs_shims();
|
|
21015
|
-
var
|
|
21150
|
+
var import_types90 = require("@neat.is/types");
|
|
21016
21151
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
21017
21152
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
21018
21153
|
const databaseName = `${config.organization}/${config.database}`;
|
|
21019
21154
|
return (signal, _ctx) => {
|
|
21020
21155
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
21021
|
-
const tableId = (0,
|
|
21156
|
+
const tableId = (0, import_types90.infraId)("sql-table", signal.targetName);
|
|
21022
21157
|
if (graph.hasNode(tableId)) {
|
|
21023
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
21158
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: import_types90.EdgeType.CALLS };
|
|
21024
21159
|
}
|
|
21025
|
-
const providerId = (0,
|
|
21160
|
+
const providerId = (0, import_types90.infraId)(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
21026
21161
|
return {
|
|
21027
21162
|
targetNodeId: providerId,
|
|
21028
21163
|
serviceName: config.serviceName,
|
|
21029
|
-
edgeType:
|
|
21164
|
+
edgeType: import_types90.EdgeType.CALLS,
|
|
21030
21165
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
21031
21166
|
};
|
|
21032
21167
|
};
|
|
@@ -21291,7 +21426,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
21291
21426
|
|
|
21292
21427
|
// src/connectors/eas/resolve.ts
|
|
21293
21428
|
init_cjs_shims();
|
|
21294
|
-
var
|
|
21429
|
+
var import_types95 = require("@neat.is/types");
|
|
21295
21430
|
var NO_ENV2 = "unknown";
|
|
21296
21431
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
21297
21432
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -21307,8 +21442,8 @@ function configBasenamesForPhase(phase) {
|
|
|
21307
21442
|
function configNodeService(graph, configNodeId) {
|
|
21308
21443
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
21309
21444
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
21310
|
-
if (edge.type !==
|
|
21311
|
-
const parsed = (0,
|
|
21445
|
+
if (edge.type !== import_types95.EdgeType.CONFIGURED_BY) continue;
|
|
21446
|
+
const parsed = (0, import_types95.parseFileId)(edge.source);
|
|
21312
21447
|
if (parsed) return parsed.service;
|
|
21313
21448
|
}
|
|
21314
21449
|
return null;
|
|
@@ -21319,7 +21454,7 @@ function findConfigNode(graph, basenames, serviceName) {
|
|
|
21319
21454
|
graph.forEachNode((id, attrs) => {
|
|
21320
21455
|
if (scoped) return;
|
|
21321
21456
|
const node = attrs;
|
|
21322
|
-
if (node.type !==
|
|
21457
|
+
if (node.type !== import_types95.NodeType.ConfigNode) return;
|
|
21323
21458
|
if (typeof node.name !== "string" || !basenames.includes(node.name)) return;
|
|
21324
21459
|
if (anyMatch === null) anyMatch = id;
|
|
21325
21460
|
if (configNodeService(graph, id) === serviceName) scoped = id;
|
|
@@ -21336,13 +21471,13 @@ function createEasResolveTarget(graph) {
|
|
|
21336
21471
|
if (basenames.length > 0) {
|
|
21337
21472
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
21338
21473
|
if (configNodeId) {
|
|
21339
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
21474
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: import_types95.EdgeType.CALLS };
|
|
21340
21475
|
}
|
|
21341
21476
|
}
|
|
21342
21477
|
return {
|
|
21343
21478
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
21344
21479
|
serviceName,
|
|
21345
|
-
edgeType:
|
|
21480
|
+
edgeType: import_types95.EdgeType.CALLS
|
|
21346
21481
|
};
|
|
21347
21482
|
};
|
|
21348
21483
|
}
|
|
@@ -21929,6 +22064,7 @@ async function startConnectorPolling(input) {
|
|
|
21929
22064
|
registration.connector,
|
|
21930
22065
|
{
|
|
21931
22066
|
projectDir: input.projectDir,
|
|
22067
|
+
project: input.project,
|
|
21932
22068
|
credentials: registration.credentials,
|
|
21933
22069
|
...input.errorsPath ? { errorsPath: input.errorsPath } : {}
|
|
21934
22070
|
},
|
|
@@ -22103,11 +22239,11 @@ function registerRoutes(scope, ctx) {
|
|
|
22103
22239
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
22104
22240
|
const parsed = [];
|
|
22105
22241
|
for (const c of candidates) {
|
|
22106
|
-
const r =
|
|
22242
|
+
const r = import_types98.DivergenceTypeSchema.safeParse(c);
|
|
22107
22243
|
if (!r.success) {
|
|
22108
22244
|
return reply.code(400).send({
|
|
22109
22245
|
error: `unknown divergence type "${c}"`,
|
|
22110
|
-
allowed:
|
|
22246
|
+
allowed: import_types98.DivergenceTypeSchema.options
|
|
22111
22247
|
});
|
|
22112
22248
|
}
|
|
22113
22249
|
parsed.push(r.data);
|
|
@@ -22224,6 +22360,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22224
22360
|
reg.connector,
|
|
22225
22361
|
{
|
|
22226
22362
|
projectDir: proj.scanPath ?? "",
|
|
22363
|
+
project: proj.name,
|
|
22227
22364
|
credentials: reg.credentials,
|
|
22228
22365
|
...incidentsPath ? { errorsPath: incidentsPath } : {}
|
|
22229
22366
|
},
|
|
@@ -22287,6 +22424,39 @@ function registerRoutes(scope, ctx) {
|
|
|
22287
22424
|
if (!result) return reply.code(404).send({ error: "no root cause found", id: nodeId });
|
|
22288
22425
|
return result;
|
|
22289
22426
|
});
|
|
22427
|
+
scope.get("/graph/incident-card/:nodeId", async (req, reply) => {
|
|
22428
|
+
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22429
|
+
if (!proj) return;
|
|
22430
|
+
const { nodeId } = req.params;
|
|
22431
|
+
if (!proj.graph.hasNode(nodeId)) {
|
|
22432
|
+
return reply.code(404).send({ error: "node not found", id: nodeId });
|
|
22433
|
+
}
|
|
22434
|
+
const epath = errorsPathFor(proj);
|
|
22435
|
+
const incidents = epath ? await readErrorEvents(epath) : [];
|
|
22436
|
+
let errorEvent;
|
|
22437
|
+
if (req.query.errorId) {
|
|
22438
|
+
errorEvent = incidents.find((e) => e.id === req.query.errorId);
|
|
22439
|
+
if (!errorEvent) {
|
|
22440
|
+
return reply.code(404).send({ error: "error event not found", id: req.query.errorId });
|
|
22441
|
+
}
|
|
22442
|
+
} else {
|
|
22443
|
+
const svc = nodeId.replace(/^service:/, "");
|
|
22444
|
+
errorEvent = [...incidents].filter((e) => e.affectedNode === nodeId || e.service === svc).sort((a, b) => (b.timestamp ?? "").localeCompare(a.timestamp ?? ""))[0];
|
|
22445
|
+
if (!errorEvent) {
|
|
22446
|
+
return reply.code(404).send({ error: "no incident found for node", id: nodeId });
|
|
22447
|
+
}
|
|
22448
|
+
}
|
|
22449
|
+
const policyPath = ctx.policyFilePathFor(proj);
|
|
22450
|
+
let policies = [];
|
|
22451
|
+
if (policyPath) {
|
|
22452
|
+
try {
|
|
22453
|
+
policies = await loadPolicyFile(policyPath);
|
|
22454
|
+
} catch {
|
|
22455
|
+
policies = [];
|
|
22456
|
+
}
|
|
22457
|
+
}
|
|
22458
|
+
return buildIncidentCard(proj.graph, errorEvent, incidents, policies);
|
|
22459
|
+
});
|
|
22290
22460
|
scope.get("/graph/blast-radius/:nodeId", async (req, reply) => {
|
|
22291
22461
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22292
22462
|
if (!proj) return;
|
|
@@ -22469,7 +22639,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22469
22639
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
22470
22640
|
let violations = await log.readAll();
|
|
22471
22641
|
if (req.query.severity) {
|
|
22472
|
-
const sev =
|
|
22642
|
+
const sev = import_types98.PolicySeveritySchema.safeParse(req.query.severity);
|
|
22473
22643
|
if (!sev.success) {
|
|
22474
22644
|
return reply.code(400).send({
|
|
22475
22645
|
error: "invalid severity",
|
|
@@ -22508,7 +22678,7 @@ function registerRoutes(scope, ctx) {
|
|
|
22508
22678
|
scope.post("/policies/check", async (req, reply) => {
|
|
22509
22679
|
const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject);
|
|
22510
22680
|
if (!proj) return;
|
|
22511
|
-
const parsed =
|
|
22681
|
+
const parsed = import_types98.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
22512
22682
|
if (!parsed.success) {
|
|
22513
22683
|
return reply.code(400).send({
|
|
22514
22684
|
error: "invalid /policies/check body",
|
|
@@ -22857,7 +23027,7 @@ function unroutedErrorsPath(neatHome3) {
|
|
|
22857
23027
|
}
|
|
22858
23028
|
|
|
22859
23029
|
// src/daemon.ts
|
|
22860
|
-
var
|
|
23030
|
+
var import_types99 = require("@neat.is/types");
|
|
22861
23031
|
function daemonJsonPath(scanPath) {
|
|
22862
23032
|
return import_node_path75.default.join(scanPath, "neat-out", "daemon.json");
|
|
22863
23033
|
}
|
|
@@ -22982,7 +23152,7 @@ function spanBelongsToSingleProject(graph, project, serviceName) {
|
|
|
22982
23152
|
if (!serviceName) return true;
|
|
22983
23153
|
if (serviceNameMatchesProject(serviceName, project)) return true;
|
|
22984
23154
|
return graph.someNode(
|
|
22985
|
-
(_id, attrs) => attrs.type ===
|
|
23155
|
+
(_id, attrs) => attrs.type === import_types99.NodeType.ServiceNode && attrs.name === serviceName
|
|
22986
23156
|
);
|
|
22987
23157
|
}
|
|
22988
23158
|
async function bootstrapProject(entry, connectors = [], neatHome3) {
|
|
@@ -23437,7 +23607,12 @@ async function startDaemon(opts = {}) {
|
|
|
23437
23607
|
onErrorSpanSync: async (span) => {
|
|
23438
23608
|
const slot = await resolveTargetSlot(span.service, span.traceId);
|
|
23439
23609
|
if (!slot) return;
|
|
23440
|
-
await makeErrorSpanWriter(
|
|
23610
|
+
await makeErrorSpanWriter(
|
|
23611
|
+
slot.paths.errorsPath,
|
|
23612
|
+
slot.graph,
|
|
23613
|
+
slot.entry.path,
|
|
23614
|
+
slot.entry.name
|
|
23615
|
+
)(span);
|
|
23441
23616
|
},
|
|
23442
23617
|
// Project-scoped route (issue #367) — the URL already named the
|
|
23443
23618
|
// project. Resolution is a direct slot lookup; service.name resolves
|
|
@@ -23460,7 +23635,12 @@ async function startDaemon(opts = {}) {
|
|
|
23460
23635
|
onProjectErrorSpanSync: async (project, span) => {
|
|
23461
23636
|
const slot = await resolveSlotByName(project, span.service, span.traceId);
|
|
23462
23637
|
if (!slot) return;
|
|
23463
|
-
await makeErrorSpanWriter(
|
|
23638
|
+
await makeErrorSpanWriter(
|
|
23639
|
+
slot.paths.errorsPath,
|
|
23640
|
+
slot.graph,
|
|
23641
|
+
slot.entry.path,
|
|
23642
|
+
slot.entry.name
|
|
23643
|
+
)(span);
|
|
23464
23644
|
},
|
|
23465
23645
|
// #881 — 404 a project-scoped POST for a project this daemon doesn't
|
|
23466
23646
|
// host, rather than accepting it and dropping the batch. `slots` covers
|