@voltro/cli 0.30.2 → 0.31.0
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/CHANGELOG.md +115 -0
- package/dist/apiBuild-BOqL1dlg.js +2 -0
- package/dist/{apiBuild-BUS1RfPi.js → apiBuild-CLPt-pX6.js} +2 -2
- package/dist/appGraph-CvQCte0z.js +2 -0
- package/dist/appGraph-gQ_6GkQQ.js +110 -0
- package/dist/bin.js +3 -3
- package/dist/checkCommand-ClRvH_SN.js +2 -0
- package/dist/{checkCommand-D_wdOFhw.js → checkCommand-D7r6_pk7.js} +309 -453
- package/dist/{commands-BgGAUcku.js → commands-CNVVv03h.js} +2566 -2505
- package/dist/{dbCommand-CbPRCD1x.js → dbCommand-BH8GAYuf.js} +22 -2
- package/dist/dbCommand-BwQ_Jl98.js +2 -0
- package/dist/{dev-tPcOmjPJ.js → dev-DOZVMVfi.js} +1 -1
- package/dist/{dev-GAOIot9G.js → dev-DdQEn2Ia.js} +1774 -1771
- package/dist/index.js +1 -1
- package/dist/{inspectMetrics-BM1vrsga.js → inspectMetrics-BeEAnjqw.js} +727 -480
- package/dist/{sdkgen-BV4fFucu.js → sdkgen-v9WV8zRi.js} +1 -1
- package/dist/{serveCommand-ClqXCX1y.js → serveCommand-KsKXXWn4.js} +289 -289
- package/dist/serveEntry.js +2 -2
- package/dist/{start-CTnNvKlk.js → start-CI2QdKy9.js} +204 -199
- package/dist/startEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.md +43 -43
- package/templates/agent-docs/_index.md +43 -43
- package/templates/agent-docs/_manifest.json +84 -42
- package/templates/agent-docs/database/migrations.md +14 -1
- package/templates/agent-docs/internationalization.md +29 -0
- package/templates/agent-docs/plugins/ai-flows.md +148 -0
- package/templates/agent-docs/plugins/analytics-postgres.md +90 -0
- package/templates/agent-docs/plugins/atlassian.md +378 -0
- package/templates/agent-docs/plugins/audit.md +324 -0
- package/templates/agent-docs/plugins/auth-auth0.md +92 -0
- package/templates/agent-docs/plugins/auth-clerk.md +90 -0
- package/templates/agent-docs/plugins/auth-kinde.md +88 -0
- package/templates/agent-docs/plugins/auth-oidc.md +95 -0
- package/templates/agent-docs/plugins/auth-supabase.md +103 -0
- package/templates/agent-docs/plugins/auth-workos.md +105 -0
- package/templates/agent-docs/plugins/auth.md +227 -0
- package/templates/agent-docs/plugins/billing.md +324 -0
- package/templates/agent-docs/plugins/broadcast.md +144 -0
- package/templates/agent-docs/plugins/cdc-out.md +116 -0
- package/templates/agent-docs/plugins/clickhouse.md +91 -0
- package/templates/agent-docs/plugins/datadog.md +105 -0
- package/templates/agent-docs/plugins/deactivation.md +114 -0
- package/templates/agent-docs/plugins/duckdb.md +82 -0
- package/templates/agent-docs/plugins/flags.md +146 -0
- package/templates/agent-docs/plugins/governance.md +143 -0
- package/templates/agent-docs/plugins/licensing.md +74 -0
- package/templates/agent-docs/plugins/logship.md +56 -0
- package/templates/agent-docs/plugins/mail.md +334 -0
- package/templates/agent-docs/plugins/moderation.md +65 -0
- package/templates/agent-docs/plugins/multitenancy.md +99 -0
- package/templates/agent-docs/plugins/notifications.md +252 -0
- package/templates/agent-docs/plugins/openapi.md +94 -0
- package/templates/agent-docs/plugins/postgis.md +140 -0
- package/templates/agent-docs/plugins/posthog.md +91 -0
- package/templates/agent-docs/plugins/presence.md +115 -0
- package/templates/agent-docs/plugins/prometheus.md +124 -0
- package/templates/agent-docs/plugins/ratelimit.md +274 -0
- package/templates/agent-docs/plugins/rbac.md +270 -0
- package/templates/agent-docs/plugins/scim.md +63 -0
- package/templates/agent-docs/plugins/search.md +116 -0
- package/templates/agent-docs/plugins/sentry.md +192 -0
- package/templates/agent-docs/plugins/soft-delete.md +72 -0
- package/templates/agent-docs/plugins/sso-saml.md +132 -0
- package/templates/agent-docs/plugins/storage.md +709 -0
- package/templates/agent-docs/plugins/tinybird.md +92 -0
- package/templates/agent-docs/plugins/versioning.md +226 -0
- package/templates/agent-docs/plugins/webhooks.md +585 -0
- package/templates/agent-docs/security.md +12 -1
- package/templates/agent-docs/whats-new.md +90 -23
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +8 -8
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +9 -9
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +2 -2
- package/dist/apiBuild-DMlxvL8h.js +0 -2
- package/dist/checkCommand-CARZ36Tr.js +0 -2
- package/dist/dbCommand-Ht47LrV-.js +0 -2
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { C as
|
|
4
|
-
import { r as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { Ct as e, et as t, f as n, n as r, nt as i, o as a, rt as o, tt as s, z as c } from "./inspectMetrics-BeEAnjqw.js";
|
|
2
|
+
import { Ht as l, Ut as u } from "./dev-DdQEn2Ia.js";
|
|
3
|
+
import { C as d, E as f, O as p, T as m, d as h, h as g, i as _, l as v, m as y, r as ee, u as te } from "./fileConventions-Cof68_BL.js";
|
|
4
|
+
import { r as ne, u as re } from "./apiBuild-CLPt-pX6.js";
|
|
5
|
+
import { r as ie } from "./appGraph-gQ_6GkQQ.js";
|
|
6
|
+
import { dirname as b, isAbsolute as ae, join as x, relative as S, resolve as C, sep as w } from "node:path";
|
|
7
|
+
import { routeDiagnosticsToStderr as oe } from "@voltro/logger";
|
|
8
|
+
import { existsSync as T, readFileSync as E, readdirSync as D, statSync as O, writeFileSync as se } from "node:fs";
|
|
8
9
|
import { Node as k, Project as A, SyntaxKind as j } from "ts-morph";
|
|
9
10
|
//#region src/cliOutput.ts
|
|
10
|
-
var
|
|
11
|
-
|
|
11
|
+
var ce = () => {
|
|
12
|
+
oe();
|
|
12
13
|
}, M = (e, t = {}) => {
|
|
13
14
|
console.log(JSON.stringify(e, null, t.pretty === !1 ? 0 : 2));
|
|
14
|
-
},
|
|
15
|
+
}, le = (e) => {
|
|
15
16
|
for (let t = 0; t < e.length; t++) {
|
|
16
17
|
let n = e[t];
|
|
17
18
|
if (n === "--json" || n === "--format=json" || n === "--format" && e[t + 1] === "json") return !0;
|
|
18
19
|
}
|
|
19
20
|
return !1;
|
|
20
|
-
},
|
|
21
|
+
}, ue = (e, t, n = !1) => {
|
|
21
22
|
let r = { ...e ?? {} }, i = t ?? process.env.VOLTRO_INSPECT_TOKEN;
|
|
22
23
|
if (i !== void 0 && i !== "" && (r.authorization = `Bearer ${i}`), n) {
|
|
23
24
|
let e = process.env.VOLTRO_INSPECT_WRITE_TOKEN;
|
|
24
25
|
e !== void 0 && e !== "" && (r["x-voltro-inspect-write"] = e);
|
|
25
26
|
}
|
|
26
27
|
return r;
|
|
27
|
-
},
|
|
28
|
+
}, de = /* @__PURE__ */ new Set([
|
|
28
29
|
"POST",
|
|
29
30
|
"PUT",
|
|
30
31
|
"PATCH",
|
|
@@ -34,7 +35,7 @@ var re = () => {
|
|
|
34
35
|
try {
|
|
35
36
|
let t = await fetch(r, {
|
|
36
37
|
method: i,
|
|
37
|
-
headers:
|
|
38
|
+
headers: ue(a ? { "content-type": "application/json" } : void 0, e.inspectToken, de.has(i)),
|
|
38
39
|
...a ? { body: JSON.stringify(n.body) } : {}
|
|
39
40
|
}), o = await t.text(), s;
|
|
40
41
|
if (o.length > 0) try {
|
|
@@ -43,7 +44,7 @@ var re = () => {
|
|
|
43
44
|
s = o;
|
|
44
45
|
}
|
|
45
46
|
if (!t.ok) {
|
|
46
|
-
let n = s, r = typeof n == "object" && n ? String(n.message ?? n.reason ?? n.error ?? `HTTP ${t.status}`) : `HTTP ${t.status}`, a =
|
|
47
|
+
let n = s, r = typeof n == "object" && n ? String(n.message ?? n.reason ?? n.error ?? `HTTP ${t.status}`) : `HTTP ${t.status}`, a = de.has(i) && (process.env.VOLTRO_INSPECT_WRITE_TOKEN ?? "") === "" && /write/i.test(r);
|
|
47
48
|
return {
|
|
48
49
|
kind: "err",
|
|
49
50
|
name: e.name,
|
|
@@ -63,7 +64,7 @@ var re = () => {
|
|
|
63
64
|
error: t.message || String(t)
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
|
-
},
|
|
67
|
+
}, P = (e, t = process.env) => {
|
|
67
68
|
let n = [], r, i;
|
|
68
69
|
for (let t = 0; t < e.length; t++) {
|
|
69
70
|
let a = e[t];
|
|
@@ -108,7 +109,7 @@ var re = () => {
|
|
|
108
109
|
},
|
|
109
110
|
rest: n
|
|
110
111
|
};
|
|
111
|
-
},
|
|
112
|
+
}, fe = (e) => ({
|
|
112
113
|
id: `remote:${e.url}`,
|
|
113
114
|
name: e.name,
|
|
114
115
|
kind: "api",
|
|
@@ -119,7 +120,7 @@ var re = () => {
|
|
|
119
120
|
status: "live",
|
|
120
121
|
logFile: "",
|
|
121
122
|
...e.token === void 0 ? {} : { inspectToken: e.token }
|
|
122
|
-
}),
|
|
123
|
+
}), pe = async (t, n) => n === void 0 ? (await e()).apps.filter((e) => e.kind === "api" && e.status === "live" && e.url.length > 0 && (t === void 0 || e.name === t)) : [fe(n)], me = (e) => {
|
|
123
124
|
let t = "pretty", n = [];
|
|
124
125
|
for (let r = 0; r < e.length; r++) {
|
|
125
126
|
let i = e[r];
|
|
@@ -143,8 +144,8 @@ var re = () => {
|
|
|
143
144
|
format: t,
|
|
144
145
|
rest: n
|
|
145
146
|
};
|
|
146
|
-
},
|
|
147
|
-
let { target: n, rest: r, error: i } =
|
|
147
|
+
}, he = (e, t = process.env) => {
|
|
148
|
+
let { target: n, rest: r, error: i } = P(e, t), a, o = [];
|
|
148
149
|
for (let e = 0; e < r.length; e++) {
|
|
149
150
|
let t = r[e];
|
|
150
151
|
if (t === "--process") {
|
|
@@ -163,112 +164,6 @@ var re = () => {
|
|
|
163
164
|
rest: o,
|
|
164
165
|
...i === void 0 ? {} : { error: i }
|
|
165
166
|
};
|
|
166
|
-
}, P = (e) => e.source === void 0 ? [] : typeof e.source == "string" ? [e.source] : e.source, fe = (e) => ({
|
|
167
|
-
tables: new Set(e.tables),
|
|
168
|
-
procedures: new Map(e.procedures.map((e) => [e.tag, e])),
|
|
169
|
-
scopes: new Set(e.scopes ?? []),
|
|
170
|
-
input: e
|
|
171
|
-
}), pe = (e) => {
|
|
172
|
-
let t = [], n = /* @__PURE__ */ new Set();
|
|
173
|
-
for (let r of e.input.procedures) {
|
|
174
|
-
for (let i of P(r)) n.add(i), e.tables.has(i) || t.push({
|
|
175
|
-
rule: "reference/dangling-source",
|
|
176
|
-
node: `${r.kind}(${r.tag})`,
|
|
177
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
178
|
-
breaks: [`reads table '${i}' which does not exist`],
|
|
179
|
-
fix: `declare a '${i}.entity.ts' table or fix the query's source`,
|
|
180
|
-
severity: "error"
|
|
181
|
-
});
|
|
182
|
-
for (let i of r.targets ?? []) n.add(i.table), e.tables.has(i.table) || t.push({
|
|
183
|
-
rule: "reference/dangling-target",
|
|
184
|
-
node: `${r.kind}(${r.tag})`,
|
|
185
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
186
|
-
breaks: [`targets table '${i.table}' (op '${i.op}') which does not exist`],
|
|
187
|
-
fix: `declare a '${i.table}.entity.ts' table or fix the mutation's target`,
|
|
188
|
-
severity: "error"
|
|
189
|
-
});
|
|
190
|
-
for (let n of r.requiresScopes ?? []) e.scopes.size > 0 && !e.scopes.has(n) && t.push({
|
|
191
|
-
rule: "rbac/unknown-scope",
|
|
192
|
-
node: `${r.kind}(${r.tag})`,
|
|
193
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
194
|
-
breaks: [`requires scope '${n}' which is not declared`],
|
|
195
|
-
fix: `declare the scope '${n}' or fix the requireScope(...) call`,
|
|
196
|
-
severity: "error"
|
|
197
|
-
});
|
|
198
|
-
r.kind === "mutation" && r.hasGuards === !1 && t.push({
|
|
199
|
-
rule: "rbac/unguarded-mutation",
|
|
200
|
-
node: `${r.kind}(${r.tag})`,
|
|
201
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
202
|
-
breaks: [`'${r.tag}' changes state but declares no guard — any caller who can reach the rpc surface can invoke it`],
|
|
203
|
-
fix: "add a guard (e.g. `.guard(requireScope('…'))`), or confirm it is intentionally public",
|
|
204
|
-
severity: "warn"
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
for (let n of e.input.routes ?? []) for (let r of n.binds) e.procedures.has(r) || t.push({
|
|
208
|
-
rule: "binding/unknown-tag",
|
|
209
|
-
node: `route(${n.pattern})`,
|
|
210
|
-
...n.file === void 0 ? {} : { file: n.file },
|
|
211
|
-
breaks: [`binds rpc tag '${r}' which does not exist`],
|
|
212
|
-
fix: `bind an existing tag, or restore '${r}' (it may have been renamed/removed)`,
|
|
213
|
-
severity: "error"
|
|
214
|
-
});
|
|
215
|
-
for (let t of e.input.procedures) for (let e of t.targets ?? []) n.add(e.table);
|
|
216
|
-
let r = new Set(e.input.frameworkOwnedTables ?? []), i = e.input.procedures.filter((e) => e.kind === "action" && P(e).length === 0 && (e.targets ?? []).length === 0).length;
|
|
217
|
-
for (let a of e.tables) r.has(a) || n.has(a) || t.push({
|
|
218
|
-
rule: "orphan/unread-table",
|
|
219
|
-
node: `table(${a})`,
|
|
220
|
-
breaks: i > 0 ? [`no query reads and no mutation writes '${a}'`, `${i} action(s) declare neither source nor target, so one of them may still use it`] : [`no query reads and no mutation writes '${a}'`],
|
|
221
|
-
fix: i > 0 ? "declare `source`/`target` on your actions so this can be answered, then re-run" : `add a query/mutation for '${a}', or remove the table if it's dead`,
|
|
222
|
-
severity: "warn"
|
|
223
|
-
});
|
|
224
|
-
if (e.scopes.size > 0) {
|
|
225
|
-
let n = /* @__PURE__ */ new Set();
|
|
226
|
-
for (let t of e.input.procedures) for (let e of t.requiresScopes ?? []) n.add(e);
|
|
227
|
-
for (let r of [...e.scopes].sort()) r === "admin:full" || n.has(r) || t.push({
|
|
228
|
-
rule: "rbac/unenforced-scope",
|
|
229
|
-
node: `scope(${r})`,
|
|
230
|
-
breaks: [`'${r}' is granted by a role but NO query/mutation/action/stream guards on it`, "a scope nobody checks grants nothing and withholds nothing — the role map reads stricter than the app is"],
|
|
231
|
-
fix: `add \`.guard(requireScope('${r}'))\` to the handlers it is meant to protect — or, if a plugin route, a REST route, or a UI-only affordance enforces it, say so where the role is declared`,
|
|
232
|
-
severity: "warn"
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
return t;
|
|
236
|
-
}, me = (e, t) => {
|
|
237
|
-
let n = [];
|
|
238
|
-
if (t.kind === "removeTable") for (let r of e.input.procedures) {
|
|
239
|
-
let e = P(r).includes(t.name), i = (r.targets ?? []).some((e) => e.table === t.name);
|
|
240
|
-
(e || i) && n.push({
|
|
241
|
-
rule: "blast/table-removed",
|
|
242
|
-
node: `${r.kind}(${r.tag})`,
|
|
243
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
244
|
-
breaks: [`${e ? "reads" : "writes"} table '${t.name}' — would break if removed`],
|
|
245
|
-
fix: `migrate or remove ${r.tag} before dropping '${t.name}'`,
|
|
246
|
-
severity: "error"
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
else if (t.kind === "removeProcedure") for (let r of e.input.routes ?? []) r.binds.includes(t.tag) && n.push({
|
|
250
|
-
rule: "blast/procedure-removed",
|
|
251
|
-
node: `route(${r.pattern})`,
|
|
252
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
253
|
-
breaks: [`binds '${t.tag}' — would break if removed`],
|
|
254
|
-
fix: `rebind ${r.pattern} to another tag before removing '${t.tag}'`,
|
|
255
|
-
severity: "error"
|
|
256
|
-
});
|
|
257
|
-
else for (let r of e.input.procedures) (r.requiresScopes ?? []).includes(t.name) && n.push({
|
|
258
|
-
rule: "blast/scope-removed",
|
|
259
|
-
node: `${r.kind}(${r.tag})`,
|
|
260
|
-
...r.file === void 0 ? {} : { file: r.file },
|
|
261
|
-
breaks: [`requires scope '${t.name}' — would become unguarded/dangling if removed`],
|
|
262
|
-
fix: `remove the requireScope('${t.name}') call or keep the scope`,
|
|
263
|
-
severity: "error"
|
|
264
|
-
});
|
|
265
|
-
return n;
|
|
266
|
-
}, he = (e, t) => {
|
|
267
|
-
let n = fe(e), r = [...pe(n), ...t === void 0 ? [] : me(n, t)];
|
|
268
|
-
return {
|
|
269
|
-
ok: !r.some((e) => e.severity === "error"),
|
|
270
|
-
diagnostics: r
|
|
271
|
-
};
|
|
272
167
|
}, ge = (e) => {
|
|
273
168
|
let t = "", n = !1;
|
|
274
169
|
for (let r = 0; r < e.length; r++) {
|
|
@@ -343,7 +238,7 @@ var re = () => {
|
|
|
343
238
|
}
|
|
344
239
|
} };
|
|
345
240
|
}, ve = (e, t = "tsconfig.json") => {
|
|
346
|
-
let n =
|
|
241
|
+
let n = ae(t) ? t : C(e, t), r = F(n, /* @__PURE__ */ new Set()), i = r?.compilerOptions?.paths;
|
|
347
242
|
if (i === void 0) return;
|
|
348
243
|
let a = {};
|
|
349
244
|
for (let [e, t] of Object.entries(i)) Array.isArray(t) && (a[e] = t.filter((e) => typeof e == "string"));
|
|
@@ -352,7 +247,7 @@ var re = () => {
|
|
|
352
247
|
paths: a
|
|
353
248
|
};
|
|
354
249
|
}, I = (e, t = "tsconfig.json") => {
|
|
355
|
-
let n =
|
|
250
|
+
let n = ae(t) ? t : C(e, t), r = F(n, /* @__PURE__ */ new Set()), i = r?.compilerOptions?.paths;
|
|
356
251
|
if (i === void 0) return [];
|
|
357
252
|
let a = C(b(n), r?.compilerOptions?.baseUrl ?? "."), o = [];
|
|
358
253
|
for (let [e, t] of Object.entries(i)) {
|
|
@@ -404,45 +299,45 @@ var re = () => {
|
|
|
404
299
|
}, xe = (e, t) => t.some((t) => e === t.dir || e.startsWith(`${t.dir}${w}`)), Se = (e, t) => t.map((t) => `${S(e, t.dir) || "."} (${t.source})`), Ce = [
|
|
405
300
|
{
|
|
406
301
|
id: "component.ui",
|
|
407
|
-
re:
|
|
302
|
+
re: _,
|
|
408
303
|
needsTest: !0
|
|
409
304
|
},
|
|
410
305
|
{
|
|
411
306
|
id: "component",
|
|
412
|
-
re:
|
|
307
|
+
re: ee,
|
|
413
308
|
needsTest: !0
|
|
414
309
|
},
|
|
415
310
|
{
|
|
416
311
|
id: "hook",
|
|
417
|
-
re:
|
|
312
|
+
re: te,
|
|
418
313
|
needsTest: !0
|
|
419
314
|
},
|
|
420
315
|
{
|
|
421
316
|
id: "tracking",
|
|
422
|
-
re:
|
|
317
|
+
re: f,
|
|
423
318
|
needsTest: !0
|
|
424
319
|
},
|
|
425
320
|
{
|
|
426
321
|
id: "store",
|
|
427
|
-
re:
|
|
322
|
+
re: d,
|
|
428
323
|
needsTest: !0
|
|
429
324
|
},
|
|
430
325
|
{
|
|
431
326
|
id: "internal",
|
|
432
|
-
re:
|
|
327
|
+
re: h,
|
|
433
328
|
needsTest: !0
|
|
434
329
|
},
|
|
435
330
|
{
|
|
436
331
|
id: "fixture",
|
|
437
|
-
re:
|
|
332
|
+
re: v,
|
|
438
333
|
needsTest: !1
|
|
439
334
|
},
|
|
440
335
|
{
|
|
441
336
|
id: "types",
|
|
442
|
-
re:
|
|
337
|
+
re: p,
|
|
443
338
|
needsTest: !1
|
|
444
339
|
}
|
|
445
|
-
], R = (e) => Ce.find((t) => t.re.test(e))?.id ?? null, we = (e) =>
|
|
340
|
+
], R = (e) => Ce.find((t) => t.re.test(e))?.id ?? null, we = (e) => m.test(e), Te = /* @__PURE__ */ new Set([
|
|
446
341
|
"useMutation",
|
|
447
342
|
"useAction",
|
|
448
343
|
"useUpload",
|
|
@@ -487,17 +382,17 @@ var re = () => {
|
|
|
487
382
|
a.isDirectory() ? Ae(r, t, n + 1) : a.isFile() && ke.test(i) && !i.endsWith(".d.ts") && t.push(r);
|
|
488
383
|
}
|
|
489
384
|
return t;
|
|
490
|
-
}, je = /\b(?:FC|FunctionComponent|ComponentType|ForwardRefExoticComponent|MemoExoticComponent)\b/, Me = /\b(?:memo|forwardRef|observer|styled)\b/,
|
|
491
|
-
if (
|
|
492
|
-
if (k.isExportAssignment(e) || k.isAsExpression(e) || k.isSatisfiesExpression(e) || k.isParenthesizedExpression(e)) return
|
|
385
|
+
}, je = /\b(?:FC|FunctionComponent|ComponentType|ForwardRefExoticComponent|MemoExoticComponent)\b/, Me = /\b(?:memo|forwardRef|observer|styled)\b/, Ne = (e) => k.isArrowFunction(e) || k.isFunctionExpression(e) || k.isFunctionDeclaration(e) || k.isClassDeclaration(e) || k.isClassExpression(e), z = (e) => {
|
|
386
|
+
if (Ne(e)) return !0;
|
|
387
|
+
if (k.isExportAssignment(e) || k.isAsExpression(e) || k.isSatisfiesExpression(e) || k.isParenthesizedExpression(e)) return z(e.getExpression());
|
|
493
388
|
if (k.isVariableDeclaration(e)) {
|
|
494
389
|
let t = e.getTypeNode();
|
|
495
390
|
if (t !== void 0 && je.test(t.getText())) return !0;
|
|
496
391
|
let n = e.getInitializer();
|
|
497
|
-
return n === void 0 ||
|
|
392
|
+
return n === void 0 || z(n);
|
|
498
393
|
}
|
|
499
|
-
return k.isCallExpression(e) ? Me.test(e.getExpression().getText()) ? !0 : e.getArguments().some((e) =>
|
|
500
|
-
},
|
|
394
|
+
return k.isCallExpression(e) ? Me.test(e.getExpression().getText()) ? !0 : e.getArguments().some((e) => Ne(e) || k.isIdentifier(e)) : k.isTaggedTemplateExpression(e) ? !0 : !(k.isObjectLiteralExpression(e) || k.isArrayLiteralExpression(e) || k.isStringLiteral(e) || k.isNoSubstitutionTemplateLiteral(e) || k.isNumericLiteral(e) || k.isTemplateExpression(e) || k.isNewExpression(e) || k.isPropertyAccessExpression(e) || e.getKind() === j.TrueKeyword || e.getKind() === j.FalseKeyword || e.getKind() === j.NullKeyword);
|
|
395
|
+
}, Pe = (e) => {
|
|
501
396
|
let t = [], n = [], r = [], i = /* @__PURE__ */ new Set();
|
|
502
397
|
for (let [a, o] of e.getExportedDeclarations()) {
|
|
503
398
|
let e = o[0];
|
|
@@ -508,7 +403,7 @@ var re = () => {
|
|
|
508
403
|
n.push(s);
|
|
509
404
|
continue;
|
|
510
405
|
}
|
|
511
|
-
if (/^[A-Z]/.test(s) &&
|
|
406
|
+
if (/^[A-Z]/.test(s) && z(e)) {
|
|
512
407
|
t.push(s);
|
|
513
408
|
continue;
|
|
514
409
|
}
|
|
@@ -520,7 +415,7 @@ var re = () => {
|
|
|
520
415
|
others: r,
|
|
521
416
|
hasRuntimeExport: t.length + n.length + r.length > 0
|
|
522
417
|
};
|
|
523
|
-
},
|
|
418
|
+
}, B = [], Fe = (e, t, n) => {
|
|
524
419
|
let r = b(e), i = [];
|
|
525
420
|
for (let e = r;; e = b(e)) {
|
|
526
421
|
let r = n.get(e);
|
|
@@ -537,8 +432,8 @@ var re = () => {
|
|
|
537
432
|
}
|
|
538
433
|
if (e === t || b(e) === e) break;
|
|
539
434
|
}
|
|
540
|
-
for (let e of i) n.set(e,
|
|
541
|
-
return
|
|
435
|
+
for (let e of i) n.set(e, B);
|
|
436
|
+
return B;
|
|
542
437
|
}, Ie = (e, t, n) => {
|
|
543
438
|
let r = t.startsWith(".") ? C(b(e), t) : ye(t, n);
|
|
544
439
|
if (r === void 0) return null;
|
|
@@ -627,14 +522,14 @@ var re = () => {
|
|
|
627
522
|
} catch {
|
|
628
523
|
continue;
|
|
629
524
|
}
|
|
630
|
-
s.set(t,
|
|
525
|
+
s.set(t, Pe(r)), c.set(t, Le(r, t, Fe(t, e, u))), l.set(t, Re(r));
|
|
631
526
|
}
|
|
632
527
|
let d = /* @__PURE__ */ new Map();
|
|
633
528
|
for (let [e, t] of c) for (let n of t.localTargets) {
|
|
634
529
|
let t = d.get(n) ?? [];
|
|
635
530
|
t.push(e), d.set(n, t);
|
|
636
531
|
}
|
|
637
|
-
let
|
|
532
|
+
let f = (e) => {
|
|
638
533
|
let t = s.get(e), n = /* @__PURE__ */ new Set([
|
|
639
534
|
...t?.components ?? [],
|
|
640
535
|
...t?.hooks ?? [],
|
|
@@ -655,12 +550,12 @@ var re = () => {
|
|
|
655
550
|
}
|
|
656
551
|
};
|
|
657
552
|
return a(e, null), [...r];
|
|
658
|
-
},
|
|
553
|
+
}, p = 0;
|
|
659
554
|
for (let e of r) {
|
|
660
555
|
let t = R(e), n = s.get(e), r = c.get(e);
|
|
661
556
|
if (n === void 0 || r === void 0) continue;
|
|
662
557
|
let i = we(e);
|
|
663
|
-
t !== null && !i && (
|
|
558
|
+
t !== null && !i && (p += 1);
|
|
664
559
|
let u = d.get(e) ?? [];
|
|
665
560
|
if ((t === "component" || t === "component.ui") && !i) {
|
|
666
561
|
let t = ze(n.components);
|
|
@@ -729,9 +624,9 @@ var re = () => {
|
|
|
729
624
|
detail: `imports write hook(s): ${t.join(", ")}`,
|
|
730
625
|
fix: "a *.component.ui.tsx renders; it does not write. Lift the mutation into the *.component.tsx that owns it and pass a handler down. Reading (useT / useCan / usePermissions) stays allowed — threading those through props is prop-drilling, not reusability"
|
|
731
626
|
});
|
|
732
|
-
let n =
|
|
627
|
+
let n = f(e), i = n.filter((e) => {
|
|
733
628
|
let t = R(e);
|
|
734
|
-
return t === "component" || t === "component.ui" ||
|
|
629
|
+
return t === "component" || t === "component.ui" || y.test(e) || g.has(e.slice(e.lastIndexOf(w) + 1));
|
|
735
630
|
});
|
|
736
631
|
n.length === 0 ? a.push({
|
|
737
632
|
rule: "ui/orphaned",
|
|
@@ -794,7 +689,7 @@ var re = () => {
|
|
|
794
689
|
}
|
|
795
690
|
return a.sort((e, t) => e.file === t.file ? e.rule.localeCompare(t.rule) : e.file.localeCompare(t.file)), {
|
|
796
691
|
findings: a,
|
|
797
|
-
declared:
|
|
692
|
+
declared: p,
|
|
798
693
|
scanned: r.length,
|
|
799
694
|
vendored: n
|
|
800
695
|
};
|
|
@@ -1173,99 +1068,14 @@ var re = () => {
|
|
|
1173
1068
|
" reaches your deploy target is not knowable from here — a secret manager",
|
|
1174
1069
|
" or a CI variable is not a file. Naming it nowhere is conclusive; naming",
|
|
1175
1070
|
" it somewhere is not a guarantee."
|
|
1176
|
-
].join("\n"), mt = (e) =>
|
|
1177
|
-
let t = [], n = e;
|
|
1178
|
-
for (let e = 0; e < 12; e++) {
|
|
1179
|
-
let e = x(n, "node_modules");
|
|
1180
|
-
T(e) && t.push(e);
|
|
1181
|
-
let r = b(n);
|
|
1182
|
-
if (r === n) break;
|
|
1183
|
-
n = r;
|
|
1184
|
-
}
|
|
1185
|
-
return t;
|
|
1186
|
-
}, _t = (e) => {
|
|
1187
|
-
try {
|
|
1188
|
-
let t = JSON.parse(E(x(e, "package.json"), "utf8"));
|
|
1189
|
-
return typeof t.version == "string" ? t.version : void 0;
|
|
1190
|
-
} catch {
|
|
1191
|
-
return;
|
|
1192
|
-
}
|
|
1193
|
-
}, vt = (e) => {
|
|
1194
|
-
let t = [], n;
|
|
1195
|
-
try {
|
|
1196
|
-
n = D(e);
|
|
1197
|
-
} catch {
|
|
1198
|
-
return t;
|
|
1199
|
-
}
|
|
1200
|
-
for (let r of n) {
|
|
1201
|
-
if (r.startsWith(".") || ht.test(r)) continue;
|
|
1202
|
-
let n = x(e, r);
|
|
1203
|
-
if (r.startsWith("@")) {
|
|
1204
|
-
let e;
|
|
1205
|
-
try {
|
|
1206
|
-
e = D(n);
|
|
1207
|
-
} catch {
|
|
1208
|
-
continue;
|
|
1209
|
-
}
|
|
1210
|
-
for (let i of e) t.push({
|
|
1211
|
-
pkg: `${r}/${i}`,
|
|
1212
|
-
dir: x(n, i)
|
|
1213
|
-
});
|
|
1214
|
-
continue;
|
|
1215
|
-
}
|
|
1216
|
-
try {
|
|
1217
|
-
if (!O(n).isDirectory()) continue;
|
|
1218
|
-
} catch {
|
|
1219
|
-
continue;
|
|
1220
|
-
}
|
|
1221
|
-
t.push({
|
|
1222
|
-
pkg: r,
|
|
1223
|
-
dir: n
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
return t;
|
|
1227
|
-
}, yt = (e) => {
|
|
1228
|
-
let t = /* @__PURE__ */ new Map();
|
|
1229
|
-
for (let n of gt(e)) for (let { pkg: e, dir: r } of vt(n)) {
|
|
1230
|
-
if (!mt(e)) continue;
|
|
1231
|
-
let n = _t(r);
|
|
1232
|
-
if (n === void 0) continue;
|
|
1233
|
-
let i = t.get(e) ?? /* @__PURE__ */ new Map();
|
|
1234
|
-
i.has(n) || i.set(n, r), t.set(e, i);
|
|
1235
|
-
}
|
|
1236
|
-
let n = [];
|
|
1237
|
-
for (let [r, i] of t) i.size < 2 || n.push({
|
|
1238
|
-
pkg: r,
|
|
1239
|
-
versions: [...i.keys()].sort(),
|
|
1240
|
-
paths: [...i.values()].map((t) => S(e, t)).sort()
|
|
1241
|
-
});
|
|
1242
|
-
return n.sort((e, t) => e.pkg.localeCompare(t.pkg));
|
|
1243
|
-
}, bt = (e) => {
|
|
1244
|
-
if (e.length !== 0) return [
|
|
1245
|
-
`• ${e.length} package(s) resolved at more than one version:`,
|
|
1246
|
-
...e.flatMap((e) => [` ${e.pkg} — ${e.versions.join(", ")}`, ...e.paths.map((e) => ` ${e}`)]),
|
|
1247
|
-
"",
|
|
1248
|
-
" Two copies of `effect` (or `@effect/*`) is the usual cause of type errors",
|
|
1249
|
-
" inside the GENERATED rpcGroup.generated.ts that look like framework bugs:",
|
|
1250
|
-
" \"Property '[TypeId]' is missing\", \"typeof Never is not assignable to All\",",
|
|
1251
|
-
" or an `Rpc<…, Stream<…>, …>` that will not go where `Any` is expected.",
|
|
1252
|
-
" Effect types are nominal, so a Schema built by one copy is not the same",
|
|
1253
|
-
" type as a Schema expected by the other — and the RUNTIME often still works,",
|
|
1254
|
-
" which is why this shows up as a red tsc against a green server.",
|
|
1255
|
-
"",
|
|
1256
|
-
" Fix it in the install, not the code: align the version across the workspace",
|
|
1257
|
-
" (a root `pnpm.overrides` / `resolutions` entry for `effect` is the blunt",
|
|
1258
|
-
" instrument), then reinstall. Do not silence the generated file — it is where",
|
|
1259
|
-
" a genuine mistake in your own descriptors surfaces."
|
|
1260
|
-
].join("\n");
|
|
1261
|
-
}, xt = (e) => {
|
|
1071
|
+
].join("\n"), mt = (e) => {
|
|
1262
1072
|
if (e.catalogCodes.length === 0) return;
|
|
1263
1073
|
let t = new Set(e.declaredLocales), n = e.catalogCodes.filter((e) => !t.has(e)).sort();
|
|
1264
1074
|
if (n.length !== 0) return {
|
|
1265
1075
|
orphaned: n,
|
|
1266
1076
|
noneDeclared: t.size === 0
|
|
1267
1077
|
};
|
|
1268
|
-
},
|
|
1078
|
+
}, ht = (e, t) => {
|
|
1269
1079
|
let n = e.orphaned.join(", ");
|
|
1270
1080
|
return e.noneDeclared ? [
|
|
1271
1081
|
`⚠ ${t} has ${e.orphaned.length} catalog(s) — ${n} — and the app declares no \`locales:\`.`,
|
|
@@ -1277,33 +1087,33 @@ var re = () => {
|
|
|
1277
1087
|
" …or delete the files. A catalog that is never loaded looks from the inside",
|
|
1278
1088
|
" exactly like one that works, which is why this is worth a line."
|
|
1279
1089
|
] : [`⚠ ${t} has catalog(s) not in \`locales:\` — ${n} — so they are never imported.`, " Add the code(s) to `locales:` in your app config, or delete the file(s)."];
|
|
1280
|
-
},
|
|
1090
|
+
}, gt = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), _t = /* @__PURE__ */ new Set([
|
|
1281
1091
|
"requireScope",
|
|
1282
1092
|
"requireAnyScope",
|
|
1283
1093
|
"requireAuth",
|
|
1284
1094
|
"assertScope",
|
|
1285
1095
|
"assertCan",
|
|
1286
1096
|
"can"
|
|
1287
|
-
]),
|
|
1097
|
+
]), vt = (e) => {
|
|
1288
1098
|
let t = /* @__PURE__ */ new Set();
|
|
1289
|
-
for (let n of e) for (let e of
|
|
1099
|
+
for (let n of e) for (let e of gt(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
|
|
1290
1100
|
return t;
|
|
1291
|
-
},
|
|
1101
|
+
}, yt = (e, t) => {
|
|
1292
1102
|
for (let n of t) if (RegExp(`\\b${n}\\s*\\(`).test(e)) return n;
|
|
1293
|
-
},
|
|
1103
|
+
}, bt = (e) => {
|
|
1294
1104
|
let t = /\bsubject\s*\.\s*id\b[^\n]*?(?:!==|===|!=|==)|(?:!==|===|!=|==)[^\n]*?\bsubject\s*\.\s*id\b/.test(e), n = /(?:Error|Denied|Forbidden|Unauthorized)\b|\b(?:fail|die|throw)\b/.test(e);
|
|
1295
1105
|
return t && n;
|
|
1296
|
-
},
|
|
1106
|
+
}, xt = (e, t, n) => {
|
|
1297
1107
|
if (e.hasDeclaredGuards) return { kind: "declared-guard" };
|
|
1298
|
-
let r =
|
|
1299
|
-
return i === void 0 ?
|
|
1108
|
+
let r = gt(e.src), i = yt(r, t);
|
|
1109
|
+
return i === void 0 ? bt(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
|
|
1300
1110
|
kind: "vocabulary-guard",
|
|
1301
1111
|
name: i
|
|
1302
1112
|
};
|
|
1303
|
-
},
|
|
1113
|
+
}, St = (e, t, n) => {
|
|
1304
1114
|
let r = e.op === "delete" ? 3 : e.op === "update" ? 2 : 1;
|
|
1305
1115
|
return e.table !== void 0 && (t.has(e.table) && (r += 2), n.has(e.table) && e.op === "delete" && (r += 2)), r;
|
|
1306
|
-
},
|
|
1116
|
+
}, Ct = (e, t, n) => {
|
|
1307
1117
|
switch (t.kind) {
|
|
1308
1118
|
case "declared-guard": return "guards: on the descriptor";
|
|
1309
1119
|
case "vocabulary-guard": return `calls ${t.name}()`;
|
|
@@ -1311,15 +1121,15 @@ var re = () => {
|
|
|
1311
1121
|
case "allowlisted": return "accepted by a previous run";
|
|
1312
1122
|
case "unchecked": return n ? e.op === "read" ? "no check in this file — this app registers a row filter; VERIFY it covers this table, then record it as reviewed= rather than debt" : `${e.op}s${e.table ? ` ${e.table}` : ""} with no check in this file — this app registers a row filter; VERIFY it covers this table, then record it as reviewed= rather than debt` : e.op === "read" ? "returns a row the client selected, with nothing compared to the caller" : `${e.op}s${e.table ? ` ${e.table}` : ""} with nothing constraining WHICH row`;
|
|
1313
1123
|
}
|
|
1314
|
-
},
|
|
1124
|
+
}, wt = (e) => {
|
|
1315
1125
|
let t = e.executors.map((t) => {
|
|
1316
|
-
let n =
|
|
1126
|
+
let n = xt(t, e.guardVocabulary, e.allowlist);
|
|
1317
1127
|
return {
|
|
1318
1128
|
tag: t.tag,
|
|
1319
1129
|
path: t.path,
|
|
1320
1130
|
verdict: n,
|
|
1321
|
-
severity:
|
|
1322
|
-
why:
|
|
1131
|
+
severity: St(t, e.tenantScopedTables, e.referencedTables),
|
|
1132
|
+
why: Ct(t, n, e.rowFilterRegistered === !0)
|
|
1323
1133
|
};
|
|
1324
1134
|
}), n = (e) => t.filter((t) => t.verdict.kind === e).length;
|
|
1325
1135
|
return {
|
|
@@ -1333,7 +1143,7 @@ var re = () => {
|
|
|
1333
1143
|
},
|
|
1334
1144
|
unchecked: t.filter((e) => e.verdict.kind === "unchecked").sort((e, t) => t.severity - e.severity || e.tag.localeCompare(t.tag))
|
|
1335
1145
|
};
|
|
1336
|
-
},
|
|
1146
|
+
}, Tt = [
|
|
1337
1147
|
"# voltro doctor — authz allowlist",
|
|
1338
1148
|
"#",
|
|
1339
1149
|
"# Two KINDS of line, and the difference is the point:",
|
|
@@ -1358,18 +1168,18 @@ var re = () => {
|
|
|
1358
1168
|
"# `--write-authz-allowlist` PRESERVES reviewed= lines. It only ever adds debt",
|
|
1359
1169
|
"# lines for executors that are newly unchecked.",
|
|
1360
1170
|
""
|
|
1361
|
-
],
|
|
1171
|
+
], Et = (e) => {
|
|
1362
1172
|
let t = [...e].map((e) => typeof e == "string" ? { tag: e } : e), n = t.filter((e) => e.reviewed === void 0).map((e) => e.tag).sort(), r = t.filter((e) => e.reviewed !== void 0).sort((e, t) => e.tag.localeCompare(t.tag));
|
|
1363
1173
|
return [
|
|
1364
|
-
...
|
|
1174
|
+
...Tt,
|
|
1365
1175
|
...n,
|
|
1366
1176
|
...r.length > 0 ? ["", "# reviewed — read by a human, open on purpose"] : [],
|
|
1367
1177
|
...r.map((e) => `${e.tag} reviewed=${e.reviewed}`),
|
|
1368
1178
|
""
|
|
1369
1179
|
].join("\n");
|
|
1370
|
-
},
|
|
1180
|
+
}, Dt = (e, t) => {
|
|
1371
1181
|
let n = [...new Set(t)].sort();
|
|
1372
|
-
if (e === void 0) return
|
|
1182
|
+
if (e === void 0) return Et(n.map((e) => ({ tag: e })));
|
|
1373
1183
|
let r = W(e).tags, i = n.filter((e) => !r.has(e));
|
|
1374
1184
|
return i.length === 0 ? e : [
|
|
1375
1185
|
e.replace(/\n+$/, ""),
|
|
@@ -1379,7 +1189,7 @@ var re = () => {
|
|
|
1379
1189
|
...i,
|
|
1380
1190
|
""
|
|
1381
1191
|
].join("\n");
|
|
1382
|
-
},
|
|
1192
|
+
}, Ot = (e, t) => {
|
|
1383
1193
|
let n = [...new Set(t)];
|
|
1384
1194
|
if (e === void 0) return {
|
|
1385
1195
|
added: n.length,
|
|
@@ -1392,7 +1202,7 @@ var re = () => {
|
|
|
1392
1202
|
kept: r.size,
|
|
1393
1203
|
removed: 0
|
|
1394
1204
|
};
|
|
1395
|
-
},
|
|
1205
|
+
}, kt = class extends Error {
|
|
1396
1206
|
tag;
|
|
1397
1207
|
constructor(e) {
|
|
1398
1208
|
super(`authz allowlist: '${e}' is marked reviewed with no reason. Write \`${e} reviewed=<why it is genuinely open>\`. A bare tag is the other, honest option — it records the executor as DEBT, which is what an unexplained exemption is.`), this.tag = e, this.name = "AllowlistReasonMissingError";
|
|
@@ -1410,7 +1220,7 @@ var re = () => {
|
|
|
1410
1220
|
continue;
|
|
1411
1221
|
}
|
|
1412
1222
|
let a = r[2].trim();
|
|
1413
|
-
if (a.length === 0) throw new
|
|
1223
|
+
if (a.length === 0) throw new kt(i);
|
|
1414
1224
|
t.push({
|
|
1415
1225
|
tag: i,
|
|
1416
1226
|
reviewed: a
|
|
@@ -1420,13 +1230,13 @@ var re = () => {
|
|
|
1420
1230
|
tags: new Set(t.map((e) => e.tag)),
|
|
1421
1231
|
entries: t
|
|
1422
1232
|
};
|
|
1423
|
-
},
|
|
1233
|
+
}, At = (e) => {
|
|
1424
1234
|
let t = e.indexOf(".");
|
|
1425
1235
|
return t <= 0 ? void 0 : e.slice(0, t);
|
|
1426
|
-
},
|
|
1236
|
+
}, jt = (e, t) => {
|
|
1427
1237
|
let n = new Set(t.tables), r = new Set(t.rpcTags), i = /* @__PURE__ */ new Map();
|
|
1428
1238
|
for (let e of t.rpcTags) {
|
|
1429
|
-
let t =
|
|
1239
|
+
let t = At(e);
|
|
1430
1240
|
if (t === void 0) continue;
|
|
1431
1241
|
let n = i.get(t);
|
|
1432
1242
|
n ? n.push(e) : i.set(t, [e]);
|
|
@@ -1455,7 +1265,7 @@ var re = () => {
|
|
|
1455
1265
|
});
|
|
1456
1266
|
continue;
|
|
1457
1267
|
}
|
|
1458
|
-
let s = new Set(o.rpcTags.map(
|
|
1268
|
+
let s = new Set(o.rpcTags.map(At).filter((e) => e !== void 0));
|
|
1459
1269
|
for (let e of s) {
|
|
1460
1270
|
let t = i.get(e);
|
|
1461
1271
|
t !== void 0 && a.push({
|
|
@@ -1468,13 +1278,13 @@ var re = () => {
|
|
|
1468
1278
|
}
|
|
1469
1279
|
}
|
|
1470
1280
|
return a;
|
|
1471
|
-
},
|
|
1281
|
+
}, Mt = (e, t) => {
|
|
1472
1282
|
let n = e.reduce((e, t) => e + t.tables.length, 0), r = [`plugin surface · ${e.length} plugin(s) contribute ${n} table(s)`];
|
|
1473
1283
|
if (t.length === 0) return r.push(" ✓ no overlap with your own tables or rpc namespaces"), r;
|
|
1474
1284
|
for (let e of t) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.plugin} — ${e.detail}`), r.push(` ${e.fix}`);
|
|
1475
1285
|
return r;
|
|
1476
|
-
},
|
|
1477
|
-
let t =
|
|
1286
|
+
}, Nt = (e) => T(C(e, "app.config.ts")) || T(C(e, "app.config.js")), Pt = (e) => {
|
|
1287
|
+
let t = re(e), n = ne(e);
|
|
1478
1288
|
return {
|
|
1479
1289
|
root: e,
|
|
1480
1290
|
serveBundle: t,
|
|
@@ -1482,19 +1292,19 @@ var re = () => {
|
|
|
1482
1292
|
apiBundle: n,
|
|
1483
1293
|
apiBundlePresent: T(n)
|
|
1484
1294
|
};
|
|
1485
|
-
},
|
|
1295
|
+
}, Ft = [
|
|
1486
1296
|
"Production `voltro serve` requires a precompiled serve bundle and never transpiles on demand.",
|
|
1487
1297
|
"Add a `voltro build .` step BEFORE `voltro serve .` in your Dockerfile / start script.",
|
|
1488
1298
|
"(Generated Dockerfiles from `voltro create-project` already do this.)"
|
|
1489
|
-
].join("\n "),
|
|
1490
|
-
let n =
|
|
1491
|
-
if (console.log(`voltro doctor — serve preflight for ${n.root}`), !
|
|
1299
|
+
].join("\n "), It = (e, t = !1) => {
|
|
1300
|
+
let n = Pt(e);
|
|
1301
|
+
if (console.log(`voltro doctor — serve preflight for ${n.root}`), !Nt(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
|
|
1492
1302
|
console.log(`${n.serveBundlePresent ? "✓" : "✗"} serve bundle: ${n.serveBundlePresent ? "present" : "MISSING"} (${n.serveBundle})`), console.log(`${n.apiBundlePresent ? "✓" : "•"} api bundle: ${n.apiBundlePresent ? "present" : "absent"} (${n.apiBundle})`);
|
|
1493
1303
|
let r = process.env.NODE_ENV === "production";
|
|
1494
1304
|
if (n.serveBundlePresent) return console.log("✓ serve preflight: ready for `voltro serve`."), 0;
|
|
1495
1305
|
let i = t || r;
|
|
1496
|
-
return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${
|
|
1497
|
-
},
|
|
1306
|
+
return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${Ft}`), +!!i;
|
|
1307
|
+
}, Lt = (e, t, n) => {
|
|
1498
1308
|
let r = new Set(e), i = I(n), a = (e) => (/\.(tsx?|jsx?)$/.test(e) ? [e] : [
|
|
1499
1309
|
`${e}.ts`,
|
|
1500
1310
|
`${e}.tsx`,
|
|
@@ -1520,7 +1330,7 @@ var re = () => {
|
|
|
1520
1330
|
r !== void 0 && o.push(r);
|
|
1521
1331
|
}
|
|
1522
1332
|
return o;
|
|
1523
|
-
}, s = /* @__PURE__ */ new Set(), c = e.filter((e) =>
|
|
1333
|
+
}, s = /* @__PURE__ */ new Set(), c = e.filter((e) => Ut.test(S(n, e))), l = new Set(c);
|
|
1524
1334
|
for (; c.length > 0;) {
|
|
1525
1335
|
let e = c.shift();
|
|
1526
1336
|
if (!s.has(e)) {
|
|
@@ -1533,11 +1343,11 @@ var re = () => {
|
|
|
1533
1343
|
let d = /* @__PURE__ */ new Set();
|
|
1534
1344
|
for (let e of s) l.has(e) || u.has(e) || d.add(e);
|
|
1535
1345
|
return d;
|
|
1536
|
-
},
|
|
1346
|
+
}, Rt = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), zt = (e, t) => (e.match(t) ?? []).length, G = (e, t) => e.getDescendantsOfKind(j.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, Bt = (e, t) => {
|
|
1537
1347
|
if (e.src.includes(t)) return !0;
|
|
1538
1348
|
let n = t.replace(/^@voltro\/plugin-/, "");
|
|
1539
1349
|
return n !== t && G(e.file, RegExp(`^${n}Plugin$`)) > 0;
|
|
1540
|
-
},
|
|
1350
|
+
}, Vt = (e, t) => {
|
|
1541
1351
|
let n = [], r = RegExp(`\\b${t}\\s*(?:<[^()]*>)?\\s*\\(`, "g"), i;
|
|
1542
1352
|
for (; (i = r.exec(e)) !== null;) {
|
|
1543
1353
|
let t = i.index + i[0].length, r = 1, a = t;
|
|
@@ -1545,10 +1355,10 @@ var re = () => {
|
|
|
1545
1355
|
n.push(e.slice(t, a - 1));
|
|
1546
1356
|
}
|
|
1547
1357
|
return n;
|
|
1548
|
-
},
|
|
1358
|
+
}, Ht = (e, t) => {
|
|
1549
1359
|
let n = t.getSymbol()?.getDeclarations()?.[0];
|
|
1550
1360
|
return n === void 0 ? [] : e.getDescendantsOfKind(j.Identifier).filter((e) => e.getSymbol()?.getDeclarations()?.[0] === n);
|
|
1551
|
-
},
|
|
1361
|
+
}, Ut = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, Wt = /\.(query|mutation|action|stream)\.server\.tsx?$/, Gt = [
|
|
1552
1362
|
"Id",
|
|
1553
1363
|
"ID",
|
|
1554
1364
|
"Hash",
|
|
@@ -1574,12 +1384,12 @@ var re = () => {
|
|
|
1574
1384
|
"Comment",
|
|
1575
1385
|
"Provider",
|
|
1576
1386
|
"Format"
|
|
1577
|
-
],
|
|
1387
|
+
], Kt = RegExp(`(?:${Gt.join("|")})$|_(?:${Gt.map((e) => e.toLowerCase()).join("|")})$`), qt = [
|
|
1578
1388
|
{
|
|
1579
1389
|
id: "hardcoded-framework-cookie",
|
|
1580
1390
|
scope: "client",
|
|
1581
1391
|
smell: "a framework cookie name written as a string literal instead of imported",
|
|
1582
|
-
use: "import the constant — `LOCALE_COOKIE` / `THEME_COOKIE` from `@voltro/ui-shadcn` — so a rename in the framework is a compile error in your app rather than a preference that quietly stops working",
|
|
1392
|
+
use: "import the constant — `LOCALE_COOKIE` / `THEME_COOKIE` from `@voltro/i18n` (or from `@voltro/ui-shadcn` if you use the kit) — so a rename in the framework is a compile error in your app rather than a preference that quietly stops working",
|
|
1583
1393
|
match: ({ src: e }) => /['"`]voltro:(?:locale|theme|lang)['"`]/.test(e)
|
|
1584
1394
|
},
|
|
1585
1395
|
{
|
|
@@ -1587,7 +1397,7 @@ var re = () => {
|
|
|
1587
1397
|
scope: "server",
|
|
1588
1398
|
smell: "an executor that never names its own descriptor — its input type is hand-written, so it can drift from the contract it implements",
|
|
1589
1399
|
use: "import the descriptor and type the input as `ExecutorInput<typeof descriptor>`, so the wire contract and the handler cannot disagree",
|
|
1590
|
-
match: ({ src: e, path: t }) =>
|
|
1400
|
+
match: ({ src: e, path: t }) => Wt.test(t) && !/\bimport\s[^;]*\bfrom\s*['"][^'"]*['"]/.test((e.match(/^\s*import\s[^;]*from\s*['"]\.[^'"]*['"]/gm) ?? []).join("\n"))
|
|
1591
1401
|
},
|
|
1592
1402
|
{
|
|
1593
1403
|
id: "subject-write-no-guard",
|
|
@@ -1595,8 +1405,8 @@ var re = () => {
|
|
|
1595
1405
|
smell: "writes ctx.request.subject.id into the database with no guard on the descriptor — an anonymous caller reaches the write and gets a raw statement failure instead of a typed refusal",
|
|
1596
1406
|
use: "add a guard (e.g. `.guard(requireScope('…'))`) or an explicit auth check, so an unauthenticated caller is refused BEFORE the write",
|
|
1597
1407
|
match: ({ src: e, path: t }) => {
|
|
1598
|
-
if (!
|
|
1599
|
-
let n =
|
|
1408
|
+
if (!Wt.test(t)) return !1;
|
|
1409
|
+
let n = Rt(e);
|
|
1600
1410
|
return /\bsubject\s*\.\s*id\b/.test(n) && /\b(?:insert|update|upsert|insertMany|updateMany|insertRow|upsertRow|updateManyRow)\s*\(/.test(n) && !/\b(?:guard|guards|requireScope|requireAnyScope|assertCan|assertScope|requireAuth|Unauthenticated)\b/.test(n);
|
|
1601
1411
|
}
|
|
1602
1412
|
},
|
|
@@ -1605,7 +1415,7 @@ var re = () => {
|
|
|
1605
1415
|
scope: "server",
|
|
1606
1416
|
smell: "raw fetch() for outbound HTTP on the server (no traceparent, no retry, and no SSRF guard where the URL is not a constant)",
|
|
1607
1417
|
use: "yield* HttpClient — the framework client. It injects traceparent, retries, and honours `http.allowHosts`. Where the URL is built from anything a caller supplied it ALSO blocks loopback / RFC-1918 / link-local targets (incl. 169.254.169.254) on the initial request AND every redirect hop — for a hard-coded host that half is redundant, and the first three are still the reason to switch",
|
|
1608
|
-
match: ({ file: e, path: t, serverOnly: n }) => (
|
|
1418
|
+
match: ({ file: e, path: t, serverOnly: n }) => (Ut.test(t) || n) && G(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
|
|
1609
1419
|
},
|
|
1610
1420
|
{
|
|
1611
1421
|
id: "form",
|
|
@@ -1640,7 +1450,7 @@ var re = () => {
|
|
|
1640
1450
|
scope: "client",
|
|
1641
1451
|
smell: "useMemo fanning in multiple subscriptions (hand-maintained dep array)",
|
|
1642
1452
|
use: "useDerived — dependency-tracked, referentially stable",
|
|
1643
|
-
match: ({ src: e }) =>
|
|
1453
|
+
match: ({ src: e }) => zt(e, /\buseSubscription\s*[(<]/g) >= 3 && zt(e, /\buseMemo\s*\(/g) >= 3
|
|
1644
1454
|
},
|
|
1645
1455
|
{
|
|
1646
1456
|
id: "next-shim",
|
|
@@ -1665,7 +1475,7 @@ var re = () => {
|
|
|
1665
1475
|
match: ({ file: e }) => e.getDescendantsOfKind(j.CallExpression).filter((e) => /(^|\.)useSubscription$/.test(e.getExpression().getText())).flatMap((e) => {
|
|
1666
1476
|
let t = e.getFirstAncestorByKind(j.VariableDeclaration)?.getNameNode();
|
|
1667
1477
|
return t === void 0 ? [] : k.isObjectBindingPattern(t) ? t.getElements().filter((e) => (e.getPropertyNameNode() ?? e.getNameNode()).getText() === "data").map((e) => e.getNameNode()) : [];
|
|
1668
|
-
}).some((t) =>
|
|
1478
|
+
}).some((t) => Ht(e, t).some((e) => {
|
|
1669
1479
|
let t = e.getParent();
|
|
1670
1480
|
if (k.isBinaryExpression(t)) {
|
|
1671
1481
|
let n = t.getOperatorToken().getText(), r = t.getLeft() === e ? t.getRight() : t.getLeft();
|
|
@@ -1716,7 +1526,7 @@ var re = () => {
|
|
|
1716
1526
|
use: ".encrypted() on the column — boot fails loudly if no cipher is configured, so it can never silently persist plaintext (a *Hash column and a vault* handle are NOT plaintext secrets: the hash IS the protection — often a unique lookup key — and the handle only names a secret held elsewhere, so both are skipped)",
|
|
1717
1527
|
match: ({ src: e }) => e.split("\n").some((e) => [...e.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*(?:text|varchar|string|longtext)\s*\(/g)].some((t) => {
|
|
1718
1528
|
let n = t[1];
|
|
1719
|
-
return !/token|secret|credential|password|apikey|accesskey/i.test(n) ||
|
|
1529
|
+
return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Kt.test(n) || /^vault/i.test(n) || /\.unique\s*\(/.test(e) ? !1 : !/\.encrypted\s*\(/.test(e);
|
|
1720
1530
|
}))
|
|
1721
1531
|
},
|
|
1722
1532
|
{
|
|
@@ -1726,7 +1536,7 @@ var re = () => {
|
|
|
1726
1536
|
use: "you cannot look a value up by equality AND encrypt it non-deterministically — `.encrypted()` would make this column unfindable. Store the HASH as the unique lookup key and keep the secret itself either `.encrypted()` in a second column or nowhere (the framework's own `_voltro_api_keys.hashedKey` is the shape: the presented value is hashed and compared, never read back). A deterministic cipher is the other option and buys equality lookup at the cost of leaking which rows share a value",
|
|
1727
1537
|
match: ({ src: e }) => e.split("\n").some((e) => [...e.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*(?:text|varchar|string|longtext)\s*\(/g)].some((t) => {
|
|
1728
1538
|
let n = t[1];
|
|
1729
|
-
return !/token|secret|credential|password|apikey|accesskey/i.test(n) ||
|
|
1539
|
+
return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Kt.test(n) || /^vault/i.test(n) ? !1 : /\.unique\s*\(/.test(e) && !/\.encrypted\s*\(/.test(e);
|
|
1730
1540
|
}))
|
|
1731
1541
|
},
|
|
1732
1542
|
{
|
|
@@ -1791,8 +1601,8 @@ var re = () => {
|
|
|
1791
1601
|
smell: "setRowFilter is registered, but no test passes `rowFilter:` to makeTestContext",
|
|
1792
1602
|
use: "wire the filter into at least one test (`makeTestContext({ subject, store, rowFilter })`) and sabotage the predicate once to watch it go red — an untested row filter is a visibility rule nothing verifies",
|
|
1793
1603
|
match: ({ file: e, testSources: t }) => G(e, /^setRowFilter$/) > 0 && ![...t.values()].some((e) => {
|
|
1794
|
-
let t =
|
|
1795
|
-
return
|
|
1604
|
+
let t = Rt(e);
|
|
1605
|
+
return Vt(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
|
|
1796
1606
|
})
|
|
1797
1607
|
},
|
|
1798
1608
|
{
|
|
@@ -1802,14 +1612,14 @@ var re = () => {
|
|
|
1802
1612
|
use: "timestampMs / timestampMsOrNull from @voltro/database/wire in the descriptor's output struct — `output` IS the serializer (it is the rpc success schema), so a Date field declared as timestampMs crosses as epoch ms on its own; declaring Schema.Number describes the WIRE type and leaves nothing to convert",
|
|
1803
1613
|
match: ({ src: e }) => /\.(getTime|toISOString)\s*\(\s*\)/.test(e) && /\.map\s*\(|=>\s*\(\{/.test(e) && /\bexport\s+default\b/.test(e)
|
|
1804
1614
|
}
|
|
1805
|
-
],
|
|
1615
|
+
], Jt = (e) => q(e), Yt = (e, t) => {
|
|
1806
1616
|
let n = /* @__PURE__ */ new Set();
|
|
1807
1617
|
for (let r of t) {
|
|
1808
1618
|
let t = S(e, r), i = t.split(/[\\/]/)[0];
|
|
1809
1619
|
n.add(i !== void 0 && i !== t ? i : ".");
|
|
1810
1620
|
}
|
|
1811
1621
|
return [...n].sort();
|
|
1812
|
-
},
|
|
1622
|
+
}, Xt = /\.(tsx?|jsx?)$/, K = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, Zt = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, Qt = (e, t = [], n = 0) => {
|
|
1813
1623
|
if (n > 12 || K.test(e)) return t;
|
|
1814
1624
|
let r;
|
|
1815
1625
|
try {
|
|
@@ -1821,7 +1631,7 @@ var re = () => {
|
|
|
1821
1631
|
let r = x(e, i.name);
|
|
1822
1632
|
if (i.isDirectory()) {
|
|
1823
1633
|
if (i.name.startsWith(".")) continue;
|
|
1824
|
-
|
|
1634
|
+
Qt(r, t, n + 1);
|
|
1825
1635
|
} else dt.test(i.name) && t.push(r);
|
|
1826
1636
|
}
|
|
1827
1637
|
return t;
|
|
@@ -1840,10 +1650,10 @@ var re = () => {
|
|
|
1840
1650
|
} catch {
|
|
1841
1651
|
continue;
|
|
1842
1652
|
}
|
|
1843
|
-
a.isDirectory() ? q(r, t, n + 1) :
|
|
1653
|
+
a.isDirectory() ? q(r, t, n + 1) : Xt.test(i) && !/\.(test|spec)\./.test(i) && !Zt.test(i) && t.push(r);
|
|
1844
1654
|
}
|
|
1845
1655
|
return t;
|
|
1846
|
-
},
|
|
1656
|
+
}, $t = (e, t = [], n = 0) => {
|
|
1847
1657
|
if (n > 12 || K.test(e)) return t;
|
|
1848
1658
|
let r;
|
|
1849
1659
|
try {
|
|
@@ -1858,17 +1668,17 @@ var re = () => {
|
|
|
1858
1668
|
} catch {
|
|
1859
1669
|
continue;
|
|
1860
1670
|
}
|
|
1861
|
-
a.isDirectory() ?
|
|
1671
|
+
a.isDirectory() ? $t(r, t, n + 1) : Xt.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
|
|
1862
1672
|
}
|
|
1863
1673
|
return t;
|
|
1864
|
-
},
|
|
1865
|
-
let t =
|
|
1674
|
+
}, en = (e) => {
|
|
1675
|
+
let t = Jt(e);
|
|
1866
1676
|
return {
|
|
1867
|
-
dirs:
|
|
1677
|
+
dirs: Yt(e, t),
|
|
1868
1678
|
fileCount: t.length
|
|
1869
1679
|
};
|
|
1870
|
-
},
|
|
1871
|
-
let t =
|
|
1680
|
+
}, tn = (e) => {
|
|
1681
|
+
let t = Jt(e);
|
|
1872
1682
|
if (t.length === 0) return [];
|
|
1873
1683
|
let n = new A({
|
|
1874
1684
|
useInMemoryFileSystem: !0,
|
|
@@ -1877,8 +1687,8 @@ var re = () => {
|
|
|
1877
1687
|
for (let e of t) try {
|
|
1878
1688
|
i.set(e, E(e, "utf8"));
|
|
1879
1689
|
} catch {}
|
|
1880
|
-
let a =
|
|
1881
|
-
for (let t of
|
|
1690
|
+
let a = Lt([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
|
|
1691
|
+
for (let t of $t(e)) try {
|
|
1882
1692
|
o.set(t, E(t, "utf8"));
|
|
1883
1693
|
} catch {}
|
|
1884
1694
|
for (let s of t) {
|
|
@@ -1896,23 +1706,23 @@ var re = () => {
|
|
|
1896
1706
|
} catch {
|
|
1897
1707
|
continue;
|
|
1898
1708
|
}
|
|
1899
|
-
for (let t of
|
|
1900
|
-
if (t.plugin !== void 0 &&
|
|
1709
|
+
for (let t of qt) {
|
|
1710
|
+
if (t.plugin !== void 0 && Bt(c, t.plugin) || !t.match(c)) continue;
|
|
1901
1711
|
let n = r.get(t.id) ?? [];
|
|
1902
1712
|
n.push(S(e, s)), r.set(t.id, n);
|
|
1903
1713
|
}
|
|
1904
1714
|
}
|
|
1905
|
-
return
|
|
1715
|
+
return qt.filter((e) => r.has(e.id)).map((e) => ({
|
|
1906
1716
|
rule: e,
|
|
1907
1717
|
files: r.get(e.id)
|
|
1908
1718
|
})).sort((e, t) => t.files.length - e.files.length || e.rule.id.localeCompare(t.rule.id));
|
|
1909
|
-
},
|
|
1910
|
-
let t =
|
|
1719
|
+
}, nn = (e) => {
|
|
1720
|
+
let t = en(e);
|
|
1911
1721
|
return {
|
|
1912
1722
|
root: e,
|
|
1913
1723
|
scannedFiles: t.fileCount,
|
|
1914
1724
|
scannedDirs: t.dirs,
|
|
1915
|
-
findings:
|
|
1725
|
+
findings: tn(e).map(({ rule: e, files: t }) => ({
|
|
1916
1726
|
id: e.id,
|
|
1917
1727
|
scope: e.scope,
|
|
1918
1728
|
smell: e.smell,
|
|
@@ -1920,13 +1730,13 @@ var re = () => {
|
|
|
1920
1730
|
files: t
|
|
1921
1731
|
}))
|
|
1922
1732
|
};
|
|
1923
|
-
},
|
|
1733
|
+
}, rn = 3, an = .2, on = 50, sn = (e, t) => e >= on && t > 0 && e / t >= an, cn = (e) => {
|
|
1924
1734
|
let t = /* @__PURE__ */ new Map();
|
|
1925
1735
|
for (let n of q(e)) try {
|
|
1926
1736
|
t.set(S(e, n), E(n, "utf8"));
|
|
1927
1737
|
} catch {}
|
|
1928
1738
|
let n = /* @__PURE__ */ new Map();
|
|
1929
|
-
for (let t of
|
|
1739
|
+
for (let t of Qt(e)) try {
|
|
1930
1740
|
n.set(S(e, t), E(t, "utf8"));
|
|
1931
1741
|
} catch {}
|
|
1932
1742
|
let r = ft({
|
|
@@ -1934,8 +1744,8 @@ var re = () => {
|
|
|
1934
1744
|
envFiles: n
|
|
1935
1745
|
});
|
|
1936
1746
|
r !== void 0 && (console.log(""), console.log(pt(r)));
|
|
1937
|
-
},
|
|
1938
|
-
let t =
|
|
1747
|
+
}, ln = (e) => {
|
|
1748
|
+
let t = nn(e);
|
|
1939
1749
|
if (console.log(""), t.scannedFiles === 0) return console.log(`\u2022 hand-roll scan: no source directories found under ${e}.`), console.log(" Walked the app root recursively (node_modules / dist / .framework pruned). Run `voltro doctor <app>` against an app root."), 0;
|
|
1940
1750
|
if (t.findings.length === 0) return console.log(`\u2713 hand-roll scan: ${t.scannedFiles} file${t.scannedFiles === 1 ? "" : "s"} across ${t.scannedDirs.join(", ")} \u2014 no hand-rolled primitives found.`), 0;
|
|
1941
1751
|
console.log(`\u2022 Shipped primitives you may be hand-rolling (scanned ${t.scannedFiles} files across ${t.scannedDirs.join(", ")}):`);
|
|
@@ -1946,56 +1756,56 @@ var re = () => {
|
|
|
1946
1756
|
console.log(` [${e}]`);
|
|
1947
1757
|
let i = [...r].sort((e, t) => e.files.length - t.files.length);
|
|
1948
1758
|
for (let e of i) {
|
|
1949
|
-
if (
|
|
1759
|
+
if (sn(e.files.length, t.scannedFiles)) {
|
|
1950
1760
|
let n = Math.round(e.files.length / t.scannedFiles * 100);
|
|
1951
1761
|
console.log(` ${e.smell} \u2014 ${e.files.length} file(s), ${n}% of those scanned: a codebase-wide pattern rather than a work list`), console.log(` \u2192 ${e.use}`), console.log(" (paths omitted on purpose at this scale — `voltro doctor --json` has every one.)");
|
|
1952
1762
|
continue;
|
|
1953
1763
|
}
|
|
1954
|
-
let r = e.files.slice(0,
|
|
1764
|
+
let r = e.files.slice(0, rn).join(", "), i = e.files.length - rn;
|
|
1955
1765
|
i > 0 && (n += i);
|
|
1956
1766
|
let a = i > 0 ? `, +${i} more` : "";
|
|
1957
1767
|
console.log(` ${e.smell} \u2014 ${e.files.length} file(s): ${r}${a}`), console.log(` \u2192 ${e.use}`);
|
|
1958
1768
|
}
|
|
1959
1769
|
}
|
|
1960
1770
|
return n > 0 && console.log(` (${n} more file path${n === 1 ? "" : "s"} not shown \u2014 \`voltro doctor --json\` prints every one.)`), console.log(" (See the \"Pick the SERVER primitive\" / \"Pick the CLIENT primitive\" rubrics in AGENTS.md / CLAUDE.md.)"), t.findings.length;
|
|
1961
|
-
},
|
|
1962
|
-
let t =
|
|
1771
|
+
}, un = "renderMode:'spa' skips this page's SSR compile while its layout shell still renders server-side — adopt it if the page BODY does not need SSR (internal/authenticated pages); keep 'ssr' if the page content needs SEO or server first-paint.", dn = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, fn = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, pn = (e) => {
|
|
1772
|
+
let t = dn.exec(e)?.[1];
|
|
1963
1773
|
if (t !== void 0) return t === "ssr" ? "ssr" : null;
|
|
1964
|
-
let n =
|
|
1774
|
+
let n = fn.exec(e)?.[1];
|
|
1965
1775
|
return n === "dynamic" ? "ssr" : n === "static" ? null : "default";
|
|
1966
|
-
},
|
|
1967
|
-
let
|
|
1968
|
-
if (!T(
|
|
1969
|
-
let { pages:
|
|
1970
|
-
for (let
|
|
1971
|
-
if (!
|
|
1972
|
-
let
|
|
1776
|
+
}, mn = async (e) => {
|
|
1777
|
+
let t = x(e, "src", "pages");
|
|
1778
|
+
if (!T(t)) return [];
|
|
1779
|
+
let { pages: i, dirs: o } = await n(t), s = [];
|
|
1780
|
+
for (let n of i) {
|
|
1781
|
+
if (!a(o, n.dirChain).some((e) => e.hasLayout)) continue;
|
|
1782
|
+
let i;
|
|
1973
1783
|
try {
|
|
1974
|
-
|
|
1784
|
+
i = E(x(t, n.file), "utf8");
|
|
1975
1785
|
} catch {
|
|
1976
1786
|
continue;
|
|
1977
1787
|
}
|
|
1978
|
-
if (
|
|
1979
|
-
let c =
|
|
1788
|
+
if (r.test(i)) continue;
|
|
1789
|
+
let c = pn(i);
|
|
1980
1790
|
c !== null && s.push({
|
|
1981
|
-
file: S(
|
|
1982
|
-
pattern:
|
|
1791
|
+
file: S(e, x(t, n.file)),
|
|
1792
|
+
pattern: n.pattern,
|
|
1983
1793
|
currentMode: c
|
|
1984
1794
|
});
|
|
1985
1795
|
}
|
|
1986
1796
|
return s;
|
|
1987
|
-
},
|
|
1797
|
+
}, hn = 10, gn = async (e) => {
|
|
1988
1798
|
if (console.log(""), !T(x(e, "src", "pages"))) return console.log("• spa-candidate scan: no src/pages here — nothing to check (web apps only)."), 0;
|
|
1989
|
-
let t = await
|
|
1799
|
+
let t = await mn(e);
|
|
1990
1800
|
if (t.length === 0) return console.log("✓ spa-candidate scan: no loader-free, layout-backed pages to flag."), 0;
|
|
1991
1801
|
console.log(`• renderMode:'spa' candidates (${t.length} page${t.length === 1 ? "" : "s"} — loader-free, under a layout, currently ssr/default):`);
|
|
1992
|
-
for (let e of t.slice(0,
|
|
1802
|
+
for (let e of t.slice(0, hn)) {
|
|
1993
1803
|
let t = e.currentMode === "ssr" ? "renderMode:'ssr'" : "default renderMode";
|
|
1994
1804
|
console.log(` ${e.file} (${e.pattern}) — ${t}`);
|
|
1995
1805
|
}
|
|
1996
|
-
let n = t.length -
|
|
1997
|
-
return n > 0 && console.log(` (+${n} more page${n === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${
|
|
1998
|
-
},
|
|
1806
|
+
let n = t.length - hn;
|
|
1807
|
+
return n > 0 && console.log(` (+${n} more page${n === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${un}`), t.length;
|
|
1808
|
+
}, _n = /* @__PURE__ */ new Set([
|
|
1999
1809
|
"node_modules",
|
|
2000
1810
|
"dist",
|
|
2001
1811
|
"build",
|
|
@@ -2003,7 +1813,7 @@ var re = () => {
|
|
|
2003
1813
|
".vite",
|
|
2004
1814
|
".framework",
|
|
2005
1815
|
".git"
|
|
2006
|
-
]),
|
|
1816
|
+
]), vn = (e, t, n) => {
|
|
2007
1817
|
let r;
|
|
2008
1818
|
try {
|
|
2009
1819
|
r = D(e, { withFileTypes: !0 });
|
|
@@ -2011,11 +1821,11 @@ var re = () => {
|
|
|
2011
1821
|
return;
|
|
2012
1822
|
}
|
|
2013
1823
|
for (let i of r) {
|
|
2014
|
-
if (
|
|
1824
|
+
if (_n.has(i.name)) continue;
|
|
2015
1825
|
let r = x(e, i.name);
|
|
2016
|
-
i.isDirectory() ?
|
|
1826
|
+
i.isDirectory() ? vn(r, t, n) : i.isFile() && i.name.endsWith(".tsx") && n.push(S(t, r));
|
|
2017
1827
|
}
|
|
2018
|
-
},
|
|
1828
|
+
}, yn = (e, t) => {
|
|
2019
1829
|
let n = /* @__PURE__ */ new Set(), r = /(?:from|import)\s*\(?\s*['"](\.[^'"]*)['"]/g;
|
|
2020
1830
|
for (let i of t) {
|
|
2021
1831
|
let t;
|
|
@@ -2040,21 +1850,21 @@ var re = () => {
|
|
|
2040
1850
|
}
|
|
2041
1851
|
}
|
|
2042
1852
|
return n;
|
|
2043
|
-
},
|
|
1853
|
+
}, bn = (e, t) => {
|
|
2044
1854
|
let n = e.slice(t.length).split(w).slice(0, -1)[0];
|
|
2045
1855
|
return n !== void 0 && n.startsWith("[");
|
|
2046
|
-
},
|
|
1856
|
+
}, J = (e) => {
|
|
2047
1857
|
let t = [], n = x(e, "src", "pages"), r = x(e, "src");
|
|
2048
1858
|
if (!T(r)) return t;
|
|
2049
|
-
let
|
|
2050
|
-
|
|
2051
|
-
let
|
|
2052
|
-
|
|
2053
|
-
for (let n of
|
|
1859
|
+
let i = [];
|
|
1860
|
+
vn(r, e, i), i.sort();
|
|
1861
|
+
let a = `${S(e, n)}${w}`;
|
|
1862
|
+
yn(e, i);
|
|
1863
|
+
for (let n of i) {
|
|
2054
1864
|
let r = n.slice(n.lastIndexOf(w) + 1);
|
|
2055
|
-
if (n.startsWith(
|
|
1865
|
+
if (n.startsWith(a)) {
|
|
2056
1866
|
if (r !== "page.tsx") continue;
|
|
2057
|
-
T(x(e,
|
|
1867
|
+
T(x(e, c(n))) || t.push({
|
|
2058
1868
|
kind: "page-without-test",
|
|
2059
1869
|
file: n
|
|
2060
1870
|
});
|
|
@@ -2065,7 +1875,7 @@ var re = () => {
|
|
|
2065
1875
|
file: n
|
|
2066
1876
|
});
|
|
2067
1877
|
} catch {}
|
|
2068
|
-
|
|
1878
|
+
bn(n, a) && t.push({
|
|
2069
1879
|
kind: "top-level-dynamic-route",
|
|
2070
1880
|
file: n
|
|
2071
1881
|
});
|
|
@@ -2077,33 +1887,33 @@ var re = () => {
|
|
|
2077
1887
|
});
|
|
2078
1888
|
}
|
|
2079
1889
|
return t;
|
|
2080
|
-
},
|
|
1890
|
+
}, xn = 10, Y = (e, t, n) => {
|
|
2081
1891
|
if (t.length === 0) return;
|
|
2082
1892
|
console.log(`• ${e} (${t.length}):`);
|
|
2083
|
-
for (let e of t.slice(0,
|
|
2084
|
-
let r = t.length -
|
|
1893
|
+
for (let e of t.slice(0, xn)) console.log(` ${e}`);
|
|
1894
|
+
let r = t.length - xn;
|
|
2085
1895
|
r > 0 && console.log(` (+${r} more not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${n}`);
|
|
2086
|
-
},
|
|
1896
|
+
}, Sn = (e) => {
|
|
2087
1897
|
if (console.log(""), !T(x(e, "src", "pages"))) return console.log("• page-convention scan: no src/pages here — nothing to check (web apps only)."), 0;
|
|
2088
|
-
let t =
|
|
1898
|
+
let t = J(e);
|
|
2089
1899
|
if (t.length === 0) return console.log("✓ page-convention scan: every route is a page.tsx in its own directory, with a test beside it."), 0;
|
|
2090
1900
|
let n = (e) => t.filter((t) => t.kind === e).map((e) => e.file);
|
|
2091
|
-
return
|
|
2092
|
-
},
|
|
2093
|
-
let t =
|
|
1901
|
+
return Y("will NEVER route — page.tsx outside src/pages/", n("suffixed-outside-pages"), "the name says \"route\", the location says otherwise, and the location wins: the URL comes from the directory chain under src/pages/. Move it into the directory whose route it serves, or rename it."), Y("pages with no test beside them", n("page-without-test"), "a page and its test belong together — `users/[id].page.tsx` → `users/[id].page.test.tsx`. Advisory only; a missing test is a gap, not a defect."), Y("routes whose FIRST segment is dynamic — they claim every URL of that depth", n("top-level-dynamic-route"), "a route like `[id]/[code]` answers `/api/health`, `/internal/readiness` and anything else with that many segments on this origin. That is what the pattern means, so it is not a bug — but it is invisible until something requests such a URL, and then the page renders, its loader runs, and the failure reads as an application error rather than as a route claiming a path nobody meant it to. Give the route a literal first segment (`scan/[id]/[code]`) if you did not intend to own the whole origin at that depth. Advisory."), Y("pages with no `meta` export — they serve the APP name as their title", n("page-without-meta"), "a page with no `meta` sets no title, so the response carries `<title>{your app.config name}</title>` — the same string on every such page, to every reader that does not run JavaScript: link previews, crawlers, a bookmark taken before hydration, a screen reader announcing the document. The client router fixes the tab after hydration, which is exactly why this is easy to miss. Add `export const meta = { title: \"…\" }` (or a function of params/loaderData). If such a page also has no real body — it redirects from an effect, say — the missing title is the symptom rather than the bug: on an `ssr` route the server answers 200 with an empty document and the redirect happens only once JavaScript runs. Move it into the loader (`redirect(...)`, a real 303). Advisory."), t.length;
|
|
1902
|
+
}, Cn = "voltro doctor [app] [flags]\n\nPreflight an app root: verify it can boot under production `voltro serve`,\nreport shipped primitives the source looks to be hand-rolling, and flag pages\nthat are safe `renderMode:'spa'` candidates.\n\nArguments:\n [app] App directory to check (default: the current directory).\n\nFlags:\n --strict Treat a missing serve bundle as blocking regardless of NODE_ENV\n (the `voltro serve --preflight` behavior). Without it, a missing\n bundle only fails when NODE_ENV=production.\n --json Print the complete scan as JSON — hand-roll findings AND spa\n candidates, every file path, nothing elided. Skips the preflight output.\n --write-authz-allowlist\n Record today's executors that reference NO access check into\n voltro-authz-allowlist.txt, so every later run fails only on\n ADDITIONS. The list is DEBT, not approval — an entry stops\n mattering as soon as its executor gains a guard.\n -h, --help Print this help.", wn = /* @__PURE__ */ new Map(), X = (e) => {
|
|
1903
|
+
let t = wn.get(e);
|
|
2094
1904
|
if (t !== void 0) return t;
|
|
2095
1905
|
let n = (async () => {
|
|
2096
|
-
let { walk: t, loadDiscovered: n } = await import("./dev-
|
|
1906
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-DOZVMVfi.js"), r = await t(e);
|
|
2097
1907
|
return {
|
|
2098
1908
|
files: r,
|
|
2099
1909
|
discovered: await n(r)
|
|
2100
1910
|
};
|
|
2101
1911
|
})();
|
|
2102
|
-
return
|
|
2103
|
-
},
|
|
1912
|
+
return wn.set(e, n), n;
|
|
1913
|
+
}, Tn = async (e) => {
|
|
2104
1914
|
let t;
|
|
2105
1915
|
try {
|
|
2106
|
-
let { files: n, discovered: r } = await
|
|
1916
|
+
let { files: n, discovered: r } = await X(e), i = r.tables.map((e) => {
|
|
2107
1917
|
let t = e;
|
|
2108
1918
|
return {
|
|
2109
1919
|
name: t.tableName,
|
|
@@ -2116,7 +1926,7 @@ var re = () => {
|
|
|
2116
1926
|
return;
|
|
2117
1927
|
}
|
|
2118
1928
|
t !== null && (console.log(""), console.log(`${t.includes("does not exist") ? "✗" : "✓"} ${t}`));
|
|
2119
|
-
},
|
|
1929
|
+
}, En = (e) => e.map((e) => {
|
|
2120
1930
|
let t = e, n = Object.entries(t.fields ?? {}).map(([e, t]) => ({
|
|
2121
1931
|
name: e,
|
|
2122
1932
|
type: typeof t?.type == "string" ? t.type : ""
|
|
@@ -2126,21 +1936,21 @@ var re = () => {
|
|
|
2126
1936
|
columns: n,
|
|
2127
1937
|
primaryKey: t.appliedPrimaryKey ?? []
|
|
2128
1938
|
};
|
|
2129
|
-
}),
|
|
1939
|
+
}), Z = async (e) => {
|
|
2130
1940
|
try {
|
|
2131
|
-
let { discovered: t } = await
|
|
2132
|
-
return Qe(
|
|
1941
|
+
let { discovered: t } = await X(e);
|
|
1942
|
+
return Qe(En(t.tables));
|
|
2133
1943
|
} catch {
|
|
2134
1944
|
return null;
|
|
2135
1945
|
}
|
|
2136
|
-
},
|
|
2137
|
-
let t = await
|
|
1946
|
+
}, Dn = async (e) => {
|
|
1947
|
+
let t = await Z(e);
|
|
2138
1948
|
if (t === null || t.tablesChecked === 0) return;
|
|
2139
1949
|
let n = et(t);
|
|
2140
1950
|
n !== null && (console.log(""), console.log(`${t.issues.length > 0 ? "✗" : "✓"} ${n}`));
|
|
2141
|
-
},
|
|
1951
|
+
}, On = async (e) => {
|
|
2142
1952
|
try {
|
|
2143
|
-
let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await
|
|
1953
|
+
let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await X(e);
|
|
2144
1954
|
return it(n.events.map((e) => {
|
|
2145
1955
|
let n = e.descriptor, r = t(n.key);
|
|
2146
1956
|
return {
|
|
@@ -2153,19 +1963,19 @@ var re = () => {
|
|
|
2153
1963
|
} catch {
|
|
2154
1964
|
return null;
|
|
2155
1965
|
}
|
|
2156
|
-
},
|
|
2157
|
-
let t = await
|
|
1966
|
+
}, kn = async (e) => {
|
|
1967
|
+
let t = await On(e);
|
|
2158
1968
|
if (t === null || t.eventsChecked === 0) return;
|
|
2159
1969
|
let n = at(t);
|
|
2160
1970
|
n !== null && (console.log(""), console.log(`• ${n}`));
|
|
2161
1971
|
let r = ot(t);
|
|
2162
1972
|
r !== null && (console.log(""), console.log(`⚠️ ${r}`));
|
|
2163
|
-
},
|
|
1973
|
+
}, An = (e) => {
|
|
2164
1974
|
let t = e, n = typeof t?.message == "string" && t.message !== "" ? t.message : String(e), r = typeof t?.code == "string" ? t.code : void 0;
|
|
2165
1975
|
return r === void 0 ? n : `${r}: ${n}`;
|
|
2166
|
-
},
|
|
1976
|
+
}, jn = async (e) => {
|
|
2167
1977
|
try {
|
|
2168
|
-
let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await
|
|
1978
|
+
let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await X(e)).discovered.serverOnlyLeaks, r = t(n);
|
|
2169
1979
|
return {
|
|
2170
1980
|
status: {
|
|
2171
1981
|
checked: !0,
|
|
@@ -2176,16 +1986,16 @@ var re = () => {
|
|
|
2176
1986
|
} catch (e) {
|
|
2177
1987
|
return { status: {
|
|
2178
1988
|
checked: !1,
|
|
2179
|
-
reason:
|
|
1989
|
+
reason: An(e)
|
|
2180
1990
|
} };
|
|
2181
1991
|
}
|
|
2182
|
-
},
|
|
2183
|
-
let { status: t, message: n } = await
|
|
1992
|
+
}, Mn = async (e) => {
|
|
1993
|
+
let { status: t, message: n } = await jn(e);
|
|
2184
1994
|
return t.checked ? n === void 0 ? !1 : (console.log(""), console.log(`✗ [serverOnly] ${n}`), !0) : (console.log(""), console.log("• serverOnly: NOT CHECKED — the app's descriptors could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), console.log(" This audit is the automated check that a hash or a token cannot reach the wire, so"), console.log(" an app that leans on `.serverOnly()` should treat a persistent skip as a failure."), console.log(" `voltro doctor --json` reports it as `serverOnly.checked: false` for a CI gate."), !1);
|
|
2185
|
-
},
|
|
1995
|
+
}, Nn = async (e) => {
|
|
2186
1996
|
let t;
|
|
2187
1997
|
try {
|
|
2188
|
-
let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await
|
|
1998
|
+
let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await X(e);
|
|
2189
1999
|
t = lt(r, i.workflows.map((e) => {
|
|
2190
2000
|
let t = e.definition, r = t.payloadSchema === void 0 ? {
|
|
2191
2001
|
required: [],
|
|
@@ -2205,13 +2015,54 @@ var re = () => {
|
|
|
2205
2015
|
console.log("");
|
|
2206
2016
|
let r = t.issues.length > 0 ? "✗" : t.unchecked.length > 0 ? "•" : "✓";
|
|
2207
2017
|
console.log(`${r} ${n}`);
|
|
2208
|
-
}, Q = "voltro-authz-allowlist.txt",
|
|
2018
|
+
}, Q = "voltro-authz-allowlist.txt", Pn = (e, t = (e) => {
|
|
2209
2019
|
try {
|
|
2210
2020
|
return E(e, "utf8");
|
|
2211
2021
|
} catch {
|
|
2212
2022
|
return "";
|
|
2213
2023
|
}
|
|
2214
|
-
}) => /* @__PURE__ */ new Set([...
|
|
2024
|
+
}) => /* @__PURE__ */ new Set([..._t, ...vt(q(e).map(t))]), Fn = async (e) => {
|
|
2025
|
+
try {
|
|
2026
|
+
let { discovered: t } = await X(e), n = t.events.map((e) => e.descriptor.name).filter((e) => typeof e == "string");
|
|
2027
|
+
if (n.length === 0) return [];
|
|
2028
|
+
let r = new Set(t.events.map((e) => e.file)), i = q(e).filter((e) => !r.has(e)).map((e) => {
|
|
2029
|
+
try {
|
|
2030
|
+
return E(e, "utf8");
|
|
2031
|
+
} catch {
|
|
2032
|
+
return "";
|
|
2033
|
+
}
|
|
2034
|
+
}).join("\n");
|
|
2035
|
+
return n.filter((e) => !i.includes(e)).sort();
|
|
2036
|
+
} catch {
|
|
2037
|
+
return [];
|
|
2038
|
+
}
|
|
2039
|
+
}, In = async (e) => {
|
|
2040
|
+
let t = await Fn(e);
|
|
2041
|
+
if (t.length !== 0) {
|
|
2042
|
+
console.log(""), console.log(`• ${t.length} declared event(s) with no emit call site found:`);
|
|
2043
|
+
for (let e of t) console.log(` ${e}`);
|
|
2044
|
+
console.log(""), console.log(" An event you declare is an event partners can subscribe to. One that"), console.log(" never fires is indistinguishable, from their side, from a broken"), console.log(" endpoint of their own — so they debug your contract instead of"), console.log(" reading it."), console.log(" ADVISORY: this looks for the event NAME in your sources. An emit"), console.log(" through a variable or an assembled name will read as missing here.");
|
|
2045
|
+
}
|
|
2046
|
+
}, Ln = async (e) => {
|
|
2047
|
+
try {
|
|
2048
|
+
let { offlineManifest: t, toInput: n } = await import("./checkCommand-ClRvH_SN.js"), { buildAppGraph: r, checkAppGraph: i } = await import("./appGraph-CvQCte0z.js"), a = await t(e);
|
|
2049
|
+
return i(r(n(a.manifest, a.tables))).filter((e) => e.rule === "rbac/unknown-scope").map((e) => ({
|
|
2050
|
+
node: e.node,
|
|
2051
|
+
...e.file === void 0 ? {} : { file: e.file },
|
|
2052
|
+
detail: e.breaks.join("; "),
|
|
2053
|
+
fix: e.fix
|
|
2054
|
+
}));
|
|
2055
|
+
} catch {
|
|
2056
|
+
return [];
|
|
2057
|
+
}
|
|
2058
|
+
}, Rn = async (e) => {
|
|
2059
|
+
let t = await Ln(e);
|
|
2060
|
+
if (t.length !== 0) {
|
|
2061
|
+
console.log(""), console.log(`• ${t.length} procedure(s) require a scope no declared role grants:`);
|
|
2062
|
+
for (let e of t) console.log(` ${e.node}${e.file === void 0 ? "" : ` ${e.file}`}`), console.log(` ${e.detail}`);
|
|
2063
|
+
console.log(""), console.log(" Each of these is uncallable by every user in every role — not"), console.log(" misconfigured, DEAD — and nothing fails at boot to say so. The"), console.log(" usual cause is a typo or a rename that moved one side only."), console.log(` ${t[0].fix}`);
|
|
2064
|
+
}
|
|
2065
|
+
}, zn = async (e) => {
|
|
2215
2066
|
let t = ["src/locales", "locales"], n, r = [];
|
|
2216
2067
|
for (let i of t) {
|
|
2217
2068
|
let t = x(e, i);
|
|
@@ -2223,23 +2074,23 @@ var re = () => {
|
|
|
2223
2074
|
if (n === void 0 || r.length === 0) return;
|
|
2224
2075
|
let i = [];
|
|
2225
2076
|
try {
|
|
2226
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
2077
|
+
let { loadApiConfig: t } = await import("./dev-DOZVMVfi.js");
|
|
2227
2078
|
i = (await t(e))?.locales ?? [];
|
|
2228
2079
|
} catch {
|
|
2229
2080
|
return;
|
|
2230
2081
|
}
|
|
2231
|
-
let a =
|
|
2082
|
+
let a = mt({
|
|
2232
2083
|
catalogCodes: r,
|
|
2233
2084
|
declaredLocales: i
|
|
2234
2085
|
});
|
|
2235
2086
|
if (a !== void 0) {
|
|
2236
2087
|
console.log("");
|
|
2237
|
-
for (let e of
|
|
2088
|
+
for (let e of ht(a, n)) console.log(e);
|
|
2238
2089
|
}
|
|
2239
|
-
},
|
|
2240
|
-
let { discovered: t } = await
|
|
2090
|
+
}, Bn = async (e) => {
|
|
2091
|
+
let { discovered: t } = await X(e), n = [];
|
|
2241
2092
|
try {
|
|
2242
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
2093
|
+
let { loadApiConfig: t } = await import("./dev-DOZVMVfi.js");
|
|
2243
2094
|
n = ((await t(e))?.plugins ?? []).map((e) => {
|
|
2244
2095
|
let t = (e.extendSchema?.tables ?? []).map((e) => {
|
|
2245
2096
|
let t = e;
|
|
@@ -2255,8 +2106,8 @@ var re = () => {
|
|
|
2255
2106
|
plugin: e.name,
|
|
2256
2107
|
tables: t,
|
|
2257
2108
|
rpcTags: n,
|
|
2258
|
-
canDisableTables:
|
|
2259
|
-
canAlias:
|
|
2109
|
+
canDisableTables: Vn.has(e.name),
|
|
2110
|
+
canAlias: Hn.has(e.name)
|
|
2260
2111
|
};
|
|
2261
2112
|
});
|
|
2262
2113
|
} catch {
|
|
@@ -2268,14 +2119,14 @@ var re = () => {
|
|
|
2268
2119
|
...t.mutations,
|
|
2269
2120
|
...t.actions,
|
|
2270
2121
|
...t.streams ?? []
|
|
2271
|
-
].map((e) => String(e.descriptor.name)), i =
|
|
2122
|
+
].map((e) => String(e.descriptor.name)), i = jt(n, {
|
|
2272
2123
|
tables: t.tables.map((e) => e.tableName),
|
|
2273
2124
|
rpcTags: r
|
|
2274
2125
|
});
|
|
2275
2126
|
console.log();
|
|
2276
|
-
for (let e of
|
|
2277
|
-
},
|
|
2278
|
-
let t = await
|
|
2127
|
+
for (let e of Mt(n, i)) console.log(e);
|
|
2128
|
+
}, Vn = /* @__PURE__ */ new Set(["@voltro/plugin-rbac"]), Hn = /* @__PURE__ */ new Set(["@voltro/plugin-ai-flows"]), $ = 20, Un = async (e) => {
|
|
2129
|
+
let t = await Wn(e), n = new Set(t.reviewed.map((e) => e.tag)), r = t.result.findings.filter((e) => e.verdict.kind === "allowlisted" && !n.has(e.tag)).length;
|
|
2279
2130
|
return {
|
|
2280
2131
|
executors: t.executorCount,
|
|
2281
2132
|
guardVocabulary: [...t.vocabulary].sort(),
|
|
@@ -2287,15 +2138,15 @@ var re = () => {
|
|
|
2287
2138
|
},
|
|
2288
2139
|
unchecked: t.result.unchecked
|
|
2289
2140
|
};
|
|
2290
|
-
},
|
|
2291
|
-
let { discovered: t } = await
|
|
2141
|
+
}, Wn = async (e) => {
|
|
2142
|
+
let { discovered: t } = await X(e), n = /* @__PURE__ */ new Map(), r = (e) => {
|
|
2292
2143
|
if (!n.has(e)) try {
|
|
2293
2144
|
n.set(e, E(e, "utf8"));
|
|
2294
2145
|
} catch {
|
|
2295
2146
|
n.set(e, "");
|
|
2296
2147
|
}
|
|
2297
2148
|
return n.get(e);
|
|
2298
|
-
}, i =
|
|
2149
|
+
}, i = Pn(e, r), a = /* @__PURE__ */ new Set();
|
|
2299
2150
|
for (let e of t.tables) for (let t of Object.values(e.fields ?? {})) try {
|
|
2300
2151
|
let e = t.references?.();
|
|
2301
2152
|
e && a.add(e.tableName);
|
|
@@ -2332,7 +2183,7 @@ var re = () => {
|
|
|
2332
2183
|
l = !0;
|
|
2333
2184
|
break;
|
|
2334
2185
|
}
|
|
2335
|
-
let u =
|
|
2186
|
+
let u = wt({
|
|
2336
2187
|
executors: o,
|
|
2337
2188
|
guardVocabulary: i,
|
|
2338
2189
|
tenantScopedTables: t.tenantScopedTables,
|
|
@@ -2349,44 +2200,49 @@ var re = () => {
|
|
|
2349
2200
|
executorCount: o.length,
|
|
2350
2201
|
allowPath: s
|
|
2351
2202
|
};
|
|
2352
|
-
},
|
|
2353
|
-
let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await
|
|
2203
|
+
}, Gn = async (e, t) => {
|
|
2204
|
+
let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await Wn(e), l = n.counts;
|
|
2354
2205
|
console.log(`\nauthz scan · ${o} executor(s)`);
|
|
2355
|
-
let u = [...r].filter((e) => !
|
|
2206
|
+
let u = [...r].filter((e) => !_t.has(e)).sort();
|
|
2356
2207
|
console.log(u.length === 0 ? " guard vocabulary: framework names only — no exported require*/assert* found in this app" : ` guard vocabulary: ${u.length} from your source (${u.slice(0, 6).join(", ")}${u.length > 6 ? ", …" : ""})`), console.log(` ✗ no access check ${String(l.unchecked).padStart(4)}`), console.log(` ⚠ inline ownership check, no named guard${String(l.inlineOwnership).padStart(4)} (informational)`), console.log(` ✓ guards: on the descriptor ${String(l.declaredGuard).padStart(4)}`), console.log(` ✓ calls a guard from the vocabulary ${String(l.vocabularyGuard).padStart(4)}`);
|
|
2357
2208
|
let d = new Set(a.map((e) => e.tag)), f = n.findings.filter((e) => e.verdict.kind === "allowlisted" && !d.has(e.tag)).length, p = l.allowlisted - f;
|
|
2358
2209
|
if (console.log(` – accepted as recorded debt ${String(f).padStart(4)} (${Q})`), console.log(` ✓ reviewed, open on purpose ${String(p).padStart(4)} (\`reviewed=<why>\` in that file)`), c && console.log(" ⓘ this app registers setRowFilter — the scan CANNOT see through it. A finding below may\n already be constrained; verify the filter covers that table and record it as `reviewed=`."), t) {
|
|
2359
|
-
let e = T(s) ? E(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r =
|
|
2360
|
-
return
|
|
2210
|
+
let e = T(s) ? E(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r = Ot(e, t);
|
|
2211
|
+
return se(s, Dt(e, t), "utf8"), console.log(`\n${Q}: +${r.added} new, ${r.kept} kept, ${r.removed} removed. Doctor now fails on ADDITIONS only.`), r.added === 0 && console.log(" (nothing new was unchecked — the file is unchanged.)"), !1;
|
|
2361
2212
|
}
|
|
2362
2213
|
if (n.unchecked.length === 0) return !1;
|
|
2363
2214
|
console.log("");
|
|
2364
2215
|
for (let e of n.unchecked.slice(0, $)) console.log(` ✗ ${e.tag} — ${e.why}\n ${e.path}`);
|
|
2365
2216
|
return n.unchecked.length > $ && console.log(` … and ${n.unchecked.length - $} more — \`voltro doctor --json\` prints every one (\`authz.unchecked\`).`), i === void 0 ? (console.log(`\nNo ${Q} yet, so this run is advisory. To start the ratchet:`), console.log("\n voltro doctor --write-authz-allowlist\n"), console.log("That records today's unchecked handlers as DEBT and fails every run after on"), console.log("anything NEW. Fix a handler and its line stops mattering — the scan reports it as"), console.log("guarded whether or not the line is still there."), !1) : (console.log(`\n${n.unchecked.length} executor(s) with no access check are not in ${Q}.`), console.log("Add a guard, or add the tag to that file if it is genuinely open."), console.log("\nBefore hand-rolling another check: `guards: [{ action, resourceType, resource }]`"), console.log("answers \"may this subject act on THIS row\" declaratively, and an app whose"), console.log("relationships live in its own tables registers its own tuple source rather than"), console.log("copying data into a framework table. See the authorization docs."), !0);
|
|
2366
|
-
},
|
|
2367
|
-
if (e.includes("--help") || e.includes("-h")) return console.log(
|
|
2368
|
-
let
|
|
2369
|
-
if (
|
|
2370
|
-
...
|
|
2371
|
-
spaCandidates: await
|
|
2372
|
-
pageConvention:
|
|
2373
|
-
fileTaxonomy: V(
|
|
2374
|
-
junctionFks: (await
|
|
2375
|
-
eventDelivery: await
|
|
2376
|
-
duplicateInstances:
|
|
2377
|
-
|
|
2378
|
-
|
|
2217
|
+
}, Kn = async (e) => {
|
|
2218
|
+
if (e.includes("--help") || e.includes("-h")) return console.log(Cn), 0;
|
|
2219
|
+
let n = e.includes("--strict"), r = C(e.find((e) => !e.startsWith("-")) ?? process.cwd());
|
|
2220
|
+
if (le(e)) return ce(), M({
|
|
2221
|
+
...nn(r),
|
|
2222
|
+
spaCandidates: await mn(r),
|
|
2223
|
+
pageConvention: J(r),
|
|
2224
|
+
fileTaxonomy: V(r).findings,
|
|
2225
|
+
junctionFks: (await Z(r))?.issues ?? [],
|
|
2226
|
+
eventDelivery: await On(r),
|
|
2227
|
+
duplicateInstances: t(r),
|
|
2228
|
+
versionSkew: s(r) ?? null,
|
|
2229
|
+
serverOnly: (await jn(r)).status,
|
|
2230
|
+
authz: await Un(r),
|
|
2231
|
+
ungrantedScopes: await Ln(r),
|
|
2232
|
+
neverEmittedEvents: await Fn(r)
|
|
2379
2233
|
}), 0;
|
|
2380
|
-
let
|
|
2381
|
-
|
|
2382
|
-
let
|
|
2383
|
-
|
|
2384
|
-
|
|
2234
|
+
let a = It(r, n);
|
|
2235
|
+
ln(r), cn(r), Sn(r), He(r), await gn(r), await Nn(r), await Tn(r), await Dn(r), await kn(r), await Bn(r), await Rn(r), await In(r), await zn(r);
|
|
2236
|
+
let c = await Mn(r), l = await Gn(r, e.includes("--write-authz-allowlist")), u = o(s(r));
|
|
2237
|
+
u !== void 0 && (console.log(""), console.log(u));
|
|
2238
|
+
let d = i(t(r));
|
|
2239
|
+
return d !== void 0 && console.log(`\n${d}`), c || l ? Math.max(a, 1) : a;
|
|
2240
|
+
}, qn = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, Jn = /* @__PURE__ */ new Set([
|
|
2385
2241
|
"insert",
|
|
2386
2242
|
"update",
|
|
2387
2243
|
"delete",
|
|
2388
2244
|
"upsert"
|
|
2389
|
-
]),
|
|
2245
|
+
]), Yn = (e, t) => {
|
|
2390
2246
|
let n = [], r = new Set(t.exercised), i = /* @__PURE__ */ new Map();
|
|
2391
2247
|
for (let e of t.edges) {
|
|
2392
2248
|
let t = i.get(e.tag);
|
|
@@ -2398,8 +2254,8 @@ var re = () => {
|
|
|
2398
2254
|
a.push(t.tag);
|
|
2399
2255
|
continue;
|
|
2400
2256
|
}
|
|
2401
|
-
let e = `${t.kind}(${t.tag})`, s = t.file, c = i.get(t.tag) ?? [], l = new Set(
|
|
2402
|
-
for (let t of c) if (
|
|
2257
|
+
let e = `${t.kind}(${t.tag})`, s = t.file, c = i.get(t.tag) ?? [], l = new Set(qn(t.source)), u = new Map((t.targets ?? []).map((e) => [e.table, e.op]));
|
|
2258
|
+
for (let t of c) if (Jn.has(t.op)) {
|
|
2403
2259
|
let r = u.get(t.table);
|
|
2404
2260
|
r === void 0 ? n.push({
|
|
2405
2261
|
rule: "observed/undeclared-write",
|
|
@@ -2455,7 +2311,7 @@ var re = () => {
|
|
|
2455
2311
|
total: e.length
|
|
2456
2312
|
}
|
|
2457
2313
|
};
|
|
2458
|
-
},
|
|
2314
|
+
}, Xn = (e, t = [], n = 0) => {
|
|
2459
2315
|
if (n > 12) return t;
|
|
2460
2316
|
let r;
|
|
2461
2317
|
try {
|
|
@@ -2473,30 +2329,30 @@ var re = () => {
|
|
|
2473
2329
|
".git",
|
|
2474
2330
|
"coverage"
|
|
2475
2331
|
].includes(i)) continue;
|
|
2476
|
-
let r = `${e}/${i}`,
|
|
2332
|
+
let r = `${e}/${i}`, a;
|
|
2477
2333
|
try {
|
|
2478
|
-
|
|
2334
|
+
a = O(r);
|
|
2479
2335
|
} catch {
|
|
2480
2336
|
continue;
|
|
2481
2337
|
}
|
|
2482
|
-
|
|
2338
|
+
a.isDirectory() ? Xn(r, t, n + 1) : a.isFile() && l.test(i) && t.push(r);
|
|
2483
2339
|
}
|
|
2484
2340
|
return t;
|
|
2485
|
-
},
|
|
2341
|
+
}, Zn = /* @__PURE__ */ new Set(["actors", "tenants"]), Qn = async (e) => {
|
|
2486
2342
|
try {
|
|
2487
2343
|
let { readFile: t } = await import("node:fs/promises"), { join: n } = await import("node:path"), r = await t(n(e, "app.graph.observed.generated.json"), "utf8"), i = JSON.parse(r);
|
|
2488
2344
|
return i?.version !== 1 || !Array.isArray(i.edges) || !Array.isArray(i.exercised) ? null : i;
|
|
2489
2345
|
} catch {
|
|
2490
2346
|
return null;
|
|
2491
2347
|
}
|
|
2492
|
-
},
|
|
2348
|
+
}, $n = (e) => {
|
|
2493
2349
|
let { exercised: t, total: n } = e.coverage, r = `\nobserved: ${t}/${n} procedures exercised (${n === 0 ? 0 : Math.round(t / n * 100)}%)`;
|
|
2494
2350
|
if (e.diagnostics.length === 0) return `${r}\n no declared/observed mismatches${e.unexercised.length > 0 ? `\n ${e.unexercised.length} unexercised — no recording, so nothing is claimed about them` : ""}`;
|
|
2495
2351
|
let i = e.diagnostics.map((e) => ` ${e.node}${e.file === void 0 ? "" : ` (${e.file})`}\n` + e.breaks.map((e) => ` ${e}`).join("\n") + `\n fix: ${e.fix}`), a = e.unexercised.length > 0 ? `\n ${e.unexercised.length} unexercised — no recording, so nothing is claimed about them` : "";
|
|
2496
2352
|
return `${r}\n${i.join("\n")}${a}`;
|
|
2497
|
-
},
|
|
2353
|
+
}, er = (e, t) => ({
|
|
2498
2354
|
tables: (t.tables ?? []).map((e) => e.name),
|
|
2499
|
-
frameworkOwnedTables: (t.tables ?? []).filter((e) => e.framework === !0 || e.name.startsWith("_voltro_") ||
|
|
2355
|
+
frameworkOwnedTables: (t.tables ?? []).filter((e) => e.framework === !0 || e.name.startsWith("_voltro_") || Zn.has(e.name)).map((e) => e.name),
|
|
2500
2356
|
scopes: e.scopes ?? [],
|
|
2501
2357
|
procedures: (e.procedures ?? []).map((e) => {
|
|
2502
2358
|
let t = (e.guards ?? []).flatMap((e) => e.kind === "scope" ? e.scope ?? [] : []);
|
|
@@ -2509,11 +2365,11 @@ var re = () => {
|
|
|
2509
2365
|
...e.guards === void 0 ? {} : { hasGuards: e.guards.length > 0 }
|
|
2510
2366
|
};
|
|
2511
2367
|
})
|
|
2512
|
-
}),
|
|
2368
|
+
}), tr = (e) => e.length === 0 ? "✓ voltro check: no issues" : e.map((e) => {
|
|
2513
2369
|
let t = e.severity === "error" ? "✗ error" : "⚠ warn", n = e.file ? ` (${e.file})` : "";
|
|
2514
2370
|
return `${t} ${e.rule} ${e.node}${n}\n ${e.breaks.join("; ")}\n fix: ${e.fix}`;
|
|
2515
|
-
}).join("\n"),
|
|
2516
|
-
let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-
|
|
2371
|
+
}).join("\n"), nr = async (e) => {
|
|
2372
|
+
let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-DOZVMVfi.js"), { buildRpcEntry: i } = await import("./manifestBuild-Dj8Jjoto.js"), { buildCapabilityManifest: a } = await import("./inspect-mmBuRXmy.js"), { relative: o } = await import("node:path"), s = await n(await t(e)), c = (t, n, r) => i(t, n, o(e, r)), l = [
|
|
2517
2373
|
...s.queries.map((e) => c(e.descriptor, "query", e.file)),
|
|
2518
2374
|
...s.mutations.map((e) => c(e.descriptor, "mutation", e.file)),
|
|
2519
2375
|
...s.actions.map((e) => c(e.descriptor, "action", e.file)),
|
|
@@ -2529,10 +2385,10 @@ var re = () => {
|
|
|
2529
2385
|
})), [], m),
|
|
2530
2386
|
tables: { tables: p }
|
|
2531
2387
|
};
|
|
2532
|
-
},
|
|
2533
|
-
let t =
|
|
2388
|
+
}, rr = async (e) => {
|
|
2389
|
+
let t = me(e.flatMap((e) => e === "--json" ? ["--format", "json"] : [e]));
|
|
2534
2390
|
if ("error" in t) return console.error(`voltro check: ${t.error}`), 1;
|
|
2535
|
-
let { process: n, target: r, rest: i } =
|
|
2391
|
+
let { process: n, target: r, rest: i } = he(t.rest), a;
|
|
2536
2392
|
for (let e = 0; e < i.length; e++) if (i[e] === "--diff") {
|
|
2537
2393
|
let [t, n] = (i[++e] ?? "").split(":");
|
|
2538
2394
|
if (t === "removeTable" && n) a = {
|
|
@@ -2549,35 +2405,35 @@ var re = () => {
|
|
|
2549
2405
|
};
|
|
2550
2406
|
else return console.error("voltro check --diff: expected removeTable:<name> | removeProcedure:<tag> | removeScope:<name>"), 1;
|
|
2551
2407
|
}
|
|
2552
|
-
let
|
|
2553
|
-
if (
|
|
2554
|
-
if (!
|
|
2408
|
+
let o = i.find((e) => !e.startsWith("-")) ?? process.cwd(), s = i.includes("--offline"), c = s ? [] : await pe(n, r), l, d;
|
|
2409
|
+
if (c.length === 0) {
|
|
2410
|
+
if (!s && r !== void 0) return console.error("voltro check: --url given but no api reachable there."), 1;
|
|
2555
2411
|
try {
|
|
2556
|
-
let e = await
|
|
2557
|
-
|
|
2412
|
+
let e = await nr(C(o));
|
|
2413
|
+
l = e.manifest, d = e.tables;
|
|
2558
2414
|
} catch (e) {
|
|
2559
2415
|
return console.error(`voltro check: could not assemble the graph from source: ${e.message}`), console.error(" Start `voltro dev` to check against a running api instead."), 1;
|
|
2560
2416
|
}
|
|
2561
2417
|
} else {
|
|
2562
|
-
let e =
|
|
2418
|
+
let e = c[0], [t, n] = await Promise.all([N(e, "/_voltro/inspect/manifest"), N(e, "/_voltro/inspect/data/tables")]);
|
|
2563
2419
|
if (t.kind === "err") return console.error(`voltro check: manifest fetch failed: ${t.error}`), 1;
|
|
2564
|
-
|
|
2420
|
+
l = t.data, d = n.kind === "ok" ? n.data : { tables: [] };
|
|
2565
2421
|
}
|
|
2566
|
-
let f =
|
|
2422
|
+
let f = er(l, d), p = ie(f, a), m = [...V(o).findings.map((e) => ({
|
|
2567
2423
|
rule: e.rule,
|
|
2568
2424
|
node: e.file,
|
|
2569
2425
|
file: e.file,
|
|
2570
2426
|
breaks: [e.detail],
|
|
2571
2427
|
fix: e.fix,
|
|
2572
2428
|
severity: e.severity
|
|
2573
|
-
})), ...
|
|
2429
|
+
})), ...J(o).map((e) => ({
|
|
2574
2430
|
rule: `page/${e.kind}`,
|
|
2575
2431
|
node: e.file,
|
|
2576
2432
|
file: e.file,
|
|
2577
2433
|
breaks: [e.kind === "suffixed-outside-pages" ? "a page.tsx outside src/pages/ never routes" : "no test beside it"],
|
|
2578
2434
|
fix: e.kind === "suffixed-outside-pages" ? "move it under src/pages/ into the directory whose route it serves, or rename it — page.tsx is reserved" : "write the test with the file — the name is derivable",
|
|
2579
2435
|
severity: e.kind === "suffixed-outside-pages" ? "error" : "warn"
|
|
2580
|
-
}))], h = (await o
|
|
2436
|
+
}))], h = (await u(o, Xn(o))).map((e) => ({
|
|
2581
2437
|
rule: "client/not-browser-safe",
|
|
2582
2438
|
node: e.file,
|
|
2583
2439
|
file: e.file,
|
|
@@ -2588,7 +2444,7 @@ var re = () => {
|
|
|
2588
2444
|
...p.diagnostics,
|
|
2589
2445
|
...m,
|
|
2590
2446
|
...h
|
|
2591
|
-
], _ = p.ok && !m.some((e) => e.severity === "error") && h.length === 0, v = await
|
|
2447
|
+
], _ = p.ok && !m.some((e) => e.severity === "error") && h.length === 0, v = await Qn(C(o)), y = v === null ? null : Yn(f.procedures, v);
|
|
2592
2448
|
return t.format === "json" ? M(y === null ? {
|
|
2593
2449
|
...p,
|
|
2594
2450
|
ok: _,
|
|
@@ -2598,7 +2454,7 @@ var re = () => {
|
|
|
2598
2454
|
ok: _,
|
|
2599
2455
|
diagnostics: g,
|
|
2600
2456
|
observed: y
|
|
2601
|
-
}) : (console.log(
|
|
2457
|
+
}) : (console.log(tr(g)), y !== null && console.log($n(y)), console.log(_ ? "\nvoltro check: OK" : "\nvoltro check: FAILED (errors above)")), +!_;
|
|
2602
2458
|
};
|
|
2603
2459
|
//#endregion
|
|
2604
|
-
export {
|
|
2460
|
+
export { ce as _, It as a, xe as c, N as d, me as f, pe as g, fe as h, Kn as i, I as l, P as m, rr as n, ze as o, he as p, er as r, be as s, nr as t, ve as u, M as v, le as y };
|