@voltro/cli 0.30.0 → 0.30.1
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 +71 -0
- package/dist/apiBuild-Ca6Sq5jy.js +2 -0
- package/dist/{apiBuild-BceikpQf.js → apiBuild-DmkzRyv7.js} +2 -2
- package/dist/bin.js +3 -3
- package/dist/{checkCommand-BMr-X48w.js → checkCommand-C4konUy9.js} +422 -298
- package/dist/checkCommand-DHD0aBeR.js +2 -0
- package/dist/{commands-D4Y1-Nlu.js → commands-BkJft9K2.js} +1609 -1607
- package/dist/{dbCommand-C7hbl5pk.js → dbCommand-qn__kLEt.js} +1 -1
- package/dist/dbCommand-wfGi3FgG.js +2 -0
- package/dist/{dev-DmnkH-wr.js → dev-C_NPcLDp.js} +1266 -1250
- package/dist/{dev-Cr-teYsz.js → dev-DXhhZ7-f.js} +1 -1
- package/dist/frameworkTableAssembly-Bn_c4Mnl.js +2 -0
- package/dist/{frameworkTableAssembly-BzAajuUv.js → frameworkTableAssembly-Cpgn2e88.js} +128 -130
- package/dist/index.js +1 -1
- package/dist/{inspectMetrics-BeJdP_3b.js → inspectMetrics-CkB2J0Zn.js} +2 -0
- package/dist/{sdkgen-CqpOq_fy.js → sdkgen-wsWLrq4l.js} +1 -1
- package/dist/{serveCommand-Ciq_wIY8.js → serveCommand-HtI4X5kj.js} +14 -14
- package/dist/serveEntry.js +2 -2
- package/dist/{start-ocqB1seX.js → start-egkbpugc.js} +177 -175
- package/dist/startEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +27 -0
- package/templates/agent-docs/routing.md +14 -0
- package/templates/agent-docs/whats-new.md +36 -342
- package/templates/agent-docs/workflows.md +2 -0
- 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-CxvR1Dwt.js +0 -2
- package/dist/checkCommand-BOk9y264.js +0 -2
- package/dist/dbCommand-D8nhyppR.js +0 -2
- package/dist/frameworkTableAssembly-DU0aOxjL.js +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { R as e, f as t, ht as n, n as r, o as i } from "./inspectMetrics-
|
|
2
|
-
import { Ut as a, Wt as o } from "./dev-
|
|
1
|
+
import { R as e, f as t, ht as n, n as r, o as i } from "./inspectMetrics-CkB2J0Zn.js";
|
|
2
|
+
import { Ut as a, Wt as o } from "./dev-C_NPcLDp.js";
|
|
3
3
|
import { C as s, E as c, O as l, T as u, d, h as f, i as p, l as m, m as h, r as g, u as _ } from "./fileConventions-Cof68_BL.js";
|
|
4
|
-
import { r as v, u as y } from "./apiBuild-
|
|
4
|
+
import { r as v, u as y } from "./apiBuild-DmkzRyv7.js";
|
|
5
5
|
import { dirname as b, isAbsolute as ee, join as x, relative as S, resolve as C, sep as w } from "node:path";
|
|
6
6
|
import { routeDiagnosticsToStderr as te } from "@voltro/logger";
|
|
7
7
|
import { existsSync as T, readFileSync as E, readdirSync as D, statSync as O, writeFileSync as ne } from "node:fs";
|
|
@@ -442,7 +442,7 @@ var re = () => {
|
|
|
442
442
|
re: l,
|
|
443
443
|
needsTest: !1
|
|
444
444
|
}
|
|
445
|
-
], R = (e) => Ce.find((t) => t.re.test(e))?.id ?? null,
|
|
445
|
+
], R = (e) => Ce.find((t) => t.re.test(e))?.id ?? null, we = (e) => u.test(e), Te = /* @__PURE__ */ new Set([
|
|
446
446
|
"useMutation",
|
|
447
447
|
"useAction",
|
|
448
448
|
"useUpload",
|
|
@@ -452,12 +452,12 @@ var re = () => {
|
|
|
452
452
|
"useAgentStream",
|
|
453
453
|
"useResumableAgentStream",
|
|
454
454
|
"useWorkflow"
|
|
455
|
-
]),
|
|
455
|
+
]), Ee = /* @__PURE__ */ new Set(["defineTracking"]), De = /* @__PURE__ */ new Set([
|
|
456
456
|
"useSubscription",
|
|
457
457
|
"useWindowedSubscription",
|
|
458
458
|
"useRecord",
|
|
459
459
|
"useQuery"
|
|
460
|
-
]),
|
|
460
|
+
]), Oe = /* @__PURE__ */ new Set([
|
|
461
461
|
"node_modules",
|
|
462
462
|
"dist",
|
|
463
463
|
"build",
|
|
@@ -468,7 +468,7 @@ var re = () => {
|
|
|
468
468
|
".git",
|
|
469
469
|
"coverage",
|
|
470
470
|
".publish"
|
|
471
|
-
]),
|
|
471
|
+
]), ke = /\.tsx?$/, z = (e, t = [], n = 0) => {
|
|
472
472
|
if (n > 12) return t;
|
|
473
473
|
let r;
|
|
474
474
|
try {
|
|
@@ -477,27 +477,27 @@ var re = () => {
|
|
|
477
477
|
return t;
|
|
478
478
|
}
|
|
479
479
|
for (let i of r) {
|
|
480
|
-
if (
|
|
480
|
+
if (Oe.has(i)) continue;
|
|
481
481
|
let r = x(e, i), a;
|
|
482
482
|
try {
|
|
483
483
|
a = O(r);
|
|
484
484
|
} catch {
|
|
485
485
|
continue;
|
|
486
486
|
}
|
|
487
|
-
a.isDirectory() ?
|
|
487
|
+
a.isDirectory() ? z(r, t, n + 1) : a.isFile() && ke.test(i) && !i.endsWith(".d.ts") && t.push(r);
|
|
488
488
|
}
|
|
489
489
|
return t;
|
|
490
|
-
},
|
|
491
|
-
if (
|
|
492
|
-
if (k.isExportAssignment(e) || k.isAsExpression(e) || k.isSatisfiesExpression(e) || k.isParenthesizedExpression(e)) return
|
|
490
|
+
}, Ae = /\b(?:FC|FunctionComponent|ComponentType|ForwardRefExoticComponent|MemoExoticComponent)\b/, je = /\b(?:memo|forwardRef|observer|styled)\b/, B = (e) => k.isArrowFunction(e) || k.isFunctionExpression(e) || k.isFunctionDeclaration(e) || k.isClassDeclaration(e) || k.isClassExpression(e), V = (e) => {
|
|
491
|
+
if (B(e)) return !0;
|
|
492
|
+
if (k.isExportAssignment(e) || k.isAsExpression(e) || k.isSatisfiesExpression(e) || k.isParenthesizedExpression(e)) return V(e.getExpression());
|
|
493
493
|
if (k.isVariableDeclaration(e)) {
|
|
494
494
|
let t = e.getTypeNode();
|
|
495
|
-
if (t !== void 0 &&
|
|
495
|
+
if (t !== void 0 && Ae.test(t.getText())) return !0;
|
|
496
496
|
let n = e.getInitializer();
|
|
497
|
-
return n === void 0 ||
|
|
497
|
+
return n === void 0 || V(n);
|
|
498
498
|
}
|
|
499
|
-
return k.isCallExpression(e) ?
|
|
500
|
-
},
|
|
499
|
+
return k.isCallExpression(e) ? je.test(e.getExpression().getText()) ? !0 : e.getArguments().some((e) => B(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);
|
|
500
|
+
}, Me = (e) => {
|
|
501
501
|
let t = [], n = [], r = [], i = /* @__PURE__ */ new Set();
|
|
502
502
|
for (let [a, o] of e.getExportedDeclarations()) {
|
|
503
503
|
let e = o[0];
|
|
@@ -508,7 +508,7 @@ var re = () => {
|
|
|
508
508
|
n.push(s);
|
|
509
509
|
continue;
|
|
510
510
|
}
|
|
511
|
-
if (/^[A-Z]/.test(s) &&
|
|
511
|
+
if (/^[A-Z]/.test(s) && V(e)) {
|
|
512
512
|
t.push(s);
|
|
513
513
|
continue;
|
|
514
514
|
}
|
|
@@ -520,7 +520,7 @@ var re = () => {
|
|
|
520
520
|
others: r,
|
|
521
521
|
hasRuntimeExport: t.length + n.length + r.length > 0
|
|
522
522
|
};
|
|
523
|
-
},
|
|
523
|
+
}, Ne = [], Pe = (e, t, n) => {
|
|
524
524
|
let r = b(e), i = [];
|
|
525
525
|
for (let e = r;; e = b(e)) {
|
|
526
526
|
let r = n.get(e);
|
|
@@ -537,9 +537,9 @@ var re = () => {
|
|
|
537
537
|
}
|
|
538
538
|
if (e === t || b(e) === e) break;
|
|
539
539
|
}
|
|
540
|
-
for (let e of i) n.set(e,
|
|
541
|
-
return
|
|
542
|
-
},
|
|
540
|
+
for (let e of i) n.set(e, Ne);
|
|
541
|
+
return Ne;
|
|
542
|
+
}, Fe = (e, t, n) => {
|
|
543
543
|
let r = t.startsWith(".") ? C(b(e), t) : ye(t, n);
|
|
544
544
|
if (r === void 0) return null;
|
|
545
545
|
for (let e of [
|
|
@@ -552,9 +552,9 @@ var re = () => {
|
|
|
552
552
|
if (O(e).isFile()) return e;
|
|
553
553
|
} catch {}
|
|
554
554
|
return null;
|
|
555
|
-
},
|
|
555
|
+
}, Ie = (e, t, n) => {
|
|
556
556
|
let r = [], i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Map(), o = (e) => {
|
|
557
|
-
let i =
|
|
557
|
+
let i = Fe(t, e, n);
|
|
558
558
|
return i !== null && r.push(i), i;
|
|
559
559
|
};
|
|
560
560
|
for (let t of e.getImportDeclarations()) if (o(t.getModuleSpecifierValue()), !t.isTypeOnly()) for (let e of t.getNamedImports()) e.isTypeOnly() || i.add(e.getName());
|
|
@@ -581,22 +581,22 @@ var re = () => {
|
|
|
581
581
|
namedBindings: i,
|
|
582
582
|
reExports: a
|
|
583
583
|
};
|
|
584
|
-
},
|
|
584
|
+
}, Le = (e) => {
|
|
585
585
|
let t = /* @__PURE__ */ new Map();
|
|
586
586
|
for (let n of e.getDescendantsOfKind(j.CallExpression)) {
|
|
587
587
|
let e = n.getExpression(), r = k.isPropertyAccessExpression(e) ? e.getName() : e.getText();
|
|
588
588
|
t.set(r, (t.get(r) ?? 0) + 1);
|
|
589
589
|
}
|
|
590
590
|
return t;
|
|
591
|
-
},
|
|
591
|
+
}, Re = (e) => {
|
|
592
592
|
if (e.length <= 1) return e.length === 1;
|
|
593
593
|
let t = [...e].sort((e, t) => e.length - t.length)[0];
|
|
594
594
|
return e.every((e) => e.startsWith(t));
|
|
595
|
-
},
|
|
595
|
+
}, ze = (e, t) => {
|
|
596
596
|
let n = b(t);
|
|
597
597
|
return e.startsWith(`${n}${w}`) || b(e) === n;
|
|
598
|
-
},
|
|
599
|
-
let t =
|
|
598
|
+
}, H = (e) => {
|
|
599
|
+
let t = z(e);
|
|
600
600
|
if (t.length === 0) return {
|
|
601
601
|
findings: [],
|
|
602
602
|
declared: 0,
|
|
@@ -627,7 +627,7 @@ var re = () => {
|
|
|
627
627
|
} catch {
|
|
628
628
|
continue;
|
|
629
629
|
}
|
|
630
|
-
s.set(t,
|
|
630
|
+
s.set(t, Me(r)), c.set(t, Ie(r, t, Pe(t, e, u))), l.set(t, Le(r));
|
|
631
631
|
}
|
|
632
632
|
let d = /* @__PURE__ */ new Map();
|
|
633
633
|
for (let [e, t] of c) for (let n of t.localTargets) {
|
|
@@ -659,11 +659,11 @@ var re = () => {
|
|
|
659
659
|
for (let e of r) {
|
|
660
660
|
let t = R(e), n = s.get(e), r = c.get(e);
|
|
661
661
|
if (n === void 0 || r === void 0) continue;
|
|
662
|
-
let i =
|
|
662
|
+
let i = we(e);
|
|
663
663
|
t !== null && !i && (m += 1);
|
|
664
664
|
let u = d.get(e) ?? [];
|
|
665
665
|
if ((t === "component" || t === "component.ui") && !i) {
|
|
666
|
-
let t =
|
|
666
|
+
let t = Re(n.components);
|
|
667
667
|
(n.components.length === 0 || !t) && a.push({
|
|
668
668
|
rule: "component/one-per-file",
|
|
669
669
|
file: o(e),
|
|
@@ -701,7 +701,7 @@ var re = () => {
|
|
|
701
701
|
].join(", ")}`,
|
|
702
702
|
fix: "a *.types.ts has NO runtime export. That is what makes importing it provably free AND makes it impossible for it to sit in a runtime import cycle — the guarantee is the point, so move the value to a sibling module"
|
|
703
703
|
}), t === "internal") {
|
|
704
|
-
let t = u.filter((t) => !
|
|
704
|
+
let t = u.filter((t) => !ze(t, e));
|
|
705
705
|
t.length > 0 && a.push({
|
|
706
706
|
rule: "internal/foreign-import",
|
|
707
707
|
file: o(e),
|
|
@@ -711,7 +711,7 @@ var re = () => {
|
|
|
711
711
|
});
|
|
712
712
|
}
|
|
713
713
|
if (t === "fixture") {
|
|
714
|
-
let t = u.filter((e) => !
|
|
714
|
+
let t = u.filter((e) => !we(e) && R(e) !== "fixture");
|
|
715
715
|
t.length > 0 && a.push({
|
|
716
716
|
rule: "fixture/production-import",
|
|
717
717
|
file: o(e),
|
|
@@ -721,7 +721,7 @@ var re = () => {
|
|
|
721
721
|
});
|
|
722
722
|
}
|
|
723
723
|
if (t === "component.ui" && !i) {
|
|
724
|
-
let t = [...r.namedBindings].filter((e) =>
|
|
724
|
+
let t = [...r.namedBindings].filter((e) => Te.has(e)).sort();
|
|
725
725
|
t.length > 0 && a.push({
|
|
726
726
|
rule: "ui/no-write",
|
|
727
727
|
file: o(e),
|
|
@@ -756,7 +756,7 @@ var re = () => {
|
|
|
756
756
|
detail: t === 0 ? "declares a store file but calls no defineStore()" : `declares ${t} stores`,
|
|
757
757
|
fix: "a store file defines exactly ONE store — the SSR seed pass and devtools address stores by name, so two in a file makes both harder to find and neither easier to reason about"
|
|
758
758
|
});
|
|
759
|
-
let n = [...l.get(e)?.keys() ?? []].filter((e) =>
|
|
759
|
+
let n = [...l.get(e)?.keys() ?? []].filter((e) => De.has(e)).sort();
|
|
760
760
|
n.length > 0 && a.push({
|
|
761
761
|
rule: "store/mirrors-server-state",
|
|
762
762
|
file: o(e),
|
|
@@ -766,7 +766,7 @@ var re = () => {
|
|
|
766
766
|
});
|
|
767
767
|
}
|
|
768
768
|
if (t !== "tracking" && !i) {
|
|
769
|
-
let t = [...l.get(e)?.keys() ?? []].filter((e) =>
|
|
769
|
+
let t = [...l.get(e)?.keys() ?? []].filter((e) => Ee.has(e)).sort();
|
|
770
770
|
t.length > 0 && a.push({
|
|
771
771
|
rule: "tracking/outside-tracking-file",
|
|
772
772
|
file: o(e),
|
|
@@ -798,8 +798,8 @@ var re = () => {
|
|
|
798
798
|
scanned: r.length,
|
|
799
799
|
vendored: n
|
|
800
800
|
};
|
|
801
|
-
},
|
|
802
|
-
let { findings: t, declared: n, scanned: r, vendored: i } =
|
|
801
|
+
}, Be = 10, Ve = (e) => {
|
|
802
|
+
let { findings: t, declared: n, scanned: r, vendored: i } = H(e);
|
|
803
803
|
console.log("");
|
|
804
804
|
for (let t of Se(e, i)) console.log(`· not ours, exempt: ${t}`);
|
|
805
805
|
if (r === 0) return console.log("• file-taxonomy scan: no sources here — nothing to check."), 0;
|
|
@@ -813,12 +813,12 @@ var re = () => {
|
|
|
813
813
|
console.log(`• file taxonomy: ${t.length} finding(s) — ${o} error, ${t.length - o} advisory (${n} declared / ${r} scanned):`);
|
|
814
814
|
for (let [e, t] of [...a].sort()) {
|
|
815
815
|
console.log(` ${t[0].severity === "error" ? "✗" : "·"} ${e} (${t.length})`);
|
|
816
|
-
for (let e of t.slice(0,
|
|
817
|
-
let n = t.length -
|
|
816
|
+
for (let e of t.slice(0, Be)) console.log(` ${e.file} — ${e.detail}`);
|
|
817
|
+
let n = t.length - Be;
|
|
818
818
|
n > 0 && console.log(` (+${n} more — \`voltro doctor --json\` prints every one.)`), console.log(` → ${t[0].fix}`);
|
|
819
819
|
}
|
|
820
820
|
return t.length;
|
|
821
|
-
},
|
|
821
|
+
}, He = /* @__PURE__ */ new Set([
|
|
822
822
|
"eq",
|
|
823
823
|
"ne",
|
|
824
824
|
"gt",
|
|
@@ -836,10 +836,10 @@ var re = () => {
|
|
|
836
836
|
"endsWith",
|
|
837
837
|
"between",
|
|
838
838
|
"jsonField"
|
|
839
|
-
]),
|
|
839
|
+
]), Ue = (e) => {
|
|
840
840
|
if (k.isPropertyAccessExpression(e)) return e.getName();
|
|
841
841
|
if (k.isIdentifier(e)) return e.getText();
|
|
842
|
-
},
|
|
842
|
+
}, We = (e) => {
|
|
843
843
|
let t = e;
|
|
844
844
|
for (; k.isCallExpression(t);) {
|
|
845
845
|
let e = t.getExpression();
|
|
@@ -847,7 +847,7 @@ var re = () => {
|
|
|
847
847
|
t = e.getExpression();
|
|
848
848
|
}
|
|
849
849
|
return t;
|
|
850
|
-
},
|
|
850
|
+
}, Ge = (e, t, n) => {
|
|
851
851
|
let r = new Map(t.map((e) => [e.name, new Set(e.columns)])), i = new Map(t.map((e) => [e.name, e.columns])), a = [], o = 0, s = new A({
|
|
852
852
|
useInMemoryFileSystem: !0,
|
|
853
853
|
skipAddingFilesFromTsConfig: !0
|
|
@@ -865,7 +865,7 @@ var re = () => {
|
|
|
865
865
|
for (let t of e.getDescendantsOfKind(j.CallExpression)) {
|
|
866
866
|
let e = t.getExpression();
|
|
867
867
|
if (!k.isPropertyAccessExpression(e) || e.getName() !== "where") continue;
|
|
868
|
-
let n =
|
|
868
|
+
let n = Ue(We(e.getExpression()));
|
|
869
869
|
if (n === void 0 || !r.has(n)) {
|
|
870
870
|
let t = e.getExpression();
|
|
871
871
|
if (k.isCallExpression(t)) {
|
|
@@ -888,7 +888,7 @@ var re = () => {
|
|
|
888
888
|
else for (let e of [u, ...u.getDescendantsOfKind(j.CallExpression)]) {
|
|
889
889
|
if (!k.isCallExpression(e)) continue;
|
|
890
890
|
let t = e.getExpression(), n = k.isIdentifier(t) ? t.getText() : k.isPropertyAccessExpression(t) ? t.getName() : void 0;
|
|
891
|
-
if (n === void 0 || !
|
|
891
|
+
if (n === void 0 || !He.has(n)) continue;
|
|
892
892
|
let r = e.getArguments()[0];
|
|
893
893
|
r !== void 0 && k.isStringLiteral(r) && l.push({
|
|
894
894
|
column: r.getLiteralValue(),
|
|
@@ -909,16 +909,16 @@ var re = () => {
|
|
|
909
909
|
issues: a,
|
|
910
910
|
checked: o
|
|
911
911
|
};
|
|
912
|
-
},
|
|
912
|
+
}, U = 12, Ke = (e) => {
|
|
913
913
|
if (e.checked === 0) return null;
|
|
914
914
|
if (e.issues.length === 0) return `predicate columns: ${e.checked} checked — every filtered column exists on its table`;
|
|
915
915
|
let t = [`predicate columns: ${e.issues.length} filter${e.issues.length, "s"} on a column that does not exist (${e.checked} checked)`];
|
|
916
916
|
for (let n of e.issues) {
|
|
917
|
-
let e = n.available.slice(0,
|
|
917
|
+
let e = n.available.slice(0, U).join(", "), r = n.available.length > U ? `, … (${n.available.length - U} more)` : "";
|
|
918
918
|
t.push(` ${n.file}:${n.line} '${n.table}' has no column '${n.column}'`), t.push(` columns: ${e}${r}`);
|
|
919
919
|
}
|
|
920
920
|
return t.push(" This type-checks today and fails at runtime as a bare SQL error."), t.join("\n");
|
|
921
|
-
},
|
|
921
|
+
}, qe = /* @__PURE__ */ new Set([
|
|
922
922
|
"id",
|
|
923
923
|
"tenantId",
|
|
924
924
|
"tenant_id",
|
|
@@ -938,7 +938,7 @@ var re = () => {
|
|
|
938
938
|
"idempotency_id",
|
|
939
939
|
"idempotencyKey",
|
|
940
940
|
"idempotency_key"
|
|
941
|
-
]),
|
|
941
|
+
]), Je = /* @__PURE__ */ new Set([
|
|
942
942
|
"id",
|
|
943
943
|
"createdAt",
|
|
944
944
|
"created_at",
|
|
@@ -948,10 +948,10 @@ var re = () => {
|
|
|
948
948
|
"deleted_at",
|
|
949
949
|
"tenantId",
|
|
950
950
|
"tenant_id"
|
|
951
|
-
]),
|
|
951
|
+
]), Ye = (e) => qe.has(e) ? !1 : /[a-z0-9]Id$/.test(e) || /_id$/.test(e), Xe = (e) => e.type === "reference", Ze = (e) => {
|
|
952
952
|
let t = [];
|
|
953
953
|
for (let n of e) {
|
|
954
|
-
let e = n.columns.filter((e) =>
|
|
954
|
+
let e = n.columns.filter((e) => Ye(e.name)), r = e.filter((e) => !Xe(e)).map((e) => e.name);
|
|
955
955
|
if (r.length === 0) continue;
|
|
956
956
|
let i = new Set(n.primaryKey), a = r.filter((e) => i.has(e));
|
|
957
957
|
if (n.primaryKey.length >= 2 && a.length > 0) {
|
|
@@ -962,7 +962,7 @@ var re = () => {
|
|
|
962
962
|
});
|
|
963
963
|
continue;
|
|
964
964
|
}
|
|
965
|
-
if (e.some(
|
|
965
|
+
if (e.some(Xe) && e.length >= 2) {
|
|
966
966
|
t.push({
|
|
967
967
|
table: n.name,
|
|
968
968
|
columns: r,
|
|
@@ -970,7 +970,7 @@ var re = () => {
|
|
|
970
970
|
});
|
|
971
971
|
continue;
|
|
972
972
|
}
|
|
973
|
-
e.length >= 2 && n.columns.filter((e) => !
|
|
973
|
+
e.length >= 2 && n.columns.filter((e) => !Ye(e.name) && !Je.has(e.name)).length === 0 && t.push({
|
|
974
974
|
table: n.name,
|
|
975
975
|
columns: r,
|
|
976
976
|
signal: "link-only"
|
|
@@ -980,20 +980,20 @@ var re = () => {
|
|
|
980
980
|
issues: t,
|
|
981
981
|
tablesChecked: e.length
|
|
982
982
|
};
|
|
983
|
-
},
|
|
983
|
+
}, Qe = {
|
|
984
984
|
"composite-pk": "part of a composite primary key",
|
|
985
985
|
"reference-sibling": "sits beside a wired reference() on this table",
|
|
986
986
|
"link-only": "this table is nothing but link columns"
|
|
987
|
-
},
|
|
987
|
+
}, $e = (e) => {
|
|
988
988
|
if (e.tablesChecked === 0) return null;
|
|
989
989
|
if (e.issues.length === 0) return `junction FKs: ${e.tablesChecked} table${e.tablesChecked === 1 ? "" : "s"} checked — every link column is a wired reference()`;
|
|
990
990
|
let t = e.issues.length, n = [`junction FKs: ${t} junction table${t === 1 ? "" : "s"} with an id column that is a plain text() and not a reference()`];
|
|
991
991
|
for (let t of e.issues) {
|
|
992
992
|
let e = t.columns.map((e) => `'${e}'`).join(", ");
|
|
993
|
-
n.push(` '${t.table}': ${e} (${
|
|
993
|
+
n.push(` '${t.table}': ${e} (${Qe[t.signal]})`);
|
|
994
994
|
}
|
|
995
995
|
return n.push(" Declare each as reference(() => <table>): the FK is enforced, the column is auto-indexed,"), n.push(" and the relationship becomes walkable (a plain text() id column is an invisible edge)."), n.join("\n");
|
|
996
|
-
},
|
|
996
|
+
}, et = /* @__PURE__ */ new Set(/* @__PURE__ */ "position.positions.move.moved.moving.cursor.pointer.mouse.drag.dragging.hover.frame.frames.tick.ticks.ping.heartbeat.typing.scroll.scrolling.zoom.pan.coord.coords.coordinate.coordinates.telemetry.sensor.sample.samples.viewport".split(".")), tt = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter((e) => e.length > 0).map((e) => e.toLowerCase()), nt = (e) => tt(e).some((e) => et.has(e)), rt = (e) => {
|
|
997
997
|
let t = [], n = [];
|
|
998
998
|
for (let r of e) t.push({
|
|
999
999
|
event: r.name,
|
|
@@ -1002,7 +1002,7 @@ var re = () => {
|
|
|
1002
1002
|
event: r.name,
|
|
1003
1003
|
kind: "wide-key",
|
|
1004
1004
|
keyFieldCount: r.keyFieldCount
|
|
1005
|
-
}), r.hasWebhook &&
|
|
1005
|
+
}), r.hasWebhook && nt(r.name) && n.push({
|
|
1006
1006
|
event: r.name,
|
|
1007
1007
|
kind: "webhook-high-rate"
|
|
1008
1008
|
});
|
|
@@ -1011,26 +1011,26 @@ var re = () => {
|
|
|
1011
1011
|
modes: t,
|
|
1012
1012
|
warnings: n
|
|
1013
1013
|
};
|
|
1014
|
-
},
|
|
1014
|
+
}, it = (e) => {
|
|
1015
1015
|
if (e.eventsChecked === 0) return null;
|
|
1016
1016
|
let t = e.eventsChecked, n = [`event delivery: ${t} declared event${t === 1 ? "" : "s"} — the mode decides what a MISSING message means`];
|
|
1017
1017
|
for (let t of e.modes) n.push(` '${t.event}': ${t.delivery}`);
|
|
1018
1018
|
return n.push(" each — every delivery matters; a slow subscriber loses the oldest and is TOLD how many (the default)."), n.push(" latest — a newer delivery supersedes a pending one; a slow subscriber gets the current value, told nothing."), n.push(" Two events with identical route/subscriber/buffer numbers mean OPPOSITE things about a drop — the mode is the difference."), n.join("\n");
|
|
1019
|
-
},
|
|
1019
|
+
}, at = (e) => {
|
|
1020
1020
|
if (e.warnings.length === 0) return null;
|
|
1021
1021
|
let t = e.warnings.length, n = [`events that may not scale as declared: ${t} finding${t === 1 ? "" : "s"}`];
|
|
1022
1022
|
for (let t of e.warnings) t.kind === "wide-key" ? (n.push(` '${t.event}': routing key has ${t.keyFieldCount ?? 0} fields — every field FRAGMENTS the subscriber set (distinct routes are the PRODUCT of the fields’ value spaces).`), n.push(" Check each is an ADDRESS the delivery is decided by (arenaId), not a discriminator the handler reads (gameType) — the latter is payload, not key.")) : (n.push(` '${t.event}': a webhook block on a per-frame-looking event — every publish is N HTTP deliveries per second per subscribed target.`), n.push(" The webhook rate limit DEFERS the excess as pending rows rather than failing, so the symptom is a growing table. Publish a coarser event (a summary / state change) for the outside world."));
|
|
1023
1023
|
return n.push(" WARNING, not a fault — a producer may intend the fan-out. `voltro doctor --json` prints every finding."), n.join("\n");
|
|
1024
|
-
},
|
|
1024
|
+
}, ot = /* @__PURE__ */ new Set([
|
|
1025
1025
|
"start",
|
|
1026
1026
|
"run",
|
|
1027
1027
|
"child"
|
|
1028
|
-
]),
|
|
1028
|
+
]), st = (e) => k.isCallExpression(e) && (() => {
|
|
1029
1029
|
let t = e.getExpression();
|
|
1030
|
-
if (!k.isPropertyAccessExpression(t) || !
|
|
1030
|
+
if (!k.isPropertyAccessExpression(t) || !ot.has(t.getName())) return !1;
|
|
1031
1031
|
let n = t.getExpression();
|
|
1032
1032
|
return k.isPropertyAccessExpression(n) ? n.getName() === "workflows" : k.isIdentifier(n) && n.getText() === "workflows";
|
|
1033
|
-
})(),
|
|
1033
|
+
})(), ct = (e, t, n) => {
|
|
1034
1034
|
let r = new Map(t.map((e) => [e.name, e])), i = [...r.keys()].sort(), a = [], o = [], s = 0, c = 0, l = new A({
|
|
1035
1035
|
useInMemoryFileSystem: !0,
|
|
1036
1036
|
skipAddingFilesFromTsConfig: !0
|
|
@@ -1046,7 +1046,7 @@ var re = () => {
|
|
|
1046
1046
|
}
|
|
1047
1047
|
let u = S(n, t);
|
|
1048
1048
|
for (let t of e.getDescendantsOfKind(j.CallExpression)) {
|
|
1049
|
-
if (!
|
|
1049
|
+
if (!st(t)) continue;
|
|
1050
1050
|
c++;
|
|
1051
1051
|
let e = t.getStartLineNumber(), [n, l] = t.getArguments();
|
|
1052
1052
|
if (n === void 0 || !k.isStringLiteral(n)) {
|
|
@@ -1130,7 +1130,7 @@ var re = () => {
|
|
|
1130
1130
|
checked: s,
|
|
1131
1131
|
callSites: c
|
|
1132
1132
|
};
|
|
1133
|
-
},
|
|
1133
|
+
}, lt = (e) => {
|
|
1134
1134
|
if (e.callSites === 0) return null;
|
|
1135
1135
|
let t = [];
|
|
1136
1136
|
t.push(`workflow starts: ${e.checked}/${e.callSites} call sites checked`);
|
|
@@ -1143,7 +1143,7 @@ var re = () => {
|
|
|
1143
1143
|
for (let n of e.unchecked) t.push(` ${n.file}:${n.line} — ${n.reason}`);
|
|
1144
1144
|
}
|
|
1145
1145
|
return e.issues.length === 0 && e.unchecked.length === 0 && t.push(" every call site matches its workflow"), t.join("\n");
|
|
1146
|
-
},
|
|
1146
|
+
}, ut = /(^|[/\\])(\.env(\.[\w.-]+)?|.*\.ya?ml|Dockerfile|.*\.tf|.*\.toml|Procfile)$/i, W = "VOLTRO_FIELD_ENCRYPTION_KEY", dt = (e) => {
|
|
1147
1147
|
let t;
|
|
1148
1148
|
for (let [n, r] of e.sources) if (t === void 0 && /\bfieldEncryption\b/.test(r) && (t = {
|
|
1149
1149
|
reason: "fieldEncryption",
|
|
@@ -1151,13 +1151,13 @@ var re = () => {
|
|
|
1151
1151
|
}), t === void 0 && /\.encrypted\s*\(/.test(r) && (t = {
|
|
1152
1152
|
reason: "encrypted-column",
|
|
1153
1153
|
file: n
|
|
1154
|
-
}), r.includes(
|
|
1154
|
+
}), r.includes(W)) return;
|
|
1155
1155
|
if (t !== void 0) {
|
|
1156
|
-
for (let [, t] of e.envFiles) if (t.includes(
|
|
1156
|
+
for (let [, t] of e.envFiles) if (t.includes(W)) return;
|
|
1157
1157
|
return t;
|
|
1158
1158
|
}
|
|
1159
|
-
},
|
|
1160
|
-
`✗ ${
|
|
1159
|
+
}, ft = (e) => [
|
|
1160
|
+
`✗ ${W} is named nowhere under this app root, and the app encrypts columns at rest`,
|
|
1161
1161
|
e.reason === "fieldEncryption" ? ` (\`fieldEncryption\` in ${e.file})` : ` (an \`.encrypted()\` column in ${e.file})`,
|
|
1162
1162
|
"",
|
|
1163
1163
|
" A deploy without it does not degrade — it refuses to boot at `onActivate`,",
|
|
@@ -1173,7 +1173,7 @@ var re = () => {
|
|
|
1173
1173
|
" reaches your deploy target is not knowable from here — a secret manager",
|
|
1174
1174
|
" or a CI variable is not a file. Naming it nowhere is conclusive; naming",
|
|
1175
1175
|
" it somewhere is not a guarantee."
|
|
1176
|
-
].join("\n"),
|
|
1176
|
+
].join("\n"), pt = (e) => e === "effect" || e.startsWith("@effect/") || e.startsWith("@voltro/") || e === "react" || e === "react-dom", mt = /(^|\/)(\.bin|\.cache|\.pnpm-store|dist|build)(\/|$)/, ht = (e) => {
|
|
1177
1177
|
let t = [], n = e;
|
|
1178
1178
|
for (let e = 0; e < 12; e++) {
|
|
1179
1179
|
let e = x(n, "node_modules");
|
|
@@ -1183,14 +1183,14 @@ var re = () => {
|
|
|
1183
1183
|
n = r;
|
|
1184
1184
|
}
|
|
1185
1185
|
return t;
|
|
1186
|
-
},
|
|
1186
|
+
}, gt = (e) => {
|
|
1187
1187
|
try {
|
|
1188
1188
|
let t = JSON.parse(E(x(e, "package.json"), "utf8"));
|
|
1189
1189
|
return typeof t.version == "string" ? t.version : void 0;
|
|
1190
1190
|
} catch {
|
|
1191
1191
|
return;
|
|
1192
1192
|
}
|
|
1193
|
-
},
|
|
1193
|
+
}, _t = (e) => {
|
|
1194
1194
|
let t = [], n;
|
|
1195
1195
|
try {
|
|
1196
1196
|
n = D(e);
|
|
@@ -1198,7 +1198,7 @@ var re = () => {
|
|
|
1198
1198
|
return t;
|
|
1199
1199
|
}
|
|
1200
1200
|
for (let r of n) {
|
|
1201
|
-
if (r.startsWith(".") ||
|
|
1201
|
+
if (r.startsWith(".") || mt.test(r)) continue;
|
|
1202
1202
|
let n = x(e, r);
|
|
1203
1203
|
if (r.startsWith("@")) {
|
|
1204
1204
|
let e;
|
|
@@ -1224,11 +1224,11 @@ var re = () => {
|
|
|
1224
1224
|
});
|
|
1225
1225
|
}
|
|
1226
1226
|
return t;
|
|
1227
|
-
},
|
|
1227
|
+
}, vt = (e) => {
|
|
1228
1228
|
let t = /* @__PURE__ */ new Map();
|
|
1229
|
-
for (let n of
|
|
1230
|
-
if (!
|
|
1231
|
-
let n =
|
|
1229
|
+
for (let n of ht(e)) for (let { pkg: e, dir: r } of _t(n)) {
|
|
1230
|
+
if (!pt(e)) continue;
|
|
1231
|
+
let n = gt(r);
|
|
1232
1232
|
if (n === void 0) continue;
|
|
1233
1233
|
let i = t.get(e) ?? /* @__PURE__ */ new Map();
|
|
1234
1234
|
i.has(n) || i.set(n, r), t.set(e, i);
|
|
@@ -1240,7 +1240,7 @@ var re = () => {
|
|
|
1240
1240
|
paths: [...i.values()].map((t) => S(e, t)).sort()
|
|
1241
1241
|
});
|
|
1242
1242
|
return n.sort((e, t) => e.pkg.localeCompare(t.pkg));
|
|
1243
|
-
},
|
|
1243
|
+
}, yt = (e) => {
|
|
1244
1244
|
if (e.length !== 0) return [
|
|
1245
1245
|
`• ${e.length} package(s) resolved at more than one version:`,
|
|
1246
1246
|
...e.flatMap((e) => [` ${e.pkg} — ${e.versions.join(", ")}`, ...e.paths.map((e) => ` ${e}`)]),
|
|
@@ -1258,33 +1258,52 @@ var re = () => {
|
|
|
1258
1258
|
" instrument), then reinstall. Do not silence the generated file — it is where",
|
|
1259
1259
|
" a genuine mistake in your own descriptors surfaces."
|
|
1260
1260
|
].join("\n");
|
|
1261
|
-
},
|
|
1261
|
+
}, bt = (e) => {
|
|
1262
|
+
if (e.catalogCodes.length === 0) return;
|
|
1263
|
+
let t = new Set(e.declaredLocales), n = e.catalogCodes.filter((e) => !t.has(e)).sort();
|
|
1264
|
+
if (n.length !== 0) return {
|
|
1265
|
+
orphaned: n,
|
|
1266
|
+
noneDeclared: t.size === 0
|
|
1267
|
+
};
|
|
1268
|
+
}, xt = (e, t) => {
|
|
1269
|
+
let n = e.orphaned.join(", ");
|
|
1270
|
+
return e.noneDeclared ? [
|
|
1271
|
+
`⚠ ${t} has ${e.orphaned.length} catalog(s) — ${n} — and the app declares no \`locales:\`.`,
|
|
1272
|
+
" Nothing imports them: no provider is generated and `useT()` would not find a catalog.",
|
|
1273
|
+
" Either declare them in your app config:",
|
|
1274
|
+
"",
|
|
1275
|
+
` locales: [${e.orphaned.map((e) => `'${e}'`).join(", ")}],`,
|
|
1276
|
+
"",
|
|
1277
|
+
" …or delete the files. A catalog that is never loaded looks from the inside",
|
|
1278
|
+
" exactly like one that works, which is why this is worth a line."
|
|
1279
|
+
] : [`⚠ ${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
|
+
}, St = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), Ct = /* @__PURE__ */ new Set([
|
|
1262
1281
|
"requireScope",
|
|
1263
1282
|
"requireAnyScope",
|
|
1264
1283
|
"requireAuth",
|
|
1265
1284
|
"assertScope",
|
|
1266
1285
|
"assertCan",
|
|
1267
1286
|
"can"
|
|
1268
|
-
]),
|
|
1287
|
+
]), wt = (e) => {
|
|
1269
1288
|
let t = /* @__PURE__ */ new Set();
|
|
1270
|
-
for (let n of e) for (let e of
|
|
1289
|
+
for (let n of e) for (let e of St(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
|
|
1271
1290
|
return t;
|
|
1272
|
-
},
|
|
1291
|
+
}, Tt = (e, t) => {
|
|
1273
1292
|
for (let n of t) if (RegExp(`\\b${n}\\s*\\(`).test(e)) return n;
|
|
1274
|
-
},
|
|
1293
|
+
}, Et = (e) => {
|
|
1275
1294
|
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);
|
|
1276
1295
|
return t && n;
|
|
1277
|
-
},
|
|
1296
|
+
}, Dt = (e, t, n) => {
|
|
1278
1297
|
if (e.hasDeclaredGuards) return { kind: "declared-guard" };
|
|
1279
|
-
let r =
|
|
1280
|
-
return i === void 0 ?
|
|
1298
|
+
let r = St(e.src), i = Tt(r, t);
|
|
1299
|
+
return i === void 0 ? Et(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
|
|
1281
1300
|
kind: "vocabulary-guard",
|
|
1282
1301
|
name: i
|
|
1283
1302
|
};
|
|
1284
|
-
},
|
|
1303
|
+
}, Ot = (e, t, n) => {
|
|
1285
1304
|
let r = e.op === "delete" ? 3 : e.op === "update" ? 2 : 1;
|
|
1286
1305
|
return e.table !== void 0 && (t.has(e.table) && (r += 2), n.has(e.table) && e.op === "delete" && (r += 2)), r;
|
|
1287
|
-
},
|
|
1306
|
+
}, kt = (e, t) => {
|
|
1288
1307
|
switch (t.kind) {
|
|
1289
1308
|
case "declared-guard": return "guards: on the descriptor";
|
|
1290
1309
|
case "vocabulary-guard": return `calls ${t.name}()`;
|
|
@@ -1292,15 +1311,15 @@ var re = () => {
|
|
|
1292
1311
|
case "allowlisted": return "accepted by a previous run";
|
|
1293
1312
|
case "unchecked": return 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`;
|
|
1294
1313
|
}
|
|
1295
|
-
},
|
|
1314
|
+
}, At = (e) => {
|
|
1296
1315
|
let t = e.executors.map((t) => {
|
|
1297
|
-
let n =
|
|
1316
|
+
let n = Dt(t, e.guardVocabulary, e.allowlist);
|
|
1298
1317
|
return {
|
|
1299
1318
|
tag: t.tag,
|
|
1300
1319
|
path: t.path,
|
|
1301
1320
|
verdict: n,
|
|
1302
|
-
severity:
|
|
1303
|
-
why:
|
|
1321
|
+
severity: Ot(t, e.tenantScopedTables, e.referencedTables),
|
|
1322
|
+
why: kt(t, n)
|
|
1304
1323
|
};
|
|
1305
1324
|
}), n = (e) => t.filter((t) => t.verdict.kind === e).length;
|
|
1306
1325
|
return {
|
|
@@ -1314,26 +1333,75 @@ var re = () => {
|
|
|
1314
1333
|
},
|
|
1315
1334
|
unchecked: t.filter((e) => e.verdict.kind === "unchecked").sort((e, t) => t.severity - e.severity || e.tag.localeCompare(t.tag))
|
|
1316
1335
|
};
|
|
1317
|
-
},
|
|
1336
|
+
}, jt = [
|
|
1318
1337
|
"# voltro doctor — authz allowlist",
|
|
1319
1338
|
"#",
|
|
1320
|
-
"#
|
|
1321
|
-
"#
|
|
1339
|
+
"# Two KINDS of line, and the difference is the point:",
|
|
1340
|
+
"#",
|
|
1341
|
+
"# <tag> DEBT, not approval. Nobody has confirmed",
|
|
1342
|
+
"# this executor is safe; it was accepted so",
|
|
1343
|
+
"# the ratchet could start. Every one of",
|
|
1344
|
+
"# these is owed work.",
|
|
1345
|
+
"#",
|
|
1346
|
+
"# <tag> reviewed=<why> REVIEWED. A human read it and states why it",
|
|
1347
|
+
"# is genuinely open — constrained by something",
|
|
1348
|
+
"# the scanner cannot see. The reason is",
|
|
1349
|
+
"# REQUIRED: \"reviewed\" with no why is the",
|
|
1350
|
+
"# claim without the evidence, and doctor",
|
|
1351
|
+
"# refuses it.",
|
|
1322
1352
|
"#",
|
|
1323
1353
|
"# Doctor fails on any executor NOT listed here, so the list can only shrink",
|
|
1324
1354
|
"# unless someone adds a line deliberately. Delete a line once its executor",
|
|
1325
1355
|
"# has a guard — doctor reports it as guarded from then on, whether or not the",
|
|
1326
1356
|
"# line is still here.",
|
|
1327
|
-
"",
|
|
1328
|
-
|
|
1357
|
+
"#",
|
|
1358
|
+
"# `--write-authz-allowlist` PRESERVES reviewed= lines. It only ever adds debt",
|
|
1359
|
+
"# lines for executors that are newly unchecked.",
|
|
1329
1360
|
""
|
|
1330
|
-
]
|
|
1361
|
+
], Mt = (e) => {
|
|
1362
|
+
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
|
+
return [
|
|
1364
|
+
...jt,
|
|
1365
|
+
...n,
|
|
1366
|
+
...r.length > 0 ? ["", "# reviewed — read by a human, open on purpose"] : [],
|
|
1367
|
+
...r.map((e) => `${e.tag} reviewed=${e.reviewed}`),
|
|
1368
|
+
""
|
|
1369
|
+
].join("\n");
|
|
1370
|
+
}, Nt = class extends Error {
|
|
1371
|
+
tag;
|
|
1372
|
+
constructor(e) {
|
|
1373
|
+
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";
|
|
1374
|
+
}
|
|
1375
|
+
}, Pt = (e) => {
|
|
1376
|
+
let t = [];
|
|
1377
|
+
for (let n of e.split("\n")) {
|
|
1378
|
+
let e = n.trim();
|
|
1379
|
+
if (e.length === 0 || e.startsWith("#")) continue;
|
|
1380
|
+
let r = /^(\S+)(?:\s+reviewed=(.*))?$/.exec(e);
|
|
1381
|
+
if (!r) continue;
|
|
1382
|
+
let i = r[1];
|
|
1383
|
+
if (r[2] === void 0) {
|
|
1384
|
+
t.push({ tag: i });
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
let a = r[2].trim();
|
|
1388
|
+
if (a.length === 0) throw new Nt(i);
|
|
1389
|
+
t.push({
|
|
1390
|
+
tag: i,
|
|
1391
|
+
reviewed: a
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
return {
|
|
1395
|
+
tags: new Set(t.map((e) => e.tag)),
|
|
1396
|
+
entries: t
|
|
1397
|
+
};
|
|
1398
|
+
}, Ft = (e) => {
|
|
1331
1399
|
let t = e.indexOf(".");
|
|
1332
1400
|
return t <= 0 ? void 0 : e.slice(0, t);
|
|
1333
|
-
},
|
|
1401
|
+
}, It = (e, t) => {
|
|
1334
1402
|
let n = new Set(t.tables), r = new Set(t.rpcTags), i = /* @__PURE__ */ new Map();
|
|
1335
1403
|
for (let e of t.rpcTags) {
|
|
1336
|
-
let t =
|
|
1404
|
+
let t = Ft(e);
|
|
1337
1405
|
if (t === void 0) continue;
|
|
1338
1406
|
let n = i.get(t);
|
|
1339
1407
|
n ? n.push(e) : i.set(t, [e]);
|
|
@@ -1362,7 +1430,7 @@ var re = () => {
|
|
|
1362
1430
|
});
|
|
1363
1431
|
continue;
|
|
1364
1432
|
}
|
|
1365
|
-
let s = new Set(o.rpcTags.map(
|
|
1433
|
+
let s = new Set(o.rpcTags.map(Ft).filter((e) => e !== void 0));
|
|
1366
1434
|
for (let e of s) {
|
|
1367
1435
|
let t = i.get(e);
|
|
1368
1436
|
t !== void 0 && a.push({
|
|
@@ -1375,12 +1443,12 @@ var re = () => {
|
|
|
1375
1443
|
}
|
|
1376
1444
|
}
|
|
1377
1445
|
return a;
|
|
1378
|
-
},
|
|
1446
|
+
}, Lt = (e, t) => {
|
|
1379
1447
|
let n = e.reduce((e, t) => e + t.tables.length, 0), r = [`plugin surface · ${e.length} plugin(s) contribute ${n} table(s)`];
|
|
1380
1448
|
if (t.length === 0) return r.push(" ✓ no overlap with your own tables or rpc namespaces"), r;
|
|
1381
1449
|
for (let e of t) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.plugin} — ${e.detail}`), r.push(` ${e.fix}`);
|
|
1382
1450
|
return r;
|
|
1383
|
-
},
|
|
1451
|
+
}, Rt = (e) => T(C(e, "app.config.ts")) || T(C(e, "app.config.js")), zt = (e) => {
|
|
1384
1452
|
let t = y(e), n = v(e);
|
|
1385
1453
|
return {
|
|
1386
1454
|
root: e,
|
|
@@ -1389,19 +1457,19 @@ var re = () => {
|
|
|
1389
1457
|
apiBundle: n,
|
|
1390
1458
|
apiBundlePresent: T(n)
|
|
1391
1459
|
};
|
|
1392
|
-
},
|
|
1460
|
+
}, Bt = [
|
|
1393
1461
|
"Production `voltro serve` requires a precompiled serve bundle and never transpiles on demand.",
|
|
1394
1462
|
"Add a `voltro build .` step BEFORE `voltro serve .` in your Dockerfile / start script.",
|
|
1395
1463
|
"(Generated Dockerfiles from `voltro create-project` already do this.)"
|
|
1396
|
-
].join("\n "),
|
|
1397
|
-
let n =
|
|
1398
|
-
if (console.log(`voltro doctor — serve preflight for ${n.root}`), !
|
|
1464
|
+
].join("\n "), Vt = (e, t = !1) => {
|
|
1465
|
+
let n = zt(e);
|
|
1466
|
+
if (console.log(`voltro doctor — serve preflight for ${n.root}`), !Rt(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
|
|
1399
1467
|
console.log(`${n.serveBundlePresent ? "✓" : "✗"} serve bundle: ${n.serveBundlePresent ? "present" : "MISSING"} (${n.serveBundle})`), console.log(`${n.apiBundlePresent ? "✓" : "•"} api bundle: ${n.apiBundlePresent ? "present" : "absent"} (${n.apiBundle})`);
|
|
1400
1468
|
let r = process.env.NODE_ENV === "production";
|
|
1401
1469
|
if (n.serveBundlePresent) return console.log("✓ serve preflight: ready for `voltro serve`."), 0;
|
|
1402
1470
|
let i = t || r;
|
|
1403
|
-
return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${
|
|
1404
|
-
},
|
|
1471
|
+
return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${Bt}`), +!!i;
|
|
1472
|
+
}, Ht = (e, t, n) => {
|
|
1405
1473
|
let r = new Set(e), i = I(n), a = (e) => (/\.(tsx?|jsx?)$/.test(e) ? [e] : [
|
|
1406
1474
|
`${e}.ts`,
|
|
1407
1475
|
`${e}.tsx`,
|
|
@@ -1427,7 +1495,7 @@ var re = () => {
|
|
|
1427
1495
|
r !== void 0 && o.push(r);
|
|
1428
1496
|
}
|
|
1429
1497
|
return o;
|
|
1430
|
-
}, s = /* @__PURE__ */ new Set(), c = e.filter((e) =>
|
|
1498
|
+
}, s = /* @__PURE__ */ new Set(), c = e.filter((e) => Jt.test(S(n, e))), l = new Set(c);
|
|
1431
1499
|
for (; c.length > 0;) {
|
|
1432
1500
|
let e = c.shift();
|
|
1433
1501
|
if (!s.has(e)) {
|
|
@@ -1440,11 +1508,11 @@ var re = () => {
|
|
|
1440
1508
|
let d = /* @__PURE__ */ new Set();
|
|
1441
1509
|
for (let e of s) l.has(e) || u.has(e) || d.add(e);
|
|
1442
1510
|
return d;
|
|
1443
|
-
},
|
|
1511
|
+
}, Ut = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), Wt = (e, t) => (e.match(t) ?? []).length, G = (e, t) => e.getDescendantsOfKind(j.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, Gt = (e, t) => {
|
|
1444
1512
|
if (e.src.includes(t)) return !0;
|
|
1445
1513
|
let n = t.replace(/^@voltro\/plugin-/, "");
|
|
1446
|
-
return n !== t &&
|
|
1447
|
-
},
|
|
1514
|
+
return n !== t && G(e.file, RegExp(`^${n}Plugin$`)) > 0;
|
|
1515
|
+
}, Kt = (e, t) => {
|
|
1448
1516
|
let n = [], r = RegExp(`\\b${t}\\s*(?:<[^()]*>)?\\s*\\(`, "g"), i;
|
|
1449
1517
|
for (; (i = r.exec(e)) !== null;) {
|
|
1450
1518
|
let t = i.index + i[0].length, r = 1, a = t;
|
|
@@ -1452,10 +1520,10 @@ var re = () => {
|
|
|
1452
1520
|
n.push(e.slice(t, a - 1));
|
|
1453
1521
|
}
|
|
1454
1522
|
return n;
|
|
1455
|
-
},
|
|
1523
|
+
}, qt = (e, t) => {
|
|
1456
1524
|
let n = t.getSymbol()?.getDeclarations()?.[0];
|
|
1457
1525
|
return n === void 0 ? [] : e.getDescendantsOfKind(j.Identifier).filter((e) => e.getSymbol()?.getDeclarations()?.[0] === n);
|
|
1458
|
-
},
|
|
1526
|
+
}, Jt = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, Yt = /\.(query|mutation|action|stream)\.server\.tsx?$/, Xt = [
|
|
1459
1527
|
"Id",
|
|
1460
1528
|
"ID",
|
|
1461
1529
|
"Hash",
|
|
@@ -1481,7 +1549,7 @@ var re = () => {
|
|
|
1481
1549
|
"Comment",
|
|
1482
1550
|
"Provider",
|
|
1483
1551
|
"Format"
|
|
1484
|
-
],
|
|
1552
|
+
], Zt = RegExp(`(?:${Xt.join("|")})$|_(?:${Xt.map((e) => e.toLowerCase()).join("|")})$`), Qt = [
|
|
1485
1553
|
{
|
|
1486
1554
|
id: "hardcoded-framework-cookie",
|
|
1487
1555
|
scope: "client",
|
|
@@ -1494,7 +1562,7 @@ var re = () => {
|
|
|
1494
1562
|
scope: "server",
|
|
1495
1563
|
smell: "an executor that never names its own descriptor — its input type is hand-written, so it can drift from the contract it implements",
|
|
1496
1564
|
use: "import the descriptor and type the input as `ExecutorInput<typeof descriptor>`, so the wire contract and the handler cannot disagree",
|
|
1497
|
-
match: ({ src: e, path: t }) =>
|
|
1565
|
+
match: ({ src: e, path: t }) => Yt.test(t) && !/\bimport\s[^;]*\bfrom\s*['"][^'"]*['"]/.test((e.match(/^\s*import\s[^;]*from\s*['"]\.[^'"]*['"]/gm) ?? []).join("\n"))
|
|
1498
1566
|
},
|
|
1499
1567
|
{
|
|
1500
1568
|
id: "subject-write-no-guard",
|
|
@@ -1502,8 +1570,8 @@ var re = () => {
|
|
|
1502
1570
|
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",
|
|
1503
1571
|
use: "add a guard (e.g. `.guard(requireScope('…'))`) or an explicit auth check, so an unauthenticated caller is refused BEFORE the write",
|
|
1504
1572
|
match: ({ src: e, path: t }) => {
|
|
1505
|
-
if (!
|
|
1506
|
-
let n =
|
|
1573
|
+
if (!Yt.test(t)) return !1;
|
|
1574
|
+
let n = Ut(e);
|
|
1507
1575
|
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);
|
|
1508
1576
|
}
|
|
1509
1577
|
},
|
|
@@ -1512,14 +1580,14 @@ var re = () => {
|
|
|
1512
1580
|
scope: "server",
|
|
1513
1581
|
smell: "raw fetch() for outbound HTTP on the server (no SSRF guard, no traceparent, no retry)",
|
|
1514
1582
|
use: "yield* HttpClient — the framework client. It blocks loopback / RFC-1918 / link-local targets (incl. 169.254.169.254) on the initial request AND every redirect hop, injects traceparent, and honours `http.allowHosts` for deliberate internal targets",
|
|
1515
|
-
match: ({ file: e, path: t, serverOnly: n }) => (
|
|
1583
|
+
match: ({ file: e, path: t, serverOnly: n }) => (Jt.test(t) || n) && G(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
|
|
1516
1584
|
},
|
|
1517
1585
|
{
|
|
1518
1586
|
id: "form",
|
|
1519
1587
|
scope: "client",
|
|
1520
1588
|
smell: "per-field useState + a submit flag (hand-rolled form)",
|
|
1521
1589
|
use: "useFormBinding — fields + validation from the mutation input Schema; server ValidationError({ field }) routes to the field",
|
|
1522
|
-
match: ({ src: e, file: t }) =>
|
|
1590
|
+
match: ({ src: e, file: t }) => G(t, /^useState$/) >= 4 && /onSubmit|handleSubmit|isSubmitting/.test(e)
|
|
1523
1591
|
},
|
|
1524
1592
|
{
|
|
1525
1593
|
id: "table",
|
|
@@ -1547,7 +1615,7 @@ var re = () => {
|
|
|
1547
1615
|
scope: "client",
|
|
1548
1616
|
smell: "useMemo fanning in multiple subscriptions (hand-maintained dep array)",
|
|
1549
1617
|
use: "useDerived — dependency-tracked, referentially stable",
|
|
1550
|
-
match: ({ src: e }) =>
|
|
1618
|
+
match: ({ src: e }) => Wt(e, /\buseSubscription\s*[(<]/g) >= 3 && Wt(e, /\buseMemo\s*\(/g) >= 3
|
|
1551
1619
|
},
|
|
1552
1620
|
{
|
|
1553
1621
|
id: "next-shim",
|
|
@@ -1572,7 +1640,7 @@ var re = () => {
|
|
|
1572
1640
|
match: ({ file: e }) => e.getDescendantsOfKind(j.CallExpression).filter((e) => /(^|\.)useSubscription$/.test(e.getExpression().getText())).flatMap((e) => {
|
|
1573
1641
|
let t = e.getFirstAncestorByKind(j.VariableDeclaration)?.getNameNode();
|
|
1574
1642
|
return t === void 0 ? [] : k.isObjectBindingPattern(t) ? t.getElements().filter((e) => (e.getPropertyNameNode() ?? e.getNameNode()).getText() === "data").map((e) => e.getNameNode()) : [];
|
|
1575
|
-
}).some((t) =>
|
|
1643
|
+
}).some((t) => qt(e, t).some((e) => {
|
|
1576
1644
|
let t = e.getParent();
|
|
1577
1645
|
if (k.isBinaryExpression(t)) {
|
|
1578
1646
|
let n = t.getOperatorToken().getText(), r = t.getLeft() === e ? t.getRight() : t.getLeft();
|
|
@@ -1600,7 +1668,7 @@ var re = () => {
|
|
|
1600
1668
|
scope: "server",
|
|
1601
1669
|
smell: "several sequential store reads assembling related data (an N+1 you are writing by hand)",
|
|
1602
1670
|
use: "reads are a parent→child walk on ONE key → relations() in a *.relations.ts + .with({ … }) (ONE JSON-aggregate query, every dialect); reads collect ids from SEVERAL sources → keep the assembly and run the independent leading reads under Effect.all (same queries, same results, only concurrent — zero parity risk)",
|
|
1603
|
-
match: (e) =>
|
|
1671
|
+
match: (e) => G(e.file, /\bstore\.query$/) >= 3 || G(e.file, /\bstore\.query$/) >= 2 && /\bnew Map\s*\(/.test(e.src)
|
|
1604
1672
|
},
|
|
1605
1673
|
{
|
|
1606
1674
|
id: "store-effect-lift",
|
|
@@ -1623,7 +1691,7 @@ var re = () => {
|
|
|
1623
1691
|
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)",
|
|
1624
1692
|
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) => {
|
|
1625
1693
|
let n = t[1];
|
|
1626
|
-
return !/token|secret|credential|password|apikey|accesskey/i.test(n) ||
|
|
1694
|
+
return !/token|secret|credential|password|apikey|accesskey/i.test(n) || Zt.test(n) || /^vault/i.test(n) ? !1 : !/\.encrypted\s*\(/.test(e);
|
|
1627
1695
|
}))
|
|
1628
1696
|
},
|
|
1629
1697
|
{
|
|
@@ -1687,9 +1755,9 @@ var re = () => {
|
|
|
1687
1755
|
scope: "server",
|
|
1688
1756
|
smell: "setRowFilter is registered, but no test passes `rowFilter:` to makeTestContext",
|
|
1689
1757
|
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",
|
|
1690
|
-
match: ({ file: e, testSources: t }) =>
|
|
1691
|
-
let t =
|
|
1692
|
-
return
|
|
1758
|
+
match: ({ file: e, testSources: t }) => G(e, /^setRowFilter$/) > 0 && ![...t.values()].some((e) => {
|
|
1759
|
+
let t = Ut(e);
|
|
1760
|
+
return Kt(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
|
|
1693
1761
|
})
|
|
1694
1762
|
},
|
|
1695
1763
|
{
|
|
@@ -1699,15 +1767,15 @@ var re = () => {
|
|
|
1699
1767
|
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",
|
|
1700
1768
|
match: ({ src: e }) => /\.(getTime|toISOString)\s*\(\s*\)/.test(e) && /\.map\s*\(|=>\s*\(\{/.test(e) && /\bexport\s+default\b/.test(e)
|
|
1701
1769
|
}
|
|
1702
|
-
],
|
|
1770
|
+
], $t = (e) => q(e), en = (e, t) => {
|
|
1703
1771
|
let n = /* @__PURE__ */ new Set();
|
|
1704
1772
|
for (let r of t) {
|
|
1705
1773
|
let t = S(e, r), i = t.split(/[\\/]/)[0];
|
|
1706
1774
|
n.add(i !== void 0 && i !== t ? i : ".");
|
|
1707
1775
|
}
|
|
1708
1776
|
return [...n].sort();
|
|
1709
|
-
},
|
|
1710
|
-
if (n > 12 ||
|
|
1777
|
+
}, tn = /\.(tsx?|jsx?)$/, K = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, nn = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, rn = (e, t = [], n = 0) => {
|
|
1778
|
+
if (n > 12 || K.test(e)) return t;
|
|
1711
1779
|
let r;
|
|
1712
1780
|
try {
|
|
1713
1781
|
r = D(e, { withFileTypes: !0 });
|
|
@@ -1718,12 +1786,12 @@ var re = () => {
|
|
|
1718
1786
|
let r = x(e, i.name);
|
|
1719
1787
|
if (i.isDirectory()) {
|
|
1720
1788
|
if (i.name.startsWith(".")) continue;
|
|
1721
|
-
|
|
1722
|
-
} else
|
|
1789
|
+
rn(r, t, n + 1);
|
|
1790
|
+
} else ut.test(i.name) && t.push(r);
|
|
1723
1791
|
}
|
|
1724
1792
|
return t;
|
|
1725
|
-
},
|
|
1726
|
-
if (n > 12 ||
|
|
1793
|
+
}, q = (e, t = [], n = 0) => {
|
|
1794
|
+
if (n > 12 || K.test(e)) return t;
|
|
1727
1795
|
let r;
|
|
1728
1796
|
try {
|
|
1729
1797
|
r = D(e);
|
|
@@ -1737,11 +1805,11 @@ var re = () => {
|
|
|
1737
1805
|
} catch {
|
|
1738
1806
|
continue;
|
|
1739
1807
|
}
|
|
1740
|
-
a.isDirectory() ?
|
|
1808
|
+
a.isDirectory() ? q(r, t, n + 1) : tn.test(i) && !/\.(test|spec)\./.test(i) && !nn.test(i) && t.push(r);
|
|
1741
1809
|
}
|
|
1742
1810
|
return t;
|
|
1743
|
-
},
|
|
1744
|
-
if (n > 12 ||
|
|
1811
|
+
}, an = (e, t = [], n = 0) => {
|
|
1812
|
+
if (n > 12 || K.test(e)) return t;
|
|
1745
1813
|
let r;
|
|
1746
1814
|
try {
|
|
1747
1815
|
r = D(e);
|
|
@@ -1755,17 +1823,17 @@ var re = () => {
|
|
|
1755
1823
|
} catch {
|
|
1756
1824
|
continue;
|
|
1757
1825
|
}
|
|
1758
|
-
a.isDirectory() ?
|
|
1826
|
+
a.isDirectory() ? an(r, t, n + 1) : tn.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
|
|
1759
1827
|
}
|
|
1760
1828
|
return t;
|
|
1761
|
-
},
|
|
1762
|
-
let t =
|
|
1829
|
+
}, on = (e) => {
|
|
1830
|
+
let t = $t(e);
|
|
1763
1831
|
return {
|
|
1764
|
-
dirs:
|
|
1832
|
+
dirs: en(e, t),
|
|
1765
1833
|
fileCount: t.length
|
|
1766
1834
|
};
|
|
1767
|
-
},
|
|
1768
|
-
let t =
|
|
1835
|
+
}, sn = (e) => {
|
|
1836
|
+
let t = $t(e);
|
|
1769
1837
|
if (t.length === 0) return [];
|
|
1770
1838
|
let n = new A({
|
|
1771
1839
|
useInMemoryFileSystem: !0,
|
|
@@ -1774,8 +1842,8 @@ var re = () => {
|
|
|
1774
1842
|
for (let e of t) try {
|
|
1775
1843
|
i.set(e, E(e, "utf8"));
|
|
1776
1844
|
} catch {}
|
|
1777
|
-
let a =
|
|
1778
|
-
for (let t of
|
|
1845
|
+
let a = Ht([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
|
|
1846
|
+
for (let t of an(e)) try {
|
|
1779
1847
|
o.set(t, E(t, "utf8"));
|
|
1780
1848
|
} catch {}
|
|
1781
1849
|
for (let s of t) {
|
|
@@ -1793,23 +1861,23 @@ var re = () => {
|
|
|
1793
1861
|
} catch {
|
|
1794
1862
|
continue;
|
|
1795
1863
|
}
|
|
1796
|
-
for (let t of
|
|
1797
|
-
if (t.plugin !== void 0 &&
|
|
1864
|
+
for (let t of Qt) {
|
|
1865
|
+
if (t.plugin !== void 0 && Gt(c, t.plugin) || !t.match(c)) continue;
|
|
1798
1866
|
let n = r.get(t.id) ?? [];
|
|
1799
1867
|
n.push(S(e, s)), r.set(t.id, n);
|
|
1800
1868
|
}
|
|
1801
1869
|
}
|
|
1802
|
-
return
|
|
1870
|
+
return Qt.filter((e) => r.has(e.id)).map((e) => ({
|
|
1803
1871
|
rule: e,
|
|
1804
1872
|
files: r.get(e.id)
|
|
1805
1873
|
})).sort((e, t) => t.files.length - e.files.length || e.rule.id.localeCompare(t.rule.id));
|
|
1806
|
-
},
|
|
1807
|
-
let t =
|
|
1874
|
+
}, cn = (e) => {
|
|
1875
|
+
let t = on(e);
|
|
1808
1876
|
return {
|
|
1809
1877
|
root: e,
|
|
1810
1878
|
scannedFiles: t.fileCount,
|
|
1811
1879
|
scannedDirs: t.dirs,
|
|
1812
|
-
findings:
|
|
1880
|
+
findings: sn(e).map(({ rule: e, files: t }) => ({
|
|
1813
1881
|
id: e.id,
|
|
1814
1882
|
scope: e.scope,
|
|
1815
1883
|
smell: e.smell,
|
|
@@ -1817,45 +1885,50 @@ var re = () => {
|
|
|
1817
1885
|
files: t
|
|
1818
1886
|
}))
|
|
1819
1887
|
};
|
|
1820
|
-
},
|
|
1888
|
+
}, ln = 3, un = .2, dn = 50, fn = (e, t) => e >= dn && t > 0 && e / t >= un, pn = (e) => {
|
|
1821
1889
|
let t = /* @__PURE__ */ new Map();
|
|
1822
|
-
for (let n of
|
|
1890
|
+
for (let n of q(e)) try {
|
|
1823
1891
|
t.set(S(e, n), E(n, "utf8"));
|
|
1824
1892
|
} catch {}
|
|
1825
1893
|
let n = /* @__PURE__ */ new Map();
|
|
1826
|
-
for (let t of
|
|
1894
|
+
for (let t of rn(e)) try {
|
|
1827
1895
|
n.set(S(e, t), E(t, "utf8"));
|
|
1828
1896
|
} catch {}
|
|
1829
|
-
let r =
|
|
1897
|
+
let r = dt({
|
|
1830
1898
|
sources: t,
|
|
1831
1899
|
envFiles: n
|
|
1832
1900
|
});
|
|
1833
|
-
r !== void 0 && (console.log(""), console.log(
|
|
1834
|
-
},
|
|
1835
|
-
let t =
|
|
1901
|
+
r !== void 0 && (console.log(""), console.log(ft(r)));
|
|
1902
|
+
}, mn = (e) => {
|
|
1903
|
+
let t = cn(e);
|
|
1836
1904
|
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;
|
|
1837
1905
|
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;
|
|
1838
1906
|
console.log(`\u2022 Shipped primitives you may be hand-rolling (scanned ${t.scannedFiles} files across ${t.scannedDirs.join(", ")}):`);
|
|
1839
1907
|
let n = 0;
|
|
1840
1908
|
for (let e of ["server", "client"]) {
|
|
1841
1909
|
let r = t.findings.filter((t) => t.scope === e);
|
|
1842
|
-
if (r.length
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
let
|
|
1848
|
-
console.log(` ${e.smell} \u2014 ${e.files.length} file(s)
|
|
1910
|
+
if (r.length === 0) continue;
|
|
1911
|
+
console.log(` [${e}]`);
|
|
1912
|
+
let i = [...r].sort((e, t) => e.files.length - t.files.length);
|
|
1913
|
+
for (let e of i) {
|
|
1914
|
+
if (fn(e.files.length, t.scannedFiles)) {
|
|
1915
|
+
let n = Math.round(e.files.length / t.scannedFiles * 100);
|
|
1916
|
+
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.)");
|
|
1917
|
+
continue;
|
|
1849
1918
|
}
|
|
1919
|
+
let r = e.files.slice(0, ln).join(", "), i = e.files.length - ln;
|
|
1920
|
+
i > 0 && (n += i);
|
|
1921
|
+
let a = i > 0 ? `, +${i} more` : "";
|
|
1922
|
+
console.log(` ${e.smell} \u2014 ${e.files.length} file(s): ${r}${a}`), console.log(` \u2192 ${e.use}`);
|
|
1850
1923
|
}
|
|
1851
1924
|
}
|
|
1852
1925
|
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;
|
|
1853
|
-
},
|
|
1854
|
-
let t =
|
|
1926
|
+
}, hn = "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.", gn = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, _n = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, vn = (e) => {
|
|
1927
|
+
let t = gn.exec(e)?.[1];
|
|
1855
1928
|
if (t !== void 0) return t === "ssr" ? "ssr" : null;
|
|
1856
|
-
let n =
|
|
1929
|
+
let n = _n.exec(e)?.[1];
|
|
1857
1930
|
return n === "dynamic" ? "ssr" : n === "static" ? null : "default";
|
|
1858
|
-
},
|
|
1931
|
+
}, yn = async (e) => {
|
|
1859
1932
|
let n = x(e, "src", "pages");
|
|
1860
1933
|
if (!T(n)) return [];
|
|
1861
1934
|
let { pages: a, dirs: o } = await t(n), s = [];
|
|
@@ -1868,7 +1941,7 @@ var re = () => {
|
|
|
1868
1941
|
continue;
|
|
1869
1942
|
}
|
|
1870
1943
|
if (r.test(a)) continue;
|
|
1871
|
-
let c =
|
|
1944
|
+
let c = vn(a);
|
|
1872
1945
|
c !== null && s.push({
|
|
1873
1946
|
file: S(e, x(n, t.file)),
|
|
1874
1947
|
pattern: t.pattern,
|
|
@@ -1876,18 +1949,18 @@ var re = () => {
|
|
|
1876
1949
|
});
|
|
1877
1950
|
}
|
|
1878
1951
|
return s;
|
|
1879
|
-
},
|
|
1952
|
+
}, bn = 10, xn = async (e) => {
|
|
1880
1953
|
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;
|
|
1881
|
-
let t = await
|
|
1954
|
+
let t = await yn(e);
|
|
1882
1955
|
if (t.length === 0) return console.log("✓ spa-candidate scan: no loader-free, layout-backed pages to flag."), 0;
|
|
1883
1956
|
console.log(`• renderMode:'spa' candidates (${t.length} page${t.length === 1 ? "" : "s"} — loader-free, under a layout, currently ssr/default):`);
|
|
1884
|
-
for (let e of t.slice(0,
|
|
1957
|
+
for (let e of t.slice(0, bn)) {
|
|
1885
1958
|
let t = e.currentMode === "ssr" ? "renderMode:'ssr'" : "default renderMode";
|
|
1886
1959
|
console.log(` ${e.file} (${e.pattern}) — ${t}`);
|
|
1887
1960
|
}
|
|
1888
|
-
let n = t.length -
|
|
1889
|
-
return n > 0 && console.log(` (+${n} more page${n === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${
|
|
1890
|
-
},
|
|
1961
|
+
let n = t.length - bn;
|
|
1962
|
+
return n > 0 && console.log(` (+${n} more page${n === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${hn}`), t.length;
|
|
1963
|
+
}, Sn = /* @__PURE__ */ new Set([
|
|
1891
1964
|
"node_modules",
|
|
1892
1965
|
"dist",
|
|
1893
1966
|
"build",
|
|
@@ -1895,7 +1968,7 @@ var re = () => {
|
|
|
1895
1968
|
".vite",
|
|
1896
1969
|
".framework",
|
|
1897
1970
|
".git"
|
|
1898
|
-
]),
|
|
1971
|
+
]), Cn = (e, t, n) => {
|
|
1899
1972
|
let r;
|
|
1900
1973
|
try {
|
|
1901
1974
|
r = D(e, { withFileTypes: !0 });
|
|
@@ -1903,11 +1976,11 @@ var re = () => {
|
|
|
1903
1976
|
return;
|
|
1904
1977
|
}
|
|
1905
1978
|
for (let i of r) {
|
|
1906
|
-
if (
|
|
1979
|
+
if (Sn.has(i.name)) continue;
|
|
1907
1980
|
let r = x(e, i.name);
|
|
1908
|
-
i.isDirectory() ?
|
|
1981
|
+
i.isDirectory() ? Cn(r, t, n) : i.isFile() && i.name.endsWith(".tsx") && n.push(S(t, r));
|
|
1909
1982
|
}
|
|
1910
|
-
},
|
|
1983
|
+
}, wn = (e, t) => {
|
|
1911
1984
|
let n = /* @__PURE__ */ new Set(), r = /(?:from|import)\s*\(?\s*['"](\.[^'"]*)['"]/g;
|
|
1912
1985
|
for (let i of t) {
|
|
1913
1986
|
let t;
|
|
@@ -1932,16 +2005,16 @@ var re = () => {
|
|
|
1932
2005
|
}
|
|
1933
2006
|
}
|
|
1934
2007
|
return n;
|
|
1935
|
-
},
|
|
2008
|
+
}, Tn = (e, t) => {
|
|
1936
2009
|
let n = e.slice(t.length).split(w).slice(0, -1)[0];
|
|
1937
2010
|
return n !== void 0 && n.startsWith("[");
|
|
1938
|
-
},
|
|
2011
|
+
}, J = (t) => {
|
|
1939
2012
|
let n = [], r = x(t, "src", "pages"), i = x(t, "src");
|
|
1940
2013
|
if (!T(i)) return n;
|
|
1941
2014
|
let a = [];
|
|
1942
|
-
|
|
2015
|
+
Cn(i, t, a), a.sort();
|
|
1943
2016
|
let o = `${S(t, r)}${w}`;
|
|
1944
|
-
|
|
2017
|
+
wn(t, a);
|
|
1945
2018
|
for (let r of a) {
|
|
1946
2019
|
let i = r.slice(r.lastIndexOf(w) + 1);
|
|
1947
2020
|
if (r.startsWith(o)) {
|
|
@@ -1949,7 +2022,7 @@ var re = () => {
|
|
|
1949
2022
|
T(x(t, e(r))) || n.push({
|
|
1950
2023
|
kind: "page-without-test",
|
|
1951
2024
|
file: r
|
|
1952
|
-
}),
|
|
2025
|
+
}), Tn(r, o) && n.push({
|
|
1953
2026
|
kind: "top-level-dynamic-route",
|
|
1954
2027
|
file: r
|
|
1955
2028
|
});
|
|
@@ -1961,33 +2034,33 @@ var re = () => {
|
|
|
1961
2034
|
});
|
|
1962
2035
|
}
|
|
1963
2036
|
return n;
|
|
1964
|
-
},
|
|
2037
|
+
}, Y = 10, X = (e, t, n) => {
|
|
1965
2038
|
if (t.length === 0) return;
|
|
1966
2039
|
console.log(`• ${e} (${t.length}):`);
|
|
1967
|
-
for (let e of t.slice(0,
|
|
1968
|
-
let r = t.length -
|
|
2040
|
+
for (let e of t.slice(0, Y)) console.log(` ${e}`);
|
|
2041
|
+
let r = t.length - Y;
|
|
1969
2042
|
r > 0 && console.log(` (+${r} more not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${n}`);
|
|
1970
|
-
},
|
|
2043
|
+
}, En = (e) => {
|
|
1971
2044
|
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;
|
|
1972
|
-
let t =
|
|
2045
|
+
let t = J(e);
|
|
1973
2046
|
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;
|
|
1974
2047
|
let n = (e) => t.filter((t) => t.kind === e).map((e) => e.file);
|
|
1975
|
-
return
|
|
1976
|
-
},
|
|
1977
|
-
let t =
|
|
2048
|
+
return X("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."), X("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."), X("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."), t.length;
|
|
2049
|
+
}, Dn = "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.", On = /* @__PURE__ */ new Map(), Z = (e) => {
|
|
2050
|
+
let t = On.get(e);
|
|
1978
2051
|
if (t !== void 0) return t;
|
|
1979
2052
|
let n = (async () => {
|
|
1980
|
-
let { walk: t, loadDiscovered: n } = await import("./dev-
|
|
2053
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-DXhhZ7-f.js"), r = await t(e);
|
|
1981
2054
|
return {
|
|
1982
2055
|
files: r,
|
|
1983
2056
|
discovered: await n(r)
|
|
1984
2057
|
};
|
|
1985
2058
|
})();
|
|
1986
|
-
return
|
|
1987
|
-
},
|
|
2059
|
+
return On.set(e, n), n;
|
|
2060
|
+
}, kn = async (e) => {
|
|
1988
2061
|
let t;
|
|
1989
2062
|
try {
|
|
1990
|
-
let { files: n, discovered: r } = await
|
|
2063
|
+
let { files: n, discovered: r } = await Z(e), i = r.tables.map((e) => {
|
|
1991
2064
|
let t = e;
|
|
1992
2065
|
return {
|
|
1993
2066
|
name: t.tableName,
|
|
@@ -1995,12 +2068,12 @@ var re = () => {
|
|
|
1995
2068
|
};
|
|
1996
2069
|
});
|
|
1997
2070
|
if (i.length === 0) return;
|
|
1998
|
-
t = Ge(
|
|
2071
|
+
t = Ke(Ge(n, i, e));
|
|
1999
2072
|
} catch {
|
|
2000
2073
|
return;
|
|
2001
2074
|
}
|
|
2002
2075
|
t !== null && (console.log(""), console.log(`${t.includes("does not exist") ? "✗" : "✓"} ${t}`));
|
|
2003
|
-
},
|
|
2076
|
+
}, An = (e) => e.map((e) => {
|
|
2004
2077
|
let t = e, n = Object.entries(t.fields ?? {}).map(([e, t]) => ({
|
|
2005
2078
|
name: e,
|
|
2006
2079
|
type: typeof t?.type == "string" ? t.type : ""
|
|
@@ -2010,22 +2083,22 @@ var re = () => {
|
|
|
2010
2083
|
columns: n,
|
|
2011
2084
|
primaryKey: t.appliedPrimaryKey ?? []
|
|
2012
2085
|
};
|
|
2013
|
-
}),
|
|
2086
|
+
}), jn = async (e) => {
|
|
2014
2087
|
try {
|
|
2015
|
-
let { discovered: t } = await
|
|
2016
|
-
return
|
|
2088
|
+
let { discovered: t } = await Z(e);
|
|
2089
|
+
return Ze(An(t.tables));
|
|
2017
2090
|
} catch {
|
|
2018
2091
|
return null;
|
|
2019
2092
|
}
|
|
2020
|
-
},
|
|
2021
|
-
let t = await
|
|
2093
|
+
}, Mn = async (e) => {
|
|
2094
|
+
let t = await jn(e);
|
|
2022
2095
|
if (t === null || t.tablesChecked === 0) return;
|
|
2023
|
-
let n =
|
|
2096
|
+
let n = $e(t);
|
|
2024
2097
|
n !== null && (console.log(""), console.log(`${t.issues.length > 0 ? "✗" : "✓"} ${n}`));
|
|
2025
|
-
},
|
|
2098
|
+
}, Nn = async (e) => {
|
|
2026
2099
|
try {
|
|
2027
|
-
let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await
|
|
2028
|
-
return
|
|
2100
|
+
let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await Z(e);
|
|
2101
|
+
return rt(n.events.map((e) => {
|
|
2029
2102
|
let n = e.descriptor, r = t(n.key);
|
|
2030
2103
|
return {
|
|
2031
2104
|
name: n.name,
|
|
@@ -2037,19 +2110,19 @@ var re = () => {
|
|
|
2037
2110
|
} catch {
|
|
2038
2111
|
return null;
|
|
2039
2112
|
}
|
|
2040
|
-
},
|
|
2041
|
-
let t = await
|
|
2113
|
+
}, Pn = async (e) => {
|
|
2114
|
+
let t = await Nn(e);
|
|
2042
2115
|
if (t === null || t.eventsChecked === 0) return;
|
|
2043
|
-
let n =
|
|
2116
|
+
let n = it(t);
|
|
2044
2117
|
n !== null && (console.log(""), console.log(`• ${n}`));
|
|
2045
|
-
let r =
|
|
2118
|
+
let r = at(t);
|
|
2046
2119
|
r !== null && (console.log(""), console.log(`⚠️ ${r}`));
|
|
2047
|
-
},
|
|
2120
|
+
}, Fn = (e) => {
|
|
2048
2121
|
let t = e, n = typeof t?.message == "string" && t.message !== "" ? t.message : String(e), r = typeof t?.code == "string" ? t.code : void 0;
|
|
2049
2122
|
return r === void 0 ? n : `${r}: ${n}`;
|
|
2050
|
-
},
|
|
2123
|
+
}, In = async (e) => {
|
|
2051
2124
|
try {
|
|
2052
|
-
let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await
|
|
2125
|
+
let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await Z(e)).discovered.serverOnlyLeaks, r = t(n);
|
|
2053
2126
|
return {
|
|
2054
2127
|
status: {
|
|
2055
2128
|
checked: !0,
|
|
@@ -2060,17 +2133,17 @@ var re = () => {
|
|
|
2060
2133
|
} catch (e) {
|
|
2061
2134
|
return { status: {
|
|
2062
2135
|
checked: !1,
|
|
2063
|
-
reason:
|
|
2136
|
+
reason: Fn(e)
|
|
2064
2137
|
} };
|
|
2065
2138
|
}
|
|
2066
|
-
},
|
|
2067
|
-
let { status: t, message: n } = await
|
|
2139
|
+
}, Ln = async (e) => {
|
|
2140
|
+
let { status: t, message: n } = await In(e);
|
|
2068
2141
|
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);
|
|
2069
|
-
},
|
|
2142
|
+
}, Rn = async (e) => {
|
|
2070
2143
|
let t;
|
|
2071
2144
|
try {
|
|
2072
|
-
let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await
|
|
2073
|
-
t =
|
|
2145
|
+
let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await Z(e);
|
|
2146
|
+
t = ct(r, i.workflows.map((e) => {
|
|
2074
2147
|
let t = e.definition, r = t.payloadSchema === void 0 ? {
|
|
2075
2148
|
required: [],
|
|
2076
2149
|
optional: []
|
|
@@ -2084,21 +2157,46 @@ var re = () => {
|
|
|
2084
2157
|
} catch {
|
|
2085
2158
|
return;
|
|
2086
2159
|
}
|
|
2087
|
-
let n =
|
|
2160
|
+
let n = lt(t);
|
|
2088
2161
|
if (n === null) return;
|
|
2089
2162
|
console.log("");
|
|
2090
2163
|
let r = t.issues.length > 0 ? "✗" : t.unchecked.length > 0 ? "•" : "✓";
|
|
2091
2164
|
console.log(`${r} ${n}`);
|
|
2092
|
-
},
|
|
2165
|
+
}, Q = "voltro-authz-allowlist.txt", zn = (e, t = (e) => {
|
|
2093
2166
|
try {
|
|
2094
2167
|
return E(e, "utf8");
|
|
2095
2168
|
} catch {
|
|
2096
2169
|
return "";
|
|
2097
2170
|
}
|
|
2098
|
-
}) => /* @__PURE__ */ new Set([...
|
|
2099
|
-
let
|
|
2171
|
+
}) => /* @__PURE__ */ new Set([...Ct, ...wt(q(e).map(t))]), Bn = async (e) => {
|
|
2172
|
+
let t = ["src/locales", "locales"], n, r = [];
|
|
2173
|
+
for (let i of t) {
|
|
2174
|
+
let t = x(e, i);
|
|
2175
|
+
if (T(t)) try {
|
|
2176
|
+
r = D(t).filter((e) => /\.tsx?$/.test(e) && !e.endsWith(".d.ts")).map((e) => e.replace(/\.tsx?$/, "")), n = i;
|
|
2177
|
+
break;
|
|
2178
|
+
} catch {}
|
|
2179
|
+
}
|
|
2180
|
+
if (n === void 0 || r.length === 0) return;
|
|
2181
|
+
let i = [];
|
|
2100
2182
|
try {
|
|
2101
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
2183
|
+
let { loadApiConfig: t } = await import("./dev-DXhhZ7-f.js");
|
|
2184
|
+
i = (await t(e))?.locales ?? [];
|
|
2185
|
+
} catch {
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
let a = bt({
|
|
2189
|
+
catalogCodes: r,
|
|
2190
|
+
declaredLocales: i
|
|
2191
|
+
});
|
|
2192
|
+
if (a !== void 0) {
|
|
2193
|
+
console.log("");
|
|
2194
|
+
for (let e of xt(a, n)) console.log(e);
|
|
2195
|
+
}
|
|
2196
|
+
}, Vn = async (e) => {
|
|
2197
|
+
let { discovered: t } = await Z(e), n = [];
|
|
2198
|
+
try {
|
|
2199
|
+
let { loadApiConfig: t } = await import("./dev-DXhhZ7-f.js");
|
|
2102
2200
|
n = ((await t(e))?.plugins ?? []).map((e) => {
|
|
2103
2201
|
let t = (e.extendSchema?.tables ?? []).map((e) => {
|
|
2104
2202
|
let t = e;
|
|
@@ -2114,8 +2212,8 @@ var re = () => {
|
|
|
2114
2212
|
plugin: e.name,
|
|
2115
2213
|
tables: t,
|
|
2116
2214
|
rpcTags: n,
|
|
2117
|
-
canDisableTables:
|
|
2118
|
-
canAlias:
|
|
2215
|
+
canDisableTables: Hn.has(e.name),
|
|
2216
|
+
canAlias: Un.has(e.name)
|
|
2119
2217
|
};
|
|
2120
2218
|
});
|
|
2121
2219
|
} catch {
|
|
@@ -2127,89 +2225,115 @@ var re = () => {
|
|
|
2127
2225
|
...t.mutations,
|
|
2128
2226
|
...t.actions,
|
|
2129
2227
|
...t.streams ?? []
|
|
2130
|
-
].map((e) => String(e.descriptor.name)), i =
|
|
2228
|
+
].map((e) => String(e.descriptor.name)), i = It(n, {
|
|
2131
2229
|
tables: t.tables.map((e) => e.tableName),
|
|
2132
2230
|
rpcTags: r
|
|
2133
2231
|
});
|
|
2134
2232
|
console.log();
|
|
2135
|
-
for (let e of
|
|
2136
|
-
},
|
|
2137
|
-
let
|
|
2138
|
-
|
|
2139
|
-
|
|
2233
|
+
for (let e of Lt(n, i)) console.log(e);
|
|
2234
|
+
}, Hn = /* @__PURE__ */ new Set(["@voltro/plugin-rbac"]), Un = /* @__PURE__ */ new Set(["@voltro/plugin-ai-flows"]), $ = 20, Wn = async (e) => {
|
|
2235
|
+
let t = await Gn(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;
|
|
2236
|
+
return {
|
|
2237
|
+
executors: t.executorCount,
|
|
2238
|
+
guardVocabulary: [...t.vocabulary].sort(),
|
|
2239
|
+
counts: t.result.counts,
|
|
2240
|
+
allowlist: {
|
|
2241
|
+
exists: t.existing !== void 0,
|
|
2242
|
+
debt: r,
|
|
2243
|
+
reviewed: t.result.counts.allowlisted - r
|
|
2244
|
+
},
|
|
2245
|
+
unchecked: t.result.unchecked
|
|
2246
|
+
};
|
|
2247
|
+
}, Gn = async (e) => {
|
|
2248
|
+
let { discovered: t } = await Z(e), n = /* @__PURE__ */ new Map(), r = (e) => {
|
|
2249
|
+
if (!n.has(e)) try {
|
|
2250
|
+
n.set(e, E(e, "utf8"));
|
|
2140
2251
|
} catch {
|
|
2141
|
-
|
|
2252
|
+
n.set(e, "");
|
|
2142
2253
|
}
|
|
2143
|
-
return
|
|
2144
|
-
},
|
|
2145
|
-
for (let e of
|
|
2254
|
+
return n.get(e);
|
|
2255
|
+
}, i = zn(e, r), a = /* @__PURE__ */ new Set();
|
|
2256
|
+
for (let e of t.tables) for (let t of Object.values(e.fields ?? {})) try {
|
|
2146
2257
|
let e = t.references?.();
|
|
2147
|
-
e &&
|
|
2258
|
+
e && a.add(e.tableName);
|
|
2148
2259
|
} catch {}
|
|
2149
|
-
let
|
|
2260
|
+
let o = [
|
|
2150
2261
|
{
|
|
2151
|
-
list:
|
|
2262
|
+
list: t.queries,
|
|
2152
2263
|
op: "read"
|
|
2153
2264
|
},
|
|
2154
2265
|
{
|
|
2155
|
-
list:
|
|
2266
|
+
list: t.mutations,
|
|
2156
2267
|
op: "update"
|
|
2157
2268
|
},
|
|
2158
2269
|
{
|
|
2159
|
-
list:
|
|
2270
|
+
list: t.actions,
|
|
2160
2271
|
op: "update"
|
|
2161
2272
|
},
|
|
2162
2273
|
{
|
|
2163
|
-
list:
|
|
2274
|
+
list: t.streams,
|
|
2164
2275
|
op: "read"
|
|
2165
2276
|
}
|
|
2166
2277
|
].flatMap(({ list: e, op: t }) => e.map((e) => {
|
|
2167
|
-
let n = e.descriptor,
|
|
2278
|
+
let n = e.descriptor, i = n.target, a = Array.isArray(i) ? i[0] : i, o = e.file.replace(/\.(tsx?)$/, ".server.$1");
|
|
2168
2279
|
return {
|
|
2169
2280
|
tag: String(n.name ?? e.file),
|
|
2170
2281
|
path: o,
|
|
2171
|
-
src:
|
|
2282
|
+
src: r(o),
|
|
2172
2283
|
hasDeclaredGuards: Array.isArray(n.guards) && n.guards.length > 0,
|
|
2173
2284
|
op: a?.op === "delete" || a?.op === "insert" ? a.op : t,
|
|
2174
2285
|
...a?.table === void 0 ? {} : { table: a.table }
|
|
2175
2286
|
};
|
|
2176
|
-
})),
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2287
|
+
})), s = x(e, Q), c = T(s) ? Pt(E(s, "utf8")) : void 0;
|
|
2288
|
+
return {
|
|
2289
|
+
result: At({
|
|
2290
|
+
executors: o,
|
|
2291
|
+
guardVocabulary: i,
|
|
2292
|
+
tenantScopedTables: t.tenantScopedTables,
|
|
2293
|
+
referencedTables: a,
|
|
2294
|
+
allowlist: c?.tags ?? /* @__PURE__ */ new Set()
|
|
2295
|
+
}),
|
|
2296
|
+
vocabulary: i,
|
|
2297
|
+
existing: c,
|
|
2298
|
+
reviewed: (c?.entries ?? []).filter((e) => e.reviewed !== void 0),
|
|
2299
|
+
executorCount: o.length,
|
|
2300
|
+
allowPath: s
|
|
2301
|
+
};
|
|
2302
|
+
}, Kn = async (e, t) => {
|
|
2303
|
+
let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s } = await Gn(e), c = n.counts;
|
|
2304
|
+
console.log(`\nauthz scan · ${o} executor(s)`);
|
|
2305
|
+
let l = [...r].filter((e) => !Ct.has(e)).sort();
|
|
2306
|
+
console.log(l.length === 0 ? " guard vocabulary: framework names only — no exported require*/assert* found in this app" : ` guard vocabulary: ${l.length} from your source (${l.slice(0, 6).join(", ")}${l.length > 6 ? ", …" : ""})`), console.log(` ✗ no access check ${String(c.unchecked).padStart(4)}`), console.log(` ⚠ inline ownership check, no named guard${String(c.inlineOwnership).padStart(4)} (informational)`), console.log(` ✓ guards: on the descriptor ${String(c.declaredGuard).padStart(4)}`), console.log(` ✓ calls a guard from the vocabulary ${String(c.vocabularyGuard).padStart(4)}`);
|
|
2307
|
+
let u = new Set(a.map((e) => e.tag)), d = n.findings.filter((e) => e.verdict.kind === "allowlisted" && !u.has(e.tag)).length, f = c.allowlisted - d;
|
|
2308
|
+
if (console.log(` – accepted as recorded debt ${String(d).padStart(4)} (${Q})`), console.log(` ✓ reviewed, open on purpose ${String(f).padStart(4)} (\`reviewed=<why>\` in that file)`), t) return ne(s, Mt([...a, ...n.unchecked.map((e) => ({ tag: e.tag }))]), "utf8"), console.log(`\nwrote ${n.unchecked.length} debt tag(s) to ${Q}${a.length > 0 ? `, keeping ${a.length} reviewed line(s)` : ""}. Doctor now fails on ADDITIONS only.`), !1;
|
|
2309
|
+
if (n.unchecked.length === 0) return !1;
|
|
2187
2310
|
console.log("");
|
|
2188
|
-
for (let e of
|
|
2189
|
-
return
|
|
2190
|
-
},
|
|
2191
|
-
if (e.includes("--help") || e.includes("-h")) return console.log(
|
|
2311
|
+
for (let e of n.unchecked.slice(0, $)) console.log(` ✗ ${e.tag} — ${e.why}\n ${e.path}`);
|
|
2312
|
+
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);
|
|
2313
|
+
}, qn = async (e) => {
|
|
2314
|
+
if (e.includes("--help") || e.includes("-h")) return console.log(Dn), 0;
|
|
2192
2315
|
let t = e.includes("--strict"), n = C(e.find((e) => !e.startsWith("-")) ?? process.cwd());
|
|
2193
2316
|
if (ie(e)) return re(), M({
|
|
2194
|
-
...
|
|
2195
|
-
spaCandidates: await
|
|
2196
|
-
pageConvention:
|
|
2197
|
-
fileTaxonomy:
|
|
2198
|
-
junctionFks: (await
|
|
2199
|
-
eventDelivery: await
|
|
2200
|
-
duplicateInstances:
|
|
2201
|
-
serverOnly: (await
|
|
2317
|
+
...cn(n),
|
|
2318
|
+
spaCandidates: await yn(n),
|
|
2319
|
+
pageConvention: J(n),
|
|
2320
|
+
fileTaxonomy: H(n).findings,
|
|
2321
|
+
junctionFks: (await jn(n))?.issues ?? [],
|
|
2322
|
+
eventDelivery: await Nn(n),
|
|
2323
|
+
duplicateInstances: vt(n),
|
|
2324
|
+
serverOnly: (await In(n)).status,
|
|
2325
|
+
authz: await Wn(n)
|
|
2202
2326
|
}), 0;
|
|
2203
|
-
let r =
|
|
2204
|
-
|
|
2205
|
-
let i = await
|
|
2327
|
+
let r = Vt(n, t);
|
|
2328
|
+
mn(n), pn(n), En(n), Ve(n), await xn(n), await Rn(n), await kn(n), await Mn(n), await Pn(n), await Vn(n), await Bn(n);
|
|
2329
|
+
let i = await Ln(n), a = await Kn(n, e.includes("--write-authz-allowlist")), o = yt(vt(n));
|
|
2206
2330
|
return o !== void 0 && console.log(`\n${o}`), i || a ? Math.max(r, 1) : r;
|
|
2207
|
-
},
|
|
2331
|
+
}, Jn = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, Yn = /* @__PURE__ */ new Set([
|
|
2208
2332
|
"insert",
|
|
2209
2333
|
"update",
|
|
2210
2334
|
"delete",
|
|
2211
2335
|
"upsert"
|
|
2212
|
-
]),
|
|
2336
|
+
]), Xn = (e, t) => {
|
|
2213
2337
|
let n = [], r = new Set(t.exercised), i = /* @__PURE__ */ new Map();
|
|
2214
2338
|
for (let e of t.edges) {
|
|
2215
2339
|
let t = i.get(e.tag);
|
|
@@ -2221,8 +2345,8 @@ var re = () => {
|
|
|
2221
2345
|
a.push(t.tag);
|
|
2222
2346
|
continue;
|
|
2223
2347
|
}
|
|
2224
|
-
let e = `${t.kind}(${t.tag})`, s = t.file, c = i.get(t.tag) ?? [], l = new Set(
|
|
2225
|
-
for (let t of c) if (
|
|
2348
|
+
let e = `${t.kind}(${t.tag})`, s = t.file, c = i.get(t.tag) ?? [], l = new Set(Jn(t.source)), u = new Map((t.targets ?? []).map((e) => [e.table, e.op]));
|
|
2349
|
+
for (let t of c) if (Yn.has(t.op)) {
|
|
2226
2350
|
let r = u.get(t.table);
|
|
2227
2351
|
r === void 0 ? n.push({
|
|
2228
2352
|
rule: "observed/undeclared-write",
|
|
@@ -2278,7 +2402,7 @@ var re = () => {
|
|
|
2278
2402
|
total: e.length
|
|
2279
2403
|
}
|
|
2280
2404
|
};
|
|
2281
|
-
},
|
|
2405
|
+
}, Zn = (e, t = [], n = 0) => {
|
|
2282
2406
|
if (n > 12) return t;
|
|
2283
2407
|
let r;
|
|
2284
2408
|
try {
|
|
@@ -2302,24 +2426,24 @@ var re = () => {
|
|
|
2302
2426
|
} catch {
|
|
2303
2427
|
continue;
|
|
2304
2428
|
}
|
|
2305
|
-
o.isDirectory() ?
|
|
2429
|
+
o.isDirectory() ? Zn(r, t, n + 1) : o.isFile() && a.test(i) && t.push(r);
|
|
2306
2430
|
}
|
|
2307
2431
|
return t;
|
|
2308
|
-
},
|
|
2432
|
+
}, Qn = /* @__PURE__ */ new Set(["actors", "tenants"]), $n = async (e) => {
|
|
2309
2433
|
try {
|
|
2310
2434
|
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);
|
|
2311
2435
|
return i?.version !== 1 || !Array.isArray(i.edges) || !Array.isArray(i.exercised) ? null : i;
|
|
2312
2436
|
} catch {
|
|
2313
2437
|
return null;
|
|
2314
2438
|
}
|
|
2315
|
-
},
|
|
2439
|
+
}, er = (e) => {
|
|
2316
2440
|
let { exercised: t, total: n } = e.coverage, r = `\nobserved: ${t}/${n} procedures exercised (${n === 0 ? 0 : Math.round(t / n * 100)}%)`;
|
|
2317
2441
|
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` : ""}`;
|
|
2318
2442
|
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` : "";
|
|
2319
2443
|
return `${r}\n${i.join("\n")}${a}`;
|
|
2320
|
-
},
|
|
2444
|
+
}, tr = (e, t) => ({
|
|
2321
2445
|
tables: (t.tables ?? []).map((e) => e.name),
|
|
2322
|
-
frameworkOwnedTables: (t.tables ?? []).filter((e) => e.framework === !0 || e.name.startsWith("_voltro_") ||
|
|
2446
|
+
frameworkOwnedTables: (t.tables ?? []).filter((e) => e.framework === !0 || e.name.startsWith("_voltro_") || Qn.has(e.name)).map((e) => e.name),
|
|
2323
2447
|
scopes: e.scopes ?? [],
|
|
2324
2448
|
procedures: (e.procedures ?? []).map((e) => {
|
|
2325
2449
|
let t = (e.guards ?? []).flatMap((e) => e.kind === "scope" ? e.scope ?? [] : []);
|
|
@@ -2332,16 +2456,16 @@ var re = () => {
|
|
|
2332
2456
|
...e.guards === void 0 ? {} : { hasGuards: e.guards.length > 0 }
|
|
2333
2457
|
};
|
|
2334
2458
|
})
|
|
2335
|
-
}),
|
|
2459
|
+
}), nr = (e) => e.length === 0 ? "✓ voltro check: no issues" : e.map((e) => {
|
|
2336
2460
|
let t = e.severity === "error" ? "✗ error" : "⚠ warn", n = e.file ? ` (${e.file})` : "";
|
|
2337
2461
|
return `${t} ${e.rule} ${e.node}${n}\n ${e.breaks.join("; ")}\n fix: ${e.fix}`;
|
|
2338
|
-
}).join("\n"),
|
|
2339
|
-
let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-
|
|
2462
|
+
}).join("\n"), rr = async (e) => {
|
|
2463
|
+
let { walk: t, loadDiscovered: n, loadApiConfig: r } = await import("./dev-DXhhZ7-f.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 = [
|
|
2340
2464
|
...s.queries.map((e) => c(e.descriptor, "query", e.file)),
|
|
2341
2465
|
...s.mutations.map((e) => c(e.descriptor, "mutation", e.file)),
|
|
2342
2466
|
...s.actions.map((e) => c(e.descriptor, "action", e.file)),
|
|
2343
2467
|
...s.streams.map((e) => c(e.descriptor, "stream", e.file))
|
|
2344
|
-
], { assembleFrameworkTables: u } = await import("./frameworkTableAssembly-
|
|
2468
|
+
], { assembleFrameworkTables: u } = await import("./frameworkTableAssembly-Bn_c4Mnl.js"), d = await u({ root: e }).catch(() => []), f = new Set(s.tables.map((e) => e.tableName)), p = [...[...f].map((e) => ({ name: e })), ...d.map((e) => e.tableName).filter((e) => !f.has(e)).map((e) => ({
|
|
2345
2469
|
name: e,
|
|
2346
2470
|
framework: !0
|
|
2347
2471
|
}))], m = await r(e).then((e) => e?.plugins ?? []).catch(() => []);
|
|
@@ -2352,7 +2476,7 @@ var re = () => {
|
|
|
2352
2476
|
})), [], m),
|
|
2353
2477
|
tables: { tables: p }
|
|
2354
2478
|
};
|
|
2355
|
-
},
|
|
2479
|
+
}, ir = async (e) => {
|
|
2356
2480
|
let t = ue(e.flatMap((e) => e === "--json" ? ["--format", "json"] : [e]));
|
|
2357
2481
|
if ("error" in t) return console.error(`voltro check: ${t.error}`), 1;
|
|
2358
2482
|
let { process: n, target: r, rest: i } = de(t.rest), a;
|
|
@@ -2376,7 +2500,7 @@ var re = () => {
|
|
|
2376
2500
|
if (l.length === 0) {
|
|
2377
2501
|
if (!c && r !== void 0) return console.error("voltro check: --url given but no api reachable there."), 1;
|
|
2378
2502
|
try {
|
|
2379
|
-
let e = await
|
|
2503
|
+
let e = await rr(C(s));
|
|
2380
2504
|
u = e.manifest, d = e.tables;
|
|
2381
2505
|
} catch (e) {
|
|
2382
2506
|
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;
|
|
@@ -2386,21 +2510,21 @@ var re = () => {
|
|
|
2386
2510
|
if (t.kind === "err") return console.error(`voltro check: manifest fetch failed: ${t.error}`), 1;
|
|
2387
2511
|
u = t.data, d = n.kind === "ok" ? n.data : { tables: [] };
|
|
2388
2512
|
}
|
|
2389
|
-
let f =
|
|
2513
|
+
let f = tr(u, d), p = he(f, a), m = [...H(s).findings.map((e) => ({
|
|
2390
2514
|
rule: e.rule,
|
|
2391
2515
|
node: e.file,
|
|
2392
2516
|
file: e.file,
|
|
2393
2517
|
breaks: [e.detail],
|
|
2394
2518
|
fix: e.fix,
|
|
2395
2519
|
severity: e.severity
|
|
2396
|
-
})), ...
|
|
2520
|
+
})), ...J(s).map((e) => ({
|
|
2397
2521
|
rule: `page/${e.kind}`,
|
|
2398
2522
|
node: e.file,
|
|
2399
2523
|
file: e.file,
|
|
2400
2524
|
breaks: [e.kind === "suffixed-outside-pages" ? "a page.tsx outside src/pages/ never routes" : "no test beside it"],
|
|
2401
2525
|
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",
|
|
2402
2526
|
severity: e.kind === "suffixed-outside-pages" ? "error" : "warn"
|
|
2403
|
-
}))], h = (await o(s,
|
|
2527
|
+
}))], h = (await o(s, Zn(s))).map((e) => ({
|
|
2404
2528
|
rule: "client/not-browser-safe",
|
|
2405
2529
|
node: e.file,
|
|
2406
2530
|
file: e.file,
|
|
@@ -2411,7 +2535,7 @@ var re = () => {
|
|
|
2411
2535
|
...p.diagnostics,
|
|
2412
2536
|
...m,
|
|
2413
2537
|
...h
|
|
2414
|
-
], _ = p.ok && !m.some((e) => e.severity === "error") && h.length === 0, v = await
|
|
2538
|
+
], _ = p.ok && !m.some((e) => e.severity === "error") && h.length === 0, v = await $n(C(s)), y = v === null ? null : Xn(f.procedures, v);
|
|
2415
2539
|
return t.format === "json" ? M(y === null ? {
|
|
2416
2540
|
...p,
|
|
2417
2541
|
ok: _,
|
|
@@ -2421,7 +2545,7 @@ var re = () => {
|
|
|
2421
2545
|
ok: _,
|
|
2422
2546
|
diagnostics: g,
|
|
2423
2547
|
observed: y
|
|
2424
|
-
}) : (console.log(
|
|
2548
|
+
}) : (console.log(nr(g)), y !== null && console.log(er(y)), console.log(_ ? "\nvoltro check: OK" : "\nvoltro check: FAILED (errors above)")), +!_;
|
|
2425
2549
|
};
|
|
2426
2550
|
//#endregion
|
|
2427
|
-
export { re as _,
|
|
2551
|
+
export { re as _, Re as a, I as c, N as d, ue as f, le as g, ce as h, Vt as i, ve as l, se as m, ir as n, be as o, de as p, qn as r, xe as s, rr as t, he as u, M as v, ie as y };
|