@neat.is/core 0.3.4 → 0.3.5
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-33ZZ2ZID.js → chunk-BUB3ASD5.js} +94 -83
- package/dist/chunk-BUB3ASD5.js.map +1 -0
- package/dist/{chunk-T3A2GK3X.js → chunk-KCEZSFU2.js} +2 -2
- package/dist/cli.cjs +94 -80
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +84 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +84 -70
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +57 -45
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-33ZZ2ZID.js.map +0 -1
- /package/dist/{chunk-T3A2GK3X.js.map → chunk-KCEZSFU2.js.map} +0 -0
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
startPersistLoop,
|
|
16
16
|
touchLastSeen,
|
|
17
17
|
writeAtomically
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-BUB3ASD5.js";
|
|
19
19
|
import {
|
|
20
20
|
buildOtelReceiver
|
|
21
21
|
} from "./chunk-4ASCXBZF.js";
|
|
@@ -278,4 +278,4 @@ export {
|
|
|
278
278
|
routeSpanToProject,
|
|
279
279
|
startDaemon
|
|
280
280
|
};
|
|
281
|
-
//# sourceMappingURL=chunk-
|
|
281
|
+
//# sourceMappingURL=chunk-KCEZSFU2.js.map
|
package/dist/cli.cjs
CHANGED
|
@@ -805,11 +805,16 @@ init_cjs_shims();
|
|
|
805
805
|
var import_types = require("@neat.is/types");
|
|
806
806
|
var ROOT_CAUSE_MAX_DEPTH = 5;
|
|
807
807
|
var BLAST_RADIUS_DEFAULT_DEPTH = 10;
|
|
808
|
+
function isFrontierNode(graph, nodeId) {
|
|
809
|
+
if (!graph.hasNode(nodeId)) return false;
|
|
810
|
+
const attrs = graph.getNodeAttributes(nodeId);
|
|
811
|
+
return attrs.type === import_types.NodeType.FrontierNode;
|
|
812
|
+
}
|
|
808
813
|
function bestEdgeBySource(graph, edgeIds) {
|
|
809
814
|
const best = /* @__PURE__ */ new Map();
|
|
810
815
|
for (const id of edgeIds) {
|
|
811
816
|
const e = graph.getEdgeAttributes(id);
|
|
812
|
-
if (e.
|
|
817
|
+
if (isFrontierNode(graph, e.source)) continue;
|
|
813
818
|
const cur = best.get(e.source);
|
|
814
819
|
if (!cur || import_types.PROV_RANK[e.provenance] > import_types.PROV_RANK[cur.provenance]) {
|
|
815
820
|
best.set(e.source, e);
|
|
@@ -821,7 +826,7 @@ function bestEdgeByTarget(graph, edgeIds) {
|
|
|
821
826
|
const best = /* @__PURE__ */ new Map();
|
|
822
827
|
for (const id of edgeIds) {
|
|
823
828
|
const e = graph.getEdgeAttributes(id);
|
|
824
|
-
if (e.
|
|
829
|
+
if (isFrontierNode(graph, e.target)) continue;
|
|
825
830
|
const cur = best.get(e.target);
|
|
826
831
|
if (!cur || import_types.PROV_RANK[e.provenance] > import_types.PROV_RANK[cur.provenance]) {
|
|
827
832
|
best.set(e.target, e);
|
|
@@ -833,8 +838,7 @@ var PROVENANCE_CEILING = {
|
|
|
833
838
|
OBSERVED: 1,
|
|
834
839
|
INFERRED: 0.7,
|
|
835
840
|
EXTRACTED: 0.5,
|
|
836
|
-
STALE: 0.3
|
|
837
|
-
FRONTIER: 0.3
|
|
841
|
+
STALE: 0.3
|
|
838
842
|
};
|
|
839
843
|
function volumeWeight(spanCount) {
|
|
840
844
|
if (!spanCount || spanCount <= 0) return 0.5;
|
|
@@ -1118,8 +1122,8 @@ var evaluateStructural = ({
|
|
|
1118
1122
|
for (const edgeId of graph.outboundEdges(id)) {
|
|
1119
1123
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1120
1124
|
if (e.type !== rule.edgeType) continue;
|
|
1121
|
-
if (e.provenance === import_types2.Provenance.FRONTIER) continue;
|
|
1122
1125
|
const target = graph.getNodeAttributes(e.target);
|
|
1126
|
+
if (target.type === import_types2.NodeType.FrontierNode) continue;
|
|
1123
1127
|
if (target.type === rule.toNodeType) {
|
|
1124
1128
|
satisfied = true;
|
|
1125
1129
|
break;
|
|
@@ -1238,8 +1242,8 @@ var evaluateCompatibility = ({
|
|
|
1238
1242
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
1239
1243
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1240
1244
|
if (e.type !== import_types2.EdgeType.CONNECTS_TO) continue;
|
|
1241
|
-
if (e.provenance === import_types2.Provenance.FRONTIER) continue;
|
|
1242
1245
|
const dbAttrs = graph.getNodeAttributes(e.target);
|
|
1246
|
+
if (dbAttrs.type === import_types2.NodeType.FrontierNode) continue;
|
|
1243
1247
|
if (dbAttrs.type !== import_types2.NodeType.DatabaseNode) continue;
|
|
1244
1248
|
const db = dbAttrs;
|
|
1245
1249
|
for (const pair of compatPairs()) {
|
|
@@ -1556,31 +1560,6 @@ function ensureFrontierNode(graph, host, ts) {
|
|
|
1556
1560
|
graph.addNode(id, node);
|
|
1557
1561
|
return id;
|
|
1558
1562
|
}
|
|
1559
|
-
function upsertFrontierEdge(graph, type, source, target, ts) {
|
|
1560
|
-
const id = (0, import_types3.frontierEdgeId)(source, target, type);
|
|
1561
|
-
if (graph.hasEdge(id)) {
|
|
1562
|
-
const existing = graph.getEdgeAttributes(id);
|
|
1563
|
-
const updated = {
|
|
1564
|
-
...existing,
|
|
1565
|
-
provenance: import_types3.Provenance.FRONTIER,
|
|
1566
|
-
lastObserved: ts,
|
|
1567
|
-
callCount: (existing.callCount ?? 0) + 1
|
|
1568
|
-
};
|
|
1569
|
-
graph.replaceEdgeAttributes(id, updated);
|
|
1570
|
-
return;
|
|
1571
|
-
}
|
|
1572
|
-
const edge = {
|
|
1573
|
-
id,
|
|
1574
|
-
source,
|
|
1575
|
-
target,
|
|
1576
|
-
type,
|
|
1577
|
-
provenance: import_types3.Provenance.FRONTIER,
|
|
1578
|
-
confidence: 1,
|
|
1579
|
-
lastObserved: ts,
|
|
1580
|
-
callCount: 1
|
|
1581
|
-
};
|
|
1582
|
-
graph.addEdgeWithKey(id, source, target, edge);
|
|
1583
|
-
}
|
|
1584
1563
|
function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
|
|
1585
1564
|
if (!graph.hasNode(source) || !graph.hasNode(target)) return null;
|
|
1586
1565
|
const id = makeObservedEdgeId(type, source, target);
|
|
@@ -1666,18 +1645,28 @@ async function appendErrorEvent(ctx, ev) {
|
|
|
1666
1645
|
await import_node_fs3.promises.mkdir(import_node_path3.default.dirname(ctx.errorsPath), { recursive: true });
|
|
1667
1646
|
await import_node_fs3.promises.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
|
|
1668
1647
|
}
|
|
1648
|
+
function sanitizeAttributes(attrs) {
|
|
1649
|
+
const out = {};
|
|
1650
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
1651
|
+
if (typeof v === "bigint") out[k] = v.toString();
|
|
1652
|
+
else out[k] = v;
|
|
1653
|
+
}
|
|
1654
|
+
return out;
|
|
1655
|
+
}
|
|
1669
1656
|
function buildErrorEventForReceiver(span) {
|
|
1670
1657
|
if (span.statusCode !== 2) return null;
|
|
1671
1658
|
const ts = span.startTimeIso ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1659
|
+
const attrs = sanitizeAttributes(span.attributes);
|
|
1672
1660
|
return {
|
|
1673
1661
|
id: `${span.traceId}:${span.spanId}`,
|
|
1674
1662
|
timestamp: ts,
|
|
1675
1663
|
service: span.service,
|
|
1676
1664
|
traceId: span.traceId,
|
|
1677
1665
|
spanId: span.spanId,
|
|
1678
|
-
errorMessage: span.exception?.message ?? span.
|
|
1666
|
+
errorMessage: span.exception?.message ?? span.name ?? "unknown error",
|
|
1679
1667
|
...span.exception?.type ? { exceptionType: span.exception.type } : {},
|
|
1680
1668
|
...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
|
|
1669
|
+
...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
|
|
1681
1670
|
affectedNode: (0, import_types3.serviceId)(span.service)
|
|
1682
1671
|
};
|
|
1683
1672
|
}
|
|
@@ -1728,11 +1717,16 @@ async function handleSpan(ctx, span) {
|
|
|
1728
1717
|
affectedNode = targetId;
|
|
1729
1718
|
resolvedViaAddress = true;
|
|
1730
1719
|
} else if (!targetId) {
|
|
1731
|
-
const
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1720
|
+
const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts);
|
|
1721
|
+
upsertObservedEdge(
|
|
1722
|
+
ctx.graph,
|
|
1723
|
+
import_types3.EdgeType.CALLS,
|
|
1724
|
+
sourceId,
|
|
1725
|
+
frontierNodeId,
|
|
1726
|
+
ts,
|
|
1727
|
+
isError
|
|
1728
|
+
);
|
|
1729
|
+
affectedNode = frontierNodeId;
|
|
1736
1730
|
resolvedViaAddress = true;
|
|
1737
1731
|
}
|
|
1738
1732
|
}
|
|
@@ -1754,15 +1748,17 @@ async function handleSpan(ctx, span) {
|
|
|
1754
1748
|
if (span.statusCode === 2) {
|
|
1755
1749
|
stitchTrace(ctx.graph, sourceId, ts);
|
|
1756
1750
|
if (ctx.writeErrorEventInline !== false) {
|
|
1751
|
+
const attrs = sanitizeAttributes(span.attributes);
|
|
1757
1752
|
const ev = {
|
|
1758
1753
|
id: `${span.traceId}:${span.spanId}`,
|
|
1759
1754
|
timestamp: ts,
|
|
1760
1755
|
service: span.service,
|
|
1761
1756
|
traceId: span.traceId,
|
|
1762
1757
|
spanId: span.spanId,
|
|
1763
|
-
errorMessage: span.exception?.message ?? span.
|
|
1758
|
+
errorMessage: span.exception?.message ?? span.name ?? "unknown error",
|
|
1764
1759
|
...span.exception?.type ? { exceptionType: span.exception.type } : {},
|
|
1765
1760
|
...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
|
|
1761
|
+
...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
|
|
1766
1762
|
affectedNode
|
|
1767
1763
|
};
|
|
1768
1764
|
await appendErrorEvent(ctx, ev);
|
|
@@ -1818,8 +1814,7 @@ function rewireFrontierEdges(graph, frontierId2, serviceId3) {
|
|
|
1818
1814
|
}
|
|
1819
1815
|
function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
1820
1816
|
graph.dropEdge(oldEdgeId);
|
|
1821
|
-
const
|
|
1822
|
-
const newId = promotedProvenance === import_types3.Provenance.OBSERVED ? (0, import_types3.observedEdgeId)(newSource, newTarget, edge.type) : promotedProvenance === import_types3.Provenance.INFERRED ? (0, import_types3.inferredEdgeId)(newSource, newTarget, edge.type) : promotedProvenance === import_types3.Provenance.EXTRACTED ? (0, import_types3.extractedEdgeId)(newSource, newTarget, edge.type) : (0, import_types3.frontierEdgeId)(newSource, newTarget, edge.type);
|
|
1817
|
+
const newId = edge.provenance === import_types3.Provenance.OBSERVED ? (0, import_types3.observedEdgeId)(newSource, newTarget, edge.type) : edge.provenance === import_types3.Provenance.INFERRED ? (0, import_types3.inferredEdgeId)(newSource, newTarget, edge.type) : (0, import_types3.extractedEdgeId)(newSource, newTarget, edge.type);
|
|
1823
1818
|
if (graph.hasEdge(newId)) {
|
|
1824
1819
|
const existing = graph.getEdgeAttributes(newId);
|
|
1825
1820
|
const merged = {
|
|
@@ -1834,8 +1829,7 @@ function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
|
1834
1829
|
...edge,
|
|
1835
1830
|
id: newId,
|
|
1836
1831
|
source: newSource,
|
|
1837
|
-
target: newTarget
|
|
1838
|
-
provenance: promotedProvenance
|
|
1832
|
+
target: newTarget
|
|
1839
1833
|
};
|
|
1840
1834
|
graph.addEdgeWithKey(newId, newSource, newTarget, rebuilt);
|
|
1841
1835
|
}
|
|
@@ -4156,7 +4150,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
4156
4150
|
init_cjs_shims();
|
|
4157
4151
|
var import_node_fs18 = require("fs");
|
|
4158
4152
|
var import_node_path31 = __toESM(require("path"), 1);
|
|
4159
|
-
var
|
|
4153
|
+
var import_types19 = require("@neat.is/types");
|
|
4154
|
+
var SCHEMA_VERSION = 3;
|
|
4160
4155
|
function migrateV1ToV2(payload) {
|
|
4161
4156
|
const nodes = payload.graph.nodes;
|
|
4162
4157
|
if (Array.isArray(nodes)) {
|
|
@@ -4168,6 +4163,25 @@ function migrateV1ToV2(payload) {
|
|
|
4168
4163
|
}
|
|
4169
4164
|
return { ...payload, schemaVersion: 2 };
|
|
4170
4165
|
}
|
|
4166
|
+
function migrateV2ToV3(payload) {
|
|
4167
|
+
const edges = payload.graph.edges;
|
|
4168
|
+
if (Array.isArray(edges)) {
|
|
4169
|
+
for (const edge of edges) {
|
|
4170
|
+
const attrs = edge.attributes;
|
|
4171
|
+
if (!attrs || attrs.provenance !== "FRONTIER") continue;
|
|
4172
|
+
attrs.provenance = import_types19.Provenance.OBSERVED;
|
|
4173
|
+
const type = typeof attrs.type === "string" ? attrs.type : void 0;
|
|
4174
|
+
const source = typeof attrs.source === "string" ? attrs.source : void 0;
|
|
4175
|
+
const target = typeof attrs.target === "string" ? attrs.target : void 0;
|
|
4176
|
+
if (type && source && target) {
|
|
4177
|
+
const newId = (0, import_types19.observedEdgeId)(source, target, type);
|
|
4178
|
+
attrs.id = newId;
|
|
4179
|
+
if (edge.key) edge.key = newId;
|
|
4180
|
+
}
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
return { ...payload, schemaVersion: 3 };
|
|
4184
|
+
}
|
|
4171
4185
|
async function ensureDir(filePath) {
|
|
4172
4186
|
await import_node_fs18.promises.mkdir(import_node_path31.default.dirname(filePath), { recursive: true });
|
|
4173
4187
|
}
|
|
@@ -4194,6 +4208,9 @@ async function loadGraphFromDisk(graph, outPath) {
|
|
|
4194
4208
|
if (payload.schemaVersion === 1) {
|
|
4195
4209
|
payload = migrateV1ToV2(payload);
|
|
4196
4210
|
}
|
|
4211
|
+
if (payload.schemaVersion === 2) {
|
|
4212
|
+
payload = migrateV2ToV3(payload);
|
|
4213
|
+
}
|
|
4197
4214
|
if (payload.schemaVersion !== SCHEMA_VERSION) {
|
|
4198
4215
|
throw new Error(
|
|
4199
4216
|
`persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`
|
|
@@ -4246,11 +4263,11 @@ var import_chokidar = __toESM(require("chokidar"), 1);
|
|
|
4246
4263
|
init_cjs_shims();
|
|
4247
4264
|
var import_fastify = __toESM(require("fastify"), 1);
|
|
4248
4265
|
var import_cors = __toESM(require("@fastify/cors"), 1);
|
|
4249
|
-
var
|
|
4266
|
+
var import_types22 = require("@neat.is/types");
|
|
4250
4267
|
|
|
4251
4268
|
// src/divergences.ts
|
|
4252
4269
|
init_cjs_shims();
|
|
4253
|
-
var
|
|
4270
|
+
var import_types20 = require("@neat.is/types");
|
|
4254
4271
|
function bucketKey(source, target, type) {
|
|
4255
4272
|
return `${type}|${source}|${target}`;
|
|
4256
4273
|
}
|
|
@@ -4258,25 +4275,22 @@ function bucketEdges(graph) {
|
|
|
4258
4275
|
const buckets = /* @__PURE__ */ new Map();
|
|
4259
4276
|
graph.forEachEdge((id, attrs) => {
|
|
4260
4277
|
const e = attrs;
|
|
4261
|
-
const parsed = (0,
|
|
4278
|
+
const parsed = (0, import_types20.parseEdgeId)(id);
|
|
4262
4279
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
4263
4280
|
const key = bucketKey(e.source, e.target, e.type);
|
|
4264
4281
|
const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
|
|
4265
4282
|
switch (provenance) {
|
|
4266
|
-
case
|
|
4283
|
+
case import_types20.Provenance.EXTRACTED:
|
|
4267
4284
|
cur.extracted = e;
|
|
4268
4285
|
break;
|
|
4269
|
-
case
|
|
4286
|
+
case import_types20.Provenance.OBSERVED:
|
|
4270
4287
|
cur.observed = e;
|
|
4271
4288
|
break;
|
|
4272
|
-
case
|
|
4289
|
+
case import_types20.Provenance.INFERRED:
|
|
4273
4290
|
cur.inferred = e;
|
|
4274
4291
|
break;
|
|
4275
|
-
case import_types19.Provenance.FRONTIER:
|
|
4276
|
-
cur.frontier = e;
|
|
4277
|
-
break;
|
|
4278
4292
|
default:
|
|
4279
|
-
if (e.provenance ===
|
|
4293
|
+
if (e.provenance === import_types20.Provenance.STALE) cur.stale = e;
|
|
4280
4294
|
}
|
|
4281
4295
|
buckets.set(key, cur);
|
|
4282
4296
|
});
|
|
@@ -4285,7 +4299,7 @@ function bucketEdges(graph) {
|
|
|
4285
4299
|
function nodeIsFrontier(graph, nodeId) {
|
|
4286
4300
|
if (!graph.hasNode(nodeId)) return false;
|
|
4287
4301
|
const attrs = graph.getNodeAttributes(nodeId);
|
|
4288
|
-
return attrs.type ===
|
|
4302
|
+
return attrs.type === import_types20.NodeType.FrontierNode;
|
|
4289
4303
|
}
|
|
4290
4304
|
function clampConfidence(n) {
|
|
4291
4305
|
if (!Number.isFinite(n)) return 0;
|
|
@@ -4346,7 +4360,7 @@ function declaredHostFor(svc) {
|
|
|
4346
4360
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
4347
4361
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
4348
4362
|
const e = graph.getEdgeAttributes(edgeId);
|
|
4349
|
-
if (e.type ===
|
|
4363
|
+
if (e.type === import_types20.EdgeType.CONFIGURED_BY && e.provenance === import_types20.Provenance.EXTRACTED) {
|
|
4350
4364
|
return true;
|
|
4351
4365
|
}
|
|
4352
4366
|
}
|
|
@@ -4359,10 +4373,10 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
4359
4373
|
const out = [];
|
|
4360
4374
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
4361
4375
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
4362
|
-
if (edge.type !==
|
|
4363
|
-
if (edge.provenance !==
|
|
4376
|
+
if (edge.type !== import_types20.EdgeType.CONNECTS_TO) continue;
|
|
4377
|
+
if (edge.provenance !== import_types20.Provenance.OBSERVED) continue;
|
|
4364
4378
|
const target = graph.getNodeAttributes(edge.target);
|
|
4365
|
-
if (target.type !==
|
|
4379
|
+
if (target.type !== import_types20.NodeType.DatabaseNode) continue;
|
|
4366
4380
|
const observedHost = target.host?.trim();
|
|
4367
4381
|
if (!observedHost) continue;
|
|
4368
4382
|
if (observedHost === declaredHost) continue;
|
|
@@ -4384,10 +4398,10 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
4384
4398
|
const deps = svc.dependencies ?? {};
|
|
4385
4399
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
4386
4400
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
4387
|
-
if (edge.type !==
|
|
4388
|
-
if (edge.provenance !==
|
|
4401
|
+
if (edge.type !== import_types20.EdgeType.CONNECTS_TO) continue;
|
|
4402
|
+
if (edge.provenance !== import_types20.Provenance.OBSERVED) continue;
|
|
4389
4403
|
const target = graph.getNodeAttributes(edge.target);
|
|
4390
|
-
if (target.type !==
|
|
4404
|
+
if (target.type !== import_types20.NodeType.DatabaseNode) continue;
|
|
4391
4405
|
for (const pair of compatPairs()) {
|
|
4392
4406
|
if (pair.engine !== target.engine) continue;
|
|
4393
4407
|
const declared = deps[pair.driver];
|
|
@@ -4448,7 +4462,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
4448
4462
|
}
|
|
4449
4463
|
graph.forEachNode((nodeId, attrs) => {
|
|
4450
4464
|
const n = attrs;
|
|
4451
|
-
if (n.type !==
|
|
4465
|
+
if (n.type !== import_types20.NodeType.ServiceNode) return;
|
|
4452
4466
|
const svc = n;
|
|
4453
4467
|
for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
|
|
4454
4468
|
for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
|
|
@@ -4481,7 +4495,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
4481
4495
|
if (a.source !== b.source) return a.source.localeCompare(b.source);
|
|
4482
4496
|
return a.target.localeCompare(b.target);
|
|
4483
4497
|
});
|
|
4484
|
-
return
|
|
4498
|
+
return import_types20.DivergenceResultSchema.parse({
|
|
4485
4499
|
divergences: filtered,
|
|
4486
4500
|
totalAffected: filtered.length,
|
|
4487
4501
|
computedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -4622,7 +4636,7 @@ init_cjs_shims();
|
|
|
4622
4636
|
var import_node_fs20 = require("fs");
|
|
4623
4637
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
4624
4638
|
var import_node_path33 = __toESM(require("path"), 1);
|
|
4625
|
-
var
|
|
4639
|
+
var import_types21 = require("@neat.is/types");
|
|
4626
4640
|
var LOCK_TIMEOUT_MS = 5e3;
|
|
4627
4641
|
var LOCK_RETRY_MS = 50;
|
|
4628
4642
|
function neatHome() {
|
|
@@ -4701,10 +4715,10 @@ async function readRegistry() {
|
|
|
4701
4715
|
throw err;
|
|
4702
4716
|
}
|
|
4703
4717
|
const parsed = JSON.parse(raw);
|
|
4704
|
-
return
|
|
4718
|
+
return import_types21.RegistryFileSchema.parse(parsed);
|
|
4705
4719
|
}
|
|
4706
4720
|
async function writeRegistry(reg) {
|
|
4707
|
-
const validated =
|
|
4721
|
+
const validated = import_types21.RegistryFileSchema.parse(reg);
|
|
4708
4722
|
await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + "\n");
|
|
4709
4723
|
}
|
|
4710
4724
|
var ProjectNameCollisionError = class extends Error {
|
|
@@ -4955,11 +4969,11 @@ function registerRoutes(scope, ctx) {
|
|
|
4955
4969
|
const candidates = req.query.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
4956
4970
|
const parsed = [];
|
|
4957
4971
|
for (const c of candidates) {
|
|
4958
|
-
const r =
|
|
4972
|
+
const r = import_types22.DivergenceTypeSchema.safeParse(c);
|
|
4959
4973
|
if (!r.success) {
|
|
4960
4974
|
return reply.code(400).send({
|
|
4961
4975
|
error: `unknown divergence type "${c}"`,
|
|
4962
|
-
allowed:
|
|
4976
|
+
allowed: import_types22.DivergenceTypeSchema.options
|
|
4963
4977
|
});
|
|
4964
4978
|
}
|
|
4965
4979
|
parsed.push(r.data);
|
|
@@ -5143,7 +5157,7 @@ function registerRoutes(scope, ctx) {
|
|
|
5143
5157
|
const log = new PolicyViolationsLog(proj.paths.policyViolationsPath);
|
|
5144
5158
|
let violations = await log.readAll();
|
|
5145
5159
|
if (req.query.severity) {
|
|
5146
|
-
const sev =
|
|
5160
|
+
const sev = import_types22.PolicySeveritySchema.safeParse(req.query.severity);
|
|
5147
5161
|
if (!sev.success) {
|
|
5148
5162
|
return reply.code(400).send({
|
|
5149
5163
|
error: "invalid severity",
|
|
@@ -5160,7 +5174,7 @@ function registerRoutes(scope, ctx) {
|
|
|
5160
5174
|
scope.post("/policies/check", async (req, reply) => {
|
|
5161
5175
|
const proj = resolveProject(registry, req, reply);
|
|
5162
5176
|
if (!proj) return;
|
|
5163
|
-
const parsed =
|
|
5177
|
+
const parsed = import_types22.PoliciesCheckBodySchema.safeParse(req.body ?? {});
|
|
5164
5178
|
if (!parsed.success) {
|
|
5165
5179
|
return reply.code(400).send({
|
|
5166
5180
|
error: "invalid /policies/check body",
|
|
@@ -6291,11 +6305,11 @@ function renderPatch(sections) {
|
|
|
6291
6305
|
}
|
|
6292
6306
|
|
|
6293
6307
|
// src/cli.ts
|
|
6294
|
-
var
|
|
6308
|
+
var import_types24 = require("@neat.is/types");
|
|
6295
6309
|
|
|
6296
6310
|
// src/cli-client.ts
|
|
6297
6311
|
init_cjs_shims();
|
|
6298
|
-
var
|
|
6312
|
+
var import_types23 = require("@neat.is/types");
|
|
6299
6313
|
var HttpError = class extends Error {
|
|
6300
6314
|
constructor(status2, message, responseBody = "") {
|
|
6301
6315
|
super(message);
|
|
@@ -6430,7 +6444,7 @@ async function runBlastRadius(client, input) {
|
|
|
6430
6444
|
}
|
|
6431
6445
|
}
|
|
6432
6446
|
function formatBlastEntry(n) {
|
|
6433
|
-
const tag = n.edgeProvenance ===
|
|
6447
|
+
const tag = n.edgeProvenance === import_types23.Provenance.STALE ? " [STALE \u2014 last seen too long ago]" : "";
|
|
6434
6448
|
return ` \u2022 ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`;
|
|
6435
6449
|
}
|
|
6436
6450
|
async function runDependencies(client, input) {
|
|
@@ -6476,9 +6490,9 @@ async function runObservedDependencies(client, input) {
|
|
|
6476
6490
|
const edges = await client.get(
|
|
6477
6491
|
projectPath(input.project, `/graph/edges/${encodeURIComponent(input.nodeId)}`)
|
|
6478
6492
|
);
|
|
6479
|
-
const observed = edges.outbound.filter((e) => e.provenance ===
|
|
6493
|
+
const observed = edges.outbound.filter((e) => e.provenance === import_types23.Provenance.OBSERVED);
|
|
6480
6494
|
if (observed.length === 0) {
|
|
6481
|
-
const hasExtracted = edges.outbound.some((e) => e.provenance ===
|
|
6495
|
+
const hasExtracted = edges.outbound.some((e) => e.provenance === import_types23.Provenance.EXTRACTED);
|
|
6482
6496
|
const note = hasExtracted ? " Static (EXTRACTED) dependencies exist but no runtime traffic has been seen \u2014 is OTel running?" : "";
|
|
6483
6497
|
return { summary: `No OBSERVED dependencies for ${input.nodeId}.${note}` };
|
|
6484
6498
|
}
|
|
@@ -6486,7 +6500,7 @@ async function runObservedDependencies(client, input) {
|
|
|
6486
6500
|
return {
|
|
6487
6501
|
summary: `${input.nodeId} has ${observed.length} runtime dependenc${observed.length === 1 ? "y" : "ies"} confirmed by OTel.`,
|
|
6488
6502
|
block: blockLines.join("\n"),
|
|
6489
|
-
provenance:
|
|
6503
|
+
provenance: import_types23.Provenance.OBSERVED
|
|
6490
6504
|
};
|
|
6491
6505
|
} catch (err) {
|
|
6492
6506
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -6540,7 +6554,7 @@ async function runIncidents(client, input) {
|
|
|
6540
6554
|
return {
|
|
6541
6555
|
summary: `${target} has ${body.total} recorded incident${body.total === 1 ? "" : "s"}; showing the ${ordered.length} most recent.`,
|
|
6542
6556
|
block: blockLines.join("\n"),
|
|
6543
|
-
provenance:
|
|
6557
|
+
provenance: import_types23.Provenance.OBSERVED
|
|
6544
6558
|
};
|
|
6545
6559
|
} catch (err) {
|
|
6546
6560
|
if (err instanceof HttpError && err.status === 404) {
|
|
@@ -6649,7 +6663,7 @@ async function runStaleEdges(client, input) {
|
|
|
6649
6663
|
return {
|
|
6650
6664
|
summary: `${events.length} stale-edge transition${events.length === 1 ? "" : "s"} recorded${input.edgeType ? ` for ${input.edgeType}` : ""}.`,
|
|
6651
6665
|
block: blockLines.join("\n"),
|
|
6652
|
-
provenance:
|
|
6666
|
+
provenance: import_types23.Provenance.STALE
|
|
6653
6667
|
};
|
|
6654
6668
|
}
|
|
6655
6669
|
async function runPolicies(client, input) {
|
|
@@ -7483,10 +7497,10 @@ async function runQueryVerb(cmd, parsed) {
|
|
|
7483
7497
|
const parts = parsed.type.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
7484
7498
|
const out = [];
|
|
7485
7499
|
for (const p of parts) {
|
|
7486
|
-
const r =
|
|
7500
|
+
const r = import_types24.DivergenceTypeSchema.safeParse(p);
|
|
7487
7501
|
if (!r.success) {
|
|
7488
7502
|
console.error(
|
|
7489
|
-
`neat divergences: unknown --type "${p}". allowed: ${
|
|
7503
|
+
`neat divergences: unknown --type "${p}". allowed: ${import_types24.DivergenceTypeSchema.options.join(", ")}`
|
|
7490
7504
|
);
|
|
7491
7505
|
return 2;
|
|
7492
7506
|
}
|