@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.
@@ -339,17 +339,21 @@ import {
339
339
  BlastRadiusResultSchema,
340
340
  NodeType,
341
341
  PROV_RANK,
342
- Provenance,
343
342
  RootCauseResultSchema,
344
343
  TransitiveDependenciesResultSchema
345
344
  } from "@neat.is/types";
346
345
  var ROOT_CAUSE_MAX_DEPTH = 5;
347
346
  var BLAST_RADIUS_DEFAULT_DEPTH = 10;
347
+ function isFrontierNode(graph, nodeId) {
348
+ if (!graph.hasNode(nodeId)) return false;
349
+ const attrs = graph.getNodeAttributes(nodeId);
350
+ return attrs.type === NodeType.FrontierNode;
351
+ }
348
352
  function bestEdgeBySource(graph, edgeIds) {
349
353
  const best = /* @__PURE__ */ new Map();
350
354
  for (const id of edgeIds) {
351
355
  const e = graph.getEdgeAttributes(id);
352
- if (e.provenance === Provenance.FRONTIER) continue;
356
+ if (isFrontierNode(graph, e.source)) continue;
353
357
  const cur = best.get(e.source);
354
358
  if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {
355
359
  best.set(e.source, e);
@@ -361,7 +365,7 @@ function bestEdgeByTarget(graph, edgeIds) {
361
365
  const best = /* @__PURE__ */ new Map();
362
366
  for (const id of edgeIds) {
363
367
  const e = graph.getEdgeAttributes(id);
364
- if (e.provenance === Provenance.FRONTIER) continue;
368
+ if (isFrontierNode(graph, e.target)) continue;
365
369
  const cur = best.get(e.target);
366
370
  if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {
367
371
  best.set(e.target, e);
@@ -373,8 +377,7 @@ var PROVENANCE_CEILING = {
373
377
  OBSERVED: 1,
374
378
  INFERRED: 0.7,
375
379
  EXTRACTED: 0.5,
376
- STALE: 0.3,
377
- FRONTIER: 0.3
380
+ STALE: 0.3
378
381
  };
379
382
  function volumeWeight(spanCount) {
380
383
  if (!spanCount || spanCount <= 0) return 0.5;
@@ -631,8 +634,7 @@ import path2 from "path";
631
634
  import {
632
635
  EdgeType,
633
636
  NodeType as NodeType2,
634
- PolicyFileSchema,
635
- Provenance as Provenance2
637
+ PolicyFileSchema
636
638
  } from "@neat.is/types";
637
639
 
638
640
  // src/events.ts
@@ -733,8 +735,8 @@ var evaluateStructural = ({
733
735
  for (const edgeId of graph.outboundEdges(id)) {
734
736
  const e = graph.getEdgeAttributes(edgeId);
735
737
  if (e.type !== rule.edgeType) continue;
736
- if (e.provenance === Provenance2.FRONTIER) continue;
737
738
  const target = graph.getNodeAttributes(e.target);
739
+ if (target.type === NodeType2.FrontierNode) continue;
738
740
  if (target.type === rule.toNodeType) {
739
741
  satisfied = true;
740
742
  break;
@@ -853,8 +855,8 @@ var evaluateCompatibility = ({
853
855
  for (const edgeId of graph.outboundEdges(svcId)) {
854
856
  const e = graph.getEdgeAttributes(edgeId);
855
857
  if (e.type !== EdgeType.CONNECTS_TO) continue;
856
- if (e.provenance === Provenance2.FRONTIER) continue;
857
858
  const dbAttrs = graph.getNodeAttributes(e.target);
859
+ if (dbAttrs.type === NodeType2.FrontierNode) continue;
858
860
  if (dbAttrs.type !== NodeType2.DatabaseNode) continue;
859
861
  const db = dbAttrs;
860
862
  for (const pair of compatPairs()) {
@@ -1017,11 +1019,10 @@ var PolicyViolationsLog = class {
1017
1019
  import {
1018
1020
  EdgeType as EdgeType2,
1019
1021
  NodeType as NodeType3,
1020
- Provenance as Provenance3,
1022
+ Provenance,
1021
1023
  confidenceForObservedSignal,
1022
1024
  databaseId,
1023
1025
  extractedEdgeId,
1024
- frontierEdgeId,
1025
1026
  frontierId,
1026
1027
  inferredEdgeId,
1027
1028
  observedEdgeId,
@@ -1183,31 +1184,6 @@ function ensureFrontierNode(graph, host, ts) {
1183
1184
  graph.addNode(id, node);
1184
1185
  return id;
1185
1186
  }
1186
- function upsertFrontierEdge(graph, type, source, target, ts) {
1187
- const id = frontierEdgeId(source, target, type);
1188
- if (graph.hasEdge(id)) {
1189
- const existing = graph.getEdgeAttributes(id);
1190
- const updated = {
1191
- ...existing,
1192
- provenance: Provenance3.FRONTIER,
1193
- lastObserved: ts,
1194
- callCount: (existing.callCount ?? 0) + 1
1195
- };
1196
- graph.replaceEdgeAttributes(id, updated);
1197
- return;
1198
- }
1199
- const edge = {
1200
- id,
1201
- source,
1202
- target,
1203
- type,
1204
- provenance: Provenance3.FRONTIER,
1205
- confidence: 1,
1206
- lastObserved: ts,
1207
- callCount: 1
1208
- };
1209
- graph.addEdgeWithKey(id, source, target, edge);
1210
- }
1211
1187
  function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
1212
1188
  if (!graph.hasNode(source) || !graph.hasNode(target)) return null;
1213
1189
  const id = makeObservedEdgeId(type, source, target);
@@ -1222,7 +1198,7 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
1222
1198
  };
1223
1199
  const updated = {
1224
1200
  ...existing,
1225
- provenance: Provenance3.OBSERVED,
1201
+ provenance: Provenance.OBSERVED,
1226
1202
  lastObserved: ts,
1227
1203
  callCount: newSpanCount,
1228
1204
  signal: newSignal,
@@ -1241,7 +1217,7 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false) {
1241
1217
  source,
1242
1218
  target,
1243
1219
  type,
1244
- provenance: Provenance3.OBSERVED,
1220
+ provenance: Provenance.OBSERVED,
1245
1221
  confidence: confidenceForObservedSignal(signal),
1246
1222
  lastObserved: ts,
1247
1223
  callCount: 1,
@@ -1260,7 +1236,7 @@ function stitchTrace(graph, sourceServiceId, ts) {
1260
1236
  const outbound = graph.outboundEdges(nodeId);
1261
1237
  for (const edgeId of outbound) {
1262
1238
  const edge = graph.getEdgeAttributes(edgeId);
1263
- if (edge.provenance !== Provenance3.EXTRACTED) continue;
1239
+ if (edge.provenance !== Provenance.EXTRACTED) continue;
1264
1240
  if (graph.hasEdge(observedEdgeId(edge.source, edge.target, edge.type))) continue;
1265
1241
  upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts);
1266
1242
  if (!visited.has(edge.target)) {
@@ -1283,7 +1259,7 @@ function upsertInferredEdge(graph, type, source, target, ts) {
1283
1259
  source,
1284
1260
  target,
1285
1261
  type,
1286
- provenance: Provenance3.INFERRED,
1262
+ provenance: Provenance.INFERRED,
1287
1263
  confidence: INFERRED_CONFIDENCE,
1288
1264
  lastObserved: ts
1289
1265
  };
@@ -1293,18 +1269,28 @@ async function appendErrorEvent(ctx, ev) {
1293
1269
  await fs3.mkdir(path3.dirname(ctx.errorsPath), { recursive: true });
1294
1270
  await fs3.appendFile(ctx.errorsPath, JSON.stringify(ev) + "\n", "utf8");
1295
1271
  }
1272
+ function sanitizeAttributes(attrs) {
1273
+ const out = {};
1274
+ for (const [k, v] of Object.entries(attrs)) {
1275
+ if (typeof v === "bigint") out[k] = v.toString();
1276
+ else out[k] = v;
1277
+ }
1278
+ return out;
1279
+ }
1296
1280
  function buildErrorEventForReceiver(span) {
1297
1281
  if (span.statusCode !== 2) return null;
1298
1282
  const ts = span.startTimeIso ?? (/* @__PURE__ */ new Date()).toISOString();
1283
+ const attrs = sanitizeAttributes(span.attributes);
1299
1284
  return {
1300
1285
  id: `${span.traceId}:${span.spanId}`,
1301
1286
  timestamp: ts,
1302
1287
  service: span.service,
1303
1288
  traceId: span.traceId,
1304
1289
  spanId: span.spanId,
1305
- errorMessage: span.exception?.message ?? span.errorMessage ?? span.name ?? "unknown error",
1290
+ errorMessage: span.exception?.message ?? span.name ?? "unknown error",
1306
1291
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
1307
1292
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
1293
+ ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
1308
1294
  affectedNode: serviceId(span.service)
1309
1295
  };
1310
1296
  }
@@ -1355,11 +1341,16 @@ async function handleSpan(ctx, span) {
1355
1341
  affectedNode = targetId;
1356
1342
  resolvedViaAddress = true;
1357
1343
  } else if (!targetId) {
1358
- const frontierId2 = ensureFrontierNode(ctx.graph, host, ts);
1359
- if (ctx.graph.hasNode(sourceId)) {
1360
- upsertFrontierEdge(ctx.graph, EdgeType2.CALLS, sourceId, frontierId2, ts);
1361
- }
1362
- affectedNode = frontierId2;
1344
+ const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts);
1345
+ upsertObservedEdge(
1346
+ ctx.graph,
1347
+ EdgeType2.CALLS,
1348
+ sourceId,
1349
+ frontierNodeId,
1350
+ ts,
1351
+ isError
1352
+ );
1353
+ affectedNode = frontierNodeId;
1363
1354
  resolvedViaAddress = true;
1364
1355
  }
1365
1356
  }
@@ -1381,15 +1372,17 @@ async function handleSpan(ctx, span) {
1381
1372
  if (span.statusCode === 2) {
1382
1373
  stitchTrace(ctx.graph, sourceId, ts);
1383
1374
  if (ctx.writeErrorEventInline !== false) {
1375
+ const attrs = sanitizeAttributes(span.attributes);
1384
1376
  const ev = {
1385
1377
  id: `${span.traceId}:${span.spanId}`,
1386
1378
  timestamp: ts,
1387
1379
  service: span.service,
1388
1380
  traceId: span.traceId,
1389
1381
  spanId: span.spanId,
1390
- errorMessage: span.exception?.message ?? span.errorMessage ?? span.name ?? "unknown error",
1382
+ errorMessage: span.exception?.message ?? span.name ?? "unknown error",
1391
1383
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
1392
1384
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
1385
+ ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
1393
1386
  affectedNode
1394
1387
  };
1395
1388
  await appendErrorEvent(ctx, ev);
@@ -1445,8 +1438,7 @@ function rewireFrontierEdges(graph, frontierId2, serviceId3) {
1445
1438
  }
1446
1439
  function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
1447
1440
  graph.dropEdge(oldEdgeId);
1448
- const promotedProvenance = edge.provenance === Provenance3.FRONTIER ? Provenance3.OBSERVED : edge.provenance;
1449
- const newId = promotedProvenance === Provenance3.OBSERVED ? observedEdgeId(newSource, newTarget, edge.type) : promotedProvenance === Provenance3.INFERRED ? inferredEdgeId(newSource, newTarget, edge.type) : promotedProvenance === Provenance3.EXTRACTED ? extractedEdgeId(newSource, newTarget, edge.type) : frontierEdgeId(newSource, newTarget, edge.type);
1441
+ const newId = edge.provenance === Provenance.OBSERVED ? observedEdgeId(newSource, newTarget, edge.type) : edge.provenance === Provenance.INFERRED ? inferredEdgeId(newSource, newTarget, edge.type) : extractedEdgeId(newSource, newTarget, edge.type);
1450
1442
  if (graph.hasEdge(newId)) {
1451
1443
  const existing = graph.getEdgeAttributes(newId);
1452
1444
  const merged = {
@@ -1461,8 +1453,7 @@ function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
1461
1453
  ...edge,
1462
1454
  id: newId,
1463
1455
  source: newSource,
1464
- target: newTarget,
1465
- provenance: promotedProvenance
1456
+ target: newTarget
1466
1457
  };
1467
1458
  graph.addEdgeWithKey(newId, newSource, newTarget, rebuilt);
1468
1459
  }
@@ -1481,12 +1472,12 @@ async function markStaleEdges(graph, options = {}) {
1481
1472
  const project = options.project ?? DEFAULT_PROJECT;
1482
1473
  graph.forEachEdge((id, attrs) => {
1483
1474
  const e = attrs;
1484
- if (e.provenance !== Provenance3.OBSERVED) return;
1475
+ if (e.provenance !== Provenance.OBSERVED) return;
1485
1476
  if (!e.lastObserved) return;
1486
1477
  const threshold = thresholdForEdgeType(e.type, thresholds);
1487
1478
  const age = now - new Date(e.lastObserved).getTime();
1488
1479
  if (age > threshold) {
1489
- const updated = { ...e, provenance: Provenance3.STALE, confidence: 0.3 };
1480
+ const updated = { ...e, provenance: Provenance.STALE, confidence: 0.3 };
1490
1481
  graph.replaceEdgeAttributes(id, updated);
1491
1482
  events.push({
1492
1483
  edgeId: id,
@@ -1503,8 +1494,8 @@ async function markStaleEdges(graph, options = {}) {
1503
1494
  project,
1504
1495
  payload: {
1505
1496
  edgeId: id,
1506
- from: Provenance3.OBSERVED,
1507
- to: Provenance3.STALE
1497
+ from: Provenance.OBSERVED,
1498
+ to: Provenance.STALE
1508
1499
  }
1509
1500
  });
1510
1501
  }
@@ -2250,7 +2241,7 @@ import path17 from "path";
2250
2241
  import {
2251
2242
  EdgeType as EdgeType3,
2252
2243
  NodeType as NodeType6,
2253
- Provenance as Provenance4,
2244
+ Provenance as Provenance2,
2254
2245
  databaseId as databaseId2,
2255
2246
  confidenceForExtracted
2256
2247
  } from "@neat.is/types";
@@ -2827,7 +2818,7 @@ async function addDatabasesAndCompat(graph, services, scanPath) {
2827
2818
  source: service.node.id,
2828
2819
  target: dbNode.id,
2829
2820
  type: EdgeType3.CONNECTS_TO,
2830
- provenance: Provenance4.EXTRACTED,
2821
+ provenance: Provenance2.EXTRACTED,
2831
2822
  confidence: confidenceForExtracted("structural"),
2832
2823
  // ADR-032 / #140 — every EXTRACTED edge carries evidence.file.
2833
2824
  // Ghost-edge cleanup keys retirement on this; the conditional
@@ -2864,7 +2855,7 @@ import path18 from "path";
2864
2855
  import {
2865
2856
  EdgeType as EdgeType4,
2866
2857
  NodeType as NodeType7,
2867
- Provenance as Provenance5,
2858
+ Provenance as Provenance3,
2868
2859
  configId,
2869
2860
  confidenceForExtracted as confidenceForExtracted2
2870
2861
  } from "@neat.is/types";
@@ -2907,7 +2898,7 @@ async function addConfigNodes(graph, services, scanPath) {
2907
2898
  source: service.node.id,
2908
2899
  target: node.id,
2909
2900
  type: EdgeType4.CONFIGURED_BY,
2910
- provenance: Provenance5.EXTRACTED,
2901
+ provenance: Provenance3.EXTRACTED,
2911
2902
  confidence: confidenceForExtracted2("structural"),
2912
2903
  evidence: { file: relPath.split(path18.sep).join("/") }
2913
2904
  };
@@ -2924,7 +2915,7 @@ async function addConfigNodes(graph, services, scanPath) {
2924
2915
  import {
2925
2916
  EdgeType as EdgeType6,
2926
2917
  NodeType as NodeType8,
2927
- Provenance as Provenance7,
2918
+ Provenance as Provenance5,
2928
2919
  confidenceForExtracted as confidenceForExtracted4,
2929
2920
  passesExtractedFloor as passesExtractedFloor2
2930
2921
  } from "@neat.is/types";
@@ -2936,7 +2927,7 @@ import JavaScript from "tree-sitter-javascript";
2936
2927
  import Python from "tree-sitter-python";
2937
2928
  import {
2938
2929
  EdgeType as EdgeType5,
2939
- Provenance as Provenance6,
2930
+ Provenance as Provenance4,
2940
2931
  confidenceForExtracted as confidenceForExtracted3,
2941
2932
  passesExtractedFloor
2942
2933
  } from "@neat.is/types";
@@ -3094,7 +3085,7 @@ async function addHttpCallEdges(graph, services) {
3094
3085
  source: service.node.id,
3095
3086
  target: targetId,
3096
3087
  type: EdgeType5.CALLS,
3097
- provenance: Provenance6.EXTRACTED,
3088
+ provenance: Provenance4.EXTRACTED,
3098
3089
  confidence,
3099
3090
  evidence: ev
3100
3091
  };
@@ -3377,7 +3368,7 @@ async function addExternalEndpointEdges(graph, services) {
3377
3368
  source: service.node.id,
3378
3369
  target: ep.infraId,
3379
3370
  type: edgeType,
3380
- provenance: Provenance7.EXTRACTED,
3371
+ provenance: Provenance5.EXTRACTED,
3381
3372
  confidence,
3382
3373
  evidence: ep.evidence
3383
3374
  };
@@ -3399,7 +3390,7 @@ async function addCallEdges(graph, services) {
3399
3390
 
3400
3391
  // src/extract/infra/docker-compose.ts
3401
3392
  import path25 from "path";
3402
- import { EdgeType as EdgeType7, Provenance as Provenance8, confidenceForExtracted as confidenceForExtracted5 } from "@neat.is/types";
3393
+ import { EdgeType as EdgeType7, Provenance as Provenance6, confidenceForExtracted as confidenceForExtracted5 } from "@neat.is/types";
3403
3394
 
3404
3395
  // src/extract/infra/shared.ts
3405
3396
  import { NodeType as NodeType9, infraId as infraId5 } from "@neat.is/types";
@@ -3492,7 +3483,7 @@ async function addComposeInfra(graph, scanPath, services) {
3492
3483
  source: sourceId,
3493
3484
  target: targetId,
3494
3485
  type: EdgeType7.DEPENDS_ON,
3495
- provenance: Provenance8.EXTRACTED,
3486
+ provenance: Provenance6.EXTRACTED,
3496
3487
  confidence: confidenceForExtracted5("structural"),
3497
3488
  evidence: { file: evidenceFile }
3498
3489
  };
@@ -3506,7 +3497,7 @@ async function addComposeInfra(graph, scanPath, services) {
3506
3497
  // src/extract/infra/dockerfile.ts
3507
3498
  import path26 from "path";
3508
3499
  import { promises as fs14 } from "fs";
3509
- import { EdgeType as EdgeType8, Provenance as Provenance9, confidenceForExtracted as confidenceForExtracted6 } from "@neat.is/types";
3500
+ import { EdgeType as EdgeType8, Provenance as Provenance7, confidenceForExtracted as confidenceForExtracted6 } from "@neat.is/types";
3510
3501
  function runtimeImage(content) {
3511
3502
  const lines = content.split("\n");
3512
3503
  let last = null;
@@ -3552,7 +3543,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
3552
3543
  source: service.node.id,
3553
3544
  target: node.id,
3554
3545
  type: EdgeType8.RUNS_ON,
3555
- provenance: Provenance9.EXTRACTED,
3546
+ provenance: Provenance7.EXTRACTED,
3556
3547
  confidence: confidenceForExtracted6("structural"),
3557
3548
  evidence: {
3558
3549
  file: path26.relative(scanPath, dockerfilePath).split(path26.sep).join("/")
@@ -3674,13 +3665,13 @@ import path30 from "path";
3674
3665
  // src/extract/retire.ts
3675
3666
  import { existsSync } from "fs";
3676
3667
  import path29 from "path";
3677
- import { Provenance as Provenance10 } from "@neat.is/types";
3668
+ import { Provenance as Provenance8 } from "@neat.is/types";
3678
3669
  function retireEdgesByFile(graph, file) {
3679
3670
  const normalized = file.split("\\").join("/");
3680
3671
  const toDrop = [];
3681
3672
  graph.forEachEdge((id, attrs) => {
3682
3673
  const edge = attrs;
3683
- if (edge.provenance !== Provenance10.EXTRACTED) return;
3674
+ if (edge.provenance !== Provenance8.EXTRACTED) return;
3684
3675
  if (!edge.evidence?.file) return;
3685
3676
  if (edge.evidence.file === normalized) toDrop.push(id);
3686
3677
  });
@@ -3692,7 +3683,7 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
3692
3683
  const bases = [scanPath, ...serviceDirs];
3693
3684
  graph.forEachEdge((id, attrs) => {
3694
3685
  const edge = attrs;
3695
- if (edge.provenance !== Provenance10.EXTRACTED) return;
3686
+ if (edge.provenance !== Provenance8.EXTRACTED) return;
3696
3687
  const evidenceFile = edge.evidence?.file;
3697
3688
  if (!evidenceFile) return;
3698
3689
  if (path29.isAbsolute(evidenceFile)) {
@@ -3771,7 +3762,8 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
3771
3762
  // src/persist.ts
3772
3763
  import { promises as fs17 } from "fs";
3773
3764
  import path31 from "path";
3774
- var SCHEMA_VERSION = 2;
3765
+ import { Provenance as Provenance9, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
3766
+ var SCHEMA_VERSION = 3;
3775
3767
  function migrateV1ToV2(payload) {
3776
3768
  const nodes = payload.graph.nodes;
3777
3769
  if (Array.isArray(nodes)) {
@@ -3783,6 +3775,25 @@ function migrateV1ToV2(payload) {
3783
3775
  }
3784
3776
  return { ...payload, schemaVersion: 2 };
3785
3777
  }
3778
+ function migrateV2ToV3(payload) {
3779
+ const edges = payload.graph.edges;
3780
+ if (Array.isArray(edges)) {
3781
+ for (const edge of edges) {
3782
+ const attrs = edge.attributes;
3783
+ if (!attrs || attrs.provenance !== "FRONTIER") continue;
3784
+ attrs.provenance = Provenance9.OBSERVED;
3785
+ const type = typeof attrs.type === "string" ? attrs.type : void 0;
3786
+ const source = typeof attrs.source === "string" ? attrs.source : void 0;
3787
+ const target = typeof attrs.target === "string" ? attrs.target : void 0;
3788
+ if (type && source && target) {
3789
+ const newId = observedEdgeId2(source, target, type);
3790
+ attrs.id = newId;
3791
+ if (edge.key) edge.key = newId;
3792
+ }
3793
+ }
3794
+ }
3795
+ return { ...payload, schemaVersion: 3 };
3796
+ }
3786
3797
  async function ensureDir(filePath) {
3787
3798
  await fs17.mkdir(path31.dirname(filePath), { recursive: true });
3788
3799
  }
@@ -3809,6 +3820,9 @@ async function loadGraphFromDisk(graph, outPath) {
3809
3820
  if (payload.schemaVersion === 1) {
3810
3821
  payload = migrateV1ToV2(payload);
3811
3822
  }
3823
+ if (payload.schemaVersion === 2) {
3824
+ payload = migrateV2ToV3(payload);
3825
+ }
3812
3826
  if (payload.schemaVersion !== SCHEMA_VERSION) {
3813
3827
  throw new Error(
3814
3828
  `persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`
@@ -4162,7 +4176,7 @@ import {
4162
4176
  EdgeType as EdgeType9,
4163
4177
  NodeType as NodeType10,
4164
4178
  parseEdgeId,
4165
- Provenance as Provenance11
4179
+ Provenance as Provenance10
4166
4180
  } from "@neat.is/types";
4167
4181
  function bucketKey(source, target, type) {
4168
4182
  return `${type}|${source}|${target}`;
@@ -4176,20 +4190,17 @@ function bucketEdges(graph) {
4176
4190
  const key = bucketKey(e.source, e.target, e.type);
4177
4191
  const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
4178
4192
  switch (provenance) {
4179
- case Provenance11.EXTRACTED:
4193
+ case Provenance10.EXTRACTED:
4180
4194
  cur.extracted = e;
4181
4195
  break;
4182
- case Provenance11.OBSERVED:
4196
+ case Provenance10.OBSERVED:
4183
4197
  cur.observed = e;
4184
4198
  break;
4185
- case Provenance11.INFERRED:
4199
+ case Provenance10.INFERRED:
4186
4200
  cur.inferred = e;
4187
4201
  break;
4188
- case Provenance11.FRONTIER:
4189
- cur.frontier = e;
4190
- break;
4191
4202
  default:
4192
- if (e.provenance === Provenance11.STALE) cur.stale = e;
4203
+ if (e.provenance === Provenance10.STALE) cur.stale = e;
4193
4204
  }
4194
4205
  buckets.set(key, cur);
4195
4206
  });
@@ -4259,7 +4270,7 @@ function declaredHostFor(svc) {
4259
4270
  function hasExtractedConfiguredBy(graph, svcId) {
4260
4271
  for (const edgeId of graph.outboundEdges(svcId)) {
4261
4272
  const e = graph.getEdgeAttributes(edgeId);
4262
- if (e.type === EdgeType9.CONFIGURED_BY && e.provenance === Provenance11.EXTRACTED) {
4273
+ if (e.type === EdgeType9.CONFIGURED_BY && e.provenance === Provenance10.EXTRACTED) {
4263
4274
  return true;
4264
4275
  }
4265
4276
  }
@@ -4273,7 +4284,7 @@ function detectHostMismatch(graph, svcId, svc) {
4273
4284
  for (const edgeId of graph.outboundEdges(svcId)) {
4274
4285
  const edge = graph.getEdgeAttributes(edgeId);
4275
4286
  if (edge.type !== EdgeType9.CONNECTS_TO) continue;
4276
- if (edge.provenance !== Provenance11.OBSERVED) continue;
4287
+ if (edge.provenance !== Provenance10.OBSERVED) continue;
4277
4288
  const target = graph.getNodeAttributes(edge.target);
4278
4289
  if (target.type !== NodeType10.DatabaseNode) continue;
4279
4290
  const observedHost = target.host?.trim();
@@ -4298,7 +4309,7 @@ function detectCompatDivergences(graph, svcId, svc) {
4298
4309
  for (const edgeId of graph.outboundEdges(svcId)) {
4299
4310
  const edge = graph.getEdgeAttributes(edgeId);
4300
4311
  if (edge.type !== EdgeType9.CONNECTS_TO) continue;
4301
- if (edge.provenance !== Provenance11.OBSERVED) continue;
4312
+ if (edge.provenance !== Provenance10.OBSERVED) continue;
4302
4313
  const target = graph.getNodeAttributes(edge.target);
4303
4314
  if (target.type !== NodeType10.DatabaseNode) continue;
4304
4315
  for (const pair of compatPairs()) {
@@ -4941,4 +4952,4 @@ export {
4941
4952
  removeProject,
4942
4953
  buildApi
4943
4954
  };
4944
- //# sourceMappingURL=chunk-33ZZ2ZID.js.map
4955
+ //# sourceMappingURL=chunk-BUB3ASD5.js.map