@neat.is/core 0.3.7 → 0.3.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.
@@ -1,3 +1,7 @@
1
+ import {
2
+ mountBearerAuth
3
+ } from "./chunk-7TYESDAI.js";
4
+
1
5
  // src/graph.ts
2
6
  import GraphDefault from "graphology";
3
7
  var MultiDirectedGraph = GraphDefault.MultiDirectedGraph;
@@ -3759,10 +3763,252 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
3759
3763
  return result;
3760
3764
  }
3761
3765
 
3766
+ // src/divergences.ts
3767
+ import {
3768
+ DivergenceResultSchema,
3769
+ EdgeType as EdgeType9,
3770
+ NodeType as NodeType10,
3771
+ parseEdgeId,
3772
+ Provenance as Provenance9
3773
+ } from "@neat.is/types";
3774
+ function bucketKey(source, target, type) {
3775
+ return `${type}|${source}|${target}`;
3776
+ }
3777
+ function bucketEdges(graph) {
3778
+ const buckets = /* @__PURE__ */ new Map();
3779
+ graph.forEachEdge((id, attrs) => {
3780
+ const e = attrs;
3781
+ const parsed = parseEdgeId(id);
3782
+ const provenance = parsed?.provenance ?? e.provenance;
3783
+ const key = bucketKey(e.source, e.target, e.type);
3784
+ const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
3785
+ switch (provenance) {
3786
+ case Provenance9.EXTRACTED:
3787
+ cur.extracted = e;
3788
+ break;
3789
+ case Provenance9.OBSERVED:
3790
+ cur.observed = e;
3791
+ break;
3792
+ case Provenance9.INFERRED:
3793
+ cur.inferred = e;
3794
+ break;
3795
+ default:
3796
+ if (e.provenance === Provenance9.STALE) cur.stale = e;
3797
+ }
3798
+ buckets.set(key, cur);
3799
+ });
3800
+ return buckets;
3801
+ }
3802
+ function nodeIsFrontier(graph, nodeId) {
3803
+ if (!graph.hasNode(nodeId)) return false;
3804
+ const attrs = graph.getNodeAttributes(nodeId);
3805
+ return attrs.type === NodeType10.FrontierNode;
3806
+ }
3807
+ function clampConfidence(n) {
3808
+ if (!Number.isFinite(n)) return 0;
3809
+ return Math.max(0, Math.min(1, n));
3810
+ }
3811
+ function reasonForMissingObserved(source, target, type) {
3812
+ return `Code declares ${source} \u2192 ${target} (${type}) but no production traffic has been observed for this edge.`;
3813
+ }
3814
+ function reasonForMissingExtracted(source, target, type) {
3815
+ return `Production observed ${source} \u2192 ${target} (${type}) but static analysis did not surface this edge.`;
3816
+ }
3817
+ var RECOMMENDATION_MISSING_OBSERVED = "Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.";
3818
+ var RECOMMENDATION_MISSING_EXTRACTED = "Likely dynamic dispatch, reflection, or a coverage gap in tree-sitter extraction. Consider an `aliases` entry on the source service or file an extractor issue.";
3819
+ var RECOMMENDATION_HOST_MISMATCH = "Check environment-specific config overrides \u2014 the runtime host differs from what static configuration declares.";
3820
+ function gradedConfidence(edge) {
3821
+ if (typeof edge.confidence === "number") return clampConfidence(edge.confidence);
3822
+ return clampConfidence(confidenceForEdge(edge));
3823
+ }
3824
+ function detectMissingDivergences(graph, bucket) {
3825
+ const out = [];
3826
+ if (bucket.extracted && !bucket.observed) {
3827
+ if (!nodeIsFrontier(graph, bucket.target)) {
3828
+ out.push({
3829
+ type: "missing-observed",
3830
+ source: bucket.source,
3831
+ target: bucket.target,
3832
+ edgeType: bucket.type,
3833
+ extracted: bucket.extracted,
3834
+ confidence: gradedConfidence(bucket.extracted),
3835
+ reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),
3836
+ recommendation: RECOMMENDATION_MISSING_OBSERVED
3837
+ });
3838
+ }
3839
+ }
3840
+ if (bucket.observed && !bucket.extracted) {
3841
+ out.push({
3842
+ type: "missing-extracted",
3843
+ source: bucket.source,
3844
+ target: bucket.target,
3845
+ edgeType: bucket.type,
3846
+ observed: bucket.observed,
3847
+ confidence: gradedConfidence(bucket.observed),
3848
+ reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),
3849
+ recommendation: RECOMMENDATION_MISSING_EXTRACTED
3850
+ });
3851
+ }
3852
+ return out;
3853
+ }
3854
+ function declaredHostFor(svc) {
3855
+ const raw = svc.dbConnectionTarget?.trim();
3856
+ if (!raw) return null;
3857
+ const colon = raw.lastIndexOf(":");
3858
+ if (colon === -1) return raw;
3859
+ const port = raw.slice(colon + 1);
3860
+ if (/^\d+$/.test(port)) return raw.slice(0, colon);
3861
+ return raw;
3862
+ }
3863
+ function hasExtractedConfiguredBy(graph, svcId) {
3864
+ for (const edgeId of graph.outboundEdges(svcId)) {
3865
+ const e = graph.getEdgeAttributes(edgeId);
3866
+ if (e.type === EdgeType9.CONFIGURED_BY && e.provenance === Provenance9.EXTRACTED) {
3867
+ return true;
3868
+ }
3869
+ }
3870
+ return false;
3871
+ }
3872
+ function detectHostMismatch(graph, svcId, svc) {
3873
+ const declaredHost = declaredHostFor(svc);
3874
+ if (!declaredHost) return [];
3875
+ if (!hasExtractedConfiguredBy(graph, svcId)) return [];
3876
+ const out = [];
3877
+ for (const edgeId of graph.outboundEdges(svcId)) {
3878
+ const edge = graph.getEdgeAttributes(edgeId);
3879
+ if (edge.type !== EdgeType9.CONNECTS_TO) continue;
3880
+ if (edge.provenance !== Provenance9.OBSERVED) continue;
3881
+ const target = graph.getNodeAttributes(edge.target);
3882
+ if (target.type !== NodeType10.DatabaseNode) continue;
3883
+ const observedHost = target.host?.trim();
3884
+ if (!observedHost) continue;
3885
+ if (observedHost === declaredHost) continue;
3886
+ out.push({
3887
+ type: "host-mismatch",
3888
+ source: svcId,
3889
+ target: edge.target,
3890
+ extractedHost: declaredHost,
3891
+ observedHost,
3892
+ confidence: clampConfidence(confidenceForEdge(edge)),
3893
+ reason: `Config declares ${svcId} connects to ${declaredHost}; production connects to ${observedHost}.`,
3894
+ recommendation: RECOMMENDATION_HOST_MISMATCH
3895
+ });
3896
+ }
3897
+ return out;
3898
+ }
3899
+ function detectCompatDivergences(graph, svcId, svc) {
3900
+ const out = [];
3901
+ const deps = svc.dependencies ?? {};
3902
+ for (const edgeId of graph.outboundEdges(svcId)) {
3903
+ const edge = graph.getEdgeAttributes(edgeId);
3904
+ if (edge.type !== EdgeType9.CONNECTS_TO) continue;
3905
+ if (edge.provenance !== Provenance9.OBSERVED) continue;
3906
+ const target = graph.getNodeAttributes(edge.target);
3907
+ if (target.type !== NodeType10.DatabaseNode) continue;
3908
+ for (const pair of compatPairs()) {
3909
+ if (pair.engine !== target.engine) continue;
3910
+ const declared = deps[pair.driver];
3911
+ if (!declared) continue;
3912
+ const result = checkCompatibility(
3913
+ pair.driver,
3914
+ declared,
3915
+ target.engine,
3916
+ target.engineVersion
3917
+ );
3918
+ if (!result.compatible && result.reason) {
3919
+ out.push({
3920
+ type: "version-mismatch",
3921
+ source: svcId,
3922
+ target: edge.target,
3923
+ extractedVersion: declared,
3924
+ observedVersion: target.engineVersion,
3925
+ compatibility: "incompatible",
3926
+ confidence: 1,
3927
+ reason: result.reason,
3928
+ recommendation: result.minDriverVersion ? `Upgrade ${pair.driver} to >= ${result.minDriverVersion}.` : `Update the ${pair.driver} driver to a version compatible with ${target.engine} ${target.engineVersion}.`
3929
+ });
3930
+ }
3931
+ }
3932
+ for (const rule of deprecatedApis()) {
3933
+ const declared = deps[rule.package];
3934
+ if (!declared) continue;
3935
+ const result = checkDeprecatedApi(rule, declared);
3936
+ if (!result.compatible && result.reason) {
3937
+ const ruleRef = {
3938
+ kind: rule.kind ?? "deprecated-api",
3939
+ reason: result.reason,
3940
+ package: rule.package
3941
+ };
3942
+ out.push({
3943
+ type: "compat-violation",
3944
+ source: svcId,
3945
+ target: edge.target,
3946
+ rule: ruleRef,
3947
+ observed: edge,
3948
+ confidence: 1,
3949
+ reason: result.reason,
3950
+ recommendation: `Replace deprecated ${rule.package}@${declared} with a supported version.`
3951
+ });
3952
+ }
3953
+ }
3954
+ }
3955
+ return out;
3956
+ }
3957
+ function involvesNode(d, nodeId) {
3958
+ return d.source === nodeId || d.target === nodeId;
3959
+ }
3960
+ function computeDivergences(graph, opts = {}) {
3961
+ const all = [];
3962
+ const buckets = bucketEdges(graph);
3963
+ for (const bucket of buckets.values()) {
3964
+ for (const d of detectMissingDivergences(graph, bucket)) all.push(d);
3965
+ }
3966
+ graph.forEachNode((nodeId, attrs) => {
3967
+ const n = attrs;
3968
+ if (n.type !== NodeType10.ServiceNode) return;
3969
+ const svc = n;
3970
+ for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
3971
+ for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
3972
+ });
3973
+ let filtered = all;
3974
+ if (opts.type) {
3975
+ const allowed = opts.type;
3976
+ filtered = filtered.filter((d) => allowed.has(d.type));
3977
+ }
3978
+ if (opts.minConfidence !== void 0) {
3979
+ const threshold = opts.minConfidence;
3980
+ filtered = filtered.filter((d) => d.confidence >= threshold);
3981
+ }
3982
+ if (opts.node) {
3983
+ const target = opts.node;
3984
+ filtered = filtered.filter((d) => involvesNode(d, target));
3985
+ }
3986
+ const TYPE_LEADERSHIP = {
3987
+ "missing-extracted": 0,
3988
+ "missing-observed": 1,
3989
+ "version-mismatch": 2,
3990
+ "host-mismatch": 3,
3991
+ "compat-violation": 4
3992
+ };
3993
+ filtered.sort((a, b) => {
3994
+ if (b.confidence !== a.confidence) return b.confidence - a.confidence;
3995
+ const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type];
3996
+ if (lead !== 0) return lead;
3997
+ if (a.type !== b.type) return a.type.localeCompare(b.type);
3998
+ if (a.source !== b.source) return a.source.localeCompare(b.source);
3999
+ return a.target.localeCompare(b.target);
4000
+ });
4001
+ return DivergenceResultSchema.parse({
4002
+ divergences: filtered,
4003
+ totalAffected: filtered.length,
4004
+ computedAt: (/* @__PURE__ */ new Date()).toISOString()
4005
+ });
4006
+ }
4007
+
3762
4008
  // src/persist.ts
3763
4009
  import { promises as fs17 } from "fs";
3764
4010
  import path31 from "path";
3765
- import { Provenance as Provenance9, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
4011
+ import { Provenance as Provenance10, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
3766
4012
  var SCHEMA_VERSION = 3;
3767
4013
  function migrateV1ToV2(payload) {
3768
4014
  const nodes = payload.graph.nodes;
@@ -3781,7 +4027,7 @@ function migrateV2ToV3(payload) {
3781
4027
  for (const edge of edges) {
3782
4028
  const attrs = edge.attributes;
3783
4029
  if (!attrs || attrs.provenance !== "FRONTIER") continue;
3784
- attrs.provenance = Provenance9.OBSERVED;
4030
+ attrs.provenance = Provenance10.OBSERVED;
3785
4031
  const type = typeof attrs.type === "string" ? attrs.type : void 0;
3786
4032
  const source = typeof attrs.source === "string" ? attrs.source : void 0;
3787
4033
  const target = typeof attrs.target === "string" ? attrs.target : void 0;
@@ -4170,248 +4416,6 @@ import Fastify from "fastify";
4170
4416
  import cors from "@fastify/cors";
4171
4417
  import { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } from "@neat.is/types";
4172
4418
 
4173
- // src/divergences.ts
4174
- import {
4175
- DivergenceResultSchema,
4176
- EdgeType as EdgeType9,
4177
- NodeType as NodeType10,
4178
- parseEdgeId,
4179
- Provenance as Provenance10
4180
- } from "@neat.is/types";
4181
- function bucketKey(source, target, type) {
4182
- return `${type}|${source}|${target}`;
4183
- }
4184
- function bucketEdges(graph) {
4185
- const buckets = /* @__PURE__ */ new Map();
4186
- graph.forEachEdge((id, attrs) => {
4187
- const e = attrs;
4188
- const parsed = parseEdgeId(id);
4189
- const provenance = parsed?.provenance ?? e.provenance;
4190
- const key = bucketKey(e.source, e.target, e.type);
4191
- const cur = buckets.get(key) ?? { source: e.source, target: e.target, type: e.type };
4192
- switch (provenance) {
4193
- case Provenance10.EXTRACTED:
4194
- cur.extracted = e;
4195
- break;
4196
- case Provenance10.OBSERVED:
4197
- cur.observed = e;
4198
- break;
4199
- case Provenance10.INFERRED:
4200
- cur.inferred = e;
4201
- break;
4202
- default:
4203
- if (e.provenance === Provenance10.STALE) cur.stale = e;
4204
- }
4205
- buckets.set(key, cur);
4206
- });
4207
- return buckets;
4208
- }
4209
- function nodeIsFrontier(graph, nodeId) {
4210
- if (!graph.hasNode(nodeId)) return false;
4211
- const attrs = graph.getNodeAttributes(nodeId);
4212
- return attrs.type === NodeType10.FrontierNode;
4213
- }
4214
- function clampConfidence(n) {
4215
- if (!Number.isFinite(n)) return 0;
4216
- return Math.max(0, Math.min(1, n));
4217
- }
4218
- function reasonForMissingObserved(source, target, type) {
4219
- return `Code declares ${source} \u2192 ${target} (${type}) but no production traffic has been observed for this edge.`;
4220
- }
4221
- function reasonForMissingExtracted(source, target, type) {
4222
- return `Production observed ${source} \u2192 ${target} (${type}) but static analysis did not surface this edge.`;
4223
- }
4224
- var RECOMMENDATION_MISSING_OBSERVED = "Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.";
4225
- var RECOMMENDATION_MISSING_EXTRACTED = "Likely dynamic dispatch, reflection, or a coverage gap in tree-sitter extraction. Consider an `aliases` entry on the source service or file an extractor issue.";
4226
- var RECOMMENDATION_HOST_MISMATCH = "Check environment-specific config overrides \u2014 the runtime host differs from what static configuration declares.";
4227
- function gradedConfidence(edge) {
4228
- if (typeof edge.confidence === "number") return clampConfidence(edge.confidence);
4229
- return clampConfidence(confidenceForEdge(edge));
4230
- }
4231
- function detectMissingDivergences(graph, bucket) {
4232
- const out = [];
4233
- if (bucket.extracted && !bucket.observed) {
4234
- if (!nodeIsFrontier(graph, bucket.target)) {
4235
- out.push({
4236
- type: "missing-observed",
4237
- source: bucket.source,
4238
- target: bucket.target,
4239
- edgeType: bucket.type,
4240
- extracted: bucket.extracted,
4241
- confidence: gradedConfidence(bucket.extracted),
4242
- reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),
4243
- recommendation: RECOMMENDATION_MISSING_OBSERVED
4244
- });
4245
- }
4246
- }
4247
- if (bucket.observed && !bucket.extracted) {
4248
- out.push({
4249
- type: "missing-extracted",
4250
- source: bucket.source,
4251
- target: bucket.target,
4252
- edgeType: bucket.type,
4253
- observed: bucket.observed,
4254
- confidence: gradedConfidence(bucket.observed),
4255
- reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),
4256
- recommendation: RECOMMENDATION_MISSING_EXTRACTED
4257
- });
4258
- }
4259
- return out;
4260
- }
4261
- function declaredHostFor(svc) {
4262
- const raw = svc.dbConnectionTarget?.trim();
4263
- if (!raw) return null;
4264
- const colon = raw.lastIndexOf(":");
4265
- if (colon === -1) return raw;
4266
- const port = raw.slice(colon + 1);
4267
- if (/^\d+$/.test(port)) return raw.slice(0, colon);
4268
- return raw;
4269
- }
4270
- function hasExtractedConfiguredBy(graph, svcId) {
4271
- for (const edgeId of graph.outboundEdges(svcId)) {
4272
- const e = graph.getEdgeAttributes(edgeId);
4273
- if (e.type === EdgeType9.CONFIGURED_BY && e.provenance === Provenance10.EXTRACTED) {
4274
- return true;
4275
- }
4276
- }
4277
- return false;
4278
- }
4279
- function detectHostMismatch(graph, svcId, svc) {
4280
- const declaredHost = declaredHostFor(svc);
4281
- if (!declaredHost) return [];
4282
- if (!hasExtractedConfiguredBy(graph, svcId)) return [];
4283
- const out = [];
4284
- for (const edgeId of graph.outboundEdges(svcId)) {
4285
- const edge = graph.getEdgeAttributes(edgeId);
4286
- if (edge.type !== EdgeType9.CONNECTS_TO) continue;
4287
- if (edge.provenance !== Provenance10.OBSERVED) continue;
4288
- const target = graph.getNodeAttributes(edge.target);
4289
- if (target.type !== NodeType10.DatabaseNode) continue;
4290
- const observedHost = target.host?.trim();
4291
- if (!observedHost) continue;
4292
- if (observedHost === declaredHost) continue;
4293
- out.push({
4294
- type: "host-mismatch",
4295
- source: svcId,
4296
- target: edge.target,
4297
- extractedHost: declaredHost,
4298
- observedHost,
4299
- confidence: clampConfidence(confidenceForEdge(edge)),
4300
- reason: `Config declares ${svcId} connects to ${declaredHost}; production connects to ${observedHost}.`,
4301
- recommendation: RECOMMENDATION_HOST_MISMATCH
4302
- });
4303
- }
4304
- return out;
4305
- }
4306
- function detectCompatDivergences(graph, svcId, svc) {
4307
- const out = [];
4308
- const deps = svc.dependencies ?? {};
4309
- for (const edgeId of graph.outboundEdges(svcId)) {
4310
- const edge = graph.getEdgeAttributes(edgeId);
4311
- if (edge.type !== EdgeType9.CONNECTS_TO) continue;
4312
- if (edge.provenance !== Provenance10.OBSERVED) continue;
4313
- const target = graph.getNodeAttributes(edge.target);
4314
- if (target.type !== NodeType10.DatabaseNode) continue;
4315
- for (const pair of compatPairs()) {
4316
- if (pair.engine !== target.engine) continue;
4317
- const declared = deps[pair.driver];
4318
- if (!declared) continue;
4319
- const result = checkCompatibility(
4320
- pair.driver,
4321
- declared,
4322
- target.engine,
4323
- target.engineVersion
4324
- );
4325
- if (!result.compatible && result.reason) {
4326
- out.push({
4327
- type: "version-mismatch",
4328
- source: svcId,
4329
- target: edge.target,
4330
- extractedVersion: declared,
4331
- observedVersion: target.engineVersion,
4332
- compatibility: "incompatible",
4333
- confidence: 1,
4334
- reason: result.reason,
4335
- recommendation: result.minDriverVersion ? `Upgrade ${pair.driver} to >= ${result.minDriverVersion}.` : `Update the ${pair.driver} driver to a version compatible with ${target.engine} ${target.engineVersion}.`
4336
- });
4337
- }
4338
- }
4339
- for (const rule of deprecatedApis()) {
4340
- const declared = deps[rule.package];
4341
- if (!declared) continue;
4342
- const result = checkDeprecatedApi(rule, declared);
4343
- if (!result.compatible && result.reason) {
4344
- const ruleRef = {
4345
- kind: rule.kind ?? "deprecated-api",
4346
- reason: result.reason,
4347
- package: rule.package
4348
- };
4349
- out.push({
4350
- type: "compat-violation",
4351
- source: svcId,
4352
- target: edge.target,
4353
- rule: ruleRef,
4354
- observed: edge,
4355
- confidence: 1,
4356
- reason: result.reason,
4357
- recommendation: `Replace deprecated ${rule.package}@${declared} with a supported version.`
4358
- });
4359
- }
4360
- }
4361
- }
4362
- return out;
4363
- }
4364
- function involvesNode(d, nodeId) {
4365
- return d.source === nodeId || d.target === nodeId;
4366
- }
4367
- function computeDivergences(graph, opts = {}) {
4368
- const all = [];
4369
- const buckets = bucketEdges(graph);
4370
- for (const bucket of buckets.values()) {
4371
- for (const d of detectMissingDivergences(graph, bucket)) all.push(d);
4372
- }
4373
- graph.forEachNode((nodeId, attrs) => {
4374
- const n = attrs;
4375
- if (n.type !== NodeType10.ServiceNode) return;
4376
- const svc = n;
4377
- for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
4378
- for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
4379
- });
4380
- let filtered = all;
4381
- if (opts.type) {
4382
- const allowed = opts.type;
4383
- filtered = filtered.filter((d) => allowed.has(d.type));
4384
- }
4385
- if (opts.minConfidence !== void 0) {
4386
- const threshold = opts.minConfidence;
4387
- filtered = filtered.filter((d) => d.confidence >= threshold);
4388
- }
4389
- if (opts.node) {
4390
- const target = opts.node;
4391
- filtered = filtered.filter((d) => involvesNode(d, target));
4392
- }
4393
- const TYPE_LEADERSHIP = {
4394
- "missing-extracted": 0,
4395
- "missing-observed": 1,
4396
- "version-mismatch": 2,
4397
- "host-mismatch": 3,
4398
- "compat-violation": 4
4399
- };
4400
- filtered.sort((a, b) => {
4401
- if (b.confidence !== a.confidence) return b.confidence - a.confidence;
4402
- const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type];
4403
- if (lead !== 0) return lead;
4404
- if (a.type !== b.type) return a.type.localeCompare(b.type);
4405
- if (a.source !== b.source) return a.source.localeCompare(b.source);
4406
- return a.target.localeCompare(b.target);
4407
- });
4408
- return DivergenceResultSchema.parse({
4409
- divergences: filtered,
4410
- totalAffected: filtered.length,
4411
- computedAt: (/* @__PURE__ */ new Date()).toISOString()
4412
- });
4413
- }
4414
-
4415
4419
  // src/streaming.ts
4416
4420
  var SSE_HEARTBEAT_MS = 3e4;
4417
4421
  var SSE_BACKPRESSURE_CAP = 1e3;
@@ -4832,6 +4836,7 @@ function registerRoutes(scope, ctx) {
4832
4836
  async function buildApi(opts) {
4833
4837
  const app = Fastify({ logger: false });
4834
4838
  await app.register(cors, { origin: true });
4839
+ mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy });
4835
4840
  const startedAt = opts.startedAt ?? Date.now();
4836
4841
  const registry = buildLegacyRegistry(opts);
4837
4842
  const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== void 0;
@@ -4930,6 +4935,7 @@ export {
4930
4935
  addInfra,
4931
4936
  retireEdgesByFile,
4932
4937
  extractFromDirectory,
4938
+ computeDivergences,
4933
4939
  saveGraphToDisk,
4934
4940
  loadGraphFromDisk,
4935
4941
  startPersistLoop,
@@ -4952,4 +4958,4 @@ export {
4952
4958
  removeProject,
4953
4959
  buildApi
4954
4960
  };
4955
- //# sourceMappingURL=chunk-ZU2RQRCN.js.map
4961
+ //# sourceMappingURL=chunk-CZ3T6TE2.js.map