@neat.is/core 0.4.31-dev.20260718 → 0.5.1-dev.20260719
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-4M2YMGUM.js → chunk-BI3XKGVG.js} +162 -34
- package/dist/chunk-BI3XKGVG.js.map +1 -0
- package/dist/{chunk-2AJHEZIB.js → chunk-O4PCNQFG.js} +39 -12
- package/dist/chunk-O4PCNQFG.js.map +1 -0
- package/dist/cli.cjs +193 -62
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +208 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +208 -55
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +158 -32
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-2AJHEZIB.js.map +0 -1
- package/dist/chunk-4M2YMGUM.js.map +0 -1
package/dist/neatd.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
reconcileDaemonRecordSync,
|
|
4
4
|
startDaemon
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-O4PCNQFG.js";
|
|
6
6
|
import {
|
|
7
7
|
listProjects,
|
|
8
8
|
registryPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BI3XKGVG.js";
|
|
10
10
|
import {
|
|
11
11
|
BindAuthorityError,
|
|
12
12
|
__require
|
package/dist/server.cjs
CHANGED
|
@@ -1445,7 +1445,7 @@ function databaseRootCauseShape(graph, origin, walk3) {
|
|
|
1445
1445
|
for (const id of walk3.path) {
|
|
1446
1446
|
const owner = resolveOwningService(graph, id);
|
|
1447
1447
|
if (!owner) continue;
|
|
1448
|
-
const { id:
|
|
1448
|
+
const { id: serviceId5, svc } = owner;
|
|
1449
1449
|
const deps = svc.dependencies ?? {};
|
|
1450
1450
|
for (const pair of candidatePairs) {
|
|
1451
1451
|
const declared = deps[pair.driver];
|
|
@@ -1458,7 +1458,7 @@ function databaseRootCauseShape(graph, origin, walk3) {
|
|
|
1458
1458
|
);
|
|
1459
1459
|
if (!result.compatible) {
|
|
1460
1460
|
return {
|
|
1461
|
-
rootCauseNode:
|
|
1461
|
+
rootCauseNode: serviceId5,
|
|
1462
1462
|
rootCauseReason: result.reason ?? "incompatible driver",
|
|
1463
1463
|
...result.minDriverVersion ? {
|
|
1464
1464
|
fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`
|
|
@@ -1473,7 +1473,7 @@ function serviceRootCauseShape(graph, _origin, walk3) {
|
|
|
1473
1473
|
for (const id of walk3.path) {
|
|
1474
1474
|
const owner = resolveOwningService(graph, id);
|
|
1475
1475
|
if (!owner) continue;
|
|
1476
|
-
const { id:
|
|
1476
|
+
const { id: serviceId5, svc } = owner;
|
|
1477
1477
|
const deps = svc.dependencies ?? {};
|
|
1478
1478
|
const serviceNodeEngine = svc.nodeEngine;
|
|
1479
1479
|
for (const constraint of nodeEngineConstraints()) {
|
|
@@ -1482,7 +1482,7 @@ function serviceRootCauseShape(graph, _origin, walk3) {
|
|
|
1482
1482
|
const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine);
|
|
1483
1483
|
if (!result.compatible && result.reason) {
|
|
1484
1484
|
return {
|
|
1485
|
-
rootCauseNode:
|
|
1485
|
+
rootCauseNode: serviceId5,
|
|
1486
1486
|
rootCauseReason: result.reason,
|
|
1487
1487
|
...result.requiredNodeVersion ? {
|
|
1488
1488
|
fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`
|
|
@@ -1497,7 +1497,7 @@ function serviceRootCauseShape(graph, _origin, walk3) {
|
|
|
1497
1497
|
const result = checkPackageConflict(conflict, declared, requiredDeclared);
|
|
1498
1498
|
if (!result.compatible && result.reason) {
|
|
1499
1499
|
return {
|
|
1500
|
-
rootCauseNode:
|
|
1500
|
+
rootCauseNode: serviceId5,
|
|
1501
1501
|
rootCauseReason: result.reason,
|
|
1502
1502
|
fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`
|
|
1503
1503
|
};
|
|
@@ -1588,9 +1588,9 @@ function rootCauseFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
1588
1588
|
function isFailingCallEdge(e) {
|
|
1589
1589
|
return e.type === import_types.EdgeType.CALLS && (e.signal?.errorCount ?? 0) > 0;
|
|
1590
1590
|
}
|
|
1591
|
-
function callSourcesForService(graph,
|
|
1592
|
-
const ids = [
|
|
1593
|
-
for (const edgeId of graph.outboundEdges(
|
|
1591
|
+
function callSourcesForService(graph, serviceId5) {
|
|
1592
|
+
const ids = [serviceId5];
|
|
1593
|
+
for (const edgeId of graph.outboundEdges(serviceId5)) {
|
|
1594
1594
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1595
1595
|
if (e.type !== import_types.EdgeType.CONTAINS) continue;
|
|
1596
1596
|
const tgt = graph.getNodeAttributes(e.target);
|
|
@@ -1607,9 +1607,9 @@ function failingCallDominates(e, id, curEdge, curId) {
|
|
|
1607
1607
|
}
|
|
1608
1608
|
return id < curId;
|
|
1609
1609
|
}
|
|
1610
|
-
function dominantFailingCall(graph,
|
|
1610
|
+
function dominantFailingCall(graph, serviceId5, visited) {
|
|
1611
1611
|
let best = null;
|
|
1612
|
-
for (const src of callSourcesForService(graph,
|
|
1612
|
+
for (const src of callSourcesForService(graph, serviceId5)) {
|
|
1613
1613
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
1614
1614
|
const e = graph.getEdgeAttributes(edgeId);
|
|
1615
1615
|
if (!isFailingCallEdge(e)) continue;
|
|
@@ -1820,14 +1820,23 @@ function getObservedDependencies(graph, nodeId) {
|
|
|
1820
1820
|
function bucketKey(source, target, type) {
|
|
1821
1821
|
return `${type}|${source}|${target}`;
|
|
1822
1822
|
}
|
|
1823
|
+
function bucketSourceFor(graph, edge) {
|
|
1824
|
+
if (edge.type !== import_types2.EdgeType.CONNECTS_TO) return edge.source;
|
|
1825
|
+
const parsed = (0, import_types2.parseFileId)(edge.source);
|
|
1826
|
+
if (!parsed || !graph.hasNode(edge.target)) return edge.source;
|
|
1827
|
+
const target = graph.getNodeAttributes(edge.target);
|
|
1828
|
+
if (target.type !== import_types2.NodeType.DatabaseNode) return edge.source;
|
|
1829
|
+
return (0, import_types2.serviceId)(parsed.service);
|
|
1830
|
+
}
|
|
1823
1831
|
function bucketEdges(graph) {
|
|
1824
1832
|
const buckets = /* @__PURE__ */ new Map();
|
|
1825
1833
|
graph.forEachEdge((id, attrs) => {
|
|
1826
1834
|
const e = attrs;
|
|
1827
1835
|
const parsed = (0, import_types2.parseEdgeId)(id);
|
|
1828
1836
|
const provenance = parsed?.provenance ?? e.provenance;
|
|
1829
|
-
const
|
|
1830
|
-
const
|
|
1837
|
+
const source = bucketSourceFor(graph, e);
|
|
1838
|
+
const key = bucketKey(source, e.target, e.type);
|
|
1839
|
+
const cur = buckets.get(key) ?? { source, target: e.target, type: e.type };
|
|
1831
1840
|
switch (provenance) {
|
|
1832
1841
|
case import_types2.Provenance.EXTRACTED:
|
|
1833
1842
|
cur.extracted = e;
|
|
@@ -3116,6 +3125,27 @@ function ensureLocalDatabaseNode(graph, serviceName, name, engine) {
|
|
|
3116
3125
|
graph.addNode(id, node);
|
|
3117
3126
|
return id;
|
|
3118
3127
|
}
|
|
3128
|
+
function findDeclaredDatabaseForService(graph, serviceNodeId, engine) {
|
|
3129
|
+
if (!graph.hasNode(serviceNodeId)) return null;
|
|
3130
|
+
const sources = [serviceNodeId];
|
|
3131
|
+
for (const edgeId of graph.outboundEdges(serviceNodeId)) {
|
|
3132
|
+
const e = graph.getEdgeAttributes(edgeId);
|
|
3133
|
+
if (e.type === import_types4.EdgeType.CONTAINS) sources.push(e.target);
|
|
3134
|
+
}
|
|
3135
|
+
const matches = /* @__PURE__ */ new Set();
|
|
3136
|
+
for (const src of sources) {
|
|
3137
|
+
if (!graph.hasNode(src)) continue;
|
|
3138
|
+
for (const edgeId of graph.outboundEdges(src)) {
|
|
3139
|
+
const edge = graph.getEdgeAttributes(edgeId);
|
|
3140
|
+
if (edge.type !== import_types4.EdgeType.CONNECTS_TO || edge.provenance !== import_types4.Provenance.EXTRACTED) continue;
|
|
3141
|
+
if (!graph.hasNode(edge.target)) continue;
|
|
3142
|
+
const target = graph.getNodeAttributes(edge.target);
|
|
3143
|
+
if (target.type !== import_types4.NodeType.DatabaseNode || target.engine !== engine) continue;
|
|
3144
|
+
matches.add(edge.target);
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
return matches.size === 1 ? [...matches][0] : null;
|
|
3148
|
+
}
|
|
3119
3149
|
function ensureFrontierNode(graph, host, ts) {
|
|
3120
3150
|
const id = frontierIdFor(host);
|
|
3121
3151
|
if (graph.hasNode(id)) {
|
|
@@ -3136,6 +3166,7 @@ function ensureFrontierNode(graph, host, ts) {
|
|
|
3136
3166
|
}
|
|
3137
3167
|
function upsertObservedEdge(graph, type, source, target, ts, isError = false, evidence) {
|
|
3138
3168
|
if (!graph.hasNode(source) || !graph.hasNode(target)) return null;
|
|
3169
|
+
const grain = source.startsWith("file:") ? "file" : "service";
|
|
3139
3170
|
const id = makeObservedEdgeId(type, source, target);
|
|
3140
3171
|
if (graph.hasEdge(id)) {
|
|
3141
3172
|
const existing = graph.getEdgeAttributes(id);
|
|
@@ -3152,7 +3183,9 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
|
|
|
3152
3183
|
lastObserved: ts,
|
|
3153
3184
|
callCount: newSpanCount,
|
|
3154
3185
|
signal: newSignal,
|
|
3155
|
-
confidence: (0, import_types4.confidenceForObservedSignal)(newSignal)
|
|
3186
|
+
confidence: (0, import_types4.confidenceForObservedSignal)(newSignal),
|
|
3187
|
+
grain
|
|
3188
|
+
// backfills legacy edges that predate ADR-142
|
|
3156
3189
|
};
|
|
3157
3190
|
graph.replaceEdgeAttributes(id, updated);
|
|
3158
3191
|
return { edge: updated, created: false };
|
|
@@ -3172,6 +3205,7 @@ function upsertObservedEdge(graph, type, source, target, ts, isError = false, ev
|
|
|
3172
3205
|
lastObserved: ts,
|
|
3173
3206
|
callCount: 1,
|
|
3174
3207
|
signal,
|
|
3208
|
+
grain,
|
|
3175
3209
|
// Call-site evidence from span code.* semconv (file-awareness.md §4 + §6).
|
|
3176
3210
|
// Only set when code.filepath was present on the span — never fabricated.
|
|
3177
3211
|
...evidence ? { evidence } : {}
|
|
@@ -3349,13 +3383,18 @@ async function handleSpan(ctx, span) {
|
|
|
3349
3383
|
ensureDatabaseNode(ctx.graph, host, span.dbSystem);
|
|
3350
3384
|
targetId = (0, import_types4.databaseId)(host);
|
|
3351
3385
|
} else {
|
|
3352
|
-
const
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
localName
|
|
3357
|
-
|
|
3358
|
-
|
|
3386
|
+
const declared = findDeclaredDatabaseForService(ctx.graph, sourceId, span.dbSystem);
|
|
3387
|
+
if (declared) {
|
|
3388
|
+
targetId = declared;
|
|
3389
|
+
} else {
|
|
3390
|
+
const localName = span.dbName ?? span.dbSystem;
|
|
3391
|
+
targetId = ensureLocalDatabaseNode(
|
|
3392
|
+
ctx.graph,
|
|
3393
|
+
span.service,
|
|
3394
|
+
localName,
|
|
3395
|
+
span.dbSystem
|
|
3396
|
+
);
|
|
3397
|
+
}
|
|
3359
3398
|
}
|
|
3360
3399
|
const result = upsertObservedEdge(
|
|
3361
3400
|
ctx.graph,
|
|
@@ -3539,29 +3578,29 @@ function promoteFrontierNodes(graph, opts = {}) {
|
|
|
3539
3578
|
toPromote.push({ frontierId: id, serviceId: target });
|
|
3540
3579
|
});
|
|
3541
3580
|
let promoted = 0;
|
|
3542
|
-
for (const { frontierId: frontierId2, serviceId:
|
|
3581
|
+
for (const { frontierId: frontierId2, serviceId: serviceId5 } of toPromote) {
|
|
3543
3582
|
if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {
|
|
3544
3583
|
const gate = canPromoteFrontier(graph, frontierId2, opts.policies, opts.policyCtx);
|
|
3545
3584
|
if (!gate.allowed) {
|
|
3546
3585
|
continue;
|
|
3547
3586
|
}
|
|
3548
3587
|
}
|
|
3549
|
-
rewireFrontierEdges(graph, frontierId2,
|
|
3588
|
+
rewireFrontierEdges(graph, frontierId2, serviceId5);
|
|
3550
3589
|
graph.dropNode(frontierId2);
|
|
3551
3590
|
promoted++;
|
|
3552
3591
|
}
|
|
3553
3592
|
return promoted;
|
|
3554
3593
|
}
|
|
3555
|
-
function rewireFrontierEdges(graph, frontierId2,
|
|
3594
|
+
function rewireFrontierEdges(graph, frontierId2, serviceId5) {
|
|
3556
3595
|
const inbound = [...graph.inboundEdges(frontierId2)];
|
|
3557
3596
|
const outbound = [...graph.outboundEdges(frontierId2)];
|
|
3558
3597
|
for (const edgeId of inbound) {
|
|
3559
3598
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
3560
|
-
rebuildEdge(graph, edge, edge.source,
|
|
3599
|
+
rebuildEdge(graph, edge, edge.source, serviceId5, edgeId);
|
|
3561
3600
|
}
|
|
3562
3601
|
for (const edgeId of outbound) {
|
|
3563
3602
|
const edge = graph.getEdgeAttributes(edgeId);
|
|
3564
|
-
rebuildEdge(graph, edge,
|
|
3603
|
+
rebuildEdge(graph, edge, serviceId5, edge.target, edgeId);
|
|
3565
3604
|
}
|
|
3566
3605
|
}
|
|
3567
3606
|
function rebuildEdge(graph, edge, newSource, newTarget, oldEdgeId) {
|
|
@@ -4357,9 +4396,9 @@ var K8S_KINDS_WITH_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
|
4357
4396
|
"StatefulSet",
|
|
4358
4397
|
"DaemonSet"
|
|
4359
4398
|
]);
|
|
4360
|
-
function addAliases(graph,
|
|
4361
|
-
if (!graph.hasNode(
|
|
4362
|
-
const node = graph.getNodeAttributes(
|
|
4399
|
+
function addAliases(graph, serviceId5, candidates) {
|
|
4400
|
+
if (!graph.hasNode(serviceId5)) return;
|
|
4401
|
+
const node = graph.getNodeAttributes(serviceId5);
|
|
4363
4402
|
if (node.type !== import_types7.NodeType.ServiceNode) return;
|
|
4364
4403
|
const set = new Set(node.aliases ?? []);
|
|
4365
4404
|
for (const c of candidates) {
|
|
@@ -4369,7 +4408,7 @@ function addAliases(graph, serviceId4, candidates) {
|
|
|
4369
4408
|
}
|
|
4370
4409
|
if (set.size === 0) return;
|
|
4371
4410
|
const updated = { ...node, aliases: [...set].sort() };
|
|
4372
|
-
graph.replaceNodeAttributes(
|
|
4411
|
+
graph.replaceNodeAttributes(serviceId5, updated);
|
|
4373
4412
|
}
|
|
4374
4413
|
function indexServicesByName(services) {
|
|
4375
4414
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -4402,12 +4441,12 @@ async function collectComposeAliases(graph, scanPath, serviceIndex) {
|
|
|
4402
4441
|
}
|
|
4403
4442
|
if (!compose?.services) return;
|
|
4404
4443
|
for (const [composeName, svc] of Object.entries(compose.services)) {
|
|
4405
|
-
const
|
|
4406
|
-
if (!
|
|
4444
|
+
const serviceId5 = serviceIndex.get(composeName);
|
|
4445
|
+
if (!serviceId5) continue;
|
|
4407
4446
|
const aliases = /* @__PURE__ */ new Set([composeName]);
|
|
4408
4447
|
if (svc.container_name) aliases.add(svc.container_name);
|
|
4409
4448
|
if (svc.hostname) aliases.add(svc.hostname);
|
|
4410
|
-
addAliases(graph,
|
|
4449
|
+
addAliases(graph, serviceId5, aliases);
|
|
4411
4450
|
}
|
|
4412
4451
|
}
|
|
4413
4452
|
var LABEL_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -5057,6 +5096,29 @@ async function readIfExists(filePath) {
|
|
|
5057
5096
|
return null;
|
|
5058
5097
|
}
|
|
5059
5098
|
}
|
|
5099
|
+
async function resolveEnvVar(serviceDir, name) {
|
|
5100
|
+
const entries = await import_node_fs14.promises.readdir(serviceDir, { withFileTypes: true }).catch(() => []);
|
|
5101
|
+
const envNames = entries.filter((e) => e.isFile() && (e.name === ".env" || e.name.startsWith(".env."))).map((e) => e.name);
|
|
5102
|
+
const rank = (n) => n === ".env.local" ? 0 : n === ".env" ? 1 : 2;
|
|
5103
|
+
envNames.sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
|
|
5104
|
+
for (const fileName of envNames) {
|
|
5105
|
+
const content = await readIfExists(import_node_path16.default.join(serviceDir, fileName));
|
|
5106
|
+
if (!content) continue;
|
|
5107
|
+
for (const line of content.split("\n")) {
|
|
5108
|
+
const trimmed = line.trim();
|
|
5109
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
5110
|
+
const eq = trimmed.indexOf("=");
|
|
5111
|
+
if (eq < 0) continue;
|
|
5112
|
+
if (trimmed.slice(0, eq).trim() !== name) continue;
|
|
5113
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
5114
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
5115
|
+
value = value.slice(1, -1);
|
|
5116
|
+
}
|
|
5117
|
+
return value || null;
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
return null;
|
|
5121
|
+
}
|
|
5060
5122
|
async function findFirst(serviceDir, candidates) {
|
|
5061
5123
|
for (const rel of candidates) {
|
|
5062
5124
|
const abs = import_node_path16.default.join(serviceDir, rel);
|
|
@@ -5154,6 +5216,14 @@ async function parse3(serviceDir) {
|
|
|
5154
5216
|
const config = parseConnectionString(urlMatch[1]);
|
|
5155
5217
|
if (config) return [{ ...config, sourceFile: schemaPath }];
|
|
5156
5218
|
}
|
|
5219
|
+
const envMatch = body.match(/url\s*=\s*env\(\s*"([^"]+)"\s*\)/);
|
|
5220
|
+
if (envMatch) {
|
|
5221
|
+
const resolved = await resolveEnvVar(serviceDir, envMatch[1]);
|
|
5222
|
+
if (resolved) {
|
|
5223
|
+
const config = parseConnectionString(resolved);
|
|
5224
|
+
if (config) return [{ ...config, sourceFile: schemaPath }];
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5157
5227
|
return [
|
|
5158
5228
|
{
|
|
5159
5229
|
host: `${engine}-prisma`,
|
|
@@ -5197,6 +5267,15 @@ async function parse4(serviceDir) {
|
|
|
5197
5267
|
const config = parseConnectionString(urlMatch[1]);
|
|
5198
5268
|
if (config) return [{ ...config, sourceFile: filePath }];
|
|
5199
5269
|
}
|
|
5270
|
+
const urlEnvMatch = content.match(
|
|
5271
|
+
/(?:url|connectionString)\s*:\s*process\.env(?:\.([A-Za-z_$][\w$]*)|\[\s*['"]([^'"]+)['"]\s*\])/
|
|
5272
|
+
);
|
|
5273
|
+
if (urlEnvMatch) {
|
|
5274
|
+
const varName = urlEnvMatch[1] ?? urlEnvMatch[2];
|
|
5275
|
+
const resolved = varName ? await resolveEnvVar(serviceDir, varName) : null;
|
|
5276
|
+
const config = resolved ? parseConnectionString(resolved) : null;
|
|
5277
|
+
if (config) return [{ ...config, sourceFile: filePath }];
|
|
5278
|
+
}
|
|
5200
5279
|
const hostMatch = content.match(/host\s*:\s*['"`]([^'"`]+)['"`]/);
|
|
5201
5280
|
if (hostMatch) {
|
|
5202
5281
|
const portMatch = content.match(/port\s*:\s*(\d+)/);
|
|
@@ -5250,6 +5329,15 @@ async function parse5(serviceDir) {
|
|
|
5250
5329
|
const config = parseConnectionString(urlMatch[1]);
|
|
5251
5330
|
if (config) return [{ ...config, sourceFile: filePath }];
|
|
5252
5331
|
}
|
|
5332
|
+
const urlEnvMatch = content.match(
|
|
5333
|
+
/connection\s*:\s*process\.env(?:\.([A-Za-z_$][\w$]*)|\[\s*['"]([^'"]+)['"]\s*\])/
|
|
5334
|
+
);
|
|
5335
|
+
if (urlEnvMatch) {
|
|
5336
|
+
const varName = urlEnvMatch[1] ?? urlEnvMatch[2];
|
|
5337
|
+
const resolved = varName ? await resolveEnvVar(serviceDir, varName) : null;
|
|
5338
|
+
const config = resolved ? parseConnectionString(resolved) : null;
|
|
5339
|
+
if (config) return [{ ...config, sourceFile: filePath }];
|
|
5340
|
+
}
|
|
5253
5341
|
const host = content.match(/host\s*:\s*['"`]([^'"`]+)['"`]/)?.[1];
|
|
5254
5342
|
if (host) {
|
|
5255
5343
|
const port = content.match(/port\s*:\s*(\d+)/)?.[1];
|
|
@@ -6798,6 +6886,16 @@ function constructorMatchesImport(name, ctx) {
|
|
|
6798
6886
|
if (name === "createClient") return ctx.hasSupabaseJs;
|
|
6799
6887
|
return ctx.hasSupabaseSsr;
|
|
6800
6888
|
}
|
|
6889
|
+
var SUPABASE_CLIENT_ASSIGN_RE = /(?:const|let|var)\s+(\w+)\s*=\s*(?:await\s+)?(createClient|createServerClient|createBrowserClient)\s*\(/g;
|
|
6890
|
+
function supabaseClientVars(content, ctx) {
|
|
6891
|
+
const vars = /* @__PURE__ */ new Set();
|
|
6892
|
+
SUPABASE_CLIENT_ASSIGN_RE.lastIndex = 0;
|
|
6893
|
+
let m;
|
|
6894
|
+
while ((m = SUPABASE_CLIENT_ASSIGN_RE.exec(content)) !== null) {
|
|
6895
|
+
if (constructorMatchesImport(m[2], ctx)) vars.add(m[1]);
|
|
6896
|
+
}
|
|
6897
|
+
return vars;
|
|
6898
|
+
}
|
|
6801
6899
|
function supabaseEndpointsFromFile(file, serviceDir) {
|
|
6802
6900
|
const ctx = readImports2(file.content);
|
|
6803
6901
|
if (!ctx.hasSupabaseJs && !ctx.hasSupabaseSsr) return [];
|
|
@@ -6830,6 +6928,34 @@ function supabaseEndpointsFromFile(file, serviceDir) {
|
|
|
6830
6928
|
}
|
|
6831
6929
|
});
|
|
6832
6930
|
}
|
|
6931
|
+
const clientVars = supabaseClientVars(file.content, ctx);
|
|
6932
|
+
for (const clientVar of clientVars) {
|
|
6933
|
+
const accessRe = new RegExp(
|
|
6934
|
+
`\\b${clientVar}\\s*\\.\\s*(from|rpc)\\s*\\(\\s*['"\`]([\\w.-]+)['"\`]`,
|
|
6935
|
+
"g"
|
|
6936
|
+
);
|
|
6937
|
+
let am;
|
|
6938
|
+
while ((am = accessRe.exec(file.content)) !== null) {
|
|
6939
|
+
const kind = am[1] === "rpc" ? "supabase-rpc" : "supabase-table";
|
|
6940
|
+
const resource = am[2];
|
|
6941
|
+
const key = `${kind}/${resource}`;
|
|
6942
|
+
if (seen.has(key)) continue;
|
|
6943
|
+
seen.add(key);
|
|
6944
|
+
const line = lineOf(file.content, am[0]);
|
|
6945
|
+
out.push({
|
|
6946
|
+
infraId: (0, import_types20.infraId)(kind, resource),
|
|
6947
|
+
name: resource,
|
|
6948
|
+
kind,
|
|
6949
|
+
edgeType: "CALLS",
|
|
6950
|
+
confidenceKind: "verified-call-site",
|
|
6951
|
+
evidence: {
|
|
6952
|
+
file: import_node_path32.default.relative(serviceDir, file.path),
|
|
6953
|
+
line,
|
|
6954
|
+
snippet: snippet(file.content, line)
|
|
6955
|
+
}
|
|
6956
|
+
});
|
|
6957
|
+
}
|
|
6958
|
+
}
|
|
6833
6959
|
return out;
|
|
6834
6960
|
}
|
|
6835
6961
|
|