@neat.is/core 0.9.11 → 0.9.12
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-3UAUMPIY.js → chunk-RBZNXA5L.js} +591 -460
- package/dist/chunk-RBZNXA5L.js.map +1 -0
- package/dist/{chunk-UNO3X6ZV.js → chunk-WE3AFQYL.js} +468 -19
- package/dist/chunk-WE3AFQYL.js.map +1 -0
- package/dist/cli.cjs +1108 -951
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1229 -645
- 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 +1245 -661
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +661 -534
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-3UAUMPIY.js.map +0 -1
- package/dist/chunk-UNO3X6ZV.js.map +0 -1
|
@@ -1252,7 +1252,7 @@ function buildServiceHostIndex(services) {
|
|
|
1252
1252
|
async function walkSourceFiles(dir, excludeDirs = []) {
|
|
1253
1253
|
const excluded = new Set(excludeDirs.map((d) => path5.resolve(d)));
|
|
1254
1254
|
const out = [];
|
|
1255
|
-
async function
|
|
1255
|
+
async function walk11(current) {
|
|
1256
1256
|
const entries = await fs5.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
1257
1257
|
for (const entry of entries) {
|
|
1258
1258
|
const full = path5.join(current, entry.name);
|
|
@@ -1260,7 +1260,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
1260
1260
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
1261
1261
|
if (excluded.has(path5.resolve(full))) continue;
|
|
1262
1262
|
if (await isPythonVenvDir(full)) continue;
|
|
1263
|
-
await
|
|
1263
|
+
await walk11(full);
|
|
1264
1264
|
} else if (entry.isFile() && SERVICE_FILE_EXTENSIONS.has(path5.extname(entry.name)) && // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it
|
|
1265
1265
|
// would attribute our instrumentation imports to the user's service.
|
|
1266
1266
|
!isNeatAuthoredSourceFile(entry.name)) {
|
|
@@ -1268,7 +1268,7 @@ async function walkSourceFiles(dir, excludeDirs = []) {
|
|
|
1268
1268
|
}
|
|
1269
1269
|
}
|
|
1270
1270
|
}
|
|
1271
|
-
await
|
|
1271
|
+
await walk11(dir);
|
|
1272
1272
|
return out;
|
|
1273
1273
|
}
|
|
1274
1274
|
async function loadSourceFiles(dir, excludeDirs = []) {
|
|
@@ -1869,8 +1869,8 @@ function chiRoutesFromSource(source, parser) {
|
|
|
1869
1869
|
chiWalk(tree.rootNode, "", out);
|
|
1870
1870
|
return out;
|
|
1871
1871
|
}
|
|
1872
|
-
function stripChiRegex(
|
|
1873
|
-
return
|
|
1872
|
+
function stripChiRegex(path73) {
|
|
1873
|
+
return path73.replace(/\{([^{}:]+):[^{}]*\}/g, "{$1}");
|
|
1874
1874
|
}
|
|
1875
1875
|
function chiWalk(node, prefix, out) {
|
|
1876
1876
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -2542,9 +2542,9 @@ function rubyRocketRoute(args) {
|
|
|
2542
2542
|
if (!pair || pair.type !== "pair") continue;
|
|
2543
2543
|
const k = pair.childForFieldName("key");
|
|
2544
2544
|
if (k?.type !== "string") continue;
|
|
2545
|
-
const
|
|
2546
|
-
if (
|
|
2547
|
-
return { path:
|
|
2545
|
+
const path73 = rubyLiteral(k);
|
|
2546
|
+
if (path73 === null) continue;
|
|
2547
|
+
return { path: path73, target: rubyLiteral(pair.childForFieldName("value")) };
|
|
2548
2548
|
}
|
|
2549
2549
|
return null;
|
|
2550
2550
|
}
|
|
@@ -5096,29 +5096,29 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
5096
5096
|
toPromote.push({ frontierId: id, serviceId: target });
|
|
5097
5097
|
});
|
|
5098
5098
|
let promoted = 0;
|
|
5099
|
-
for (const { frontierId: frontierId2, serviceId:
|
|
5099
|
+
for (const { frontierId: frontierId2, serviceId: serviceId17 } of toPromote) {
|
|
5100
5100
|
if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {
|
|
5101
5101
|
const gate = canPromoteFrontier(graph, frontierId2, opts.policies, opts.policyCtx);
|
|
5102
5102
|
if (!gate.allowed) {
|
|
5103
5103
|
continue;
|
|
5104
5104
|
}
|
|
5105
5105
|
}
|
|
5106
|
-
rewireFrontierEdges(graph, frontierId2,
|
|
5106
|
+
rewireFrontierEdges(graph, frontierId2, serviceId17);
|
|
5107
5107
|
graph.dropNode(frontierId2);
|
|
5108
5108
|
promoted++;
|
|
5109
5109
|
}
|
|
5110
5110
|
return promoted;
|
|
5111
5111
|
}
|
|
5112
|
-
function rewireFrontierEdges(graph, frontierId2,
|
|
5112
|
+
function rewireFrontierEdges(graph, frontierId2, serviceId17) {
|
|
5113
5113
|
const inbound = [...graph.inboundEdges(frontierId2)];
|
|
5114
5114
|
const outbound = [...graph.outboundEdges(frontierId2)];
|
|
5115
5115
|
for (const edgeId of inbound) {
|
|
5116
5116
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
5117
|
-
rebuildEdge(graph, edge, edge.source,
|
|
5117
|
+
rebuildEdge(graph, edge, edge.source, serviceId17, edgeId);
|
|
5118
5118
|
}
|
|
5119
5119
|
for (const edgeId of outbound) {
|
|
5120
5120
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
5121
|
-
rebuildEdge(graph, edge,
|
|
5121
|
+
rebuildEdge(graph, edge, serviceId17, edge.target, edgeId);
|
|
5122
5122
|
}
|
|
5123
5123
|
}
|
|
5124
5124
|
function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
@@ -5471,19 +5471,19 @@ function confidenceFromMix(edges, now = Date.now()) {
|
|
|
5471
5471
|
function longestIncomingWalk(graph, start, maxDepth) {
|
|
5472
5472
|
let best = { path: [start], edges: [] };
|
|
5473
5473
|
const visited = /* @__PURE__ */ new Set([start]);
|
|
5474
|
-
function step(node,
|
|
5475
|
-
if (
|
|
5476
|
-
best = { path: [...
|
|
5474
|
+
function step(node, path73, edges) {
|
|
5475
|
+
if (path73.length > best.path.length) {
|
|
5476
|
+
best = { path: [...path73], edges: [...edges] };
|
|
5477
5477
|
}
|
|
5478
|
-
if (
|
|
5478
|
+
if (path73.length - 1 >= maxDepth) return;
|
|
5479
5479
|
const incoming = bestEdgeBySource(graph, graph.inboundEdges(node));
|
|
5480
5480
|
for (const [srcId, edge] of incoming) {
|
|
5481
5481
|
if (visited.has(srcId)) continue;
|
|
5482
5482
|
visited.add(srcId);
|
|
5483
|
-
|
|
5483
|
+
path73.push(srcId);
|
|
5484
5484
|
edges.push(edge);
|
|
5485
|
-
step(srcId,
|
|
5486
|
-
|
|
5485
|
+
step(srcId, path73, edges);
|
|
5486
|
+
path73.pop();
|
|
5487
5487
|
edges.pop();
|
|
5488
5488
|
visited.delete(srcId);
|
|
5489
5489
|
}
|
|
@@ -5491,14 +5491,14 @@ function longestIncomingWalk(graph, start, maxDepth) {
|
|
|
5491
5491
|
step(start, [start], []);
|
|
5492
5492
|
return best;
|
|
5493
5493
|
}
|
|
5494
|
-
function databaseRootCauseShape(graph, origin,
|
|
5494
|
+
function databaseRootCauseShape(graph, origin, walk11) {
|
|
5495
5495
|
const targetDb = origin;
|
|
5496
5496
|
const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine);
|
|
5497
5497
|
if (candidatePairs.length === 0) return null;
|
|
5498
|
-
for (const id of
|
|
5498
|
+
for (const id of walk11.path) {
|
|
5499
5499
|
const owner = resolveOwningService(graph, id);
|
|
5500
5500
|
if (!owner) continue;
|
|
5501
|
-
const { id:
|
|
5501
|
+
const { id: serviceId17, svc } = owner;
|
|
5502
5502
|
const deps = svc.dependencies ?? {};
|
|
5503
5503
|
for (const pair of candidatePairs) {
|
|
5504
5504
|
const declared = deps[pair.driver];
|
|
@@ -5511,7 +5511,7 @@ function databaseRootCauseShape(graph, origin, walk10) {
|
|
|
5511
5511
|
);
|
|
5512
5512
|
if (!result.compatible) {
|
|
5513
5513
|
return {
|
|
5514
|
-
rootCauseNode:
|
|
5514
|
+
rootCauseNode: serviceId17,
|
|
5515
5515
|
rootCauseReason: result.reason ?? "incompatible driver",
|
|
5516
5516
|
...result.minDriverVersion ? {
|
|
5517
5517
|
fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`
|
|
@@ -5522,11 +5522,11 @@ function databaseRootCauseShape(graph, origin, walk10) {
|
|
|
5522
5522
|
}
|
|
5523
5523
|
return null;
|
|
5524
5524
|
}
|
|
5525
|
-
function serviceRootCauseShape(graph, _origin,
|
|
5526
|
-
for (const id of
|
|
5525
|
+
function serviceRootCauseShape(graph, _origin, walk11) {
|
|
5526
|
+
for (const id of walk11.path) {
|
|
5527
5527
|
const owner = resolveOwningService(graph, id);
|
|
5528
5528
|
if (!owner) continue;
|
|
5529
|
-
const { id:
|
|
5529
|
+
const { id: serviceId17, svc } = owner;
|
|
5530
5530
|
const deps = svc.dependencies ?? {};
|
|
5531
5531
|
const serviceNodeEngine = svc.nodeEngine;
|
|
5532
5532
|
for (const constraint of nodeEngineConstraints()) {
|
|
@@ -5535,7 +5535,7 @@ function serviceRootCauseShape(graph, _origin, walk10) {
|
|
|
5535
5535
|
const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine);
|
|
5536
5536
|
if (!result.compatible && result.reason) {
|
|
5537
5537
|
return {
|
|
5538
|
-
rootCauseNode:
|
|
5538
|
+
rootCauseNode: serviceId17,
|
|
5539
5539
|
rootCauseReason: result.reason,
|
|
5540
5540
|
...result.requiredNodeVersion ? {
|
|
5541
5541
|
fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`
|
|
@@ -5550,7 +5550,7 @@ function serviceRootCauseShape(graph, _origin, walk10) {
|
|
|
5550
5550
|
const result = checkPackageConflict(conflict, declared, requiredDeclared);
|
|
5551
5551
|
if (!result.compatible && result.reason) {
|
|
5552
5552
|
return {
|
|
5553
|
-
rootCauseNode:
|
|
5553
|
+
rootCauseNode: serviceId17,
|
|
5554
5554
|
rootCauseReason: result.reason,
|
|
5555
5555
|
fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`
|
|
5556
5556
|
};
|
|
@@ -5559,15 +5559,15 @@ function serviceRootCauseShape(graph, _origin, walk10) {
|
|
|
5559
5559
|
}
|
|
5560
5560
|
return null;
|
|
5561
5561
|
}
|
|
5562
|
-
function fileRootCauseShape(graph, origin,
|
|
5562
|
+
function fileRootCauseShape(graph, origin, walk11) {
|
|
5563
5563
|
const owner = resolveOwningService(graph, origin.id);
|
|
5564
5564
|
if (!owner) return null;
|
|
5565
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
5565
|
+
return serviceRootCauseShape(graph, owner.svc, walk11);
|
|
5566
5566
|
}
|
|
5567
|
-
function symbolRootCauseShape(graph, origin,
|
|
5567
|
+
function symbolRootCauseShape(graph, origin, walk11) {
|
|
5568
5568
|
const owner = resolveOwningService(graph, origin.id);
|
|
5569
5569
|
if (!owner) return null;
|
|
5570
|
-
return serviceRootCauseShape(graph, owner.svc,
|
|
5570
|
+
return serviceRootCauseShape(graph, owner.svc, walk11);
|
|
5571
5571
|
}
|
|
5572
5572
|
var rootCauseShapes = {
|
|
5573
5573
|
[NodeType5.DatabaseNode]: databaseRootCauseShape,
|
|
@@ -5580,8 +5580,8 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
5580
5580
|
const origin = graph.getNodeAttributes(errorNodeId);
|
|
5581
5581
|
const shape = rootCauseShapes[origin.type];
|
|
5582
5582
|
if (shape) {
|
|
5583
|
-
const
|
|
5584
|
-
const match = shape(graph, origin,
|
|
5583
|
+
const walk11 = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH);
|
|
5584
|
+
const match = shape(graph, origin, walk11);
|
|
5585
5585
|
if (match) {
|
|
5586
5586
|
const reason = errorEvent ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})` : match.rootCauseReason;
|
|
5587
5587
|
return {
|
|
@@ -5589,9 +5589,9 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
5589
5589
|
result: RootCauseResultSchema.parse({
|
|
5590
5590
|
rootCauseNode: match.rootCauseNode,
|
|
5591
5591
|
rootCauseReason: reason,
|
|
5592
|
-
traversalPath:
|
|
5593
|
-
edgeProvenances:
|
|
5594
|
-
confidence: confidenceFromMix(
|
|
5592
|
+
traversalPath: walk11.path,
|
|
5593
|
+
edgeProvenances: walk11.edges.map((e) => e.provenance),
|
|
5594
|
+
confidence: confidenceFromMix(walk11.edges),
|
|
5595
5595
|
fixRecommendation: match.fixRecommendation
|
|
5596
5596
|
})
|
|
5597
5597
|
};
|
|
@@ -5655,9 +5655,9 @@ function rootCauseFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
5655
5655
|
function isFailingCallEdge(e) {
|
|
5656
5656
|
return e.type === EdgeType6.CALLS && (e.signal?.errorCount ?? 0) > 0;
|
|
5657
5657
|
}
|
|
5658
|
-
function callSourcesForService(graph,
|
|
5659
|
-
const ids = [
|
|
5660
|
-
for (const edgeId of graph.outboundEdges(
|
|
5658
|
+
function callSourcesForService(graph, serviceId17) {
|
|
5659
|
+
const ids = [serviceId17];
|
|
5660
|
+
for (const edgeId of graph.outboundEdges(serviceId17)) {
|
|
5661
5661
|
const e = graph.getEdgeAttributes(edgeId);
|
|
5662
5662
|
if (e.type !== EdgeType6.CONTAINS) continue;
|
|
5663
5663
|
const tgt = graph.getNodeAttributes(e.target);
|
|
@@ -5681,9 +5681,9 @@ function failingCallDominates(e, id, curEdge, curId) {
|
|
|
5681
5681
|
}
|
|
5682
5682
|
return id < curId;
|
|
5683
5683
|
}
|
|
5684
|
-
function dominantFailingCall(graph,
|
|
5684
|
+
function dominantFailingCall(graph, serviceId17, visited) {
|
|
5685
5685
|
let best = null;
|
|
5686
|
-
for (const src of callSourcesForService(graph,
|
|
5686
|
+
for (const src of callSourcesForService(graph, serviceId17)) {
|
|
5687
5687
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
5688
5688
|
const e = graph.getEdgeAttributes(edgeId);
|
|
5689
5689
|
if (!isFailingCallEdge(e)) continue;
|
|
@@ -5698,20 +5698,20 @@ function dominantFailingCall(graph, serviceId16, visited) {
|
|
|
5698
5698
|
return best;
|
|
5699
5699
|
}
|
|
5700
5700
|
function followFailingCallChain(graph, originServiceId, maxDepth) {
|
|
5701
|
-
const
|
|
5701
|
+
const path73 = [originServiceId];
|
|
5702
5702
|
const edges = [];
|
|
5703
5703
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
5704
5704
|
let current = originServiceId;
|
|
5705
5705
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
5706
5706
|
const hop = dominantFailingCall(graph, current, visited);
|
|
5707
5707
|
if (!hop) break;
|
|
5708
|
-
|
|
5708
|
+
path73.push(hop.nextService);
|
|
5709
5709
|
edges.push(hop.edge);
|
|
5710
5710
|
visited.add(hop.nextService);
|
|
5711
5711
|
current = hop.nextService;
|
|
5712
5712
|
}
|
|
5713
5713
|
if (edges.length === 0) return null;
|
|
5714
|
-
return { path:
|
|
5714
|
+
return { path: path73, edges, culprit: current };
|
|
5715
5715
|
}
|
|
5716
5716
|
function isStaleCallEdge(e) {
|
|
5717
5717
|
return e.type === EdgeType6.CALLS && e.provenance === Provenance6.STALE;
|
|
@@ -5722,9 +5722,9 @@ function staleCallDominates(e, id, curEdge, curId) {
|
|
|
5722
5722
|
if (ev !== cv) return ev > cv;
|
|
5723
5723
|
return id < curId;
|
|
5724
5724
|
}
|
|
5725
|
-
function dominantStaleCall(graph,
|
|
5725
|
+
function dominantStaleCall(graph, serviceId17, visited) {
|
|
5726
5726
|
const bestByCallee = /* @__PURE__ */ new Map();
|
|
5727
|
-
for (const src of callSourcesForService(graph,
|
|
5727
|
+
for (const src of callSourcesForService(graph, serviceId17)) {
|
|
5728
5728
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
5729
5729
|
const e = graph.getEdgeAttributes(edgeId);
|
|
5730
5730
|
if (e.type !== EdgeType6.CALLS) continue;
|
|
@@ -5747,26 +5747,26 @@ function dominantStaleCall(graph, serviceId16, visited) {
|
|
|
5747
5747
|
return best;
|
|
5748
5748
|
}
|
|
5749
5749
|
function followStaleCallChain(graph, originServiceId, maxDepth) {
|
|
5750
|
-
const
|
|
5750
|
+
const path73 = [originServiceId];
|
|
5751
5751
|
const edges = [];
|
|
5752
5752
|
const visited = /* @__PURE__ */ new Set([originServiceId]);
|
|
5753
5753
|
let current = originServiceId;
|
|
5754
5754
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
5755
5755
|
const hop = dominantStaleCall(graph, current, visited);
|
|
5756
5756
|
if (!hop) break;
|
|
5757
|
-
|
|
5757
|
+
path73.push(hop.nextService);
|
|
5758
5758
|
edges.push(hop.edge);
|
|
5759
5759
|
visited.add(hop.nextService);
|
|
5760
5760
|
current = hop.nextService;
|
|
5761
5761
|
}
|
|
5762
5762
|
if (edges.length === 0) return null;
|
|
5763
|
-
return { path:
|
|
5763
|
+
return { path: path73, edges, culprit: current };
|
|
5764
5764
|
}
|
|
5765
5765
|
function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
5766
5766
|
const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH);
|
|
5767
5767
|
if (!chain) return null;
|
|
5768
5768
|
const culprit = chain.culprit;
|
|
5769
|
-
const
|
|
5769
|
+
const path73 = [...chain.path];
|
|
5770
5770
|
const edgeProvenances = chain.edges.map((e) => e.provenance);
|
|
5771
5771
|
const baseConfidence = confidenceFromMix(chain.edges);
|
|
5772
5772
|
const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE));
|
|
@@ -5774,14 +5774,14 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
5774
5774
|
if (loc) {
|
|
5775
5775
|
let rootCauseNode = culprit;
|
|
5776
5776
|
if (loc.fileNode) {
|
|
5777
|
-
|
|
5777
|
+
path73.push(loc.fileNode);
|
|
5778
5778
|
edgeProvenances.push(Provenance6.OBSERVED);
|
|
5779
5779
|
rootCauseNode = loc.fileNode;
|
|
5780
5780
|
}
|
|
5781
5781
|
return RootCauseResultSchema.parse({
|
|
5782
5782
|
rootCauseNode,
|
|
5783
5783
|
rootCauseReason: loc.rootCauseReason,
|
|
5784
|
-
traversalPath:
|
|
5784
|
+
traversalPath: path73,
|
|
5785
5785
|
edgeProvenances,
|
|
5786
5786
|
confidence,
|
|
5787
5787
|
...loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}
|
|
@@ -5793,7 +5793,7 @@ function crossServiceRootCause(graph, originId, incidents, errorEvent) {
|
|
|
5793
5793
|
return RootCauseResultSchema.parse({
|
|
5794
5794
|
rootCauseNode: culprit,
|
|
5795
5795
|
rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? "" : "s"})`,
|
|
5796
|
-
traversalPath:
|
|
5796
|
+
traversalPath: path73,
|
|
5797
5797
|
edgeProvenances,
|
|
5798
5798
|
confidence,
|
|
5799
5799
|
fixRecommendation: `Inspect ${culpritName}'s failing handler`
|
|
@@ -6406,10 +6406,10 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
|
6406
6406
|
traversalPath = staleChain.path;
|
|
6407
6407
|
edgeProvenances = staleChain.edges.map((e) => e.provenance);
|
|
6408
6408
|
} else if (top.node !== seedNode) {
|
|
6409
|
-
const
|
|
6410
|
-
if (
|
|
6411
|
-
traversalPath =
|
|
6412
|
-
edgeProvenances =
|
|
6409
|
+
const path73 = findPath(graph, errorNodeId, top.node, "up", ROOT_CAUSE_MAX_DEPTH);
|
|
6410
|
+
if (path73) {
|
|
6411
|
+
traversalPath = path73.nodes;
|
|
6412
|
+
edgeProvenances = path73.edges.map((e) => e.provenance);
|
|
6413
6413
|
} else {
|
|
6414
6414
|
traversalPath = [errorNodeId, top.node];
|
|
6415
6415
|
edgeProvenances = [top.provenance ?? Provenance6.OBSERVED];
|
|
@@ -7334,9 +7334,9 @@ var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
|
7334
7334
|
"StatefulSet",
|
|
7335
7335
|
"DaemonSet"
|
|
7336
7336
|
]);
|
|
7337
|
-
function addAliases(graph,
|
|
7338
|
-
if (!graph.hasNode(
|
|
7339
|
-
const node = graph.getNodeAttributes(
|
|
7337
|
+
function addAliases(graph, serviceId17, candidates) {
|
|
7338
|
+
if (!graph.hasNode(serviceId17)) return;
|
|
7339
|
+
const node = graph.getNodeAttributes(serviceId17);
|
|
7340
7340
|
if (node.type !== NodeType16.ServiceNode) return;
|
|
7341
7341
|
const set = new Set(node.aliases ?? []);
|
|
7342
7342
|
for (const c of candidates) {
|
|
@@ -7346,7 +7346,7 @@ function addAliases(graph, serviceId16, candidates) {
|
|
|
7346
7346
|
}
|
|
7347
7347
|
if (set.size === 0) return;
|
|
7348
7348
|
const updated = { ...node, aliases: [...set].sort() };
|
|
7349
|
-
graph.replaceNodeAttributes(
|
|
7349
|
+
graph.replaceNodeAttributes(serviceId17, updated);
|
|
7350
7350
|
}
|
|
7351
7351
|
function indexServicesByName(services) {
|
|
7352
7352
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -7379,12 +7379,12 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
|
|
|
7379
7379
|
}
|
|
7380
7380
|
if (!compose?.services) return;
|
|
7381
7381
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
7382
|
-
const
|
|
7383
|
-
if (!
|
|
7382
|
+
const serviceId17 = serviceIndex.get(composeName);
|
|
7383
|
+
if (!serviceId17) continue;
|
|
7384
7384
|
const aliases = /* @__PURE__ */ new Set([composeName]);
|
|
7385
7385
|
if (svc.container_name) aliases.add(svc.container_name);
|
|
7386
7386
|
if (svc.hostname) aliases.add(svc.hostname);
|
|
7387
|
-
addAliases(graph,
|
|
7387
|
+
addAliases(graph, serviceId17, aliases);
|
|
7388
7388
|
}
|
|
7389
7389
|
}
|
|
7390
7390
|
var LABEL_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -8506,7 +8506,7 @@ async function addSymbolEdges(graph, services) {
|
|
|
8506
8506
|
return best;
|
|
8507
8507
|
};
|
|
8508
8508
|
const requests = [];
|
|
8509
|
-
const
|
|
8509
|
+
const walk11 = (node) => {
|
|
8510
8510
|
if (node.type === "class_declaration" || node.type === "abstract_class_declaration" || node.type === "class") {
|
|
8511
8511
|
const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`);
|
|
8512
8512
|
if (self && self.kind === "class") {
|
|
@@ -8552,10 +8552,10 @@ async function addSymbolEdges(graph, services) {
|
|
|
8552
8552
|
}
|
|
8553
8553
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
8554
8554
|
const child = node.namedChild(i);
|
|
8555
|
-
if (child)
|
|
8555
|
+
if (child) walk11(child);
|
|
8556
8556
|
}
|
|
8557
8557
|
};
|
|
8558
|
-
|
|
8558
|
+
walk11(root);
|
|
8559
8559
|
for (const req of requests) {
|
|
8560
8560
|
const targetSid = resolveTarget(req.targetName, req.wantKind);
|
|
8561
8561
|
if (!targetSid) continue;
|
|
@@ -9733,7 +9733,7 @@ import {
|
|
|
9733
9733
|
async function walkConfigFiles(dir, excludeDirs = []) {
|
|
9734
9734
|
const excluded = new Set(excludeDirs.map((d) => path35.resolve(d)));
|
|
9735
9735
|
const out = [];
|
|
9736
|
-
async function
|
|
9736
|
+
async function walk11(current) {
|
|
9737
9737
|
const entries = await fs23.readdir(current, { withFileTypes: true });
|
|
9738
9738
|
for (const entry of entries) {
|
|
9739
9739
|
const full = path35.join(current, entry.name);
|
|
@@ -9741,13 +9741,13 @@ async function walkConfigFiles(dir, excludeDirs = []) {
|
|
|
9741
9741
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
9742
9742
|
if (excluded.has(path35.resolve(full))) continue;
|
|
9743
9743
|
if (await isPythonVenvDir(full)) continue;
|
|
9744
|
-
await
|
|
9744
|
+
await walk11(full);
|
|
9745
9745
|
} else if (entry.isFile() && isConfigFile(entry.name).match) {
|
|
9746
9746
|
out.push(full);
|
|
9747
9747
|
}
|
|
9748
9748
|
}
|
|
9749
9749
|
}
|
|
9750
|
-
await
|
|
9750
|
+
await walk11(dir);
|
|
9751
9751
|
return out;
|
|
9752
9752
|
}
|
|
9753
9753
|
async function addConfigNodes(graph, services, scanPath) {
|
|
@@ -9844,7 +9844,7 @@ function grpcMethodsFromProto(content, fqPackage) {
|
|
|
9844
9844
|
async function walkProtoFiles(dir, excludeDirs = []) {
|
|
9845
9845
|
const excluded = new Set(excludeDirs.map((d) => path36.resolve(d)));
|
|
9846
9846
|
const out = [];
|
|
9847
|
-
async function
|
|
9847
|
+
async function walk11(current) {
|
|
9848
9848
|
const entries = await fs24.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
9849
9849
|
for (const entry of entries) {
|
|
9850
9850
|
const full = path36.join(current, entry.name);
|
|
@@ -9852,13 +9852,13 @@ async function walkProtoFiles(dir, excludeDirs = []) {
|
|
|
9852
9852
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
9853
9853
|
if (excluded.has(path36.resolve(full))) continue;
|
|
9854
9854
|
if (await isPythonVenvDir(full)) continue;
|
|
9855
|
-
await
|
|
9855
|
+
await walk11(full);
|
|
9856
9856
|
} else if (entry.isFile() && path36.extname(entry.name) === PROTO_EXTENSION) {
|
|
9857
9857
|
out.push(full);
|
|
9858
9858
|
}
|
|
9859
9859
|
}
|
|
9860
9860
|
}
|
|
9861
|
-
await
|
|
9861
|
+
await walk11(dir);
|
|
9862
9862
|
return out;
|
|
9863
9863
|
}
|
|
9864
9864
|
async function addGrpcMethods(graph, services) {
|
|
@@ -10870,7 +10870,7 @@ function isFirestoreClientFactory(node) {
|
|
|
10870
10870
|
}
|
|
10871
10871
|
function firestoreClientVars(root) {
|
|
10872
10872
|
const vars = /* @__PURE__ */ new Set();
|
|
10873
|
-
const
|
|
10873
|
+
const walk11 = (node) => {
|
|
10874
10874
|
if (node.type === "variable_declarator") {
|
|
10875
10875
|
const name = node.childForFieldName("name");
|
|
10876
10876
|
let value = node.childForFieldName("value");
|
|
@@ -10879,9 +10879,9 @@ function firestoreClientVars(root) {
|
|
|
10879
10879
|
vars.add(name.text);
|
|
10880
10880
|
}
|
|
10881
10881
|
}
|
|
10882
|
-
for (const c of namedChildren(node))
|
|
10882
|
+
for (const c of namedChildren(node)) walk11(c);
|
|
10883
10883
|
};
|
|
10884
|
-
|
|
10884
|
+
walk11(root);
|
|
10885
10885
|
return vars;
|
|
10886
10886
|
}
|
|
10887
10887
|
function isClientExpr(node, clientVars) {
|
|
@@ -11036,7 +11036,7 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11036
11036
|
}
|
|
11037
11037
|
s.add(field);
|
|
11038
11038
|
};
|
|
11039
|
-
const
|
|
11039
|
+
const walk11 = (node) => {
|
|
11040
11040
|
if (node.type === "call_expression") {
|
|
11041
11041
|
const fn = node.childForFieldName("function");
|
|
11042
11042
|
const line = node.startPosition.row + 1;
|
|
@@ -11076,9 +11076,9 @@ function firestoreEndpointsFromFile(file, serviceDir) {
|
|
|
11076
11076
|
}
|
|
11077
11077
|
}
|
|
11078
11078
|
}
|
|
11079
|
-
for (const c of namedChildren(node))
|
|
11079
|
+
for (const c of namedChildren(node)) walk11(c);
|
|
11080
11080
|
};
|
|
11081
|
-
|
|
11081
|
+
walk11(tree.rootNode);
|
|
11082
11082
|
const out = [];
|
|
11083
11083
|
for (const [collPath, line] of collLine) {
|
|
11084
11084
|
const byField = writes.get(collPath);
|
|
@@ -11692,12 +11692,12 @@ function pythonOrmCrossFileEndpoints(files, serviceDir) {
|
|
|
11692
11692
|
return out;
|
|
11693
11693
|
}
|
|
11694
11694
|
|
|
11695
|
-
// src/extract/calls/
|
|
11695
|
+
// src/extract/calls/socket.ts
|
|
11696
11696
|
import path47 from "path";
|
|
11697
11697
|
import Parser10 from "tree-sitter";
|
|
11698
11698
|
import Python6 from "tree-sitter-python";
|
|
11699
11699
|
import { infraId as infraId10 } from "@neat.is/types";
|
|
11700
|
-
var
|
|
11700
|
+
var SOCKET_IMPORT_RE = /(?:^|\n)\s*(?:import\s+socket\b|from\s+socket\s+import\b)/;
|
|
11701
11701
|
var PARSE_CHUNK7 = 16384;
|
|
11702
11702
|
function makePyParser4() {
|
|
11703
11703
|
const p = new Parser10();
|
|
@@ -11717,22 +11717,108 @@ function namedChildren3(node) {
|
|
|
11717
11717
|
}
|
|
11718
11718
|
return out;
|
|
11719
11719
|
}
|
|
11720
|
+
function walk4(node, visit) {
|
|
11721
|
+
visit(node);
|
|
11722
|
+
for (const c of namedChildren3(node)) walk4(c, visit);
|
|
11723
|
+
}
|
|
11720
11724
|
function pyStaticStringText3(node) {
|
|
11721
11725
|
if (node.type !== "string") return null;
|
|
11722
|
-
for (const
|
|
11726
|
+
for (const child of namedChildren3(node)) {
|
|
11727
|
+
if (child.type === "interpolation") return null;
|
|
11728
|
+
if (child.type === "string_content") return child.text;
|
|
11729
|
+
}
|
|
11730
|
+
return "";
|
|
11731
|
+
}
|
|
11732
|
+
function hasSocketConstructor(root) {
|
|
11733
|
+
let found = false;
|
|
11734
|
+
walk4(root, (n) => {
|
|
11735
|
+
if (found || n.type !== "call") return;
|
|
11736
|
+
const t = n.childForFieldName("function")?.text;
|
|
11737
|
+
if (t === "socket.socket" || t === "socket") found = true;
|
|
11738
|
+
});
|
|
11739
|
+
return found;
|
|
11740
|
+
}
|
|
11741
|
+
function socketEndpointsFromFile(file, serviceDir) {
|
|
11742
|
+
if (!SOCKET_IMPORT_RE.test(file.content)) return [];
|
|
11743
|
+
const tree = parseSource7(makePyParser4(), file.content);
|
|
11744
|
+
if (!hasSocketConstructor(tree.rootNode)) return [];
|
|
11745
|
+
const out = [];
|
|
11746
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11747
|
+
walk4(tree.rootNode, (node) => {
|
|
11748
|
+
if (node.type !== "call") return;
|
|
11749
|
+
const fn = node.childForFieldName("function");
|
|
11750
|
+
if (fn?.type !== "attribute" || fn.childForFieldName("attribute")?.text !== "connect") return;
|
|
11751
|
+
const args = node.childForFieldName("arguments");
|
|
11752
|
+
const first = args ? namedChildren3(args).find((a) => a.type !== "keyword_argument") : void 0;
|
|
11753
|
+
if (!first || first.type !== "tuple") return;
|
|
11754
|
+
const elems = namedChildren3(first);
|
|
11755
|
+
if (elems.length < 2) return;
|
|
11756
|
+
const hostNode = elems[0];
|
|
11757
|
+
const host = hostNode.type === "string" ? pyStaticStringText3(hostNode) : null;
|
|
11758
|
+
const portNode = elems[1];
|
|
11759
|
+
const port = portNode.type === "integer" ? portNode.text : null;
|
|
11760
|
+
const name = host ? port ? `${host}:${port}` : host : "env";
|
|
11761
|
+
if (seen.has(name)) return;
|
|
11762
|
+
seen.add(name);
|
|
11763
|
+
const line = node.startPosition.row + 1;
|
|
11764
|
+
out.push({
|
|
11765
|
+
infraId: infraId10("socket", name),
|
|
11766
|
+
name,
|
|
11767
|
+
kind: "socket",
|
|
11768
|
+
edgeType: "CALLS",
|
|
11769
|
+
// A verified `socket.socket(...)` + `.connect((host, port))` call site.
|
|
11770
|
+
confidenceKind: "verified-call-site",
|
|
11771
|
+
evidence: {
|
|
11772
|
+
file: path47.relative(serviceDir, file.path),
|
|
11773
|
+
line,
|
|
11774
|
+
snippet: snippet(file.content, line)
|
|
11775
|
+
}
|
|
11776
|
+
});
|
|
11777
|
+
});
|
|
11778
|
+
return out;
|
|
11779
|
+
}
|
|
11780
|
+
|
|
11781
|
+
// src/extract/calls/django-orm.ts
|
|
11782
|
+
import path48 from "path";
|
|
11783
|
+
import Parser11 from "tree-sitter";
|
|
11784
|
+
import Python7 from "tree-sitter-python";
|
|
11785
|
+
import { infraId as infraId11 } from "@neat.is/types";
|
|
11786
|
+
var DJANGO_IMPORT_RE = /(?:from|import)\s+django\b/;
|
|
11787
|
+
var PARSE_CHUNK8 = 16384;
|
|
11788
|
+
function makePyParser5() {
|
|
11789
|
+
const p = new Parser11();
|
|
11790
|
+
p.setLanguage(Python7);
|
|
11791
|
+
return p;
|
|
11792
|
+
}
|
|
11793
|
+
function parseSource8(parser, source) {
|
|
11794
|
+
return parser.parse(
|
|
11795
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK8)
|
|
11796
|
+
);
|
|
11797
|
+
}
|
|
11798
|
+
function namedChildren4(node) {
|
|
11799
|
+
const out = [];
|
|
11800
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11801
|
+
const c = node.namedChild(i);
|
|
11802
|
+
if (c) out.push(c);
|
|
11803
|
+
}
|
|
11804
|
+
return out;
|
|
11805
|
+
}
|
|
11806
|
+
function pyStaticStringText4(node) {
|
|
11807
|
+
if (node.type !== "string") return null;
|
|
11808
|
+
for (const c of namedChildren4(node)) {
|
|
11723
11809
|
if (c.type === "interpolation") return null;
|
|
11724
11810
|
if (c.type === "string_content") return c.text;
|
|
11725
11811
|
}
|
|
11726
11812
|
return "";
|
|
11727
11813
|
}
|
|
11728
|
-
function
|
|
11814
|
+
function walk5(node, visit) {
|
|
11729
11815
|
visit(node);
|
|
11730
|
-
for (const c of
|
|
11816
|
+
for (const c of namedChildren4(node)) walk5(c, visit);
|
|
11731
11817
|
}
|
|
11732
11818
|
function extendsDjangoModel(cls) {
|
|
11733
11819
|
const supers = cls.childForFieldName("superclasses");
|
|
11734
11820
|
if (!supers) return false;
|
|
11735
|
-
for (const a of
|
|
11821
|
+
for (const a of namedChildren4(supers)) {
|
|
11736
11822
|
const t = a.text;
|
|
11737
11823
|
if (t === "models.Model" || t === "Model" || t.endsWith(".Model")) return true;
|
|
11738
11824
|
}
|
|
@@ -11740,31 +11826,31 @@ function extendsDjangoModel(cls) {
|
|
|
11740
11826
|
}
|
|
11741
11827
|
function readMeta(body) {
|
|
11742
11828
|
const out = {};
|
|
11743
|
-
for (const stmt of
|
|
11829
|
+
for (const stmt of namedChildren4(body)) {
|
|
11744
11830
|
if (stmt.type !== "class_definition") continue;
|
|
11745
11831
|
if (stmt.childForFieldName("name")?.text !== "Meta") continue;
|
|
11746
11832
|
const metaBody = stmt.childForFieldName("body");
|
|
11747
11833
|
if (!metaBody) continue;
|
|
11748
|
-
for (const ms of
|
|
11834
|
+
for (const ms of namedChildren4(metaBody)) {
|
|
11749
11835
|
if (ms.type !== "expression_statement") continue;
|
|
11750
11836
|
const a = ms.namedChild(0);
|
|
11751
11837
|
if (a?.type !== "assignment") continue;
|
|
11752
11838
|
const l = a.childForFieldName("left")?.text;
|
|
11753
11839
|
const r = a.childForFieldName("right");
|
|
11754
11840
|
if (r?.type !== "string") continue;
|
|
11755
|
-
if (l === "db_table") out.dbTable =
|
|
11756
|
-
if (l === "app_label") out.appLabel =
|
|
11841
|
+
if (l === "db_table") out.dbTable = pyStaticStringText4(r) ?? void 0;
|
|
11842
|
+
if (l === "app_label") out.appLabel = pyStaticStringText4(r) ?? void 0;
|
|
11757
11843
|
}
|
|
11758
11844
|
}
|
|
11759
11845
|
return out;
|
|
11760
11846
|
}
|
|
11761
11847
|
function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
11762
11848
|
if (!DJANGO_IMPORT_RE.test(file.content)) return [];
|
|
11763
|
-
const tree =
|
|
11849
|
+
const tree = parseSource8(makePyParser5(), file.content);
|
|
11764
11850
|
const out = [];
|
|
11765
11851
|
const seen = /* @__PURE__ */ new Set();
|
|
11766
|
-
const defaultAppLabel =
|
|
11767
|
-
|
|
11852
|
+
const defaultAppLabel = path48.basename(path48.dirname(file.path));
|
|
11853
|
+
walk5(tree.rootNode, (node) => {
|
|
11768
11854
|
if (node.type !== "class_definition") return;
|
|
11769
11855
|
if (!extendsDjangoModel(node)) return;
|
|
11770
11856
|
const nameNode = node.childForFieldName("name");
|
|
@@ -11776,30 +11862,30 @@ function djangoOrmEndpointsFromFile(file, serviceDir) {
|
|
|
11776
11862
|
seen.add(table);
|
|
11777
11863
|
const line = node.startPosition.row + 1;
|
|
11778
11864
|
out.push({
|
|
11779
|
-
infraId:
|
|
11865
|
+
infraId: infraId11("sql-table", table),
|
|
11780
11866
|
name: table,
|
|
11781
11867
|
kind: "sql-table",
|
|
11782
11868
|
edgeType: "CALLS",
|
|
11783
11869
|
confidenceKind: "verified-call-site",
|
|
11784
|
-
evidence: { file:
|
|
11870
|
+
evidence: { file: path48.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) }
|
|
11785
11871
|
});
|
|
11786
11872
|
});
|
|
11787
11873
|
return out;
|
|
11788
11874
|
}
|
|
11789
11875
|
|
|
11790
11876
|
// src/extract/calls/drizzle.ts
|
|
11791
|
-
import
|
|
11792
|
-
import
|
|
11877
|
+
import path49 from "path";
|
|
11878
|
+
import Parser12 from "tree-sitter";
|
|
11793
11879
|
import JavaScript7 from "tree-sitter-javascript";
|
|
11794
|
-
import { infraId as
|
|
11880
|
+
import { infraId as infraId12 } from "@neat.is/types";
|
|
11795
11881
|
var DRIZZLE_IMPORT_RE = /drizzle-orm/;
|
|
11796
11882
|
var TABLE_BUILDERS = /* @__PURE__ */ new Set(["pgTable", "mysqlTable", "sqliteTable"]);
|
|
11797
11883
|
function parserForExt3(ext) {
|
|
11798
|
-
const p = new
|
|
11884
|
+
const p = new Parser12();
|
|
11799
11885
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? JavaScript7);
|
|
11800
11886
|
return p;
|
|
11801
11887
|
}
|
|
11802
|
-
function
|
|
11888
|
+
function namedChildren5(node) {
|
|
11803
11889
|
const out = [];
|
|
11804
11890
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
11805
11891
|
const c = node.namedChild(i);
|
|
@@ -11809,7 +11895,7 @@ function namedChildren4(node) {
|
|
|
11809
11895
|
}
|
|
11810
11896
|
function stringLiteralText4(node) {
|
|
11811
11897
|
if (!node || node.type !== "string") return null;
|
|
11812
|
-
for (const child of
|
|
11898
|
+
for (const child of namedChildren5(node)) {
|
|
11813
11899
|
if (child.type === "string_fragment") return child.text;
|
|
11814
11900
|
}
|
|
11815
11901
|
return "";
|
|
@@ -11817,7 +11903,7 @@ function stringLiteralText4(node) {
|
|
|
11817
11903
|
function firstStringArg(call) {
|
|
11818
11904
|
const args = call.childForFieldName("arguments");
|
|
11819
11905
|
if (!args) return null;
|
|
11820
|
-
for (const arg of
|
|
11906
|
+
for (const arg of namedChildren5(args)) {
|
|
11821
11907
|
if (arg.type === "string") return stringLiteralText4(arg);
|
|
11822
11908
|
return null;
|
|
11823
11909
|
}
|
|
@@ -11852,7 +11938,7 @@ function keyName2(key) {
|
|
|
11852
11938
|
function columnsFromObject(obj) {
|
|
11853
11939
|
const out = [];
|
|
11854
11940
|
const seen = /* @__PURE__ */ new Set();
|
|
11855
|
-
for (const child of
|
|
11941
|
+
for (const child of namedChildren5(obj)) {
|
|
11856
11942
|
if (child.type !== "pair") continue;
|
|
11857
11943
|
const value = child.childForFieldName("value");
|
|
11858
11944
|
const key = keyName2(child.childForFieldName("key"));
|
|
@@ -11866,15 +11952,15 @@ function columnsFromObject(obj) {
|
|
|
11866
11952
|
}
|
|
11867
11953
|
function drizzleEndpointsFromFile(file, serviceDir) {
|
|
11868
11954
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
11869
|
-
const tree = parseSource3(parserForExt3(
|
|
11955
|
+
const tree = parseSource3(parserForExt3(path49.extname(file.path)), file.content);
|
|
11870
11956
|
const out = [];
|
|
11871
11957
|
const seen = /* @__PURE__ */ new Set();
|
|
11872
|
-
const
|
|
11958
|
+
const walk11 = (node) => {
|
|
11873
11959
|
if (node.type === "call_expression") {
|
|
11874
11960
|
const fn = node.childForFieldName("function");
|
|
11875
11961
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
11876
11962
|
const args = node.childForFieldName("arguments");
|
|
11877
|
-
const argNodes = args ?
|
|
11963
|
+
const argNodes = args ? namedChildren5(args) : [];
|
|
11878
11964
|
const tableName = stringLiteralText4(argNodes[0] ?? null);
|
|
11879
11965
|
const obj = argNodes[1];
|
|
11880
11966
|
if (tableName && obj?.type === "object" && !seen.has(tableName)) {
|
|
@@ -11882,14 +11968,14 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
11882
11968
|
const columns = columnsFromObject(obj);
|
|
11883
11969
|
const line = node.startPosition.row + 1;
|
|
11884
11970
|
out.push({
|
|
11885
|
-
infraId:
|
|
11971
|
+
infraId: infraId12("sql-table", tableName),
|
|
11886
11972
|
name: tableName,
|
|
11887
11973
|
kind: "sql-table",
|
|
11888
11974
|
edgeType: "CALLS",
|
|
11889
11975
|
confidenceKind: "structural",
|
|
11890
11976
|
columns,
|
|
11891
11977
|
evidence: {
|
|
11892
|
-
file:
|
|
11978
|
+
file: path49.relative(serviceDir, file.path),
|
|
11893
11979
|
line,
|
|
11894
11980
|
snippet: snippet(file.content, line)
|
|
11895
11981
|
}
|
|
@@ -11897,9 +11983,9 @@ function drizzleEndpointsFromFile(file, serviceDir) {
|
|
|
11897
11983
|
}
|
|
11898
11984
|
}
|
|
11899
11985
|
}
|
|
11900
|
-
for (const c of
|
|
11986
|
+
for (const c of namedChildren5(node)) walk11(c);
|
|
11901
11987
|
};
|
|
11902
|
-
|
|
11988
|
+
walk11(tree.rootNode);
|
|
11903
11989
|
return out;
|
|
11904
11990
|
}
|
|
11905
11991
|
function enclosingVarName(call) {
|
|
@@ -11921,12 +12007,12 @@ function enclosingVarName(call) {
|
|
|
11921
12007
|
function collectDrizzleTables(root) {
|
|
11922
12008
|
const tables = [];
|
|
11923
12009
|
const varToTable = /* @__PURE__ */ new Map();
|
|
11924
|
-
const
|
|
12010
|
+
const walk11 = (node) => {
|
|
11925
12011
|
if (node.type === "call_expression") {
|
|
11926
12012
|
const fn = node.childForFieldName("function");
|
|
11927
12013
|
if (fn?.type === "identifier" && TABLE_BUILDERS.has(fn.text)) {
|
|
11928
12014
|
const args = node.childForFieldName("arguments");
|
|
11929
|
-
const argNodes = args ?
|
|
12015
|
+
const argNodes = args ? namedChildren5(args) : [];
|
|
11930
12016
|
const tableName = stringLiteralText4(argNodes[0] ?? null);
|
|
11931
12017
|
const obj = argNodes[1]?.type === "object" ? argNodes[1] : null;
|
|
11932
12018
|
if (tableName) {
|
|
@@ -11936,9 +12022,9 @@ function collectDrizzleTables(root) {
|
|
|
11936
12022
|
}
|
|
11937
12023
|
}
|
|
11938
12024
|
}
|
|
11939
|
-
for (const c of
|
|
12025
|
+
for (const c of namedChildren5(node)) walk11(c);
|
|
11940
12026
|
};
|
|
11941
|
-
|
|
12027
|
+
walk11(root);
|
|
11942
12028
|
return { tables, varToTable };
|
|
11943
12029
|
}
|
|
11944
12030
|
function referencesTargetVar(call) {
|
|
@@ -11946,7 +12032,7 @@ function referencesTargetVar(call) {
|
|
|
11946
12032
|
if (fn?.type !== "member_expression") return null;
|
|
11947
12033
|
if (fn.childForFieldName("property")?.text !== "references") return null;
|
|
11948
12034
|
const args = call.childForFieldName("arguments");
|
|
11949
|
-
const first = args ?
|
|
12035
|
+
const first = args ? namedChildren5(args)[0] ?? null : null;
|
|
11950
12036
|
if (first?.type !== "arrow_function") return null;
|
|
11951
12037
|
const body = first.childForFieldName("body");
|
|
11952
12038
|
if (body?.type !== "member_expression") return null;
|
|
@@ -11955,13 +12041,13 @@ function referencesTargetVar(call) {
|
|
|
11955
12041
|
}
|
|
11956
12042
|
function drizzleForeignKeys(file, serviceDir) {
|
|
11957
12043
|
if (!DRIZZLE_IMPORT_RE.test(file.content)) return [];
|
|
11958
|
-
const tree = parseSource3(parserForExt3(
|
|
12044
|
+
const tree = parseSource3(parserForExt3(path49.extname(file.path)), file.content);
|
|
11959
12045
|
const { tables, varToTable } = collectDrizzleTables(tree.rootNode);
|
|
11960
12046
|
const out = [];
|
|
11961
12047
|
const seen = /* @__PURE__ */ new Set();
|
|
11962
12048
|
for (const table of tables) {
|
|
11963
12049
|
if (!table.object) continue;
|
|
11964
|
-
const
|
|
12050
|
+
const walk11 = (node) => {
|
|
11965
12051
|
if (node.type === "call_expression") {
|
|
11966
12052
|
const targetVar = referencesTargetVar(node);
|
|
11967
12053
|
const parentTable = targetVar ? varToTable.get(targetVar) : void 0;
|
|
@@ -11974,7 +12060,7 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
11974
12060
|
childTable: table.tableName,
|
|
11975
12061
|
parentTable,
|
|
11976
12062
|
evidence: {
|
|
11977
|
-
file:
|
|
12063
|
+
file: path49.relative(serviceDir, file.path),
|
|
11978
12064
|
line,
|
|
11979
12065
|
snippet: snippet(file.content, line)
|
|
11980
12066
|
}
|
|
@@ -11982,16 +12068,16 @@ function drizzleForeignKeys(file, serviceDir) {
|
|
|
11982
12068
|
}
|
|
11983
12069
|
}
|
|
11984
12070
|
}
|
|
11985
|
-
for (const c of
|
|
12071
|
+
for (const c of namedChildren5(node)) walk11(c);
|
|
11986
12072
|
};
|
|
11987
|
-
|
|
12073
|
+
walk11(table.object);
|
|
11988
12074
|
}
|
|
11989
12075
|
return out;
|
|
11990
12076
|
}
|
|
11991
12077
|
|
|
11992
12078
|
// src/extract/calls/prisma.ts
|
|
11993
|
-
import
|
|
11994
|
-
import { infraId as
|
|
12079
|
+
import path50 from "path";
|
|
12080
|
+
import { infraId as infraId13 } from "@neat.is/types";
|
|
11995
12081
|
var SCALAR_TYPES = /* @__PURE__ */ new Set([
|
|
11996
12082
|
"Int",
|
|
11997
12083
|
"String",
|
|
@@ -12039,14 +12125,14 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12039
12125
|
if (seenTable.has(b.tableName)) return;
|
|
12040
12126
|
seenTable.add(b.tableName);
|
|
12041
12127
|
out.push({
|
|
12042
|
-
infraId:
|
|
12128
|
+
infraId: infraId13("sql-table", b.tableName),
|
|
12043
12129
|
name: b.tableName,
|
|
12044
12130
|
kind: "sql-table",
|
|
12045
12131
|
edgeType: "CALLS",
|
|
12046
12132
|
confidenceKind: "structural",
|
|
12047
12133
|
columns: b.columns,
|
|
12048
12134
|
evidence: {
|
|
12049
|
-
file:
|
|
12135
|
+
file: path50.relative(serviceDir, file.path),
|
|
12050
12136
|
line: b.startLine,
|
|
12051
12137
|
snippet: snippet(content, b.startLine)
|
|
12052
12138
|
}
|
|
@@ -12107,7 +12193,7 @@ function prismaColumnsFromSchema(file, serviceDir) {
|
|
|
12107
12193
|
}
|
|
12108
12194
|
async function prismaColumnEndpoints(serviceDir) {
|
|
12109
12195
|
const schemaPath = await findFirst(serviceDir, [
|
|
12110
|
-
|
|
12196
|
+
path50.join("prisma", "schema.prisma"),
|
|
12111
12197
|
"schema.prisma"
|
|
12112
12198
|
]);
|
|
12113
12199
|
if (!schemaPath) return [];
|
|
@@ -12182,7 +12268,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12182
12268
|
childTable: current.table,
|
|
12183
12269
|
parentTable,
|
|
12184
12270
|
evidence: {
|
|
12185
|
-
file:
|
|
12271
|
+
file: path50.relative(serviceDir, file.path),
|
|
12186
12272
|
line: lineNo,
|
|
12187
12273
|
snippet: snippet(content, lineNo)
|
|
12188
12274
|
}
|
|
@@ -12197,7 +12283,7 @@ function prismaForeignKeysFromSchema(file, serviceDir) {
|
|
|
12197
12283
|
}
|
|
12198
12284
|
async function prismaForeignKeys(serviceDir) {
|
|
12199
12285
|
const schemaPath = await findFirst(serviceDir, [
|
|
12200
|
-
|
|
12286
|
+
path50.join("prisma", "schema.prisma"),
|
|
12201
12287
|
"schema.prisma"
|
|
12202
12288
|
]);
|
|
12203
12289
|
if (!schemaPath) return [];
|
|
@@ -12207,27 +12293,27 @@ async function prismaForeignKeys(serviceDir) {
|
|
|
12207
12293
|
}
|
|
12208
12294
|
|
|
12209
12295
|
// src/extract/calls/activerecord.ts
|
|
12210
|
-
import
|
|
12211
|
-
import
|
|
12296
|
+
import path51 from "path";
|
|
12297
|
+
import Parser13 from "tree-sitter";
|
|
12212
12298
|
import Ruby3 from "tree-sitter-ruby";
|
|
12213
|
-
import { infraId as
|
|
12299
|
+
import { infraId as infraId14 } from "@neat.is/types";
|
|
12214
12300
|
var AR_SCHEMA_RE = /ActiveRecord::Schema/;
|
|
12215
|
-
var
|
|
12301
|
+
var PARSE_CHUNK9 = 16384;
|
|
12216
12302
|
function makeRubyParser2() {
|
|
12217
|
-
const p = new
|
|
12303
|
+
const p = new Parser13();
|
|
12218
12304
|
p.setLanguage(Ruby3);
|
|
12219
12305
|
return p;
|
|
12220
12306
|
}
|
|
12221
|
-
function
|
|
12307
|
+
function parseSource9(parser, source) {
|
|
12222
12308
|
return parser.parse(
|
|
12223
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
12309
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK9)
|
|
12224
12310
|
);
|
|
12225
12311
|
}
|
|
12226
|
-
function
|
|
12312
|
+
function walk6(node, visit) {
|
|
12227
12313
|
visit(node);
|
|
12228
12314
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
12229
12315
|
const c = node.namedChild(i);
|
|
12230
|
-
if (c)
|
|
12316
|
+
if (c) walk6(c, visit);
|
|
12231
12317
|
}
|
|
12232
12318
|
}
|
|
12233
12319
|
function rubyLiteral2(node) {
|
|
@@ -12398,24 +12484,24 @@ function readCreateTable(call) {
|
|
|
12398
12484
|
}
|
|
12399
12485
|
function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
12400
12486
|
if (!AR_SCHEMA_RE.test(file.content)) return [];
|
|
12401
|
-
const tree =
|
|
12487
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
12402
12488
|
const out = [];
|
|
12403
12489
|
const seen = /* @__PURE__ */ new Set();
|
|
12404
|
-
|
|
12490
|
+
walk6(tree.rootNode, (node) => {
|
|
12405
12491
|
if (node.type !== "call") return;
|
|
12406
12492
|
if (blockCallMethod(node) !== "create_table") return;
|
|
12407
12493
|
const table = readCreateTable(node);
|
|
12408
12494
|
if (!table || seen.has(table.name)) return;
|
|
12409
12495
|
seen.add(table.name);
|
|
12410
12496
|
out.push({
|
|
12411
|
-
infraId:
|
|
12497
|
+
infraId: infraId14("sql-table", table.name),
|
|
12412
12498
|
name: table.name,
|
|
12413
12499
|
kind: "sql-table",
|
|
12414
12500
|
edgeType: "CALLS",
|
|
12415
12501
|
confidenceKind: "structural",
|
|
12416
12502
|
...table.columns.length > 0 ? { columns: table.columns } : {},
|
|
12417
12503
|
evidence: {
|
|
12418
|
-
file:
|
|
12504
|
+
file: path51.relative(serviceDir, file.path),
|
|
12419
12505
|
line: table.line,
|
|
12420
12506
|
snippet: snippet(file.content, table.line)
|
|
12421
12507
|
}
|
|
@@ -12425,7 +12511,7 @@ function railsSchemaEndpointsFromFile(file, serviceDir) {
|
|
|
12425
12511
|
}
|
|
12426
12512
|
function railsSchemaForeignKeys(file, serviceDir) {
|
|
12427
12513
|
if (!AR_SCHEMA_RE.test(file.content)) return [];
|
|
12428
|
-
const tree =
|
|
12514
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
12429
12515
|
const out = [];
|
|
12430
12516
|
const seen = /* @__PURE__ */ new Set();
|
|
12431
12517
|
const emit = (childTable, parentTable, line) => {
|
|
@@ -12437,13 +12523,13 @@ function railsSchemaForeignKeys(file, serviceDir) {
|
|
|
12437
12523
|
childTable,
|
|
12438
12524
|
parentTable,
|
|
12439
12525
|
evidence: {
|
|
12440
|
-
file:
|
|
12526
|
+
file: path51.relative(serviceDir, file.path),
|
|
12441
12527
|
line,
|
|
12442
12528
|
snippet: snippet(file.content, line)
|
|
12443
12529
|
}
|
|
12444
12530
|
});
|
|
12445
12531
|
};
|
|
12446
|
-
|
|
12532
|
+
walk6(tree.rootNode, (node) => {
|
|
12447
12533
|
if (node.type !== "call") return;
|
|
12448
12534
|
const method = blockCallMethod(node);
|
|
12449
12535
|
if (method === "add_foreign_key") {
|
|
@@ -12504,23 +12590,23 @@ function modelTable(cls) {
|
|
|
12504
12590
|
return tableize(nameNode.text);
|
|
12505
12591
|
}
|
|
12506
12592
|
function railsModelEndpointsFromFile(file, serviceDir) {
|
|
12507
|
-
const tree =
|
|
12593
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
12508
12594
|
const out = [];
|
|
12509
12595
|
const seen = /* @__PURE__ */ new Set();
|
|
12510
|
-
|
|
12596
|
+
walk6(tree.rootNode, (node) => {
|
|
12511
12597
|
if (node.type !== "class" || !isActiveRecordModel(node)) return;
|
|
12512
12598
|
const table = modelTable(node);
|
|
12513
12599
|
if (!table || seen.has(table)) return;
|
|
12514
12600
|
seen.add(table);
|
|
12515
12601
|
const line = node.startPosition.row + 1;
|
|
12516
12602
|
out.push({
|
|
12517
|
-
infraId:
|
|
12603
|
+
infraId: infraId14("sql-table", table),
|
|
12518
12604
|
name: table,
|
|
12519
12605
|
kind: "sql-table",
|
|
12520
12606
|
edgeType: "CALLS",
|
|
12521
12607
|
confidenceKind: "verified-call-site",
|
|
12522
12608
|
evidence: {
|
|
12523
|
-
file:
|
|
12609
|
+
file: path51.relative(serviceDir, file.path),
|
|
12524
12610
|
line,
|
|
12525
12611
|
snippet: snippet(file.content, line)
|
|
12526
12612
|
}
|
|
@@ -12530,10 +12616,10 @@ function railsModelEndpointsFromFile(file, serviceDir) {
|
|
|
12530
12616
|
}
|
|
12531
12617
|
var AR_ASSOCIATIONS = /* @__PURE__ */ new Set(["belongs_to", "has_many", "has_one"]);
|
|
12532
12618
|
function railsModelForeignKeys(file, serviceDir) {
|
|
12533
|
-
const tree =
|
|
12619
|
+
const tree = parseSource9(makeRubyParser2(), file.content);
|
|
12534
12620
|
const out = [];
|
|
12535
12621
|
const seen = /* @__PURE__ */ new Set();
|
|
12536
|
-
|
|
12622
|
+
walk6(tree.rootNode, (node) => {
|
|
12537
12623
|
if (node.type !== "class" || !isActiveRecordModel(node)) return;
|
|
12538
12624
|
const thisTable = modelTable(node);
|
|
12539
12625
|
if (!thisTable) return;
|
|
@@ -12557,7 +12643,7 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12557
12643
|
childTable,
|
|
12558
12644
|
parentTable,
|
|
12559
12645
|
evidence: {
|
|
12560
|
-
file:
|
|
12646
|
+
file: path51.relative(serviceDir, file.path),
|
|
12561
12647
|
line,
|
|
12562
12648
|
snippet: snippet(file.content, line)
|
|
12563
12649
|
}
|
|
@@ -12568,27 +12654,27 @@ function railsModelForeignKeys(file, serviceDir) {
|
|
|
12568
12654
|
}
|
|
12569
12655
|
|
|
12570
12656
|
// src/extract/calls/eloquent.ts
|
|
12571
|
-
import
|
|
12572
|
-
import
|
|
12657
|
+
import path52 from "path";
|
|
12658
|
+
import Parser14 from "tree-sitter";
|
|
12573
12659
|
import Php3 from "tree-sitter-php";
|
|
12574
|
-
import { infraId as
|
|
12660
|
+
import { infraId as infraId15 } from "@neat.is/types";
|
|
12575
12661
|
var LARAVEL_SCHEMA_RE = /\bSchema::(create|createIfNotExists|table)\b/;
|
|
12576
|
-
var
|
|
12662
|
+
var PARSE_CHUNK10 = 16384;
|
|
12577
12663
|
function makePhpParser2() {
|
|
12578
|
-
const p = new
|
|
12664
|
+
const p = new Parser14();
|
|
12579
12665
|
p.setLanguage(Php3.php_only);
|
|
12580
12666
|
return p;
|
|
12581
12667
|
}
|
|
12582
|
-
function
|
|
12668
|
+
function parseSource10(parser, source) {
|
|
12583
12669
|
return parser.parse(
|
|
12584
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
12670
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK10)
|
|
12585
12671
|
);
|
|
12586
12672
|
}
|
|
12587
|
-
function
|
|
12673
|
+
function walk7(node, visit) {
|
|
12588
12674
|
visit(node);
|
|
12589
12675
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
12590
12676
|
const c = node.namedChild(i);
|
|
12591
|
-
if (c)
|
|
12677
|
+
if (c) walk7(c, visit);
|
|
12592
12678
|
}
|
|
12593
12679
|
}
|
|
12594
12680
|
function phpStaticString2(node) {
|
|
@@ -12799,9 +12885,9 @@ function columnsFromCall(chain, blueprintVar) {
|
|
|
12799
12885
|
}
|
|
12800
12886
|
function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
12801
12887
|
if (!LARAVEL_SCHEMA_RE.test(file.content)) return [];
|
|
12802
|
-
const tree =
|
|
12888
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
12803
12889
|
const out = [];
|
|
12804
|
-
|
|
12890
|
+
walk7(tree.rootNode, (node) => {
|
|
12805
12891
|
if (!isSchemaCall(node)) return;
|
|
12806
12892
|
const bp = readBlueprint(node);
|
|
12807
12893
|
if (!bp) return;
|
|
@@ -12818,14 +12904,14 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
12818
12904
|
}
|
|
12819
12905
|
}
|
|
12820
12906
|
out.push({
|
|
12821
|
-
infraId:
|
|
12907
|
+
infraId: infraId15("sql-table", bp.table),
|
|
12822
12908
|
name: bp.table,
|
|
12823
12909
|
kind: "sql-table",
|
|
12824
12910
|
edgeType: "CALLS",
|
|
12825
12911
|
confidenceKind: "structural",
|
|
12826
12912
|
...columns.length > 0 ? { columns } : {},
|
|
12827
12913
|
evidence: {
|
|
12828
|
-
file:
|
|
12914
|
+
file: path52.relative(serviceDir, file.path),
|
|
12829
12915
|
line: bp.line,
|
|
12830
12916
|
snippet: snippet(file.content, bp.line)
|
|
12831
12917
|
}
|
|
@@ -12835,7 +12921,7 @@ function laravelMigrationEndpointsFromFile(file, serviceDir) {
|
|
|
12835
12921
|
}
|
|
12836
12922
|
function laravelMigrationForeignKeys(file, serviceDir) {
|
|
12837
12923
|
if (!LARAVEL_SCHEMA_RE.test(file.content)) return [];
|
|
12838
|
-
const tree =
|
|
12924
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
12839
12925
|
const out = [];
|
|
12840
12926
|
const seen = /* @__PURE__ */ new Set();
|
|
12841
12927
|
const emit = (childTable, parentTable, line) => {
|
|
@@ -12847,13 +12933,13 @@ function laravelMigrationForeignKeys(file, serviceDir) {
|
|
|
12847
12933
|
childTable,
|
|
12848
12934
|
parentTable,
|
|
12849
12935
|
evidence: {
|
|
12850
|
-
file:
|
|
12936
|
+
file: path52.relative(serviceDir, file.path),
|
|
12851
12937
|
line,
|
|
12852
12938
|
snippet: snippet(file.content, line)
|
|
12853
12939
|
}
|
|
12854
12940
|
});
|
|
12855
12941
|
};
|
|
12856
|
-
|
|
12942
|
+
walk7(tree.rootNode, (node) => {
|
|
12857
12943
|
if (!isSchemaCall(node)) return;
|
|
12858
12944
|
const bp = readBlueprint(node);
|
|
12859
12945
|
if (!bp || !bp.closureBody) return;
|
|
@@ -12951,23 +13037,23 @@ function walkWithinClass(cls, visit) {
|
|
|
12951
13037
|
recur(body);
|
|
12952
13038
|
}
|
|
12953
13039
|
function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
12954
|
-
const tree =
|
|
13040
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
12955
13041
|
const out = [];
|
|
12956
13042
|
const seen = /* @__PURE__ */ new Set();
|
|
12957
|
-
|
|
13043
|
+
walk7(tree.rootNode, (node) => {
|
|
12958
13044
|
if (node.type !== "class_declaration" || !isEloquentModel(node)) return;
|
|
12959
13045
|
const table = modelTable2(node);
|
|
12960
13046
|
if (!table || seen.has(table)) return;
|
|
12961
13047
|
seen.add(table);
|
|
12962
13048
|
const line = node.startPosition.row + 1;
|
|
12963
13049
|
out.push({
|
|
12964
|
-
infraId:
|
|
13050
|
+
infraId: infraId15("sql-table", table),
|
|
12965
13051
|
name: table,
|
|
12966
13052
|
kind: "sql-table",
|
|
12967
13053
|
edgeType: "CALLS",
|
|
12968
13054
|
confidenceKind: "verified-call-site",
|
|
12969
13055
|
evidence: {
|
|
12970
|
-
file:
|
|
13056
|
+
file: path52.relative(serviceDir, file.path),
|
|
12971
13057
|
line,
|
|
12972
13058
|
snippet: snippet(file.content, line)
|
|
12973
13059
|
}
|
|
@@ -12977,10 +13063,10 @@ function laravelModelEndpointsFromFile(file, serviceDir) {
|
|
|
12977
13063
|
}
|
|
12978
13064
|
var ELOQUENT_RELATIONS = /* @__PURE__ */ new Set(["belongsTo", "hasMany", "hasOne"]);
|
|
12979
13065
|
function laravelModelForeignKeys(file, serviceDir) {
|
|
12980
|
-
const tree =
|
|
13066
|
+
const tree = parseSource10(makePhpParser2(), file.content);
|
|
12981
13067
|
const out = [];
|
|
12982
13068
|
const seen = /* @__PURE__ */ new Set();
|
|
12983
|
-
|
|
13069
|
+
walk7(tree.rootNode, (node) => {
|
|
12984
13070
|
if (node.type !== "class_declaration" || !isEloquentModel(node)) return;
|
|
12985
13071
|
const thisTable = modelTable2(node);
|
|
12986
13072
|
if (!thisTable) return;
|
|
@@ -13003,7 +13089,7 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13003
13089
|
childTable,
|
|
13004
13090
|
parentTable,
|
|
13005
13091
|
evidence: {
|
|
13006
|
-
file:
|
|
13092
|
+
file: path52.relative(serviceDir, file.path),
|
|
13007
13093
|
line,
|
|
13008
13094
|
snippet: snippet(file.content, line)
|
|
13009
13095
|
}
|
|
@@ -13014,11 +13100,11 @@ function laravelModelForeignKeys(file, serviceDir) {
|
|
|
13014
13100
|
}
|
|
13015
13101
|
|
|
13016
13102
|
// src/extract/calls/go.ts
|
|
13017
|
-
import
|
|
13018
|
-
import
|
|
13103
|
+
import path53 from "path";
|
|
13104
|
+
import Parser15 from "tree-sitter";
|
|
13019
13105
|
import Go4 from "tree-sitter-go";
|
|
13020
|
-
import { infraId as
|
|
13021
|
-
var
|
|
13106
|
+
import { infraId as infraId16 } from "@neat.is/types";
|
|
13107
|
+
var PARSE_CHUNK11 = 16384;
|
|
13022
13108
|
var DATABASE_SQL_METHODS = /* @__PURE__ */ new Set([
|
|
13023
13109
|
"Query",
|
|
13024
13110
|
"QueryContext",
|
|
@@ -13044,20 +13130,20 @@ var SQLX_METHODS = /* @__PURE__ */ new Set([
|
|
|
13044
13130
|
var DATABASE_SQL_IMPORT = "database/sql";
|
|
13045
13131
|
var SQLX_IMPORT = "github.com/jmoiron/sqlx";
|
|
13046
13132
|
function makeGoParser3() {
|
|
13047
|
-
const p = new
|
|
13133
|
+
const p = new Parser15();
|
|
13048
13134
|
p.setLanguage(Go4);
|
|
13049
13135
|
return p;
|
|
13050
13136
|
}
|
|
13051
|
-
function
|
|
13137
|
+
function parseSource11(parser, source) {
|
|
13052
13138
|
return parser.parse(
|
|
13053
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
13139
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK11)
|
|
13054
13140
|
);
|
|
13055
13141
|
}
|
|
13056
|
-
function
|
|
13142
|
+
function walk8(node, visit) {
|
|
13057
13143
|
visit(node);
|
|
13058
13144
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13059
13145
|
const child = node.namedChild(i);
|
|
13060
|
-
if (child)
|
|
13146
|
+
if (child) walk8(child, visit);
|
|
13061
13147
|
}
|
|
13062
13148
|
}
|
|
13063
13149
|
function goStringLiteralValue(node) {
|
|
@@ -13070,7 +13156,7 @@ function goStringLiteralValue(node) {
|
|
|
13070
13156
|
}
|
|
13071
13157
|
function goImportsAny(root, names) {
|
|
13072
13158
|
let found = false;
|
|
13073
|
-
|
|
13159
|
+
walk8(root, (node) => {
|
|
13074
13160
|
if (found || node.type !== "import_spec") return;
|
|
13075
13161
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13076
13162
|
const value = goStringLiteralValue(node.namedChild(i));
|
|
@@ -13088,14 +13174,14 @@ function firstStringLiteralArg(argsNode) {
|
|
|
13088
13174
|
return null;
|
|
13089
13175
|
}
|
|
13090
13176
|
function goSqlEndpointsFromFile(file, serviceDir) {
|
|
13091
|
-
if (
|
|
13177
|
+
if (path53.extname(file.path) !== ".go") return [];
|
|
13092
13178
|
if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return [];
|
|
13093
|
-
const tree =
|
|
13179
|
+
const tree = parseSource11(makeGoParser3(), file.content);
|
|
13094
13180
|
const importsDatabaseSql = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([DATABASE_SQL_IMPORT]));
|
|
13095
13181
|
const importsSqlx = goImportsAny(tree.rootNode, /* @__PURE__ */ new Set([SQLX_IMPORT]));
|
|
13096
13182
|
if (!importsDatabaseSql && !importsSqlx) return [];
|
|
13097
13183
|
const out = [];
|
|
13098
|
-
|
|
13184
|
+
walk8(tree.rootNode, (node) => {
|
|
13099
13185
|
if (node.type !== "call_expression") return;
|
|
13100
13186
|
const fn = node.childForFieldName("function");
|
|
13101
13187
|
if (fn?.type !== "selector_expression") return;
|
|
@@ -13110,14 +13196,14 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13110
13196
|
const columns = columnsFromSqlStatement(sql);
|
|
13111
13197
|
const line = node.startPosition.row + 1;
|
|
13112
13198
|
out.push({
|
|
13113
|
-
infraId:
|
|
13199
|
+
infraId: infraId16("sql-table", table),
|
|
13114
13200
|
name: table,
|
|
13115
13201
|
kind: "sql-table",
|
|
13116
13202
|
edgeType: "CALLS",
|
|
13117
13203
|
confidenceKind: "verified-call-site",
|
|
13118
13204
|
...columns.length > 0 ? { columns } : {},
|
|
13119
13205
|
evidence: {
|
|
13120
|
-
file: toPosix(
|
|
13206
|
+
file: toPosix(path53.relative(serviceDir, file.path)),
|
|
13121
13207
|
line,
|
|
13122
13208
|
snippet: snippet(file.content, line)
|
|
13123
13209
|
}
|
|
@@ -13127,27 +13213,27 @@ function goSqlEndpointsFromFile(file, serviceDir) {
|
|
|
13127
13213
|
}
|
|
13128
13214
|
|
|
13129
13215
|
// src/extract/calls/gorm.ts
|
|
13130
|
-
import
|
|
13131
|
-
import
|
|
13216
|
+
import path54 from "path";
|
|
13217
|
+
import Parser16 from "tree-sitter";
|
|
13132
13218
|
import Go5 from "tree-sitter-go";
|
|
13133
|
-
import { infraId as
|
|
13219
|
+
import { infraId as infraId17 } from "@neat.is/types";
|
|
13134
13220
|
var GORM_IMPORT_RE = /gorm\.io\/gorm/;
|
|
13135
|
-
var
|
|
13221
|
+
var PARSE_CHUNK12 = 16384;
|
|
13136
13222
|
function makeGoParser4() {
|
|
13137
|
-
const p = new
|
|
13223
|
+
const p = new Parser16();
|
|
13138
13224
|
p.setLanguage(Go5);
|
|
13139
13225
|
return p;
|
|
13140
13226
|
}
|
|
13141
|
-
function
|
|
13227
|
+
function parseSource12(parser, source) {
|
|
13142
13228
|
return parser.parse(
|
|
13143
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
13229
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK12)
|
|
13144
13230
|
);
|
|
13145
13231
|
}
|
|
13146
|
-
function
|
|
13232
|
+
function walk9(node, visit) {
|
|
13147
13233
|
visit(node);
|
|
13148
13234
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13149
13235
|
const c = node.namedChild(i);
|
|
13150
|
-
if (c)
|
|
13236
|
+
if (c) walk9(c, visit);
|
|
13151
13237
|
}
|
|
13152
13238
|
}
|
|
13153
13239
|
var COMMON_INITIALISMS = [
|
|
@@ -13380,7 +13466,7 @@ function readField(fieldDecl) {
|
|
|
13380
13466
|
}
|
|
13381
13467
|
function collectStructs(tree) {
|
|
13382
13468
|
const structs = /* @__PURE__ */ new Map();
|
|
13383
|
-
|
|
13469
|
+
walk9(tree.rootNode, (node) => {
|
|
13384
13470
|
if (node.type !== "type_spec") return;
|
|
13385
13471
|
const nameNode = node.childForFieldName("name");
|
|
13386
13472
|
const typeNode = node.childForFieldName("type");
|
|
@@ -13429,7 +13515,7 @@ function compositeStructName(arg) {
|
|
|
13429
13515
|
}
|
|
13430
13516
|
function collectCallModels(tree) {
|
|
13431
13517
|
const models = /* @__PURE__ */ new Set();
|
|
13432
|
-
|
|
13518
|
+
walk9(tree.rootNode, (node) => {
|
|
13433
13519
|
if (node.type !== "call_expression") return;
|
|
13434
13520
|
const fn = node.childForFieldName("function");
|
|
13435
13521
|
if (fn?.type !== "selector_expression") return;
|
|
@@ -13449,7 +13535,7 @@ function collectCallModels(tree) {
|
|
|
13449
13535
|
function collectTableNameOverrides(tree) {
|
|
13450
13536
|
const overrides = /* @__PURE__ */ new Map();
|
|
13451
13537
|
const declarers = /* @__PURE__ */ new Set();
|
|
13452
|
-
|
|
13538
|
+
walk9(tree.rootNode, (node) => {
|
|
13453
13539
|
if (node.type !== "method_declaration") return;
|
|
13454
13540
|
if (node.childForFieldName("name")?.text !== "TableName") return;
|
|
13455
13541
|
const receiver = node.childForFieldName("receiver");
|
|
@@ -13466,7 +13552,7 @@ function collectTableNameOverrides(tree) {
|
|
|
13466
13552
|
const body = node.childForFieldName("body");
|
|
13467
13553
|
if (!body) return;
|
|
13468
13554
|
let literal = null;
|
|
13469
|
-
|
|
13555
|
+
walk9(body, (n) => {
|
|
13470
13556
|
if (literal !== null) return;
|
|
13471
13557
|
if (n.type !== "return_statement") return;
|
|
13472
13558
|
const exprList = n.namedChild(0);
|
|
@@ -13560,9 +13646,9 @@ function collectColumns(struct, structs, seen, prefix, out, emitted) {
|
|
|
13560
13646
|
seen.delete(struct.name);
|
|
13561
13647
|
}
|
|
13562
13648
|
function gormEndpointsFromFile(file, serviceDir) {
|
|
13563
|
-
if (
|
|
13649
|
+
if (path54.extname(file.path) !== ".go") return [];
|
|
13564
13650
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13565
|
-
const tree =
|
|
13651
|
+
const tree = parseSource12(makeGoParser4(), file.content);
|
|
13566
13652
|
const { structs, models, tableFor } = analyze(tree);
|
|
13567
13653
|
const out = [];
|
|
13568
13654
|
const seenTables = /* @__PURE__ */ new Set();
|
|
@@ -13575,14 +13661,14 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13575
13661
|
const columns = [];
|
|
13576
13662
|
collectColumns(struct, structs, /* @__PURE__ */ new Set(), "", columns, /* @__PURE__ */ new Set());
|
|
13577
13663
|
out.push({
|
|
13578
|
-
infraId:
|
|
13664
|
+
infraId: infraId17("sql-table", table),
|
|
13579
13665
|
name: table,
|
|
13580
13666
|
kind: "sql-table",
|
|
13581
13667
|
edgeType: "CALLS",
|
|
13582
13668
|
confidenceKind: "structural",
|
|
13583
13669
|
...columns.length > 0 ? { columns } : {},
|
|
13584
13670
|
evidence: {
|
|
13585
|
-
file: toPosix(
|
|
13671
|
+
file: toPosix(path54.relative(serviceDir, file.path)),
|
|
13586
13672
|
line: struct.line,
|
|
13587
13673
|
snippet: snippet(file.content, struct.line)
|
|
13588
13674
|
}
|
|
@@ -13591,9 +13677,9 @@ function gormEndpointsFromFile(file, serviceDir) {
|
|
|
13591
13677
|
return out;
|
|
13592
13678
|
}
|
|
13593
13679
|
function gormForeignKeys(file, serviceDir) {
|
|
13594
|
-
if (
|
|
13680
|
+
if (path54.extname(file.path) !== ".go") return [];
|
|
13595
13681
|
if (!GORM_IMPORT_RE.test(file.content)) return [];
|
|
13596
|
-
const tree =
|
|
13682
|
+
const tree = parseSource12(makeGoParser4(), file.content);
|
|
13597
13683
|
const { structs, models, tableFor } = analyze(tree);
|
|
13598
13684
|
const out = [];
|
|
13599
13685
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -13606,7 +13692,7 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13606
13692
|
childTable,
|
|
13607
13693
|
parentTable,
|
|
13608
13694
|
evidence: {
|
|
13609
|
-
file: toPosix(
|
|
13695
|
+
file: toPosix(path54.relative(serviceDir, file.path)),
|
|
13610
13696
|
line,
|
|
13611
13697
|
snippet: snippet(file.content, line)
|
|
13612
13698
|
}
|
|
@@ -13642,27 +13728,27 @@ function gormForeignKeys(file, serviceDir) {
|
|
|
13642
13728
|
}
|
|
13643
13729
|
|
|
13644
13730
|
// src/extract/calls/efcore.ts
|
|
13645
|
-
import
|
|
13646
|
-
import
|
|
13731
|
+
import path55 from "path";
|
|
13732
|
+
import Parser17 from "tree-sitter";
|
|
13647
13733
|
import CSharp2 from "tree-sitter-c-sharp";
|
|
13648
|
-
import { infraId as
|
|
13734
|
+
import { infraId as infraId18 } from "@neat.is/types";
|
|
13649
13735
|
var EFCORE_GATE = /Microsoft\.EntityFrameworkCore|DataAnnotations\.Schema|\bDbContext\b|\bDbSet\s*</;
|
|
13650
|
-
var
|
|
13736
|
+
var PARSE_CHUNK13 = 16384;
|
|
13651
13737
|
function makeCsParser() {
|
|
13652
|
-
const p = new
|
|
13738
|
+
const p = new Parser17();
|
|
13653
13739
|
p.setLanguage(CSharp2);
|
|
13654
13740
|
return p;
|
|
13655
13741
|
}
|
|
13656
|
-
function
|
|
13742
|
+
function parseSource13(parser, source) {
|
|
13657
13743
|
return parser.parse(
|
|
13658
|
-
(index) => index >= source.length ? "" : source.slice(index, index +
|
|
13744
|
+
(index) => index >= source.length ? "" : source.slice(index, index + PARSE_CHUNK13)
|
|
13659
13745
|
);
|
|
13660
13746
|
}
|
|
13661
|
-
function
|
|
13747
|
+
function walk10(node, visit) {
|
|
13662
13748
|
visit(node);
|
|
13663
13749
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
13664
13750
|
const c = node.namedChild(i);
|
|
13665
|
-
if (c)
|
|
13751
|
+
if (c) walk10(c, visit);
|
|
13666
13752
|
}
|
|
13667
13753
|
}
|
|
13668
13754
|
function firstChildOfType(node, type) {
|
|
@@ -13721,28 +13807,28 @@ function tableFromToTable(call) {
|
|
|
13721
13807
|
return value ? csStringLiteral(value) : null;
|
|
13722
13808
|
}
|
|
13723
13809
|
function efcoreEndpointsFromFile(file, serviceDir) {
|
|
13724
|
-
if (
|
|
13810
|
+
if (path55.extname(file.path) !== ".cs") return [];
|
|
13725
13811
|
if (!EFCORE_GATE.test(file.content)) return [];
|
|
13726
|
-
const tree =
|
|
13812
|
+
const tree = parseSource13(makeCsParser(), file.content);
|
|
13727
13813
|
const out = [];
|
|
13728
13814
|
const seen = /* @__PURE__ */ new Set();
|
|
13729
13815
|
const push = (name, line) => {
|
|
13730
13816
|
if (!name || seen.has(name)) return;
|
|
13731
13817
|
seen.add(name);
|
|
13732
13818
|
out.push({
|
|
13733
|
-
infraId:
|
|
13819
|
+
infraId: infraId18("sql-table", name),
|
|
13734
13820
|
name,
|
|
13735
13821
|
kind: "sql-table",
|
|
13736
13822
|
edgeType: "CALLS",
|
|
13737
13823
|
confidenceKind: "structural",
|
|
13738
13824
|
evidence: {
|
|
13739
|
-
file: toPosix(
|
|
13825
|
+
file: toPosix(path55.relative(serviceDir, file.path)),
|
|
13740
13826
|
line,
|
|
13741
13827
|
snippet: snippet(file.content, line)
|
|
13742
13828
|
}
|
|
13743
13829
|
});
|
|
13744
13830
|
};
|
|
13745
|
-
|
|
13831
|
+
walk10(tree.rootNode, (node) => {
|
|
13746
13832
|
if (node.type === "attribute") {
|
|
13747
13833
|
const table = tableFromAttribute(node);
|
|
13748
13834
|
if (table) push(table, node.startPosition.row + 1);
|
|
@@ -13819,6 +13905,11 @@ async function addExternalEndpointEdges(graph, services) {
|
|
|
13819
13905
|
} catch (err) {
|
|
13820
13906
|
recordExtractionError("efcore data-axis extraction", file.path, err);
|
|
13821
13907
|
}
|
|
13908
|
+
try {
|
|
13909
|
+
endpoints.push(...socketEndpointsFromFile(file, service.dir));
|
|
13910
|
+
} catch (err) {
|
|
13911
|
+
recordExtractionError("python socket call extraction", file.path, err);
|
|
13912
|
+
}
|
|
13822
13913
|
}
|
|
13823
13914
|
endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
|
|
13824
13915
|
endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
|
|
@@ -13922,7 +14013,7 @@ import {
|
|
|
13922
14013
|
Provenance as Provenance16,
|
|
13923
14014
|
confidenceForExtracted as confidenceForExtracted13,
|
|
13924
14015
|
extractedEdgeId as extractedEdgeId10,
|
|
13925
|
-
infraId as
|
|
14016
|
+
infraId as infraId19
|
|
13926
14017
|
} from "@neat.is/types";
|
|
13927
14018
|
async function addTableEdges(graph, services) {
|
|
13928
14019
|
let nodesAdded = 0;
|
|
@@ -13951,8 +14042,8 @@ async function addTableEdges(graph, services) {
|
|
|
13951
14042
|
}
|
|
13952
14043
|
refs.push(...modelRefs);
|
|
13953
14044
|
for (const ref of refs) {
|
|
13954
|
-
const childId =
|
|
13955
|
-
const parentId =
|
|
14045
|
+
const childId = infraId19("sql-table", ref.childTable);
|
|
14046
|
+
const parentId = infraId19("sql-table", ref.parentTable);
|
|
13956
14047
|
if (childId === parentId) continue;
|
|
13957
14048
|
nodesAdded += ensureTableNode(graph, childId, ref.childTable);
|
|
13958
14049
|
nodesAdded += ensureTableNode(graph, parentId, ref.parentTable);
|
|
@@ -13987,14 +14078,14 @@ function ensureTableNode(graph, id, name) {
|
|
|
13987
14078
|
}
|
|
13988
14079
|
|
|
13989
14080
|
// src/extract/infra/docker-compose.ts
|
|
13990
|
-
import
|
|
14081
|
+
import path56 from "path";
|
|
13991
14082
|
import { EdgeType as EdgeType17, Provenance as Provenance18, confidenceForExtracted as confidenceForExtracted15 } from "@neat.is/types";
|
|
13992
14083
|
|
|
13993
14084
|
// src/extract/infra/shared.ts
|
|
13994
|
-
import { NodeType as NodeType26, Provenance as Provenance17, confidenceForExtracted as confidenceForExtracted14, infraId as
|
|
14085
|
+
import { NodeType as NodeType26, Provenance as Provenance17, confidenceForExtracted as confidenceForExtracted14, infraId as infraId20 } from "@neat.is/types";
|
|
13995
14086
|
function makeInfraNode(kind, name, provider = "self", extras) {
|
|
13996
14087
|
return {
|
|
13997
|
-
id:
|
|
14088
|
+
id: infraId20(kind, name),
|
|
13998
14089
|
type: NodeType26.InfraNode,
|
|
13999
14090
|
name,
|
|
14000
14091
|
provider,
|
|
@@ -14057,7 +14148,7 @@ function dependsOnList(value) {
|
|
|
14057
14148
|
}
|
|
14058
14149
|
function serviceNameToServiceNode(name, services) {
|
|
14059
14150
|
for (const s of services) {
|
|
14060
|
-
if (s.node.name === name ||
|
|
14151
|
+
if (s.node.name === name || path56.basename(s.dir) === name) return s.node.id;
|
|
14061
14152
|
}
|
|
14062
14153
|
return null;
|
|
14063
14154
|
}
|
|
@@ -14066,7 +14157,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14066
14157
|
let edgesAdded = 0;
|
|
14067
14158
|
let composePath = null;
|
|
14068
14159
|
for (const name of ["docker-compose.yml", "docker-compose.yaml"]) {
|
|
14069
|
-
const abs =
|
|
14160
|
+
const abs = path56.join(scanPath, name);
|
|
14070
14161
|
if (await exists(abs)) {
|
|
14071
14162
|
composePath = abs;
|
|
14072
14163
|
break;
|
|
@@ -14079,13 +14170,13 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14079
14170
|
} catch (err) {
|
|
14080
14171
|
recordExtractionError(
|
|
14081
14172
|
"infra docker-compose",
|
|
14082
|
-
|
|
14173
|
+
path56.relative(scanPath, composePath),
|
|
14083
14174
|
err
|
|
14084
14175
|
);
|
|
14085
14176
|
return { nodesAdded, edgesAdded };
|
|
14086
14177
|
}
|
|
14087
14178
|
if (!compose?.services) return { nodesAdded, edgesAdded };
|
|
14088
|
-
const evidenceFile =
|
|
14179
|
+
const evidenceFile = path56.relative(scanPath, composePath).split(path56.sep).join("/");
|
|
14089
14180
|
const composeNameToNodeId = /* @__PURE__ */ new Map();
|
|
14090
14181
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
14091
14182
|
const matchedServiceId = serviceNameToServiceNode(composeName, services);
|
|
@@ -14126,7 +14217,7 @@ async function addComposeInfra(graph, scanPath, services) {
|
|
|
14126
14217
|
}
|
|
14127
14218
|
|
|
14128
14219
|
// src/extract/infra/dockerfile.ts
|
|
14129
|
-
import
|
|
14220
|
+
import path57 from "path";
|
|
14130
14221
|
import { promises as fs25 } from "fs";
|
|
14131
14222
|
import { EdgeType as EdgeType18, Provenance as Provenance19, confidenceForExtracted as confidenceForExtracted16 } from "@neat.is/types";
|
|
14132
14223
|
function readDockerfile(content) {
|
|
@@ -14157,7 +14248,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14157
14248
|
let nodesAdded = 0;
|
|
14158
14249
|
let edgesAdded = 0;
|
|
14159
14250
|
for (const service of services) {
|
|
14160
|
-
const dockerfilePath =
|
|
14251
|
+
const dockerfilePath = path57.join(service.dir, "Dockerfile");
|
|
14161
14252
|
if (!await exists(dockerfilePath)) continue;
|
|
14162
14253
|
let content;
|
|
14163
14254
|
try {
|
|
@@ -14165,7 +14256,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14165
14256
|
} catch (err) {
|
|
14166
14257
|
recordExtractionError(
|
|
14167
14258
|
"infra dockerfile",
|
|
14168
|
-
|
|
14259
|
+
path57.relative(scanPath, dockerfilePath),
|
|
14169
14260
|
err
|
|
14170
14261
|
);
|
|
14171
14262
|
continue;
|
|
@@ -14177,8 +14268,8 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14177
14268
|
graph.addNode(node.id, node);
|
|
14178
14269
|
nodesAdded++;
|
|
14179
14270
|
}
|
|
14180
|
-
const relDockerfile = toPosix(
|
|
14181
|
-
const evidenceFile = toPosix(
|
|
14271
|
+
const relDockerfile = toPosix(path57.relative(service.dir, dockerfilePath));
|
|
14272
|
+
const evidenceFile = toPosix(path57.relative(scanPath, dockerfilePath));
|
|
14182
14273
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14183
14274
|
graph,
|
|
14184
14275
|
service.pkg.name,
|
|
@@ -14230,7 +14321,7 @@ async function addDockerfileRuntimes(graph, services, scanPath) {
|
|
|
14230
14321
|
|
|
14231
14322
|
// src/extract/infra/terraform.ts
|
|
14232
14323
|
import { promises as fs26 } from "fs";
|
|
14233
|
-
import
|
|
14324
|
+
import path58 from "path";
|
|
14234
14325
|
import { EdgeType as EdgeType19, Provenance as Provenance20, confidenceForExtracted as confidenceForExtracted17 } from "@neat.is/types";
|
|
14235
14326
|
var RESOURCE_RE = /resource\s+"(aws_[A-Za-z0-9_]+)"\s+"([A-Za-z0-9_-]+)"/g;
|
|
14236
14327
|
var REFERENCE_RE = /(?<![\w.])(aws_[A-Za-z0-9_]+)\.([A-Za-z0-9_-]+)/g;
|
|
@@ -14241,11 +14332,11 @@ async function walkTfFiles(start, depth = 0, max = 5) {
|
|
|
14241
14332
|
for (const entry of entries) {
|
|
14242
14333
|
if (entry.isDirectory()) {
|
|
14243
14334
|
if (IGNORED_DIRS.has(entry.name) || entry.name === ".terraform") continue;
|
|
14244
|
-
const child =
|
|
14335
|
+
const child = path58.join(start, entry.name);
|
|
14245
14336
|
if (await isPythonVenvDir(child)) continue;
|
|
14246
14337
|
out.push(...await walkTfFiles(child, depth + 1, max));
|
|
14247
14338
|
} else if (entry.isFile() && entry.name.endsWith(".tf")) {
|
|
14248
|
-
out.push(
|
|
14339
|
+
out.push(path58.join(start, entry.name));
|
|
14249
14340
|
}
|
|
14250
14341
|
}
|
|
14251
14342
|
return out;
|
|
@@ -14277,7 +14368,7 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14277
14368
|
const files = await walkTfFiles(scanPath);
|
|
14278
14369
|
for (const file of files) {
|
|
14279
14370
|
const content = await fs26.readFile(file, "utf8");
|
|
14280
|
-
const evidenceFile = toPosix(
|
|
14371
|
+
const evidenceFile = toPosix(path58.relative(scanPath, file));
|
|
14281
14372
|
const resources = [];
|
|
14282
14373
|
const byKey = /* @__PURE__ */ new Map();
|
|
14283
14374
|
RESOURCE_RE.lastIndex = 0;
|
|
@@ -14334,8 +14425,9 @@ async function addTerraformResources(graph, scanPath) {
|
|
|
14334
14425
|
|
|
14335
14426
|
// src/extract/infra/k8s.ts
|
|
14336
14427
|
import { promises as fs27 } from "fs";
|
|
14337
|
-
import
|
|
14428
|
+
import path59 from "path";
|
|
14338
14429
|
import { parseAllDocuments as parseAllDocuments2 } from "yaml";
|
|
14430
|
+
import { EdgeType as EdgeType20, serviceId as serviceId13 } from "@neat.is/types";
|
|
14339
14431
|
var K8S_KIND_TO_INFRA_KIND = {
|
|
14340
14432
|
Service: "k8s-service",
|
|
14341
14433
|
Deployment: "k8s-deployment",
|
|
@@ -14345,6 +14437,7 @@ var K8S_KIND_TO_INFRA_KIND = {
|
|
|
14345
14437
|
Job: "k8s-job",
|
|
14346
14438
|
Ingress: "k8s-ingress"
|
|
14347
14439
|
};
|
|
14440
|
+
var WORKLOAD_KINDS = /* @__PURE__ */ new Set(["Deployment", "StatefulSet", "DaemonSet"]);
|
|
14348
14441
|
async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
14349
14442
|
if (depth > max) return [];
|
|
14350
14443
|
const out = [];
|
|
@@ -14352,17 +14445,18 @@ async function walkYamlFiles2(start, depth = 0, max = 5) {
|
|
|
14352
14445
|
for (const entry of entries) {
|
|
14353
14446
|
if (entry.isDirectory()) {
|
|
14354
14447
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
14355
|
-
const child =
|
|
14448
|
+
const child = path59.join(start, entry.name);
|
|
14356
14449
|
if (await isPythonVenvDir(child)) continue;
|
|
14357
14450
|
out.push(...await walkYamlFiles2(child, depth + 1, max));
|
|
14358
|
-
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(
|
|
14359
|
-
out.push(
|
|
14451
|
+
} else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path59.extname(entry.name))) {
|
|
14452
|
+
out.push(path59.join(start, entry.name));
|
|
14360
14453
|
}
|
|
14361
14454
|
}
|
|
14362
14455
|
return out;
|
|
14363
14456
|
}
|
|
14364
14457
|
async function addK8sResources(graph, scanPath) {
|
|
14365
14458
|
let nodesAdded = 0;
|
|
14459
|
+
let edgesAdded = 0;
|
|
14366
14460
|
const files = await walkYamlFiles2(scanPath);
|
|
14367
14461
|
for (const file of files) {
|
|
14368
14462
|
const content = await fs27.readFile(file, "utf8");
|
|
@@ -14372,30 +14466,62 @@ async function addK8sResources(graph, scanPath) {
|
|
|
14372
14466
|
} catch {
|
|
14373
14467
|
continue;
|
|
14374
14468
|
}
|
|
14469
|
+
const relFile = toPosix(path59.relative(scanPath, file));
|
|
14375
14470
|
for (const doc of docs) {
|
|
14376
14471
|
if (!doc?.kind || !doc.metadata?.name) continue;
|
|
14377
14472
|
const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind];
|
|
14378
14473
|
if (!infraKind) continue;
|
|
14379
|
-
const
|
|
14380
|
-
const
|
|
14474
|
+
const name = doc.metadata.name;
|
|
14475
|
+
const isWorkload = WORKLOAD_KINDS.has(doc.kind);
|
|
14476
|
+
const image = isWorkload ? doc.spec?.template?.spec?.containers?.[0]?.image : void 0;
|
|
14477
|
+
const replicas = isWorkload && typeof doc.spec?.replicas === "number" ? doc.spec.replicas : void 0;
|
|
14478
|
+
const base = makeInfraNode(infraKind, name, "kubernetes");
|
|
14479
|
+
const node = {
|
|
14480
|
+
...base,
|
|
14481
|
+
...doc.metadata.namespace ? { namespace: doc.metadata.namespace } : {},
|
|
14482
|
+
...image ? { image } : {},
|
|
14483
|
+
...replicas !== void 0 ? { replicas } : {}
|
|
14484
|
+
};
|
|
14381
14485
|
if (!graph.hasNode(node.id)) {
|
|
14382
14486
|
graph.addNode(node.id, node);
|
|
14383
14487
|
nodesAdded++;
|
|
14384
14488
|
}
|
|
14489
|
+
if (isWorkload) {
|
|
14490
|
+
const svcId = serviceId13(name);
|
|
14491
|
+
if (graph.hasNode(svcId)) {
|
|
14492
|
+
const svc = graph.getNodeAttributes(svcId);
|
|
14493
|
+
graph.replaceNodeAttributes(svcId, {
|
|
14494
|
+
...svc,
|
|
14495
|
+
platform: svc.platform ?? "kubernetes",
|
|
14496
|
+
...image ? { declaredImage: image } : {},
|
|
14497
|
+
...replicas !== void 0 ? { declaredReplicas: replicas } : {}
|
|
14498
|
+
});
|
|
14499
|
+
edgesAdded += emitPlatformResourceEdge(
|
|
14500
|
+
graph,
|
|
14501
|
+
svcId,
|
|
14502
|
+
EdgeType20.RUNS_ON,
|
|
14503
|
+
infraKind,
|
|
14504
|
+
name,
|
|
14505
|
+
"kubernetes",
|
|
14506
|
+
relFile,
|
|
14507
|
+
lineContaining(content, image)
|
|
14508
|
+
).edgesAdded;
|
|
14509
|
+
}
|
|
14510
|
+
}
|
|
14385
14511
|
}
|
|
14386
14512
|
}
|
|
14387
|
-
return { nodesAdded, edgesAdded
|
|
14513
|
+
return { nodesAdded, edgesAdded };
|
|
14388
14514
|
}
|
|
14389
14515
|
|
|
14390
14516
|
// src/extract/infra/cloudflare.ts
|
|
14391
14517
|
import { promises as fs28 } from "fs";
|
|
14392
|
-
import
|
|
14518
|
+
import path60 from "path";
|
|
14393
14519
|
import { parse as parseToml3 } from "smol-toml";
|
|
14394
|
-
import { EdgeType as
|
|
14520
|
+
import { EdgeType as EdgeType21, Provenance as Provenance21, confidenceForExtracted as confidenceForExtracted18 } from "@neat.is/types";
|
|
14395
14521
|
var WRANGLER_FILENAMES = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
|
|
14396
14522
|
async function readWranglerConfig(dir) {
|
|
14397
14523
|
for (const filename of WRANGLER_FILENAMES) {
|
|
14398
|
-
const abs =
|
|
14524
|
+
const abs = path60.join(dir, filename);
|
|
14399
14525
|
if (!await exists(abs)) continue;
|
|
14400
14526
|
const raw = await fs28.readFile(abs, "utf8");
|
|
14401
14527
|
const config = filename === "wrangler.toml" ? parseToml3(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -14458,11 +14584,11 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14458
14584
|
try {
|
|
14459
14585
|
read = await readWranglerConfig(service.dir);
|
|
14460
14586
|
} catch (err) {
|
|
14461
|
-
recordExtractionError("infra cloudflare",
|
|
14587
|
+
recordExtractionError("infra cloudflare", path60.relative(scanPath, service.dir), err);
|
|
14462
14588
|
continue;
|
|
14463
14589
|
}
|
|
14464
14590
|
if (!read || !read.config.name) continue;
|
|
14465
|
-
const evidenceFile = toPosix(
|
|
14591
|
+
const evidenceFile = toPosix(path60.relative(scanPath, path60.join(service.dir, read.relFile)));
|
|
14466
14592
|
discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile });
|
|
14467
14593
|
}
|
|
14468
14594
|
for (const worker of discovered) {
|
|
@@ -14474,7 +14600,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14474
14600
|
}
|
|
14475
14601
|
let anchorId = service.node.id;
|
|
14476
14602
|
if (config.main) {
|
|
14477
|
-
const entryRelPath = toPosix(
|
|
14603
|
+
const entryRelPath = toPosix(path60.normalize(config.main));
|
|
14478
14604
|
const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(
|
|
14479
14605
|
graph,
|
|
14480
14606
|
service.pkg.name,
|
|
@@ -14501,13 +14627,13 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14501
14627
|
nodesAdded++;
|
|
14502
14628
|
}
|
|
14503
14629
|
if (runtimeNode.id !== anchorId) {
|
|
14504
|
-
const runsOnId = extractedEdgeId(anchorId, runtimeNode.id,
|
|
14630
|
+
const runsOnId = extractedEdgeId(anchorId, runtimeNode.id, EdgeType21.RUNS_ON);
|
|
14505
14631
|
if (!graph.hasEdge(runsOnId)) {
|
|
14506
14632
|
const edge = {
|
|
14507
14633
|
id: runsOnId,
|
|
14508
14634
|
source: anchorId,
|
|
14509
14635
|
target: runtimeNode.id,
|
|
14510
|
-
type:
|
|
14636
|
+
type: EdgeType21.RUNS_ON,
|
|
14511
14637
|
provenance: Provenance21.EXTRACTED,
|
|
14512
14638
|
confidence: confidenceForExtracted18("structural"),
|
|
14513
14639
|
evidence: {
|
|
@@ -14523,7 +14649,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14523
14649
|
const result = addResourceEdge(
|
|
14524
14650
|
graph,
|
|
14525
14651
|
anchorId,
|
|
14526
|
-
|
|
14652
|
+
EdgeType21.CONNECTS_TO,
|
|
14527
14653
|
"cloudflare-route",
|
|
14528
14654
|
route,
|
|
14529
14655
|
evidenceFile,
|
|
@@ -14547,7 +14673,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14547
14673
|
const result = addResourceEdge(
|
|
14548
14674
|
graph,
|
|
14549
14675
|
anchorId,
|
|
14550
|
-
|
|
14676
|
+
EdgeType21.DEPENDS_ON,
|
|
14551
14677
|
group.kind,
|
|
14552
14678
|
name,
|
|
14553
14679
|
evidenceFile,
|
|
@@ -14561,7 +14687,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14561
14687
|
const result = addResourceEdge(
|
|
14562
14688
|
graph,
|
|
14563
14689
|
anchorId,
|
|
14564
|
-
|
|
14690
|
+
EdgeType21.DEPENDS_ON,
|
|
14565
14691
|
"cloudflare-cron",
|
|
14566
14692
|
cron,
|
|
14567
14693
|
evidenceFile,
|
|
@@ -14574,7 +14700,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14574
14700
|
const result = addResourceEdge(
|
|
14575
14701
|
graph,
|
|
14576
14702
|
anchorId,
|
|
14577
|
-
|
|
14703
|
+
EdgeType21.DEPENDS_ON,
|
|
14578
14704
|
"cloudflare-env-var",
|
|
14579
14705
|
varName,
|
|
14580
14706
|
evidenceFile,
|
|
@@ -14587,13 +14713,13 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14587
14713
|
if (!svc.service) continue;
|
|
14588
14714
|
const target = workerIndex.get(svc.service);
|
|
14589
14715
|
if (target && target.anchorId !== anchorId) {
|
|
14590
|
-
const edgeId = extractedEdgeId(anchorId, target.anchorId,
|
|
14716
|
+
const edgeId = extractedEdgeId(anchorId, target.anchorId, EdgeType21.CALLS);
|
|
14591
14717
|
if (!graph.hasEdge(edgeId)) {
|
|
14592
14718
|
const edge = {
|
|
14593
14719
|
id: edgeId,
|
|
14594
14720
|
source: anchorId,
|
|
14595
14721
|
target: target.anchorId,
|
|
14596
|
-
type:
|
|
14722
|
+
type: EdgeType21.CALLS,
|
|
14597
14723
|
provenance: Provenance21.EXTRACTED,
|
|
14598
14724
|
confidence: confidenceForExtracted18("structural"),
|
|
14599
14725
|
evidence: { file: evidenceFile, line: lineContaining2(raw, svc.service) }
|
|
@@ -14606,7 +14732,7 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14606
14732
|
const result = addResourceEdge(
|
|
14607
14733
|
graph,
|
|
14608
14734
|
anchorId,
|
|
14609
|
-
|
|
14735
|
+
EdgeType21.DEPENDS_ON,
|
|
14610
14736
|
"cloudflare-service-binding",
|
|
14611
14737
|
svc.service,
|
|
14612
14738
|
evidenceFile,
|
|
@@ -14621,12 +14747,12 @@ async function addCloudflareWorkers(graph, services, scanPath) {
|
|
|
14621
14747
|
|
|
14622
14748
|
// src/extract/infra/vercel.ts
|
|
14623
14749
|
import { promises as fs29 } from "fs";
|
|
14624
|
-
import
|
|
14625
|
-
import { EdgeType as
|
|
14750
|
+
import path61 from "path";
|
|
14751
|
+
import { EdgeType as EdgeType22 } from "@neat.is/types";
|
|
14626
14752
|
var VERCEL_CONFIG_FILENAMES = ["vercel.json", "vercel.jsonc"];
|
|
14627
14753
|
async function readVercelConfig(dir) {
|
|
14628
14754
|
for (const filename of VERCEL_CONFIG_FILENAMES) {
|
|
14629
|
-
const abs =
|
|
14755
|
+
const abs = path61.join(dir, filename);
|
|
14630
14756
|
if (!await exists(abs)) continue;
|
|
14631
14757
|
const raw = await fs29.readFile(abs, "utf8");
|
|
14632
14758
|
const config = JSON.parse(maskCommentsInSource(raw));
|
|
@@ -14635,7 +14761,7 @@ async function readVercelConfig(dir) {
|
|
|
14635
14761
|
return null;
|
|
14636
14762
|
}
|
|
14637
14763
|
async function readLinkedProjectName(dir) {
|
|
14638
|
-
const abs =
|
|
14764
|
+
const abs = path61.join(dir, ".vercel", "project.json");
|
|
14639
14765
|
if (!await exists(abs)) return void 0;
|
|
14640
14766
|
const parsed = JSON.parse(await fs29.readFile(abs, "utf8"));
|
|
14641
14767
|
return typeof parsed.projectName === "string" ? parsed.projectName : void 0;
|
|
@@ -14653,7 +14779,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14653
14779
|
read = await readVercelConfig(service.dir);
|
|
14654
14780
|
projectName = await readLinkedProjectName(service.dir);
|
|
14655
14781
|
} catch (err) {
|
|
14656
|
-
recordExtractionError("infra vercel",
|
|
14782
|
+
recordExtractionError("infra vercel", path61.relative(scanPath, service.dir), err);
|
|
14657
14783
|
continue;
|
|
14658
14784
|
}
|
|
14659
14785
|
if (!read && !projectName) continue;
|
|
@@ -14669,7 +14795,7 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14669
14795
|
const anchorId = service.node.id;
|
|
14670
14796
|
if (!read) continue;
|
|
14671
14797
|
const { config, relFile, raw } = read;
|
|
14672
|
-
const evidenceFile = toPosix(
|
|
14798
|
+
const evidenceFile = toPosix(path61.relative(scanPath, path61.join(service.dir, relFile)));
|
|
14673
14799
|
const add = (edgeType, kind, name) => {
|
|
14674
14800
|
if (!name) return;
|
|
14675
14801
|
const result = emitPlatformResourceEdge(
|
|
@@ -14685,12 +14811,12 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14685
14811
|
nodesAdded += result.nodesAdded;
|
|
14686
14812
|
edgesAdded += result.edgesAdded;
|
|
14687
14813
|
};
|
|
14688
|
-
add(
|
|
14689
|
-
for (const cron of config.crons ?? []) add(
|
|
14690
|
-
for (const varName of Object.keys(config.env ?? {})) add(
|
|
14691
|
-
for (const varName of Object.keys(config.build?.env ?? {})) add(
|
|
14814
|
+
add(EdgeType22.RUNS_ON, "vercel", "vercel");
|
|
14815
|
+
for (const cron of config.crons ?? []) add(EdgeType22.DEPENDS_ON, "vercel-cron", cron.path ?? cron.schedule);
|
|
14816
|
+
for (const varName of Object.keys(config.env ?? {})) add(EdgeType22.DEPENDS_ON, "vercel-env-var", varName);
|
|
14817
|
+
for (const varName of Object.keys(config.build?.env ?? {})) add(EdgeType22.DEPENDS_ON, "vercel-env-var", varName);
|
|
14692
14818
|
for (const route of [...config.rewrites ?? [], ...config.redirects ?? [], ...config.routes ?? []]) {
|
|
14693
|
-
add(
|
|
14819
|
+
add(EdgeType22.CONNECTS_TO, "vercel-route", routeSource(route));
|
|
14694
14820
|
}
|
|
14695
14821
|
}
|
|
14696
14822
|
return { nodesAdded, edgesAdded };
|
|
@@ -14698,13 +14824,13 @@ async function addVercelServices(graph, services, scanPath) {
|
|
|
14698
14824
|
|
|
14699
14825
|
// src/extract/infra/railway.ts
|
|
14700
14826
|
import { promises as fs30 } from "fs";
|
|
14701
|
-
import
|
|
14827
|
+
import path62 from "path";
|
|
14702
14828
|
import { parse as parseToml4 } from "smol-toml";
|
|
14703
|
-
import { EdgeType as
|
|
14829
|
+
import { EdgeType as EdgeType23 } from "@neat.is/types";
|
|
14704
14830
|
var RAILWAY_FILENAMES = ["railway.toml", "railway.json", "railway.jsonc"];
|
|
14705
14831
|
async function readRailwayConfig(dir) {
|
|
14706
14832
|
for (const filename of RAILWAY_FILENAMES) {
|
|
14707
|
-
const abs =
|
|
14833
|
+
const abs = path62.join(dir, filename);
|
|
14708
14834
|
if (!await exists(abs)) continue;
|
|
14709
14835
|
const raw = await fs30.readFile(abs, "utf8");
|
|
14710
14836
|
const config = filename === "railway.toml" ? parseToml4(raw) : JSON.parse(maskCommentsInSource(raw));
|
|
@@ -14720,7 +14846,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14720
14846
|
try {
|
|
14721
14847
|
read = await readRailwayConfig(service.dir);
|
|
14722
14848
|
} catch (err) {
|
|
14723
|
-
recordExtractionError("infra railway",
|
|
14849
|
+
recordExtractionError("infra railway", path62.relative(scanPath, service.dir), err);
|
|
14724
14850
|
continue;
|
|
14725
14851
|
}
|
|
14726
14852
|
if (!read) continue;
|
|
@@ -14730,7 +14856,7 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14730
14856
|
}
|
|
14731
14857
|
const anchorId = service.node.id;
|
|
14732
14858
|
const { config, relFile, raw } = read;
|
|
14733
|
-
const evidenceFile = toPosix(
|
|
14859
|
+
const evidenceFile = toPosix(path62.relative(scanPath, path62.join(service.dir, relFile)));
|
|
14734
14860
|
const add = (edgeType, kind, name) => {
|
|
14735
14861
|
if (!name) return;
|
|
14736
14862
|
const result = emitPlatformResourceEdge(
|
|
@@ -14746,21 +14872,21 @@ async function addRailwayServices(graph, services, scanPath) {
|
|
|
14746
14872
|
nodesAdded += result.nodesAdded;
|
|
14747
14873
|
edgesAdded += result.edgesAdded;
|
|
14748
14874
|
};
|
|
14749
|
-
add(
|
|
14750
|
-
add(
|
|
14751
|
-
add(
|
|
14875
|
+
add(EdgeType23.RUNS_ON, "railway", "railway");
|
|
14876
|
+
add(EdgeType23.CONNECTS_TO, "railway-route", config.deploy?.healthcheckPath);
|
|
14877
|
+
add(EdgeType23.DEPENDS_ON, "railway-cron", config.deploy?.cronSchedule);
|
|
14752
14878
|
}
|
|
14753
14879
|
return { nodesAdded, edgesAdded };
|
|
14754
14880
|
}
|
|
14755
14881
|
|
|
14756
14882
|
// src/extract/infra/supabase.ts
|
|
14757
14883
|
import { promises as fs31 } from "fs";
|
|
14758
|
-
import
|
|
14884
|
+
import path63 from "path";
|
|
14759
14885
|
import { parse as parseToml5 } from "smol-toml";
|
|
14760
|
-
import { EdgeType as
|
|
14886
|
+
import { EdgeType as EdgeType24 } from "@neat.is/types";
|
|
14761
14887
|
async function readSupabaseConfig(dir) {
|
|
14762
|
-
const relFile =
|
|
14763
|
-
const abs =
|
|
14888
|
+
const relFile = path63.join("supabase", "config.toml");
|
|
14889
|
+
const abs = path63.join(dir, relFile);
|
|
14764
14890
|
if (!await exists(abs)) return null;
|
|
14765
14891
|
const raw = await fs31.readFile(abs, "utf8");
|
|
14766
14892
|
const config = parseToml5(raw);
|
|
@@ -14774,7 +14900,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14774
14900
|
try {
|
|
14775
14901
|
read = await readSupabaseConfig(service.dir);
|
|
14776
14902
|
} catch (err) {
|
|
14777
|
-
recordExtractionError("infra supabase",
|
|
14903
|
+
recordExtractionError("infra supabase", path63.relative(scanPath, service.dir), err);
|
|
14778
14904
|
continue;
|
|
14779
14905
|
}
|
|
14780
14906
|
if (!read) continue;
|
|
@@ -14789,7 +14915,7 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14789
14915
|
});
|
|
14790
14916
|
}
|
|
14791
14917
|
const anchorId = service.node.id;
|
|
14792
|
-
const evidenceFile = toPosix(
|
|
14918
|
+
const evidenceFile = toPosix(path63.relative(scanPath, path63.join(service.dir, relFile)));
|
|
14793
14919
|
const add = (edgeType, kind, name) => {
|
|
14794
14920
|
if (!name) return;
|
|
14795
14921
|
const result = emitPlatformResourceEdge(
|
|
@@ -14805,10 +14931,10 @@ async function addSupabaseProjects(graph, services, scanPath) {
|
|
|
14805
14931
|
nodesAdded += result.nodesAdded;
|
|
14806
14932
|
edgesAdded += result.edgesAdded;
|
|
14807
14933
|
};
|
|
14808
|
-
add(
|
|
14809
|
-
for (const fn of Object.keys(config.functions ?? {})) add(
|
|
14810
|
-
if (config.storage) add(
|
|
14811
|
-
if (config.auth) add(
|
|
14934
|
+
add(EdgeType24.RUNS_ON, "supabase", "supabase");
|
|
14935
|
+
for (const fn of Object.keys(config.functions ?? {})) add(EdgeType24.DEPENDS_ON, "supabase-function", fn);
|
|
14936
|
+
if (config.storage) add(EdgeType24.DEPENDS_ON, "supabase-storage", "storage");
|
|
14937
|
+
if (config.auth) add(EdgeType24.DEPENDS_ON, "supabase-auth", "auth");
|
|
14812
14938
|
}
|
|
14813
14939
|
return { nodesAdded, edgesAdded };
|
|
14814
14940
|
}
|
|
@@ -14830,25 +14956,25 @@ async function addInfra(graph, scanPath, services) {
|
|
|
14830
14956
|
}
|
|
14831
14957
|
|
|
14832
14958
|
// src/extract/zod-shapes.ts
|
|
14833
|
-
import
|
|
14834
|
-
import
|
|
14959
|
+
import path64 from "path";
|
|
14960
|
+
import Parser18 from "tree-sitter";
|
|
14835
14961
|
import JavaScript8 from "tree-sitter-javascript";
|
|
14836
14962
|
import {
|
|
14837
|
-
EdgeType as
|
|
14963
|
+
EdgeType as EdgeType25,
|
|
14838
14964
|
NodeType as NodeType27,
|
|
14839
14965
|
Provenance as Provenance22,
|
|
14840
14966
|
confidenceForExtracted as confidenceForExtracted19,
|
|
14841
14967
|
extractedEdgeId as extractedEdgeId11,
|
|
14842
|
-
infraId as
|
|
14968
|
+
infraId as infraId21
|
|
14843
14969
|
} from "@neat.is/types";
|
|
14844
14970
|
var ZOD_IMPORT_RE = /\bzod\b/;
|
|
14845
14971
|
var ZOD_OBJECTS = /* @__PURE__ */ new Set(["z", "zod"]);
|
|
14846
14972
|
function parserForExt4(ext) {
|
|
14847
|
-
const p = new
|
|
14973
|
+
const p = new Parser18();
|
|
14848
14974
|
p.setLanguage(GRAMMAR_BY_EXT[ext] ?? JavaScript8);
|
|
14849
14975
|
return p;
|
|
14850
14976
|
}
|
|
14851
|
-
function
|
|
14977
|
+
function namedChildren6(node) {
|
|
14852
14978
|
const out = [];
|
|
14853
14979
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14854
14980
|
const c = node.namedChild(i);
|
|
@@ -14858,7 +14984,7 @@ function namedChildren5(node) {
|
|
|
14858
14984
|
}
|
|
14859
14985
|
function stringLiteralText5(node) {
|
|
14860
14986
|
if (!node || node.type !== "string") return null;
|
|
14861
|
-
for (const child of
|
|
14987
|
+
for (const child of namedChildren6(node)) {
|
|
14862
14988
|
if (child.type === "string_fragment") return child.text;
|
|
14863
14989
|
}
|
|
14864
14990
|
return "";
|
|
@@ -14883,12 +15009,12 @@ function zodCallKind(call) {
|
|
|
14883
15009
|
function firstArg(call) {
|
|
14884
15010
|
const args = call.childForFieldName("arguments");
|
|
14885
15011
|
if (!args) return null;
|
|
14886
|
-
return
|
|
15012
|
+
return namedChildren6(args)[0] ?? null;
|
|
14887
15013
|
}
|
|
14888
15014
|
function fieldsFromObject(obj) {
|
|
14889
15015
|
const out = [];
|
|
14890
15016
|
const seen = /* @__PURE__ */ new Set();
|
|
14891
|
-
for (const child of
|
|
15017
|
+
for (const child of namedChildren6(obj)) {
|
|
14892
15018
|
if (child.type === "spread_element") return null;
|
|
14893
15019
|
if (child.type !== "pair") continue;
|
|
14894
15020
|
const key = child.childForFieldName("key");
|
|
@@ -14904,7 +15030,7 @@ function fieldsFromObject(obj) {
|
|
|
14904
15030
|
function membersFromEnum(arr) {
|
|
14905
15031
|
const out = [];
|
|
14906
15032
|
const seen = /* @__PURE__ */ new Set();
|
|
14907
|
-
for (const child of
|
|
15033
|
+
for (const child of namedChildren6(arr)) {
|
|
14908
15034
|
if (child.type !== "string") return null;
|
|
14909
15035
|
const value = stringLiteralText5(child);
|
|
14910
15036
|
if (value !== null && value !== "" && !seen.has(value)) {
|
|
@@ -14916,10 +15042,10 @@ function membersFromEnum(arr) {
|
|
|
14916
15042
|
}
|
|
14917
15043
|
function topLevelSchemas(root) {
|
|
14918
15044
|
const out = [];
|
|
14919
|
-
for (const stmt of
|
|
15045
|
+
for (const stmt of namedChildren6(root)) {
|
|
14920
15046
|
const decl = stmt.type === "export_statement" ? stmt.childForFieldName("declaration") : stmt;
|
|
14921
15047
|
if (decl?.type !== "lexical_declaration" && decl?.type !== "variable_declaration") continue;
|
|
14922
|
-
for (const declarator of
|
|
15048
|
+
for (const declarator of namedChildren6(decl)) {
|
|
14923
15049
|
if (declarator.type !== "variable_declarator") continue;
|
|
14924
15050
|
const name = declarator.childForFieldName("name");
|
|
14925
15051
|
const value = declarator.childForFieldName("value");
|
|
@@ -14932,7 +15058,7 @@ function topLevelSchemas(root) {
|
|
|
14932
15058
|
}
|
|
14933
15059
|
function zodShapesFromFile(file, serviceDir) {
|
|
14934
15060
|
if (!ZOD_IMPORT_RE.test(file.content)) return [];
|
|
14935
|
-
const tree = parseSource3(parserForExt4(
|
|
15061
|
+
const tree = parseSource3(parserForExt4(path64.extname(file.path)), file.content);
|
|
14936
15062
|
const out = [];
|
|
14937
15063
|
const seen = /* @__PURE__ */ new Set();
|
|
14938
15064
|
for (const { name, call } of topLevelSchemas(tree.rootNode)) {
|
|
@@ -14946,11 +15072,11 @@ function zodShapesFromFile(file, serviceDir) {
|
|
|
14946
15072
|
seen.add(name);
|
|
14947
15073
|
const line = call.startPosition.row + 1;
|
|
14948
15074
|
out.push({
|
|
14949
|
-
infraId:
|
|
15075
|
+
infraId: infraId21("zod-schema", name),
|
|
14950
15076
|
name,
|
|
14951
15077
|
fields,
|
|
14952
15078
|
evidence: {
|
|
14953
|
-
file:
|
|
15079
|
+
file: path64.relative(serviceDir, file.path),
|
|
14954
15080
|
line,
|
|
14955
15081
|
snippet: snippet(file.content, line)
|
|
14956
15082
|
}
|
|
@@ -15012,13 +15138,13 @@ async function addZodShapes(graph, services) {
|
|
|
15012
15138
|
);
|
|
15013
15139
|
nodesAdded += n;
|
|
15014
15140
|
edgesAdded += e;
|
|
15015
|
-
const edgeId = extractedEdgeId11(fileNodeId, shape.infraId,
|
|
15141
|
+
const edgeId = extractedEdgeId11(fileNodeId, shape.infraId, EdgeType25.CONTAINS);
|
|
15016
15142
|
if (!graph.hasEdge(edgeId)) {
|
|
15017
15143
|
const edge = {
|
|
15018
15144
|
id: edgeId,
|
|
15019
15145
|
source: fileNodeId,
|
|
15020
15146
|
target: shape.infraId,
|
|
15021
|
-
type:
|
|
15147
|
+
type: EdgeType25.CONTAINS,
|
|
15022
15148
|
provenance: Provenance22.EXTRACTED,
|
|
15023
15149
|
confidence: confidenceForExtracted19("structural"),
|
|
15024
15150
|
evidence: shape.evidence
|
|
@@ -15186,11 +15312,11 @@ async function addFirestoreRules(graph, services) {
|
|
|
15186
15312
|
}
|
|
15187
15313
|
|
|
15188
15314
|
// src/extract/index.ts
|
|
15189
|
-
import
|
|
15315
|
+
import path66 from "path";
|
|
15190
15316
|
|
|
15191
15317
|
// src/extract/retire.ts
|
|
15192
15318
|
import { existsSync as existsSync2 } from "fs";
|
|
15193
|
-
import
|
|
15319
|
+
import path65 from "path";
|
|
15194
15320
|
import { NodeType as NodeType29, Provenance as Provenance23 } from "@neat.is/types";
|
|
15195
15321
|
function dropOrphanedFileNodes(graph) {
|
|
15196
15322
|
const orphans = [];
|
|
@@ -15224,11 +15350,11 @@ function retireExtractedEdgesByMissingFile(graph, scanPath, serviceDirs = []) {
|
|
|
15224
15350
|
if (edge.provenance !== Provenance23.EXTRACTED) return;
|
|
15225
15351
|
const evidenceFile = edge.evidence?.file;
|
|
15226
15352
|
if (!evidenceFile) return;
|
|
15227
|
-
if (
|
|
15353
|
+
if (path65.isAbsolute(evidenceFile)) {
|
|
15228
15354
|
if (!existsSync2(evidenceFile)) toDrop.push(id);
|
|
15229
15355
|
return;
|
|
15230
15356
|
}
|
|
15231
|
-
const found = bases.some((base) => existsSync2(
|
|
15357
|
+
const found = bases.some((base) => existsSync2(path65.join(base, evidenceFile)));
|
|
15232
15358
|
if (!found) toDrop.push(id);
|
|
15233
15359
|
});
|
|
15234
15360
|
for (const id of toDrop) graph.dropEdge(id);
|
|
@@ -15285,7 +15411,7 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15285
15411
|
}
|
|
15286
15412
|
const droppedEntries = drainDroppedExtracted();
|
|
15287
15413
|
if (isRejectedLogEnabled() && opts.errorsPath && droppedEntries.length > 0) {
|
|
15288
|
-
const rejectedPath =
|
|
15414
|
+
const rejectedPath = path66.join(path66.dirname(opts.errorsPath), "rejected.ndjson");
|
|
15289
15415
|
try {
|
|
15290
15416
|
await writeRejectedExtracted(droppedEntries, rejectedPath);
|
|
15291
15417
|
} catch (err) {
|
|
@@ -15321,24 +15447,24 @@ async function extractFromDirectory(graph, scanPath, opts = {}) {
|
|
|
15321
15447
|
import {
|
|
15322
15448
|
databaseId as databaseId3,
|
|
15323
15449
|
DivergenceResultSchema,
|
|
15324
|
-
EdgeType as
|
|
15450
|
+
EdgeType as EdgeType26,
|
|
15325
15451
|
NodeType as NodeType30,
|
|
15326
15452
|
parseEdgeId,
|
|
15327
15453
|
parseFileId,
|
|
15328
15454
|
parseSymbolId as parseSymbolId2,
|
|
15329
15455
|
Provenance as Provenance24,
|
|
15330
|
-
serviceId as
|
|
15456
|
+
serviceId as serviceId14
|
|
15331
15457
|
} from "@neat.is/types";
|
|
15332
15458
|
function bucketKey(source, target, type) {
|
|
15333
15459
|
return `${type}|${source}|${target}`;
|
|
15334
15460
|
}
|
|
15335
15461
|
function bucketSourceFor(graph, edge) {
|
|
15336
|
-
if (edge.type !==
|
|
15462
|
+
if (edge.type !== EdgeType26.CONNECTS_TO) return edge.source;
|
|
15337
15463
|
const parsed = parseFileId(edge.source);
|
|
15338
15464
|
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
15339
15465
|
const target = graph.getNodeAttributes(edge.target);
|
|
15340
15466
|
if (target.type !== NodeType30.DatabaseNode) return edge.source;
|
|
15341
|
-
return
|
|
15467
|
+
return serviceId14(parsed.service);
|
|
15342
15468
|
}
|
|
15343
15469
|
function bucketEdges(graph) {
|
|
15344
15470
|
const buckets2 = /* @__PURE__ */ new Map();
|
|
@@ -15404,14 +15530,14 @@ function gradedConfidence(edge) {
|
|
|
15404
15530
|
return clampConfidence(confidenceForEdge(edge));
|
|
15405
15531
|
}
|
|
15406
15532
|
var OBSERVABLE_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15533
|
+
EdgeType26.CALLS,
|
|
15534
|
+
EdgeType26.CONNECTS_TO,
|
|
15535
|
+
EdgeType26.PUBLISHES_TO,
|
|
15536
|
+
EdgeType26.CONSUMES_FROM
|
|
15411
15537
|
]);
|
|
15412
15538
|
function detectMissingDivergences(graph, bucket) {
|
|
15413
15539
|
const out = [];
|
|
15414
|
-
if (bucket.type ===
|
|
15540
|
+
if (bucket.type === EdgeType26.CONTAINS) return out;
|
|
15415
15541
|
if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out;
|
|
15416
15542
|
if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {
|
|
15417
15543
|
if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {
|
|
@@ -15453,7 +15579,7 @@ function declaredHostFor(svc) {
|
|
|
15453
15579
|
function hasExtractedConfiguredBy(graph, svcId) {
|
|
15454
15580
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
15455
15581
|
const e = graph.getEdgeAttributes(edgeId);
|
|
15456
|
-
if (e.type ===
|
|
15582
|
+
if (e.type === EdgeType26.CONFIGURED_BY && e.provenance === Provenance24.EXTRACTED) {
|
|
15457
15583
|
return true;
|
|
15458
15584
|
}
|
|
15459
15585
|
}
|
|
@@ -15466,7 +15592,7 @@ function detectHostMismatch(graph, svcId, svc) {
|
|
|
15466
15592
|
const out = [];
|
|
15467
15593
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
15468
15594
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
15469
|
-
if (edge.type !==
|
|
15595
|
+
if (edge.type !== EdgeType26.CONNECTS_TO) continue;
|
|
15470
15596
|
if (edge.provenance !== Provenance24.OBSERVED) continue;
|
|
15471
15597
|
const target = graph.getNodeAttributes(edge.target);
|
|
15472
15598
|
if (target.type !== NodeType30.DatabaseNode) continue;
|
|
@@ -15491,7 +15617,7 @@ function detectCompatDivergences(graph, svcId, svc) {
|
|
|
15491
15617
|
const deps = svc.dependencies ?? {};
|
|
15492
15618
|
for (const edgeId of graph.outboundEdges(svcId)) {
|
|
15493
15619
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
15494
|
-
if (edge.type !==
|
|
15620
|
+
if (edge.type !== EdgeType26.CONNECTS_TO) continue;
|
|
15495
15621
|
if (edge.provenance !== Provenance24.OBSERVED) continue;
|
|
15496
15622
|
const target = graph.getNodeAttributes(edge.target);
|
|
15497
15623
|
if (target.type !== NodeType30.DatabaseNode) continue;
|
|
@@ -15642,7 +15768,7 @@ function symbolLocus(graph, ev) {
|
|
|
15642
15768
|
if (affectedIsCode) return { node: affected, ...location ? { location } : {} };
|
|
15643
15769
|
if (!location) return null;
|
|
15644
15770
|
if (affectedInGraph) return { node: affected, location };
|
|
15645
|
-
const svc =
|
|
15771
|
+
const svc = serviceId14(ev.service);
|
|
15646
15772
|
if (graph.hasNode(svc)) return { node: svc, location };
|
|
15647
15773
|
return null;
|
|
15648
15774
|
}
|
|
@@ -15845,10 +15971,10 @@ function datastoreEverObserved(graph, nodeId) {
|
|
|
15845
15971
|
}
|
|
15846
15972
|
return false;
|
|
15847
15973
|
}
|
|
15848
|
-
function serviceHasObservedSameEngineStore(graph, buckets2,
|
|
15974
|
+
function serviceHasObservedSameEngineStore(graph, buckets2, serviceId17, engine, excludeTarget) {
|
|
15849
15975
|
for (const bucket of buckets2.values()) {
|
|
15850
|
-
if (bucket.type !==
|
|
15851
|
-
if (bucket.source !==
|
|
15976
|
+
if (bucket.type !== EdgeType26.CONNECTS_TO) continue;
|
|
15977
|
+
if (bucket.source !== serviceId17) continue;
|
|
15852
15978
|
if (bucket.target === excludeTarget) continue;
|
|
15853
15979
|
if (!graph.hasNode(bucket.target)) continue;
|
|
15854
15980
|
const target = graph.getNodeAttributes(bucket.target);
|
|
@@ -15862,7 +15988,7 @@ var DEAD_CODE_PROBE_CONFIDENCE = 0.1;
|
|
|
15862
15988
|
function dampenDeadCodeProbes(graph, buckets2, all) {
|
|
15863
15989
|
return all.map((d) => {
|
|
15864
15990
|
if (d.type !== "missing-observed") return d;
|
|
15865
|
-
if (!d.extracted || d.edgeType !==
|
|
15991
|
+
if (!d.extracted || d.edgeType !== EdgeType26.CONNECTS_TO) return d;
|
|
15866
15992
|
if (!graph.hasNode(d.target)) return d;
|
|
15867
15993
|
const target = graph.getNodeAttributes(d.target);
|
|
15868
15994
|
if (target.type !== NodeType30.DatabaseNode) return d;
|
|
@@ -15980,7 +16106,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
15980
16106
|
|
|
15981
16107
|
// src/persist.ts
|
|
15982
16108
|
import { promises as fs32 } from "fs";
|
|
15983
|
-
import
|
|
16109
|
+
import path67 from "path";
|
|
15984
16110
|
import { NodeType as NodeType31, Provenance as Provenance25, observedEdgeId as observedEdgeId2 } from "@neat.is/types";
|
|
15985
16111
|
var SCHEMA_VERSION = 7;
|
|
15986
16112
|
function migrateV1ToV2(payload) {
|
|
@@ -16035,7 +16161,7 @@ function migrateV2ToV3(payload) {
|
|
|
16035
16161
|
return { ...payload, schemaVersion: 3 };
|
|
16036
16162
|
}
|
|
16037
16163
|
async function ensureDir(filePath) {
|
|
16038
|
-
await fs32.mkdir(
|
|
16164
|
+
await fs32.mkdir(path67.dirname(filePath), { recursive: true });
|
|
16039
16165
|
}
|
|
16040
16166
|
async function saveGraphToDisk(graph, outPath) {
|
|
16041
16167
|
await ensureDir(outPath);
|
|
@@ -16200,23 +16326,23 @@ function canonicalJson(value) {
|
|
|
16200
16326
|
}
|
|
16201
16327
|
|
|
16202
16328
|
// src/projects.ts
|
|
16203
|
-
import
|
|
16329
|
+
import path68 from "path";
|
|
16204
16330
|
function pathsForProject(project, baseDir) {
|
|
16205
16331
|
if (project === DEFAULT_PROJECT) {
|
|
16206
16332
|
return {
|
|
16207
|
-
snapshotPath:
|
|
16208
|
-
errorsPath:
|
|
16209
|
-
staleEventsPath:
|
|
16210
|
-
embeddingsCachePath:
|
|
16211
|
-
policyViolationsPath:
|
|
16333
|
+
snapshotPath: path68.join(baseDir, "graph.json"),
|
|
16334
|
+
errorsPath: path68.join(baseDir, "errors.ndjson"),
|
|
16335
|
+
staleEventsPath: path68.join(baseDir, "stale-events.ndjson"),
|
|
16336
|
+
embeddingsCachePath: path68.join(baseDir, "embeddings.json"),
|
|
16337
|
+
policyViolationsPath: path68.join(baseDir, "policy-violations.ndjson")
|
|
16212
16338
|
};
|
|
16213
16339
|
}
|
|
16214
16340
|
return {
|
|
16215
|
-
snapshotPath:
|
|
16216
|
-
errorsPath:
|
|
16217
|
-
staleEventsPath:
|
|
16218
|
-
embeddingsCachePath:
|
|
16219
|
-
policyViolationsPath:
|
|
16341
|
+
snapshotPath: path68.join(baseDir, `${project}.json`),
|
|
16342
|
+
errorsPath: path68.join(baseDir, `errors.${project}.ndjson`),
|
|
16343
|
+
staleEventsPath: path68.join(baseDir, `stale-events.${project}.ndjson`),
|
|
16344
|
+
embeddingsCachePath: path68.join(baseDir, `embeddings.${project}.json`),
|
|
16345
|
+
policyViolationsPath: path68.join(baseDir, `policy-violations.${project}.ndjson`)
|
|
16220
16346
|
};
|
|
16221
16347
|
}
|
|
16222
16348
|
var Projects = class {
|
|
@@ -16257,7 +16383,7 @@ function parseExtraProjects(raw) {
|
|
|
16257
16383
|
// src/registry.ts
|
|
16258
16384
|
import { promises as fs34 } from "fs";
|
|
16259
16385
|
import os2 from "os";
|
|
16260
|
-
import
|
|
16386
|
+
import path69 from "path";
|
|
16261
16387
|
import {
|
|
16262
16388
|
RegistryFileSchema
|
|
16263
16389
|
} from "@neat.is/types";
|
|
@@ -16265,20 +16391,20 @@ var LOCK_TIMEOUT_MS = 5e3;
|
|
|
16265
16391
|
var LOCK_RETRY_MS = 50;
|
|
16266
16392
|
function neatHome() {
|
|
16267
16393
|
const override = process.env.NEAT_HOME;
|
|
16268
|
-
if (override && override.length > 0) return
|
|
16269
|
-
return
|
|
16394
|
+
if (override && override.length > 0) return path69.resolve(override);
|
|
16395
|
+
return path69.join(os2.homedir(), ".neat");
|
|
16270
16396
|
}
|
|
16271
16397
|
function registryPath() {
|
|
16272
|
-
return
|
|
16398
|
+
return path69.join(neatHome(), "projects.json");
|
|
16273
16399
|
}
|
|
16274
16400
|
function registryLockPath() {
|
|
16275
|
-
return
|
|
16401
|
+
return path69.join(neatHome(), "projects.json.lock");
|
|
16276
16402
|
}
|
|
16277
16403
|
function daemonPidPath() {
|
|
16278
|
-
return
|
|
16404
|
+
return path69.join(neatHome(), "neatd.pid");
|
|
16279
16405
|
}
|
|
16280
16406
|
function daemonsDir() {
|
|
16281
|
-
return
|
|
16407
|
+
return path69.join(neatHome(), "daemons");
|
|
16282
16408
|
}
|
|
16283
16409
|
function isFiniteInt(v) {
|
|
16284
16410
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -16319,7 +16445,7 @@ async function discoverDaemons(probe = defaultDiscoveryProbe) {
|
|
|
16319
16445
|
const out = [];
|
|
16320
16446
|
for (const name of names) {
|
|
16321
16447
|
if (!name.endsWith(".json")) continue;
|
|
16322
|
-
const file =
|
|
16448
|
+
const file = path69.join(dir, name);
|
|
16323
16449
|
let raw;
|
|
16324
16450
|
try {
|
|
16325
16451
|
raw = await fs34.readFile(file, "utf8");
|
|
@@ -16440,7 +16566,7 @@ function lockHolderMessage(holder, lockPath, timeoutMs) {
|
|
|
16440
16566
|
}
|
|
16441
16567
|
}
|
|
16442
16568
|
async function normalizeProjectPath(input) {
|
|
16443
|
-
const resolved =
|
|
16569
|
+
const resolved = path69.resolve(input);
|
|
16444
16570
|
try {
|
|
16445
16571
|
return await fs34.realpath(resolved);
|
|
16446
16572
|
} catch {
|
|
@@ -16448,7 +16574,7 @@ async function normalizeProjectPath(input) {
|
|
|
16448
16574
|
}
|
|
16449
16575
|
}
|
|
16450
16576
|
async function writeAtomically(target, contents) {
|
|
16451
|
-
await fs34.mkdir(
|
|
16577
|
+
await fs34.mkdir(path69.dirname(target), { recursive: true });
|
|
16452
16578
|
const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
16453
16579
|
const fd = await fs34.open(tmp, "w");
|
|
16454
16580
|
try {
|
|
@@ -16461,7 +16587,7 @@ async function writeAtomically(target, contents) {
|
|
|
16461
16587
|
}
|
|
16462
16588
|
async function acquireLock(lockPath, timeoutMs = LOCK_TIMEOUT_MS, probe = defaultLockHolderProbe) {
|
|
16463
16589
|
const deadline = Date.now() + timeoutMs;
|
|
16464
|
-
await fs34.mkdir(
|
|
16590
|
+
await fs34.mkdir(path69.dirname(lockPath), { recursive: true });
|
|
16465
16591
|
let probedHolder = false;
|
|
16466
16592
|
while (true) {
|
|
16467
16593
|
try {
|
|
@@ -16657,13 +16783,13 @@ import { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } f
|
|
|
16657
16783
|
|
|
16658
16784
|
// src/extend/index.ts
|
|
16659
16785
|
import { promises as fs36 } from "fs";
|
|
16660
|
-
import
|
|
16786
|
+
import path71 from "path";
|
|
16661
16787
|
import os3 from "os";
|
|
16662
16788
|
import { resolve as registryResolve, list as registryList } from "@neat.is/instrumentation-registry";
|
|
16663
16789
|
|
|
16664
16790
|
// src/installers/package-manager.ts
|
|
16665
16791
|
import { promises as fs35 } from "fs";
|
|
16666
|
-
import
|
|
16792
|
+
import path70 from "path";
|
|
16667
16793
|
import { spawn } from "child_process";
|
|
16668
16794
|
var LOCKFILE_PRIORITY = [
|
|
16669
16795
|
{ lockfile: "bun.lockb", pm: "bun", args: ["install", "--no-summary"] },
|
|
@@ -16685,22 +16811,22 @@ async function exists2(p) {
|
|
|
16685
16811
|
}
|
|
16686
16812
|
}
|
|
16687
16813
|
async function detectPackageManager(serviceDir) {
|
|
16688
|
-
let dir =
|
|
16814
|
+
let dir = path70.resolve(serviceDir);
|
|
16689
16815
|
const stops = /* @__PURE__ */ new Set();
|
|
16690
16816
|
for (let i = 0; i < 64; i++) {
|
|
16691
16817
|
if (stops.has(dir)) break;
|
|
16692
16818
|
stops.add(dir);
|
|
16693
16819
|
for (const candidate of LOCKFILE_PRIORITY) {
|
|
16694
|
-
const lockPath =
|
|
16820
|
+
const lockPath = path70.join(dir, candidate.lockfile);
|
|
16695
16821
|
if (await exists2(lockPath)) {
|
|
16696
16822
|
return { pm: candidate.pm, cwd: dir, args: [...candidate.args] };
|
|
16697
16823
|
}
|
|
16698
16824
|
}
|
|
16699
|
-
const parent =
|
|
16825
|
+
const parent = path70.dirname(dir);
|
|
16700
16826
|
if (parent === dir) break;
|
|
16701
16827
|
dir = parent;
|
|
16702
16828
|
}
|
|
16703
|
-
return { pm: "npm", cwd:
|
|
16829
|
+
return { pm: "npm", cwd: path70.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] };
|
|
16704
16830
|
}
|
|
16705
16831
|
async function runPackageManagerInstall(cmd) {
|
|
16706
16832
|
return new Promise((resolve) => {
|
|
@@ -16749,7 +16875,7 @@ async function fileExists2(p) {
|
|
|
16749
16875
|
}
|
|
16750
16876
|
}
|
|
16751
16877
|
async function readPackageJson(scanPath) {
|
|
16752
|
-
const pkgPath =
|
|
16878
|
+
const pkgPath = path71.join(scanPath, "package.json");
|
|
16753
16879
|
const raw = await fs36.readFile(pkgPath, "utf8");
|
|
16754
16880
|
return JSON.parse(raw);
|
|
16755
16881
|
}
|
|
@@ -16763,27 +16889,27 @@ var HOOK_WALK_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
16763
16889
|
]);
|
|
16764
16890
|
async function findHookFiles(scanPath) {
|
|
16765
16891
|
const found = [];
|
|
16766
|
-
const
|
|
16892
|
+
const walk11 = async (dir) => {
|
|
16767
16893
|
const entries = await fs36.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
16768
16894
|
for (const entry of entries) {
|
|
16769
16895
|
if (entry.isDirectory()) {
|
|
16770
16896
|
if (entry.name.startsWith(".") || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue;
|
|
16771
|
-
await
|
|
16897
|
+
await walk11(path71.join(dir, entry.name));
|
|
16772
16898
|
} else if (entry.isFile()) {
|
|
16773
16899
|
if ((entry.name.startsWith("instrumentation") || entry.name.startsWith("otel-init")) && /\.(ts|js|cjs|mjs)$/.test(entry.name)) {
|
|
16774
|
-
const rel =
|
|
16775
|
-
found.push(rel.split(
|
|
16900
|
+
const rel = path71.relative(scanPath, path71.join(dir, entry.name));
|
|
16901
|
+
found.push(rel.split(path71.sep).join("/"));
|
|
16776
16902
|
}
|
|
16777
16903
|
}
|
|
16778
16904
|
}
|
|
16779
16905
|
};
|
|
16780
|
-
await
|
|
16906
|
+
await walk11(scanPath);
|
|
16781
16907
|
return found.sort();
|
|
16782
16908
|
}
|
|
16783
16909
|
async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
16784
16910
|
let fallback = null;
|
|
16785
16911
|
for (const file of hookFiles) {
|
|
16786
|
-
const content = await fs36.readFile(
|
|
16912
|
+
const content = await fs36.readFile(path71.join(scanPath, file), "utf8");
|
|
16787
16913
|
const patched = splicedContent(content, snippet2);
|
|
16788
16914
|
if (patched !== null) return { file, content, patched };
|
|
16789
16915
|
if (fallback === null) fallback = { file, content };
|
|
@@ -16791,11 +16917,11 @@ async function pickPrimaryHookFile(scanPath, hookFiles, snippet2) {
|
|
|
16791
16917
|
return { file: fallback.file, content: fallback.content, patched: null };
|
|
16792
16918
|
}
|
|
16793
16919
|
function extendLogPath() {
|
|
16794
|
-
return process.env.NEAT_EXTEND_LOG ??
|
|
16920
|
+
return process.env.NEAT_EXTEND_LOG ?? path71.join(os3.homedir(), ".neat", "extend-log.ndjson");
|
|
16795
16921
|
}
|
|
16796
16922
|
async function appendExtendLog(entry) {
|
|
16797
16923
|
const logPath = extendLogPath();
|
|
16798
|
-
await fs36.mkdir(
|
|
16924
|
+
await fs36.mkdir(path71.dirname(logPath), { recursive: true });
|
|
16799
16925
|
await fs36.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
16800
16926
|
}
|
|
16801
16927
|
function splicedContent(fileContent, snippet2) {
|
|
@@ -16854,7 +16980,7 @@ function lookupInstrumentation(library, installedVersion) {
|
|
|
16854
16980
|
}
|
|
16855
16981
|
async function describeProjectInstrumentation(ctx) {
|
|
16856
16982
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
16857
|
-
const envNeat = await fileExists2(
|
|
16983
|
+
const envNeat = await fileExists2(path71.join(ctx.scanPath, ".env.neat"));
|
|
16858
16984
|
const registryInstrPackages = new Set(
|
|
16859
16985
|
registryList().map((e) => e.instrumentation_package).filter((p) => !!p)
|
|
16860
16986
|
);
|
|
@@ -16876,7 +17002,7 @@ async function applyExtension(ctx, args, options) {
|
|
|
16876
17002
|
);
|
|
16877
17003
|
}
|
|
16878
17004
|
for (const file of hookFiles) {
|
|
16879
|
-
const content = await fs36.readFile(
|
|
17005
|
+
const content = await fs36.readFile(path71.join(ctx.scanPath, file), "utf8");
|
|
16880
17006
|
if (content.includes(args.registration_snippet)) {
|
|
16881
17007
|
return { library: args.library, filesTouched: [], depsAdded: [], installOutput: "", alreadyApplied: true };
|
|
16882
17008
|
}
|
|
@@ -16888,10 +17014,10 @@ async function applyExtension(ctx, args, options) {
|
|
|
16888
17014
|
);
|
|
16889
17015
|
}
|
|
16890
17016
|
const primaryFile = primary.file;
|
|
16891
|
-
const primaryPath =
|
|
17017
|
+
const primaryPath = path71.join(ctx.scanPath, primaryFile);
|
|
16892
17018
|
const filesTouched = [];
|
|
16893
17019
|
const depsAdded = [];
|
|
16894
|
-
const pkgPath =
|
|
17020
|
+
const pkgPath = path71.join(ctx.scanPath, "package.json");
|
|
16895
17021
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
16896
17022
|
if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {
|
|
16897
17023
|
pkg.dependencies = { ...pkg.dependencies ?? {}, [args.instrumentation_package]: args.version };
|
|
@@ -16930,7 +17056,7 @@ async function dryRunExtension(ctx, args) {
|
|
|
16930
17056
|
};
|
|
16931
17057
|
}
|
|
16932
17058
|
for (const file of hookFiles) {
|
|
16933
|
-
const content = await fs36.readFile(
|
|
17059
|
+
const content = await fs36.readFile(path71.join(ctx.scanPath, file), "utf8");
|
|
16934
17060
|
if (content.includes(args.registration_snippet)) {
|
|
16935
17061
|
return {
|
|
16936
17062
|
library: args.library,
|
|
@@ -16971,7 +17097,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
16971
17097
|
if (!match) {
|
|
16972
17098
|
return { undone: false, message: "no apply found for library" };
|
|
16973
17099
|
}
|
|
16974
|
-
const pkgPath =
|
|
17100
|
+
const pkgPath = path71.join(ctx.scanPath, "package.json");
|
|
16975
17101
|
if (await fileExists2(pkgPath)) {
|
|
16976
17102
|
const pkg = await readPackageJson(ctx.scanPath);
|
|
16977
17103
|
if (pkg.dependencies?.[match.instrumentation_package]) {
|
|
@@ -16982,7 +17108,7 @@ async function rollbackExtension(ctx, args) {
|
|
|
16982
17108
|
}
|
|
16983
17109
|
const hookFiles = await findHookFiles(ctx.scanPath);
|
|
16984
17110
|
for (const file of hookFiles) {
|
|
16985
|
-
const filePath =
|
|
17111
|
+
const filePath = path71.join(ctx.scanPath, file);
|
|
16986
17112
|
const content = await fs36.readFile(filePath, "utf8");
|
|
16987
17113
|
if (content.includes(match.registration_snippet)) {
|
|
16988
17114
|
const filtered = content.split("\n").filter((line) => !line.includes(match.registration_snippet)).join("\n");
|
|
@@ -17195,7 +17321,7 @@ function buildIncidentCard(graph, errorEvent, incidents, policies) {
|
|
|
17195
17321
|
}
|
|
17196
17322
|
|
|
17197
17323
|
// src/ask.ts
|
|
17198
|
-
import { AskResultSchema, NodeType as NodeType32, Provenance as Provenance27, serviceId as
|
|
17324
|
+
import { AskResultSchema, NodeType as NodeType32, Provenance as Provenance27, serviceId as serviceId15 } from "@neat.is/types";
|
|
17199
17325
|
var DEFAULT_MAX_NODES = 3;
|
|
17200
17326
|
var MAX_FACTS_PER_SECTION = 6;
|
|
17201
17327
|
var INTENT_RULES = [
|
|
@@ -17618,7 +17744,7 @@ function buildGlobalIncidentsSection(incidents) {
|
|
|
17618
17744
|
}
|
|
17619
17745
|
const byKey = /* @__PURE__ */ new Map();
|
|
17620
17746
|
for (const ev of incidents) {
|
|
17621
|
-
const key = ev.affectedNode ||
|
|
17747
|
+
const key = ev.affectedNode || serviceId15(ev.service);
|
|
17622
17748
|
const cur = byKey.get(key);
|
|
17623
17749
|
if (!cur) {
|
|
17624
17750
|
byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage });
|
|
@@ -17678,7 +17804,7 @@ function buildOverviewSections(graph, incidents) {
|
|
|
17678
17804
|
if (incidents && incidents.length > 0) {
|
|
17679
17805
|
const incCount = /* @__PURE__ */ new Map();
|
|
17680
17806
|
for (const ev of incidents) {
|
|
17681
|
-
const key = ev.affectedNode ||
|
|
17807
|
+
const key = ev.affectedNode || serviceId15(ev.service);
|
|
17682
17808
|
incCount.set(key, (incCount.get(key) ?? 0) + 1);
|
|
17683
17809
|
}
|
|
17684
17810
|
const top = [...incCount.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_FACTS_PER_SECTION);
|
|
@@ -17892,7 +18018,7 @@ data: ${JSON.stringify(envelope.payload)}
|
|
|
17892
18018
|
|
|
17893
18019
|
// src/connectors-config.ts
|
|
17894
18020
|
import os4 from "os";
|
|
17895
|
-
import
|
|
18021
|
+
import path72 from "path";
|
|
17896
18022
|
import { promises as fs37 } from "fs";
|
|
17897
18023
|
var CONNECTORS_CONFIG_VERSION = 1;
|
|
17898
18024
|
var EnvRefUnsetError = class extends Error {
|
|
@@ -17907,11 +18033,11 @@ var EnvRefUnsetError = class extends Error {
|
|
|
17907
18033
|
};
|
|
17908
18034
|
function neatHome2() {
|
|
17909
18035
|
const override = process.env.NEAT_HOME;
|
|
17910
|
-
if (override && override.length > 0) return
|
|
17911
|
-
return
|
|
18036
|
+
if (override && override.length > 0) return path72.resolve(override);
|
|
18037
|
+
return path72.join(os4.homedir(), ".neat");
|
|
17912
18038
|
}
|
|
17913
18039
|
function connectorsConfigPath(home = neatHome2()) {
|
|
17914
|
-
return
|
|
18040
|
+
return path72.join(home, "connectors.json");
|
|
17915
18041
|
}
|
|
17916
18042
|
var MODE_MASK_LOOSER_THAN_0600 = 63;
|
|
17917
18043
|
async function warnIfModeLooserThan0600(file) {
|
|
@@ -18042,7 +18168,7 @@ function connectorMatchesProject(entry, project) {
|
|
|
18042
18168
|
var CONNECTORS_LOCK_TIMEOUT_MS = 5e3;
|
|
18043
18169
|
var CONNECTORS_LOCK_RETRY_MS = 50;
|
|
18044
18170
|
function connectorsConfigLockPath(home = neatHome2()) {
|
|
18045
|
-
return
|
|
18171
|
+
return path72.join(home, "connectors.json.lock");
|
|
18046
18172
|
}
|
|
18047
18173
|
function isEnvRef(value) {
|
|
18048
18174
|
return value.length > 1 && value.startsWith("$");
|
|
@@ -18055,7 +18181,7 @@ function redactCredentialRef(ref) {
|
|
|
18055
18181
|
return out;
|
|
18056
18182
|
}
|
|
18057
18183
|
async function writeConfigAtomically0600(file, contents) {
|
|
18058
|
-
await fs37.mkdir(
|
|
18184
|
+
await fs37.mkdir(path72.dirname(file), { recursive: true });
|
|
18059
18185
|
const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
18060
18186
|
const fd = await fs37.open(tmp, "w", 384);
|
|
18061
18187
|
try {
|
|
@@ -18069,7 +18195,7 @@ async function writeConfigAtomically0600(file, contents) {
|
|
|
18069
18195
|
}
|
|
18070
18196
|
async function acquireConnectorsLock(lockPath, timeoutMs = CONNECTORS_LOCK_TIMEOUT_MS) {
|
|
18071
18197
|
const deadline = Date.now() + timeoutMs;
|
|
18072
|
-
await fs37.mkdir(
|
|
18198
|
+
await fs37.mkdir(path72.dirname(lockPath), { recursive: true });
|
|
18073
18199
|
for (; ; ) {
|
|
18074
18200
|
try {
|
|
18075
18201
|
const fd = await fs37.open(lockPath, "wx");
|
|
@@ -18721,10 +18847,10 @@ var SUPABASE_RPC_TARGET_KIND = "supabase-rpc";
|
|
|
18721
18847
|
// src/connectors/supabase/map.ts
|
|
18722
18848
|
var REST_RPC_PATH_RE = /^\/rest\/v1\/rpc\/([^/?]+)/;
|
|
18723
18849
|
var REST_TABLE_PATH_RE = /^\/rest\/v1\/([^/?]+)/;
|
|
18724
|
-
function targetFromRestPath(
|
|
18725
|
-
const rpcMatch = REST_RPC_PATH_RE.exec(
|
|
18850
|
+
function targetFromRestPath(path73) {
|
|
18851
|
+
const rpcMatch = REST_RPC_PATH_RE.exec(path73);
|
|
18726
18852
|
if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1] };
|
|
18727
|
-
const tableMatch = REST_TABLE_PATH_RE.exec(
|
|
18853
|
+
const tableMatch = REST_TABLE_PATH_RE.exec(path73);
|
|
18728
18854
|
if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1] };
|
|
18729
18855
|
return null;
|
|
18730
18856
|
}
|
|
@@ -18833,23 +18959,23 @@ async function fetchPgStatStatements(connectionString, limit = DEFAULT_STATEMENT
|
|
|
18833
18959
|
}
|
|
18834
18960
|
|
|
18835
18961
|
// src/connectors/supabase/resolve.ts
|
|
18836
|
-
import { EdgeType as
|
|
18962
|
+
import { EdgeType as EdgeType27, infraId as infraId22 } from "@neat.is/types";
|
|
18837
18963
|
function createSupabaseResolveTarget(graph, config) {
|
|
18838
18964
|
return (signal, _ctx) => {
|
|
18839
18965
|
if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {
|
|
18840
18966
|
return null;
|
|
18841
18967
|
}
|
|
18842
|
-
const subResourceId =
|
|
18968
|
+
const subResourceId = infraId22(signal.targetKind, `${config.nodeRef}/${signal.targetName}`);
|
|
18843
18969
|
if (graph.hasNode(subResourceId)) {
|
|
18844
|
-
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType:
|
|
18970
|
+
return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: EdgeType27.CALLS };
|
|
18845
18971
|
}
|
|
18846
|
-
const bareResourceId =
|
|
18972
|
+
const bareResourceId = infraId22(signal.targetKind, signal.targetName);
|
|
18847
18973
|
if (graph.hasNode(bareResourceId)) {
|
|
18848
|
-
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType:
|
|
18974
|
+
return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: EdgeType27.CALLS };
|
|
18849
18975
|
}
|
|
18850
|
-
const projectLevelId =
|
|
18976
|
+
const projectLevelId = infraId22("supabase", config.nodeRef);
|
|
18851
18977
|
if (graph.hasNode(projectLevelId)) {
|
|
18852
|
-
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType:
|
|
18978
|
+
return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: EdgeType27.CALLS };
|
|
18853
18979
|
}
|
|
18854
18980
|
return null;
|
|
18855
18981
|
};
|
|
@@ -18941,7 +19067,7 @@ function createSupabaseConnector(graph, config, deps = {}) {
|
|
|
18941
19067
|
}
|
|
18942
19068
|
|
|
18943
19069
|
// src/connectors/railway/index.ts
|
|
18944
|
-
import { EdgeType as
|
|
19070
|
+
import { EdgeType as EdgeType28, NodeType as NodeType34, serviceId as serviceId16 } from "@neat.is/types";
|
|
18945
19071
|
|
|
18946
19072
|
// src/connectors/railway/client.ts
|
|
18947
19073
|
var DEFAULT_RAILWAY_API_URL = "https://backboard.railway.com/graphql/v2";
|
|
@@ -19195,12 +19321,12 @@ function createRailwayResolveTarget(config) {
|
|
|
19195
19321
|
const serviceName = config.serviceNameById[config.serviceId];
|
|
19196
19322
|
if (!serviceName) return null;
|
|
19197
19323
|
if (signal.targetKind === ROUTE_TARGET_KIND) {
|
|
19198
|
-
return { targetNodeId: signal.targetName, serviceName, edgeType:
|
|
19324
|
+
return { targetNodeId: signal.targetName, serviceName, edgeType: EdgeType28.CALLS };
|
|
19199
19325
|
}
|
|
19200
19326
|
if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {
|
|
19201
19327
|
const peerName = config.serviceNameById[signal.targetName];
|
|
19202
19328
|
if (!peerName) return null;
|
|
19203
|
-
return { targetNodeId:
|
|
19329
|
+
return { targetNodeId: serviceId16(peerName), serviceName, edgeType: EdgeType28.CONNECTS_TO };
|
|
19204
19330
|
}
|
|
19205
19331
|
return null;
|
|
19206
19332
|
};
|
|
@@ -19319,9 +19445,9 @@ function parseFirebaseTargetName(targetName) {
|
|
|
19319
19445
|
const secondSep = rest.indexOf(FIELD_SEP);
|
|
19320
19446
|
if (secondSep === -1) return null;
|
|
19321
19447
|
const method = rest.slice(0, secondSep);
|
|
19322
|
-
const
|
|
19323
|
-
if (!resourceName || !method || !
|
|
19324
|
-
return { resourceName, method, path:
|
|
19448
|
+
const path73 = rest.slice(secondSep + 1);
|
|
19449
|
+
if (!resourceName || !method || !path73) return null;
|
|
19450
|
+
return { resourceName, method, path: path73 };
|
|
19325
19451
|
}
|
|
19326
19452
|
function resourceNameFor(type, labels) {
|
|
19327
19453
|
if (!labels) return null;
|
|
@@ -19359,14 +19485,14 @@ function mapLogEntryToSignal(entry) {
|
|
|
19359
19485
|
if (!req) return null;
|
|
19360
19486
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
19361
19487
|
const method = req.requestMethod.toUpperCase();
|
|
19362
|
-
const
|
|
19363
|
-
if (
|
|
19488
|
+
const path73 = pathFromRequestUrl(req.requestUrl);
|
|
19489
|
+
if (path73 === null) return null;
|
|
19364
19490
|
const timestamp = entry.timestamp;
|
|
19365
19491
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
19366
19492
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD2;
|
|
19367
19493
|
return {
|
|
19368
19494
|
targetKind: resourceType,
|
|
19369
|
-
targetName: packFirebaseTargetName({ resourceName, method, path:
|
|
19495
|
+
targetName: packFirebaseTargetName({ resourceName, method, path: path73 }),
|
|
19370
19496
|
callCount: 1,
|
|
19371
19497
|
errorCount: isError ? 1 : 0,
|
|
19372
19498
|
lastObservedIso: timestamp
|
|
@@ -19382,7 +19508,7 @@ function mapLogEntriesToSignals(entries) {
|
|
|
19382
19508
|
}
|
|
19383
19509
|
|
|
19384
19510
|
// src/connectors/firebase/resolve.ts
|
|
19385
|
-
import { NodeType as NodeType35, EdgeType as
|
|
19511
|
+
import { NodeType as NodeType35, EdgeType as EdgeType29 } from "@neat.is/types";
|
|
19386
19512
|
function neatServiceNameFor(resourceType, resourceName, serviceMap) {
|
|
19387
19513
|
switch (resourceType) {
|
|
19388
19514
|
case "cloud_function":
|
|
@@ -19429,7 +19555,7 @@ function createFirebaseResolveTarget(graph, serviceMap) {
|
|
|
19429
19555
|
return {
|
|
19430
19556
|
targetNodeId: match.routeNodeId,
|
|
19431
19557
|
serviceName,
|
|
19432
|
-
edgeType:
|
|
19558
|
+
edgeType: EdgeType29.CALLS
|
|
19433
19559
|
};
|
|
19434
19560
|
};
|
|
19435
19561
|
}
|
|
@@ -19452,7 +19578,7 @@ function createFirebaseConnector(graph, serviceMap) {
|
|
|
19452
19578
|
}
|
|
19453
19579
|
|
|
19454
19580
|
// src/connectors/cloudflare/connector.ts
|
|
19455
|
-
import { EdgeType as
|
|
19581
|
+
import { EdgeType as EdgeType30, NodeType as NodeType36, fileId as fileId5, infraId as infraId23 } from "@neat.is/types";
|
|
19456
19582
|
|
|
19457
19583
|
// src/connectors/cloudflare/client.ts
|
|
19458
19584
|
import { randomUUID } from "crypto";
|
|
@@ -19563,7 +19689,7 @@ function mapEventToSignal(event) {
|
|
|
19563
19689
|
if (Number.isNaN(observedAt.getTime())) return null;
|
|
19564
19690
|
const statusCode = metadata?.statusCode;
|
|
19565
19691
|
const isError = typeof statusCode === "number" && statusCode >= ERROR_STATUS_THRESHOLD3;
|
|
19566
|
-
const
|
|
19692
|
+
const path73 = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : void 0;
|
|
19567
19693
|
return {
|
|
19568
19694
|
targetKind: CLOUDFLARE_TARGET_KIND,
|
|
19569
19695
|
targetName: scriptName,
|
|
@@ -19571,7 +19697,7 @@ function mapEventToSignal(event) {
|
|
|
19571
19697
|
errorCount: isError ? 1 : 0,
|
|
19572
19698
|
lastObservedIso: observedAt.toISOString(),
|
|
19573
19699
|
method,
|
|
19574
|
-
...
|
|
19700
|
+
...path73 ? { path: path73 } : {},
|
|
19575
19701
|
...typeof statusCode === "number" ? { statusCode } : {},
|
|
19576
19702
|
...typeof metadata?.duration === "number" ? { duration: metadata.duration } : {}
|
|
19577
19703
|
};
|
|
@@ -19617,8 +19743,8 @@ function findTaggedWorkerFileNode(graph, workerName) {
|
|
|
19617
19743
|
});
|
|
19618
19744
|
return found;
|
|
19619
19745
|
}
|
|
19620
|
-
function findMatchingRouteNode(graph, serviceName, method,
|
|
19621
|
-
const normalizedPath = normalizePathTemplate(
|
|
19746
|
+
function findMatchingRouteNode(graph, serviceName, method, path73) {
|
|
19747
|
+
const normalizedPath = normalizePathTemplate(path73);
|
|
19622
19748
|
let found = null;
|
|
19623
19749
|
graph.forEachNode((id, attrs) => {
|
|
19624
19750
|
if (found) return;
|
|
@@ -19635,10 +19761,10 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
19635
19761
|
return (signal) => {
|
|
19636
19762
|
if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null;
|
|
19637
19763
|
const scriptName = signal.targetName;
|
|
19638
|
-
const { method, path:
|
|
19764
|
+
const { method, path: path73 } = signal;
|
|
19639
19765
|
const resolveRouteGrain = (serviceName, wholeFileId) => {
|
|
19640
|
-
if (!method || !
|
|
19641
|
-
return findMatchingRouteNode(graph, serviceName, method,
|
|
19766
|
+
if (!method || !path73) return wholeFileId;
|
|
19767
|
+
return findMatchingRouteNode(graph, serviceName, method, path73) ?? wholeFileId;
|
|
19642
19768
|
};
|
|
19643
19769
|
const mapping = config.workers?.[scriptName];
|
|
19644
19770
|
if (mapping) {
|
|
@@ -19646,7 +19772,7 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
19646
19772
|
return {
|
|
19647
19773
|
targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
|
|
19648
19774
|
serviceName: mapping.service,
|
|
19649
|
-
edgeType:
|
|
19775
|
+
edgeType: EdgeType30.CALLS
|
|
19650
19776
|
};
|
|
19651
19777
|
}
|
|
19652
19778
|
const taggedFileId = findTaggedWorkerFileNode(graph, scriptName);
|
|
@@ -19655,13 +19781,13 @@ function createCloudflareResolveTarget(config, graph) {
|
|
|
19655
19781
|
return {
|
|
19656
19782
|
targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),
|
|
19657
19783
|
serviceName: fileNode.service,
|
|
19658
|
-
edgeType:
|
|
19784
|
+
edgeType: EdgeType30.CALLS
|
|
19659
19785
|
};
|
|
19660
19786
|
}
|
|
19661
19787
|
return {
|
|
19662
|
-
targetNodeId:
|
|
19788
|
+
targetNodeId: infraId23("cloudflare-worker", scriptName),
|
|
19663
19789
|
serviceName: scriptName,
|
|
19664
|
-
edgeType:
|
|
19790
|
+
edgeType: EdgeType30.CALLS,
|
|
19665
19791
|
ensureInfraNode: { kind: "cloudflare-worker", name: scriptName, provider: "cloudflare" }
|
|
19666
19792
|
};
|
|
19667
19793
|
};
|
|
@@ -19843,14 +19969,14 @@ function diffNeonStatementsToSignals(rows, previous, observedAtIso) {
|
|
|
19843
19969
|
}
|
|
19844
19970
|
|
|
19845
19971
|
// src/connectors/neon/resolve.ts
|
|
19846
|
-
import { EdgeType as
|
|
19972
|
+
import { EdgeType as EdgeType31, infraId as infraId24 } from "@neat.is/types";
|
|
19847
19973
|
function createNeonResolveTarget(config) {
|
|
19848
19974
|
return (signal) => {
|
|
19849
19975
|
if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
19850
19976
|
return {
|
|
19851
|
-
targetNodeId:
|
|
19977
|
+
targetNodeId: infraId24("sql-table", signal.targetName),
|
|
19852
19978
|
serviceName: config.serviceName,
|
|
19853
|
-
edgeType:
|
|
19979
|
+
edgeType: EdgeType31.CALLS,
|
|
19854
19980
|
ensureInfraNode: { kind: "sql-table", name: signal.targetName, provider: "neon" }
|
|
19855
19981
|
};
|
|
19856
19982
|
};
|
|
@@ -19968,9 +20094,9 @@ function parseCloudRunTargetName(targetName) {
|
|
|
19968
20094
|
const secondSep = rest.indexOf(FIELD_SEP2);
|
|
19969
20095
|
if (secondSep === -1) return null;
|
|
19970
20096
|
const method = rest.slice(0, secondSep);
|
|
19971
|
-
const
|
|
19972
|
-
if (!serviceName || !method || !
|
|
19973
|
-
return { serviceName, method, path:
|
|
20097
|
+
const path73 = rest.slice(secondSep + 1);
|
|
20098
|
+
if (!serviceName || !method || !path73) return null;
|
|
20099
|
+
return { serviceName, method, path: path73 };
|
|
19974
20100
|
}
|
|
19975
20101
|
|
|
19976
20102
|
// src/connectors/cloud-run/map.ts
|
|
@@ -19999,14 +20125,14 @@ function mapLogEntryToSignal2(entry) {
|
|
|
19999
20125
|
if (!req) return null;
|
|
20000
20126
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
20001
20127
|
const method = req.requestMethod.toUpperCase();
|
|
20002
|
-
const
|
|
20003
|
-
if (
|
|
20128
|
+
const path73 = pathFromRequestUrl2(req.requestUrl);
|
|
20129
|
+
if (path73 === null) return null;
|
|
20004
20130
|
const timestamp = entry.timestamp;
|
|
20005
20131
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
20006
20132
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD4;
|
|
20007
20133
|
return {
|
|
20008
20134
|
targetKind: CLOUD_RUN_TARGET_KIND,
|
|
20009
|
-
targetName: packCloudRunTargetName({ serviceName, method, path:
|
|
20135
|
+
targetName: packCloudRunTargetName({ serviceName, method, path: path73 }),
|
|
20010
20136
|
callCount: 1,
|
|
20011
20137
|
errorCount: isError ? 1 : 0,
|
|
20012
20138
|
lastObservedIso: timestamp
|
|
@@ -20022,7 +20148,7 @@ function mapLogEntriesToSignals2(entries) {
|
|
|
20022
20148
|
}
|
|
20023
20149
|
|
|
20024
20150
|
// src/connectors/cloud-run/resolve.ts
|
|
20025
|
-
import { EdgeType as
|
|
20151
|
+
import { EdgeType as EdgeType32, NodeType as NodeType37, infraId as infraId25 } from "@neat.is/types";
|
|
20026
20152
|
var CLOUD_RUN_SERVICE_INFRA_KIND = "cloud-run-service";
|
|
20027
20153
|
function findMatchingRouteNode2(graph, serviceName, method, normalizedPath) {
|
|
20028
20154
|
let found = null;
|
|
@@ -20044,23 +20170,23 @@ function createCloudRunResolveTarget(graph, config) {
|
|
|
20044
20170
|
if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null;
|
|
20045
20171
|
const identity = parseCloudRunTargetName(signal.targetName);
|
|
20046
20172
|
if (!identity) return null;
|
|
20047
|
-
const { serviceName: gcpServiceName, method, path:
|
|
20173
|
+
const { serviceName: gcpServiceName, method, path: path73 } = identity;
|
|
20048
20174
|
const mappedService = config.serviceMap?.[gcpServiceName];
|
|
20049
20175
|
if (mappedService) {
|
|
20050
20176
|
const routeNodeId = findMatchingRouteNode2(
|
|
20051
20177
|
graph,
|
|
20052
20178
|
mappedService,
|
|
20053
20179
|
method,
|
|
20054
|
-
normalizePathTemplate(
|
|
20180
|
+
normalizePathTemplate(path73)
|
|
20055
20181
|
);
|
|
20056
20182
|
if (routeNodeId) {
|
|
20057
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20183
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: EdgeType32.CALLS };
|
|
20058
20184
|
}
|
|
20059
20185
|
}
|
|
20060
20186
|
return {
|
|
20061
|
-
targetNodeId:
|
|
20187
|
+
targetNodeId: infraId25(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),
|
|
20062
20188
|
serviceName: mappedService ?? gcpServiceName,
|
|
20063
|
-
edgeType:
|
|
20189
|
+
edgeType: EdgeType32.CALLS,
|
|
20064
20190
|
ensureInfraNode: {
|
|
20065
20191
|
kind: CLOUD_RUN_SERVICE_INFRA_KIND,
|
|
20066
20192
|
name: gcpServiceName,
|
|
@@ -20179,9 +20305,9 @@ function parseGcpLbTargetName(targetName) {
|
|
|
20179
20305
|
const secondSep = rest.indexOf(FIELD_SEP3);
|
|
20180
20306
|
if (secondSep === -1) return null;
|
|
20181
20307
|
const method = rest.slice(0, secondSep);
|
|
20182
|
-
const
|
|
20183
|
-
if (!backendServiceName || !method || !
|
|
20184
|
-
return { backendServiceName, method, path:
|
|
20308
|
+
const path73 = rest.slice(secondSep + 1);
|
|
20309
|
+
if (!backendServiceName || !method || !path73) return null;
|
|
20310
|
+
return { backendServiceName, method, path: path73 };
|
|
20185
20311
|
}
|
|
20186
20312
|
|
|
20187
20313
|
// src/connectors/gcp-lb/map.ts
|
|
@@ -20210,14 +20336,14 @@ function mapLogEntryToSignal3(entry) {
|
|
|
20210
20336
|
if (!req) return null;
|
|
20211
20337
|
if (typeof req.requestMethod !== "string" || req.requestMethod.length === 0) return null;
|
|
20212
20338
|
const method = req.requestMethod.toUpperCase();
|
|
20213
|
-
const
|
|
20214
|
-
if (
|
|
20339
|
+
const path73 = pathFromRequestUrl3(req.requestUrl);
|
|
20340
|
+
if (path73 === null) return null;
|
|
20215
20341
|
const timestamp = entry.timestamp;
|
|
20216
20342
|
if (typeof timestamp !== "string" || timestamp.length === 0) return null;
|
|
20217
20343
|
const isError = typeof req.status === "number" && req.status >= ERROR_STATUS_THRESHOLD5;
|
|
20218
20344
|
return {
|
|
20219
20345
|
targetKind: GCP_LB_TARGET_KIND,
|
|
20220
|
-
targetName: packGcpLbTargetName({ backendServiceName, method, path:
|
|
20346
|
+
targetName: packGcpLbTargetName({ backendServiceName, method, path: path73 }),
|
|
20221
20347
|
callCount: 1,
|
|
20222
20348
|
errorCount: isError ? 1 : 0,
|
|
20223
20349
|
lastObservedIso: timestamp
|
|
@@ -20233,7 +20359,7 @@ function mapLogEntriesToSignals3(entries) {
|
|
|
20233
20359
|
}
|
|
20234
20360
|
|
|
20235
20361
|
// src/connectors/gcp-lb/resolve.ts
|
|
20236
|
-
import { EdgeType as
|
|
20362
|
+
import { EdgeType as EdgeType33, NodeType as NodeType38, infraId as infraId26 } from "@neat.is/types";
|
|
20237
20363
|
var GCP_LB_BACKEND_INFRA_KIND = "gcp-lb-backend";
|
|
20238
20364
|
function findMatchingRouteNode3(graph, serviceName, method, normalizedPath) {
|
|
20239
20365
|
let found = null;
|
|
@@ -20255,23 +20381,23 @@ function createGcpLbResolveTarget(graph, config) {
|
|
|
20255
20381
|
if (signal.targetKind !== GCP_LB_TARGET_KIND) return null;
|
|
20256
20382
|
const identity = parseGcpLbTargetName(signal.targetName);
|
|
20257
20383
|
if (!identity) return null;
|
|
20258
|
-
const { backendServiceName, method, path:
|
|
20384
|
+
const { backendServiceName, method, path: path73 } = identity;
|
|
20259
20385
|
const mappedService = config.backendServiceMap?.[backendServiceName];
|
|
20260
20386
|
if (mappedService) {
|
|
20261
20387
|
const routeNodeId = findMatchingRouteNode3(
|
|
20262
20388
|
graph,
|
|
20263
20389
|
mappedService,
|
|
20264
20390
|
method,
|
|
20265
|
-
normalizePathTemplate(
|
|
20391
|
+
normalizePathTemplate(path73)
|
|
20266
20392
|
);
|
|
20267
20393
|
if (routeNodeId) {
|
|
20268
|
-
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType:
|
|
20394
|
+
return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: EdgeType33.CALLS };
|
|
20269
20395
|
}
|
|
20270
20396
|
}
|
|
20271
20397
|
return {
|
|
20272
|
-
targetNodeId:
|
|
20398
|
+
targetNodeId: infraId26(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),
|
|
20273
20399
|
serviceName: mappedService ?? backendServiceName,
|
|
20274
|
-
edgeType:
|
|
20400
|
+
edgeType: EdgeType33.CALLS,
|
|
20275
20401
|
ensureInfraNode: {
|
|
20276
20402
|
kind: GCP_LB_BACKEND_INFRA_KIND,
|
|
20277
20403
|
name: backendServiceName,
|
|
@@ -20311,7 +20437,7 @@ function createGcpLbConnector(graph, config = {}) {
|
|
|
20311
20437
|
}
|
|
20312
20438
|
|
|
20313
20439
|
// src/connectors/render/index.ts
|
|
20314
|
-
import { EdgeType as
|
|
20440
|
+
import { EdgeType as EdgeType34, NodeType as NodeType39 } from "@neat.is/types";
|
|
20315
20441
|
|
|
20316
20442
|
// src/connectors/render/types.ts
|
|
20317
20443
|
function readRenderToken(credentials) {
|
|
@@ -20472,7 +20598,7 @@ function mapRenderRequestLogsToSignals(entries, routeIndex) {
|
|
|
20472
20598
|
function createRenderResolveTarget(config) {
|
|
20473
20599
|
return (signal) => {
|
|
20474
20600
|
if (signal.targetKind === ROUTE_TARGET_KIND2) {
|
|
20475
|
-
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType:
|
|
20601
|
+
return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: EdgeType34.CALLS };
|
|
20476
20602
|
}
|
|
20477
20603
|
return null;
|
|
20478
20604
|
};
|
|
@@ -20601,21 +20727,21 @@ function mapInsightsToSignals(rows, observedAtIso) {
|
|
|
20601
20727
|
}
|
|
20602
20728
|
|
|
20603
20729
|
// src/connectors/planetscale/resolve.ts
|
|
20604
|
-
import { EdgeType as
|
|
20730
|
+
import { EdgeType as EdgeType35, infraId as infraId27 } from "@neat.is/types";
|
|
20605
20731
|
var PLANETSCALE_DATABASE_KIND = "planetscale-database";
|
|
20606
20732
|
function createPlanetscaleResolveTarget(graph, config) {
|
|
20607
20733
|
const databaseName = `${config.organization}/${config.database}`;
|
|
20608
20734
|
return (signal, _ctx) => {
|
|
20609
20735
|
if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null;
|
|
20610
|
-
const tableId =
|
|
20736
|
+
const tableId = infraId27("sql-table", signal.targetName);
|
|
20611
20737
|
if (graph.hasNode(tableId)) {
|
|
20612
|
-
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType:
|
|
20738
|
+
return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: EdgeType35.CALLS };
|
|
20613
20739
|
}
|
|
20614
|
-
const providerId =
|
|
20740
|
+
const providerId = infraId27(PLANETSCALE_DATABASE_KIND, databaseName);
|
|
20615
20741
|
return {
|
|
20616
20742
|
targetNodeId: providerId,
|
|
20617
20743
|
serviceName: config.serviceName,
|
|
20618
|
-
edgeType:
|
|
20744
|
+
edgeType: EdgeType35.CALLS,
|
|
20619
20745
|
ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: "planetscale" }
|
|
20620
20746
|
};
|
|
20621
20747
|
};
|
|
@@ -20871,7 +20997,7 @@ function mapBuildsToSignals(builds, serviceName) {
|
|
|
20871
20997
|
}
|
|
20872
20998
|
|
|
20873
20999
|
// src/connectors/eas/resolve.ts
|
|
20874
|
-
import { EdgeType as
|
|
21000
|
+
import { EdgeType as EdgeType36, NodeType as NodeType40, parseFileId as parseFileId3 } from "@neat.is/types";
|
|
20875
21001
|
var NO_ENV2 = "unknown";
|
|
20876
21002
|
var EAS_JSON_PHASES = /* @__PURE__ */ new Set(["READ_EAS_JSON"]);
|
|
20877
21003
|
var APP_CONFIG_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -20887,7 +21013,7 @@ function configBasenamesForPhase(phase) {
|
|
|
20887
21013
|
function configNodeService(graph, configNodeId) {
|
|
20888
21014
|
for (const edgeId of graph.inboundEdges(configNodeId)) {
|
|
20889
21015
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
20890
|
-
if (edge.type !==
|
|
21016
|
+
if (edge.type !== EdgeType36.CONFIGURED_BY) continue;
|
|
20891
21017
|
const parsed = parseFileId3(edge.source);
|
|
20892
21018
|
if (parsed) return parsed.service;
|
|
20893
21019
|
}
|
|
@@ -20916,13 +21042,13 @@ function createEasResolveTarget(graph) {
|
|
|
20916
21042
|
if (basenames.length > 0) {
|
|
20917
21043
|
const configNodeId = findConfigNode(graph, basenames, serviceName);
|
|
20918
21044
|
if (configNodeId) {
|
|
20919
|
-
return { targetNodeId: configNodeId, serviceName, edgeType:
|
|
21045
|
+
return { targetNodeId: configNodeId, serviceName, edgeType: EdgeType36.CALLS };
|
|
20920
21046
|
}
|
|
20921
21047
|
}
|
|
20922
21048
|
return {
|
|
20923
21049
|
targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV2),
|
|
20924
21050
|
serviceName,
|
|
20925
|
-
edgeType:
|
|
21051
|
+
edgeType: EdgeType36.CALLS
|
|
20926
21052
|
};
|
|
20927
21053
|
};
|
|
20928
21054
|
}
|
|
@@ -22538,6 +22664,7 @@ export {
|
|
|
22538
22664
|
addImports,
|
|
22539
22665
|
addRoutes,
|
|
22540
22666
|
thresholdForEdgeType,
|
|
22667
|
+
resolveFusedServiceId,
|
|
22541
22668
|
stitchTrace,
|
|
22542
22669
|
makeErrorSpanWriter,
|
|
22543
22670
|
handleSpan,
|
|
@@ -22588,11 +22715,15 @@ export {
|
|
|
22588
22715
|
removeProject,
|
|
22589
22716
|
pruneRegistry,
|
|
22590
22717
|
readConnectorsConfig,
|
|
22718
|
+
resolveCredential,
|
|
22591
22719
|
isEnvRef,
|
|
22592
22720
|
upsertConnectorEntry,
|
|
22593
22721
|
removeConnectorEntry,
|
|
22594
22722
|
autoSlugConnectorId,
|
|
22595
22723
|
describeCredential,
|
|
22724
|
+
startConnectorPollLoop,
|
|
22725
|
+
bearerAuthHeader,
|
|
22726
|
+
junctionFetch,
|
|
22596
22727
|
isPushProvider,
|
|
22597
22728
|
getProviderFieldSchema,
|
|
22598
22729
|
knownProviderNames,
|
|
@@ -22602,4 +22733,4 @@ export {
|
|
|
22602
22733
|
deprovisionConnector,
|
|
22603
22734
|
buildApi
|
|
22604
22735
|
};
|
|
22605
|
-
//# sourceMappingURL=chunk-
|
|
22736
|
+
//# sourceMappingURL=chunk-RBZNXA5L.js.map
|