@voltro/cli 0.44.0 → 0.45.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 +120 -1
- package/dist/{apiBuild-DvWreIQP.js → apiBuild-CDQBNRDx.js} +1 -1
- package/dist/apiBuild-yJCqJYQ8.js +2 -0
- package/dist/bin.d.ts +16 -0
- package/dist/bin.js +46 -11
- package/dist/{build-Ckc-FA7d.js → build-yvsLG77U.js} +7 -7
- package/dist/{checkCommand-BNfEs4KG.js → checkCommand-Boxov8lr.js} +11 -11
- package/dist/{checkCommand-AlbawIal.js → checkCommand-lrzwOzV1.js} +1 -1
- package/dist/codegen-DcE2li1i.js +2 -0
- package/dist/{codegen-CbpGCWLG.js → codegen-sbN1Y8PB.js} +37 -37
- package/dist/codegenCommand-CQOLytL-.js +144 -0
- package/dist/{codemodRunner-BKTnaGOz.js → codemodRunner-5ZhDH3rB.js} +41 -0
- package/dist/{commands-fsnezHLH.js → commands-CEkVoFM5.js} +19 -19
- package/dist/{dashboardCommand-DHDmlo9A.js → dashboardCommand-0ahyp-zA.js} +1 -1
- package/dist/{dataCommand-sfpGV694.js → dataCommand-D4IlZcih.js} +277 -210
- package/dist/{dev-D-JZ6CGQ.js → dev-DAM5CnAa.js} +1856 -1801
- package/dist/{dev-BZO5aLdr.js → dev-P4HyeY9W.js} +1 -1
- package/dist/devActivity.d.ts +16 -0
- package/dist/doctorCommand-2K1dIzYk.js +2 -0
- package/dist/{doctorCommand-BlUyESpD.js → doctorCommand-DW2cwAvC.js} +244 -223
- package/dist/doctorSourceRelations-CPjSwYuZ.js +83 -0
- package/dist/{dormancyCommand-lQxdrU8C.js → dormancyCommand-BqQz7lbM.js} +1 -1
- package/dist/{embeddingsCommand-ByBTju6X.js → embeddingsCommand-DJyArpU4.js} +1 -1
- package/dist/{envCommand-CpCbYAgR.js → envCommand-CviRZx1L.js} +1 -1
- package/dist/{evolveCommand-CBV3-TtK.js → evolveCommand-qdlP-R9G.js} +2 -2
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-DJoA9cKD.js → infoCommand-CNWPSUcW.js} +1 -1
- package/dist/inspectState.d.ts +16 -0
- package/dist/{runtimeTrace-DJ9tPhrc.js → runtimeTrace-BDZSt9W_.js} +1 -1
- package/dist/{sdkgen-7dr8-Onw.js → sdkgen-sNaD3oZB.js} +1 -1
- package/dist/{serveCommand-BlnAlNQg.js → serveCommand-BBhT2U94.js} +731 -737
- package/dist/serveCommand-DY2jLy0o.js +2 -0
- package/dist/serveEntry.d.ts +16 -0
- package/dist/serveEntry.js +1 -1
- package/dist/startEntry.d.ts +16 -0
- package/dist/startup.d.ts +16 -0
- package/dist/{test-CLYXrZ2F.js → test-CHb7UwvE.js} +1 -1
- package/dist/updateCommand-BH6EGuCc.js +2 -0
- package/dist/{updateCommand-BvRidHp6.js → updateCommand-rCnhaj84.js} +1 -1
- package/dist/{webhooksCommand-BfO_JF2b.js → webhooksCommand-C0iZZfaI.js} +1 -1
- package/package.json +23 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +63 -3
- package/templates/agent-docs/data.md +33 -3
- package/templates/agent-docs/plugins/versioning.md +2 -0
- package/templates/agent-docs/whats-new.md +83 -14
- 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 +9 -9
- 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 +10 -10
- 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 +4 -4
- package/dist/apiBuild-XaW40W8x.js +0 -2
- package/dist/codegen-i8QGcHsi.js +0 -2
- package/dist/codegenCommand-iClXoRCW.js +0 -129
- package/dist/doctorCommand-BeLOwq7S.js +0 -2
- package/dist/serveCommand-Dg_E1ev4.js +0 -2
- package/dist/updateCommand-DcKVmLVN.js +0 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Bt as e, Ht as t, Vt as n } from "./dev-
|
|
1
|
+
import { Bt as e, Ht as t, Vt as n } from "./dev-DAM5CnAa.js";
|
|
2
2
|
import { at as r, it as i, ot as a, s as o, st as s, t as c, w as l, y as u } from "./webDev-101csg6Q.js";
|
|
3
3
|
import { w as d } from "./frameworkTableAssembly-oMPBKqlE.js";
|
|
4
4
|
import { n as f } from "./pageConvention-cEiRxdab.js";
|
|
5
|
-
import { r as p, u as m } from "./apiBuild-
|
|
5
|
+
import { r as p, u as m } from "./apiBuild-CDQBNRDx.js";
|
|
6
6
|
import { n as h, r as g, t as ee } from "./cliOutput-D1tSBoRM.js";
|
|
7
7
|
import { n as _, t as te } from "./tsconfigPaths-BWXBWgcl.js";
|
|
8
8
|
import { n as ne, r as re } from "./fileTaxonomy-CJfgOllU.js";
|
|
@@ -477,33 +477,33 @@ var le = /* @__PURE__ */ new Set([
|
|
|
477
477
|
for (let n of e.problems) t.push(` • ${n}`);
|
|
478
478
|
}
|
|
479
479
|
return e.unreadable.length > 0 && t.push(`… ${e.file}: ${e.unreadable.length} matcher(s) not statically readable (${e.unreadable.join(", ")}) — doctor did NOT check them. The boot still does.`), e.seen === 0 && t.push(`… ${e.file}: no \`defineMiddleware(...)\` found — doctor checked nothing here. A middleware assigned through a variable or re-exported from another module is invisible to this rule.`), t.length === 0 && e.seen > 0 && t.push(`✓ ${e.file}: ${e.seen} middleware(s), matchers resolve and do not overlap`), t;
|
|
480
|
-
},
|
|
480
|
+
}, ze = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/[^\n]*/g, "$1"), Be = /* @__PURE__ */ new Set([
|
|
481
481
|
"requireScope",
|
|
482
482
|
"requireAnyScope",
|
|
483
483
|
"requireAuth",
|
|
484
484
|
"assertScope",
|
|
485
485
|
"assertCan",
|
|
486
486
|
"can"
|
|
487
|
-
]),
|
|
487
|
+
]), Ve = (e) => {
|
|
488
488
|
let t = /* @__PURE__ */ new Set();
|
|
489
|
-
for (let n of e) for (let e of
|
|
489
|
+
for (let n of e) for (let e of ze(n).matchAll(/\bexport\s+(?:const|function|async\s+function)\s+((?:require|assert)[A-Z]\w*)/g)) t.add(e[1]);
|
|
490
490
|
return t;
|
|
491
|
-
},
|
|
491
|
+
}, He = (e, t) => {
|
|
492
492
|
for (let n of t) if (RegExp(`\\b${n}\\s*\\(`).test(e)) return n;
|
|
493
|
-
},
|
|
493
|
+
}, Ue = (e) => {
|
|
494
494
|
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);
|
|
495
495
|
return t && n;
|
|
496
|
-
},
|
|
496
|
+
}, We = (e, t, n) => {
|
|
497
497
|
if (e.hasDeclaredGuards) return { kind: "declared-guard" };
|
|
498
|
-
let r =
|
|
499
|
-
return i === void 0 ?
|
|
498
|
+
let r = ze(e.src), i = He(r, t);
|
|
499
|
+
return i === void 0 ? Ue(r) ? { kind: "inline-ownership" } : n.has(e.tag) ? { kind: "allowlisted" } : { kind: "unchecked" } : {
|
|
500
500
|
kind: "vocabulary-guard",
|
|
501
501
|
name: i
|
|
502
502
|
};
|
|
503
|
-
},
|
|
503
|
+
}, Ge = (e, t, n) => {
|
|
504
504
|
let r = e.op === "delete" ? 3 : e.op === "update" ? 2 : 1;
|
|
505
505
|
return e.table !== void 0 && (t.has(e.table) && (r += 2), n.has(e.table) && e.op === "delete" && (r += 2)), r;
|
|
506
|
-
},
|
|
506
|
+
}, Ke = (e, t, n) => {
|
|
507
507
|
switch (t.kind) {
|
|
508
508
|
case "declared-guard": return "guards: on the descriptor";
|
|
509
509
|
case "vocabulary-guard": return `calls ${t.name}()`;
|
|
@@ -511,15 +511,15 @@ var le = /* @__PURE__ */ new Set([
|
|
|
511
511
|
case "allowlisted": return "accepted by a previous run";
|
|
512
512
|
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`;
|
|
513
513
|
}
|
|
514
|
-
},
|
|
514
|
+
}, qe = (e) => {
|
|
515
515
|
let t = e.executors.map((t) => {
|
|
516
|
-
let n =
|
|
516
|
+
let n = We(t, e.guardVocabulary, e.allowlist);
|
|
517
517
|
return {
|
|
518
518
|
tag: t.tag,
|
|
519
519
|
path: t.path,
|
|
520
520
|
verdict: n,
|
|
521
|
-
severity:
|
|
522
|
-
why:
|
|
521
|
+
severity: Ge(t, e.tenantScopedTables, e.referencedTables),
|
|
522
|
+
why: Ke(t, n, e.rowFilterRegistered === !0)
|
|
523
523
|
};
|
|
524
524
|
}), n = (e) => t.filter((t) => t.verdict.kind === e).length;
|
|
525
525
|
return {
|
|
@@ -533,7 +533,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
533
533
|
},
|
|
534
534
|
unchecked: t.filter((e) => e.verdict.kind === "unchecked").sort((e, t) => t.severity - e.severity || e.tag.localeCompare(t.tag))
|
|
535
535
|
};
|
|
536
|
-
},
|
|
536
|
+
}, Je = [
|
|
537
537
|
"# voltro doctor — authz allowlist",
|
|
538
538
|
"#",
|
|
539
539
|
"# Two KINDS of line, and the difference is the point:",
|
|
@@ -558,19 +558,19 @@ var le = /* @__PURE__ */ new Set([
|
|
|
558
558
|
"# `--write-authz-allowlist` PRESERVES reviewed= lines. It only ever adds debt",
|
|
559
559
|
"# lines for executors that are newly unchecked.",
|
|
560
560
|
""
|
|
561
|
-
],
|
|
561
|
+
], Ye = (e) => {
|
|
562
562
|
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));
|
|
563
563
|
return [
|
|
564
|
-
...
|
|
564
|
+
...Je,
|
|
565
565
|
...n,
|
|
566
566
|
...r.length > 0 ? ["", "# reviewed — read by a human, open on purpose"] : [],
|
|
567
567
|
...r.map((e) => `${e.tag} reviewed=${e.reviewed}`),
|
|
568
568
|
""
|
|
569
569
|
].join("\n");
|
|
570
|
-
},
|
|
570
|
+
}, Xe = (e, t) => {
|
|
571
571
|
let n = [...new Set(t)].sort();
|
|
572
|
-
if (e === void 0) return
|
|
573
|
-
let r =
|
|
572
|
+
if (e === void 0) return Ye(n.map((e) => ({ tag: e })));
|
|
573
|
+
let r = j(e).tags, i = n.filter((e) => !r.has(e));
|
|
574
574
|
return i.length === 0 ? e : [
|
|
575
575
|
e.replace(/\n+$/, ""),
|
|
576
576
|
"",
|
|
@@ -579,25 +579,25 @@ var le = /* @__PURE__ */ new Set([
|
|
|
579
579
|
...i,
|
|
580
580
|
""
|
|
581
581
|
].join("\n");
|
|
582
|
-
},
|
|
582
|
+
}, Ze = (e, t) => {
|
|
583
583
|
let n = [...new Set(t)];
|
|
584
584
|
if (e === void 0) return {
|
|
585
585
|
added: n.length,
|
|
586
586
|
kept: 0,
|
|
587
587
|
removed: 0
|
|
588
588
|
};
|
|
589
|
-
let r =
|
|
589
|
+
let r = j(e).tags;
|
|
590
590
|
return {
|
|
591
591
|
added: n.filter((e) => !r.has(e)).length,
|
|
592
592
|
kept: r.size,
|
|
593
593
|
removed: 0
|
|
594
594
|
};
|
|
595
|
-
},
|
|
595
|
+
}, Qe = class extends Error {
|
|
596
596
|
tag;
|
|
597
597
|
constructor(e) {
|
|
598
598
|
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";
|
|
599
599
|
}
|
|
600
|
-
},
|
|
600
|
+
}, j = (e) => {
|
|
601
601
|
let t = [];
|
|
602
602
|
for (let n of e.split("\n")) {
|
|
603
603
|
let e = n.trim();
|
|
@@ -610,7 +610,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
610
610
|
continue;
|
|
611
611
|
}
|
|
612
612
|
let a = r[2].trim();
|
|
613
|
-
if (a.length === 0) throw new
|
|
613
|
+
if (a.length === 0) throw new Qe(i);
|
|
614
614
|
t.push({
|
|
615
615
|
tag: i,
|
|
616
616
|
reviewed: a
|
|
@@ -620,13 +620,13 @@ var le = /* @__PURE__ */ new Set([
|
|
|
620
620
|
tags: new Set(t.map((e) => e.tag)),
|
|
621
621
|
entries: t
|
|
622
622
|
};
|
|
623
|
-
},
|
|
623
|
+
}, $e = (e) => {
|
|
624
624
|
let t = e.indexOf(".");
|
|
625
625
|
return t <= 0 ? void 0 : e.slice(0, t);
|
|
626
|
-
},
|
|
626
|
+
}, et = (e, t) => {
|
|
627
627
|
let n = new Set(t.tables), r = new Set(t.rpcTags), i = /* @__PURE__ */ new Map();
|
|
628
628
|
for (let e of t.rpcTags) {
|
|
629
|
-
let t =
|
|
629
|
+
let t = $e(e);
|
|
630
630
|
if (t === void 0) continue;
|
|
631
631
|
let n = i.get(t);
|
|
632
632
|
n ? n.push(e) : i.set(t, [e]);
|
|
@@ -655,7 +655,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
655
655
|
});
|
|
656
656
|
continue;
|
|
657
657
|
}
|
|
658
|
-
let s = new Set(o.rpcTags.map(
|
|
658
|
+
let s = new Set(o.rpcTags.map($e).filter((e) => e !== void 0));
|
|
659
659
|
for (let e of s) {
|
|
660
660
|
let t = i.get(e);
|
|
661
661
|
t !== void 0 && a.push({
|
|
@@ -668,12 +668,12 @@ var le = /* @__PURE__ */ new Set([
|
|
|
668
668
|
}
|
|
669
669
|
}
|
|
670
670
|
return a;
|
|
671
|
-
},
|
|
671
|
+
}, tt = (e, t) => {
|
|
672
672
|
let n = e.reduce((e, t) => e + t.tables.length, 0), r = [`plugin surface · ${e.length} plugin(s) contribute ${n} table(s)`];
|
|
673
673
|
if (t.length === 0) return r.push(" ✓ no overlap with your own tables or rpc namespaces"), r;
|
|
674
674
|
for (let e of t) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.plugin} — ${e.detail}`), r.push(` ${e.fix}`);
|
|
675
675
|
return r;
|
|
676
|
-
},
|
|
676
|
+
}, nt = async (e) => {
|
|
677
677
|
if (!await e.hasWorkflows().catch(() => !1)) return { kind: "not-applicable" };
|
|
678
678
|
let t;
|
|
679
679
|
try {
|
|
@@ -697,12 +697,12 @@ var le = /* @__PURE__ */ new Set([
|
|
|
697
697
|
} finally {
|
|
698
698
|
await t.close().catch(() => {});
|
|
699
699
|
}
|
|
700
|
-
},
|
|
700
|
+
}, rt = (e) => {
|
|
701
701
|
let t = Math.round(e / 6e4);
|
|
702
702
|
if (t < 90) return `${t}m`;
|
|
703
703
|
let n = Math.round(t / 60);
|
|
704
704
|
return n < 48 ? `${n}h` : `${Math.round(n / 24)}d`;
|
|
705
|
-
},
|
|
705
|
+
}, it = (e) => {
|
|
706
706
|
if (e.kind === "not-applicable") return null;
|
|
707
707
|
if (e.kind === "skipped") return `• stuck runs: NOT CHECKED — ${e.reason}\n This is the one doctor rule that reads the database rather than your source.
|
|
708
708
|
Run it where the app's DB env vars are set, or ignore this line locally.`;
|
|
@@ -710,13 +710,13 @@ var le = /* @__PURE__ */ new Set([
|
|
|
710
710
|
if (t.stalled.length === 0) n.push(`✓ stuck runs: none (${t.examined} live run(s) old enough to examine${t.waitingOnTimer > 0 ? `, ${t.waitingOnTimer} waiting on a durable timer` : ""}${t.alreadyReported > 0 ? `, ${t.alreadyReported} already reported` : ""})`);
|
|
711
711
|
else {
|
|
712
712
|
n.push(`✗ stuck runs: ${t.stalled.length} run(s) have made no progress`);
|
|
713
|
-
for (let e of t.stalled.slice(0, 20)) n.push(` ${e.tag} ${e.runId} idle ${
|
|
713
|
+
for (let e of t.stalled.slice(0, 20)) n.push(` ${e.tag} ${e.runId} idle ${rt(e.idleMs)} ${e.reason}`);
|
|
714
714
|
t.stalled.length > 20 && n.push(` … and ${t.stalled.length - 20} more`), n.push(" Nothing was changed — this is a SUSPICION, not a verdict. `awaiting-signal` usually means the sender never came.");
|
|
715
715
|
}
|
|
716
716
|
t.sawFullRunPage && n.push(" (the examined page filled up — more old runs exist than were read this pass)");
|
|
717
717
|
for (let e of t.failures) n.push(` ! could not examine ${e.subject}: ${e.detail}`);
|
|
718
718
|
return n.join("\n");
|
|
719
|
-
},
|
|
719
|
+
}, at = (e) => S(b(e, "app.config.ts")) || S(b(e, "app.config.js")), ot = (e) => {
|
|
720
720
|
let t = m(e), n = p(e);
|
|
721
721
|
return {
|
|
722
722
|
root: e,
|
|
@@ -725,22 +725,22 @@ var le = /* @__PURE__ */ new Set([
|
|
|
725
725
|
apiBundle: n,
|
|
726
726
|
apiBundlePresent: S(n)
|
|
727
727
|
};
|
|
728
|
-
},
|
|
728
|
+
}, st = [
|
|
729
729
|
"Production `voltro serve` requires a precompiled serve bundle and never transpiles on demand.",
|
|
730
730
|
"Add a `voltro build .` step BEFORE `voltro serve .` in your Dockerfile / start script.",
|
|
731
731
|
"(Generated Dockerfiles from `voltro create-project` already do this.)"
|
|
732
|
-
].join("\n "),
|
|
733
|
-
let n =
|
|
734
|
-
if (console.log(`voltro doctor — serve preflight for ${n.root}`), !
|
|
732
|
+
].join("\n "), ct = (e, t = !1) => {
|
|
733
|
+
let n = ot(e);
|
|
734
|
+
if (console.log(`voltro doctor — serve preflight for ${n.root}`), !at(e)) return console.log("• no app.config found here — nothing to check (run against an app root)."), 0;
|
|
735
735
|
console.log(`${n.serveBundlePresent ? "✓" : "✗"} serve bundle: ${n.serveBundlePresent ? "present" : "MISSING"} (${n.serveBundle})`), console.log(`${n.apiBundlePresent ? "✓" : "•"} api bundle: ${n.apiBundlePresent ? "present" : "absent"} (${n.apiBundle})`);
|
|
736
736
|
let r = process.env.NODE_ENV === "production";
|
|
737
737
|
if (n.serveBundlePresent) return console.log("✓ serve preflight: ready for `voltro serve`."), 0;
|
|
738
738
|
let i = t || r;
|
|
739
|
-
return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${
|
|
740
|
-
},
|
|
739
|
+
return console.error(`${i ? "✗" : "•"} serve bundle missing — ${i ? "production `voltro serve` will FAIL." : "a non-production `voltro serve` still runs via tsx."}`), console.error(` ${st}`), +!!i;
|
|
740
|
+
}, lt = (e) => {
|
|
741
741
|
let t = e.absPath.replace(/\.server\.(tsx?)$/, ".$1");
|
|
742
742
|
if (t !== e.absPath) return e.sources.get(t) ?? e.sources.get(t.replace(/\.ts$/, ".tsx"));
|
|
743
|
-
},
|
|
743
|
+
}, ut = (e, t, n) => {
|
|
744
744
|
let r = new Set(e), i = _(n), a = (e) => (/\.(tsx?|jsx?)$/.test(e) ? [e] : [
|
|
745
745
|
`${e}.ts`,
|
|
746
746
|
`${e}.tsx`,
|
|
@@ -766,7 +766,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
766
766
|
r !== void 0 && o.push(r);
|
|
767
767
|
}
|
|
768
768
|
return o;
|
|
769
|
-
}, s = /* @__PURE__ */ new Set(), c = e.filter((e) =>
|
|
769
|
+
}, s = /* @__PURE__ */ new Set(), c = e.filter((e) => ht.test(y(n, e))), l = new Set(c);
|
|
770
770
|
for (; c.length > 0;) {
|
|
771
771
|
let e = c.shift();
|
|
772
772
|
if (!s.has(e)) {
|
|
@@ -779,11 +779,11 @@ var le = /* @__PURE__ */ new Set([
|
|
|
779
779
|
let d = /* @__PURE__ */ new Set();
|
|
780
780
|
for (let e of s) l.has(e) || u.has(e) || d.add(e);
|
|
781
781
|
return d;
|
|
782
|
-
},
|
|
782
|
+
}, M = (e) => e.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1").replace(/'(?:[^'\\\n]|\\.)*'/g, "''").replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\""), dt = (e, t) => (e.match(t) ?? []).length, N = (e, t) => e.getDescendantsOfKind(O.CallExpression).filter((e) => t.test(e.getExpression().getText())).length, ft = (e, t) => {
|
|
783
783
|
if (e.src.includes(t)) return !0;
|
|
784
784
|
let n = t.replace(/^@voltro\/plugin-/, "");
|
|
785
|
-
return n !== t &&
|
|
786
|
-
},
|
|
785
|
+
return n !== t && N(e.file, RegExp(`^${n}Plugin$`)) > 0;
|
|
786
|
+
}, pt = (e, t) => {
|
|
787
787
|
let n = [], r = RegExp(`\\b${t}\\s*(?:<[^()]*>)?\\s*\\(`, "g"), i;
|
|
788
788
|
for (; (i = r.exec(e)) !== null;) {
|
|
789
789
|
let t = i.index + i[0].length, r = 1, a = t;
|
|
@@ -791,10 +791,10 @@ var le = /* @__PURE__ */ new Set([
|
|
|
791
791
|
n.push(e.slice(t, a - 1));
|
|
792
792
|
}
|
|
793
793
|
return n;
|
|
794
|
-
},
|
|
794
|
+
}, mt = (e, t) => {
|
|
795
795
|
let n = t.getSymbol()?.getDeclarations()?.[0];
|
|
796
796
|
return n === void 0 ? [] : e.getDescendantsOfKind(O.Identifier).filter((e) => e.getSymbol()?.getDeclarations()?.[0] === n);
|
|
797
|
-
},
|
|
797
|
+
}, ht = /\.(server|cron|workflow\.server|subscribe|reaction|outbox|startup|trigger|webhook|migration|seed)\.tsx?$/, gt = /\.(query|mutation|action|stream)\.server\.tsx?$/, _t = [
|
|
798
798
|
"Id",
|
|
799
799
|
"ID",
|
|
800
800
|
"Hash",
|
|
@@ -820,7 +820,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
820
820
|
"Comment",
|
|
821
821
|
"Provider",
|
|
822
822
|
"Format"
|
|
823
|
-
],
|
|
823
|
+
], vt = RegExp(`(?:${_t.join("|")})$|_(?:${_t.map((e) => e.toLowerCase()).join("|")})$`), yt = [
|
|
824
824
|
{
|
|
825
825
|
id: "hardcoded-framework-cookie",
|
|
826
826
|
scope: "client",
|
|
@@ -833,7 +833,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
833
833
|
scope: "server",
|
|
834
834
|
smell: "an executor that never names its own descriptor — its input type is hand-written, so it can drift from the contract it implements",
|
|
835
835
|
use: "import the descriptor and type the input as `ExecutorInput<typeof descriptor>`, so the wire contract and the handler cannot disagree",
|
|
836
|
-
match: ({ src: e, path: t }) =>
|
|
836
|
+
match: ({ src: e, path: t }) => gt.test(t) && !/\bimport\s[^;]*\bfrom\s*['"][^'"]*['"]/.test((e.match(/^\s*import\s[^;]*from\s*['"]\.[^'"]*['"]/gm) ?? []).join("\n"))
|
|
837
837
|
},
|
|
838
838
|
{
|
|
839
839
|
id: "subject-write-no-guard",
|
|
@@ -842,12 +842,12 @@ var le = /* @__PURE__ */ new Set([
|
|
|
842
842
|
use: "declare `guards:` on the descriptor, or — if the procedure really is open — compare the loaded row's owner against `ctx.request.subject.id` and fail with a typed error",
|
|
843
843
|
match: (e) => {
|
|
844
844
|
let { src: t, path: n } = e;
|
|
845
|
-
if (!
|
|
846
|
-
let r =
|
|
845
|
+
if (!gt.test(n)) return !1;
|
|
846
|
+
let r = M(t);
|
|
847
847
|
if (!(/\bsubject\s*\.\s*id\b/.test(r) && /\b(?:insert|update|upsert|insertMany|updateMany|insertRow|upsertRow|updateManyRow)\s*\(/.test(r)) || /\b(?:guard|guards|requireScope|requireAnyScope|assertCan|assertScope|requireAuth|Unauthenticated)\b/.test(r) || /[=!]==?\s*[^;\n]*\bsubject\s*\.\s*id\b|\bsubject\s*\.\s*id\b\s*[=!]==/.test(r)) return !1;
|
|
848
|
-
let i =
|
|
848
|
+
let i = lt(e);
|
|
849
849
|
if (i === void 0) return !1;
|
|
850
|
-
let a =
|
|
850
|
+
let a = M(i);
|
|
851
851
|
return /\binternal\s*:\s*true\b/.test(a) || /\bguards\s*:\s*\[/.test(a) || /\.guard\s*\(/.test(a) ? !1 : /\bopenAccess\s*:/.test(a);
|
|
852
852
|
}
|
|
853
853
|
},
|
|
@@ -856,14 +856,14 @@ var le = /* @__PURE__ */ new Set([
|
|
|
856
856
|
scope: "server",
|
|
857
857
|
smell: "raw fetch() for outbound HTTP on the server (no traceparent, no retry, and no SSRF guard where the URL is not a constant)",
|
|
858
858
|
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",
|
|
859
|
-
match: ({ file: e, path: t, serverOnly: n }) => (
|
|
859
|
+
match: ({ file: e, path: t, serverOnly: n }) => (ht.test(t) || n) && N(e, /^(?:globalThis\.|window\.|self\.)?fetch$/) > 0
|
|
860
860
|
},
|
|
861
861
|
{
|
|
862
862
|
id: "form",
|
|
863
863
|
scope: "client",
|
|
864
864
|
smell: "per-field useState + a submit flag (hand-rolled form)",
|
|
865
865
|
use: "useFormBinding — fields + validation from the mutation input Schema; server ValidationError({ field }) routes to the field",
|
|
866
|
-
match: ({ src: e, file: t }) =>
|
|
866
|
+
match: ({ src: e, file: t }) => N(t, /^useState$/) >= 4 && /onSubmit|handleSubmit|isSubmitting/.test(e)
|
|
867
867
|
},
|
|
868
868
|
{
|
|
869
869
|
id: "table",
|
|
@@ -891,7 +891,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
891
891
|
scope: "client",
|
|
892
892
|
smell: "useMemo fanning in multiple subscriptions (hand-maintained dep array)",
|
|
893
893
|
use: "useDerived — dependency-tracked, referentially stable",
|
|
894
|
-
match: ({ src: e }) =>
|
|
894
|
+
match: ({ src: e }) => dt(e, /\buseSubscription\s*[(<]/g) >= 3 && dt(e, /\buseMemo\s*\(/g) >= 3
|
|
895
895
|
},
|
|
896
896
|
{
|
|
897
897
|
id: "next-shim",
|
|
@@ -916,7 +916,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
916
916
|
match: ({ file: e }) => e.getDescendantsOfKind(O.CallExpression).filter((e) => /(^|\.)useSubscription$/.test(e.getExpression().getText())).flatMap((e) => {
|
|
917
917
|
let t = e.getFirstAncestorByKind(O.VariableDeclaration)?.getNameNode();
|
|
918
918
|
return t === void 0 ? [] : E.isObjectBindingPattern(t) ? t.getElements().filter((e) => (e.getPropertyNameNode() ?? e.getNameNode()).getText() === "data").map((e) => e.getNameNode()) : [];
|
|
919
|
-
}).some((t) =>
|
|
919
|
+
}).some((t) => mt(e, t).some((e) => {
|
|
920
920
|
let t = e.getParent();
|
|
921
921
|
if (E.isBinaryExpression(t)) {
|
|
922
922
|
let n = t.getOperatorToken().getText(), r = t.getLeft() === e ? t.getRight() : t.getLeft();
|
|
@@ -944,7 +944,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
944
944
|
scope: "server",
|
|
945
945
|
smell: "several sequential store reads assembling related data (an N+1 you are writing by hand)",
|
|
946
946
|
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)",
|
|
947
|
-
match: (e) =>
|
|
947
|
+
match: (e) => N(e.file, /\bstore\.query$/) >= 3 || N(e.file, /\bstore\.query$/) >= 2 && /\bnew Map\s*\(/.test(e.src)
|
|
948
948
|
},
|
|
949
949
|
{
|
|
950
950
|
id: "store-effect-lift",
|
|
@@ -967,7 +967,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
967
967
|
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)",
|
|
968
968
|
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) => {
|
|
969
969
|
let n = t[1];
|
|
970
|
-
return !/token|secret|credential|password|apikey|accesskey/i.test(n) ||
|
|
970
|
+
return !/token|secret|credential|password|apikey|accesskey/i.test(n) || vt.test(n) || /^vault/i.test(n) || /\.unique\s*\(/.test(e) ? !1 : !/\.encrypted\s*\(/.test(e);
|
|
971
971
|
}))
|
|
972
972
|
},
|
|
973
973
|
{
|
|
@@ -977,7 +977,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
977
977
|
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",
|
|
978
978
|
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) => {
|
|
979
979
|
let n = t[1];
|
|
980
|
-
return !/token|secret|credential|password|apikey|accesskey/i.test(n) ||
|
|
980
|
+
return !/token|secret|credential|password|apikey|accesskey/i.test(n) || vt.test(n) || /^vault/i.test(n) ? !1 : /\.unique\s*\(/.test(e) && !/\.encrypted\s*\(/.test(e);
|
|
981
981
|
}))
|
|
982
982
|
},
|
|
983
983
|
{
|
|
@@ -1041,9 +1041,9 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1041
1041
|
scope: "server",
|
|
1042
1042
|
smell: "setRowFilter is registered, but no test passes `rowFilter:` to makeTestContext",
|
|
1043
1043
|
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",
|
|
1044
|
-
match: ({ file: e, testSources: t }) =>
|
|
1045
|
-
let t =
|
|
1046
|
-
return
|
|
1044
|
+
match: ({ file: e, testSources: t }) => N(e, /^setRowFilter$/) > 0 && ![...t.values()].some((e) => {
|
|
1045
|
+
let t = M(e);
|
|
1046
|
+
return pt(t, "makeTestContext").length > 0 && /\browFilter\b/.test(t);
|
|
1047
1047
|
})
|
|
1048
1048
|
},
|
|
1049
1049
|
{
|
|
@@ -1053,15 +1053,15 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1053
1053
|
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",
|
|
1054
1054
|
match: ({ src: e }) => /\.(getTime|toISOString)\s*\(\s*\)/.test(e) && /\.map\s*\(|=>\s*\(\{/.test(e) && /\bexport\s+default\b/.test(e)
|
|
1055
1055
|
}
|
|
1056
|
-
],
|
|
1056
|
+
], bt = (e) => F(e), xt = (e, t) => {
|
|
1057
1057
|
let n = /* @__PURE__ */ new Set();
|
|
1058
1058
|
for (let r of t) {
|
|
1059
1059
|
let t = y(e, r), i = t.split(/[\\/]/)[0];
|
|
1060
1060
|
n.add(i !== void 0 && i !== t ? i : ".");
|
|
1061
1061
|
}
|
|
1062
1062
|
return [...n].sort();
|
|
1063
|
-
},
|
|
1064
|
-
if (n > 12 ||
|
|
1063
|
+
}, St = /\.(tsx?|jsx?)$/, P = /(^|\/)(node_modules|dist|build|\.framework|\.next|coverage)(\/|$)/, Ct = /(^|[\\/])[^\\/]*\.generated\.[cm]?[jt]sx?$|\.d\.[cm]?ts$/, wt = (e, t = [], n = 0) => {
|
|
1064
|
+
if (n > 12 || P.test(e)) return t;
|
|
1065
1065
|
let r;
|
|
1066
1066
|
try {
|
|
1067
1067
|
r = w(e, { withFileTypes: !0 });
|
|
@@ -1072,12 +1072,12 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1072
1072
|
let r = v(e, i.name);
|
|
1073
1073
|
if (i.isDirectory()) {
|
|
1074
1074
|
if (i.name.startsWith(".")) continue;
|
|
1075
|
-
|
|
1075
|
+
wt(r, t, n + 1);
|
|
1076
1076
|
} else je.test(i.name) && t.push(r);
|
|
1077
1077
|
}
|
|
1078
1078
|
return t;
|
|
1079
|
-
},
|
|
1080
|
-
if (n > 12 ||
|
|
1079
|
+
}, F = (e, t = [], n = 0) => {
|
|
1080
|
+
if (n > 12 || P.test(e)) return t;
|
|
1081
1081
|
let r;
|
|
1082
1082
|
try {
|
|
1083
1083
|
r = w(e);
|
|
@@ -1091,11 +1091,11 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1091
1091
|
} catch {
|
|
1092
1092
|
continue;
|
|
1093
1093
|
}
|
|
1094
|
-
a.isDirectory() ?
|
|
1094
|
+
a.isDirectory() ? F(r, t, n + 1) : St.test(i) && !/\.(test|spec)\./.test(i) && !Ct.test(i) && t.push(r);
|
|
1095
1095
|
}
|
|
1096
1096
|
return t;
|
|
1097
|
-
},
|
|
1098
|
-
if (n > 12 ||
|
|
1097
|
+
}, I = (e, t = [], n = 0) => {
|
|
1098
|
+
if (n > 12 || P.test(e)) return t;
|
|
1099
1099
|
let r;
|
|
1100
1100
|
try {
|
|
1101
1101
|
r = w(e);
|
|
@@ -1109,17 +1109,17 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1109
1109
|
} catch {
|
|
1110
1110
|
continue;
|
|
1111
1111
|
}
|
|
1112
|
-
a.isDirectory() ?
|
|
1112
|
+
a.isDirectory() ? I(r, t, n + 1) : St.test(i) && /\.(test|spec)\./.test(i) && t.push(r);
|
|
1113
1113
|
}
|
|
1114
1114
|
return t;
|
|
1115
|
-
},
|
|
1116
|
-
let t =
|
|
1115
|
+
}, L = (e) => {
|
|
1116
|
+
let t = bt(e);
|
|
1117
1117
|
return {
|
|
1118
|
-
dirs:
|
|
1118
|
+
dirs: xt(e, t),
|
|
1119
1119
|
fileCount: t.length
|
|
1120
1120
|
};
|
|
1121
|
-
},
|
|
1122
|
-
let t =
|
|
1121
|
+
}, Tt = (e) => {
|
|
1122
|
+
let t = bt(e);
|
|
1123
1123
|
if (t.length === 0) return [];
|
|
1124
1124
|
let n = new D({
|
|
1125
1125
|
useInMemoryFileSystem: !0,
|
|
@@ -1128,8 +1128,8 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1128
1128
|
for (let e of t) try {
|
|
1129
1129
|
i.set(e, C(e, "utf8"));
|
|
1130
1130
|
} catch {}
|
|
1131
|
-
let a =
|
|
1132
|
-
for (let t of
|
|
1131
|
+
let a = ut([...i.keys()], i, e), o = /* @__PURE__ */ new Map();
|
|
1132
|
+
for (let t of I(e)) try {
|
|
1133
1133
|
o.set(t, C(t, "utf8"));
|
|
1134
1134
|
} catch {}
|
|
1135
1135
|
for (let s of t) {
|
|
@@ -1149,23 +1149,23 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1149
1149
|
} catch {
|
|
1150
1150
|
continue;
|
|
1151
1151
|
}
|
|
1152
|
-
for (let t of
|
|
1153
|
-
if (t.plugin !== void 0 &&
|
|
1152
|
+
for (let t of yt) {
|
|
1153
|
+
if (t.plugin !== void 0 && ft(c, t.plugin) || !t.match(c)) continue;
|
|
1154
1154
|
let n = r.get(t.id) ?? [];
|
|
1155
1155
|
n.push(y(e, s)), r.set(t.id, n);
|
|
1156
1156
|
}
|
|
1157
1157
|
}
|
|
1158
|
-
return
|
|
1158
|
+
return yt.filter((e) => r.has(e.id)).map((e) => ({
|
|
1159
1159
|
rule: e,
|
|
1160
1160
|
files: r.get(e.id)
|
|
1161
1161
|
})).sort((e, t) => t.files.length - e.files.length || e.rule.id.localeCompare(t.rule.id));
|
|
1162
|
-
},
|
|
1163
|
-
let t =
|
|
1162
|
+
}, R = (e) => {
|
|
1163
|
+
let t = L(e);
|
|
1164
1164
|
return {
|
|
1165
1165
|
root: e,
|
|
1166
1166
|
scannedFiles: t.fileCount,
|
|
1167
1167
|
scannedDirs: t.dirs,
|
|
1168
|
-
findings:
|
|
1168
|
+
findings: Tt(e).map(({ rule: e, files: t }) => ({
|
|
1169
1169
|
id: e.id,
|
|
1170
1170
|
scope: e.scope,
|
|
1171
1171
|
smell: e.smell,
|
|
@@ -1173,13 +1173,13 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1173
1173
|
files: t
|
|
1174
1174
|
}))
|
|
1175
1175
|
};
|
|
1176
|
-
},
|
|
1176
|
+
}, Et = 3, Dt = .2, Ot = 50, kt = (e, t) => e >= Ot && t > 0 && e / t >= Dt, At = (e) => {
|
|
1177
1177
|
let t = /* @__PURE__ */ new Map();
|
|
1178
|
-
for (let n of
|
|
1178
|
+
for (let n of F(e)) try {
|
|
1179
1179
|
t.set(y(e, n), C(n, "utf8"));
|
|
1180
1180
|
} catch {}
|
|
1181
1181
|
let n = /* @__PURE__ */ new Map();
|
|
1182
|
-
for (let t of
|
|
1182
|
+
for (let t of wt(e)) try {
|
|
1183
1183
|
n.set(y(e, t), C(t, "utf8"));
|
|
1184
1184
|
} catch {}
|
|
1185
1185
|
let r = Me({
|
|
@@ -1187,8 +1187,8 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1187
1187
|
envFiles: n
|
|
1188
1188
|
});
|
|
1189
1189
|
r !== void 0 && (console.log(""), console.log(Ne(r)));
|
|
1190
|
-
},
|
|
1191
|
-
let t =
|
|
1190
|
+
}, z = (e) => {
|
|
1191
|
+
let t = R(e);
|
|
1192
1192
|
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;
|
|
1193
1193
|
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;
|
|
1194
1194
|
console.log(`\u2022 Shipped primitives you may be hand-rolling (scanned ${t.scannedFiles} files across ${t.scannedDirs.join(", ")}):`);
|
|
@@ -1199,24 +1199,24 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1199
1199
|
console.log(` [${e}]`);
|
|
1200
1200
|
let i = [...r].sort((e, t) => e.files.length - t.files.length);
|
|
1201
1201
|
for (let e of i) {
|
|
1202
|
-
if (
|
|
1202
|
+
if (kt(e.files.length, t.scannedFiles)) {
|
|
1203
1203
|
let n = Math.round(e.files.length / t.scannedFiles * 100);
|
|
1204
1204
|
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.)");
|
|
1205
1205
|
continue;
|
|
1206
1206
|
}
|
|
1207
|
-
let r = e.files.slice(0,
|
|
1207
|
+
let r = e.files.slice(0, Et).join(", "), i = e.files.length - Et;
|
|
1208
1208
|
i > 0 && (n += i);
|
|
1209
1209
|
let a = i > 0 ? `, +${i} more` : "";
|
|
1210
1210
|
console.log(` ${e.smell} \u2014 ${e.files.length} file(s): ${r}${a}`), console.log(` \u2192 ${e.use}`);
|
|
1211
1211
|
}
|
|
1212
1212
|
}
|
|
1213
1213
|
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;
|
|
1214
|
-
},
|
|
1215
|
-
let t =
|
|
1214
|
+
}, jt = "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.", Mt = /export\s+const\s+renderMode\s*(?::[^=]+)?=\s*['"]([^'"]*)['"]/, Nt = /export\s+const\s+dynamic\s*=\s*['"]force-(dynamic|static)['"]/, Pt = (e) => {
|
|
1215
|
+
let t = Mt.exec(e)?.[1];
|
|
1216
1216
|
if (t !== void 0) return t === "ssr" ? "ssr" : null;
|
|
1217
|
-
let n =
|
|
1217
|
+
let n = Nt.exec(e)?.[1];
|
|
1218
1218
|
return n === "dynamic" ? "ssr" : n === "static" ? null : "default";
|
|
1219
|
-
},
|
|
1219
|
+
}, B = async (e) => {
|
|
1220
1220
|
let t = v(e, "src", "pages");
|
|
1221
1221
|
if (!S(t)) return [];
|
|
1222
1222
|
let { pages: n, dirs: r } = await u(t), i = [];
|
|
@@ -1229,7 +1229,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1229
1229
|
continue;
|
|
1230
1230
|
}
|
|
1231
1231
|
if (c.test(n)) continue;
|
|
1232
|
-
let s =
|
|
1232
|
+
let s = Pt(n);
|
|
1233
1233
|
s !== null && i.push({
|
|
1234
1234
|
file: y(e, v(t, a.file)),
|
|
1235
1235
|
pattern: a.pattern,
|
|
@@ -1237,20 +1237,20 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1237
1237
|
});
|
|
1238
1238
|
}
|
|
1239
1239
|
return i;
|
|
1240
|
-
},
|
|
1240
|
+
}, Ft = 10, It = async (e) => {
|
|
1241
1241
|
console.log("");
|
|
1242
1242
|
let t = v(e, "src", "pages");
|
|
1243
1243
|
if (!S(t)) return console.log("• spa-candidate scan: no src/pages here — nothing to check (web apps only)."), 0;
|
|
1244
|
-
let n = await
|
|
1244
|
+
let n = await B(e);
|
|
1245
1245
|
if (n.length === 0) return console.log("✓ spa-candidate scan: no loader-free, layout-backed pages to flag."), 0;
|
|
1246
1246
|
console.log(`• renderMode:'spa' candidates (${n.length} page${n.length === 1 ? "" : "s"} — loader-free, under a layout, currently ssr/default):`);
|
|
1247
|
-
for (let e of n.slice(0,
|
|
1247
|
+
for (let e of n.slice(0, Ft)) {
|
|
1248
1248
|
let t = e.currentMode === "ssr" ? "renderMode:'ssr'" : "default renderMode";
|
|
1249
1249
|
console.log(` ${e.file} (${e.pattern}) — ${t}`);
|
|
1250
1250
|
}
|
|
1251
|
-
let r = n.length -
|
|
1252
|
-
return r > 0 && console.log(` (+${r} more page${r === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${
|
|
1253
|
-
},
|
|
1251
|
+
let r = n.length - Ft;
|
|
1252
|
+
return r > 0 && console.log(` (+${r} more page${r === 1 ? "" : "s"} not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${jt}`), n.length;
|
|
1253
|
+
}, Lt = /* @__PURE__ */ new Set([
|
|
1254
1254
|
"node_modules",
|
|
1255
1255
|
"dist",
|
|
1256
1256
|
"build",
|
|
@@ -1258,7 +1258,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1258
1258
|
".vite",
|
|
1259
1259
|
".framework",
|
|
1260
1260
|
".git"
|
|
1261
|
-
]),
|
|
1261
|
+
]), Rt = (e, t, n) => {
|
|
1262
1262
|
let r;
|
|
1263
1263
|
try {
|
|
1264
1264
|
r = w(e, { withFileTypes: !0 });
|
|
@@ -1266,11 +1266,11 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1266
1266
|
return;
|
|
1267
1267
|
}
|
|
1268
1268
|
for (let i of r) {
|
|
1269
|
-
if (
|
|
1269
|
+
if (Lt.has(i.name)) continue;
|
|
1270
1270
|
let r = v(e, i.name);
|
|
1271
|
-
i.isDirectory() ?
|
|
1271
|
+
i.isDirectory() ? Rt(r, t, n) : i.isFile() && i.name.endsWith(".tsx") && n.push(y(t, r));
|
|
1272
1272
|
}
|
|
1273
|
-
},
|
|
1273
|
+
}, zt = (e, t) => {
|
|
1274
1274
|
let n = /* @__PURE__ */ new Set(), r = /(?:from|import)\s*\(?\s*['"](\.[^'"]*)['"]/g;
|
|
1275
1275
|
for (let i of t) {
|
|
1276
1276
|
let t;
|
|
@@ -1295,16 +1295,16 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1295
1295
|
}
|
|
1296
1296
|
}
|
|
1297
1297
|
return n;
|
|
1298
|
-
},
|
|
1298
|
+
}, Bt = (e, t) => {
|
|
1299
1299
|
let n = e.slice(t.length).split(x).slice(0, -1)[0];
|
|
1300
1300
|
return n !== void 0 && n.startsWith("[");
|
|
1301
|
-
},
|
|
1301
|
+
}, V = (e) => {
|
|
1302
1302
|
let t = [], n = v(e, "src", "pages"), r = v(e, "src");
|
|
1303
1303
|
if (!S(r)) return t;
|
|
1304
1304
|
let i = [];
|
|
1305
|
-
|
|
1305
|
+
Rt(r, e, i), i.sort();
|
|
1306
1306
|
let a = `${y(e, n)}${x}`;
|
|
1307
|
-
|
|
1307
|
+
zt(e, i);
|
|
1308
1308
|
for (let n of i) {
|
|
1309
1309
|
let r = n.slice(n.lastIndexOf(x) + 1);
|
|
1310
1310
|
if (n.startsWith(a)) {
|
|
@@ -1320,7 +1320,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1320
1320
|
file: n
|
|
1321
1321
|
});
|
|
1322
1322
|
} catch {}
|
|
1323
|
-
|
|
1323
|
+
Bt(n, a) && t.push({
|
|
1324
1324
|
kind: "top-level-dynamic-route",
|
|
1325
1325
|
file: n
|
|
1326
1326
|
});
|
|
@@ -1332,35 +1332,35 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1332
1332
|
});
|
|
1333
1333
|
}
|
|
1334
1334
|
return t;
|
|
1335
|
-
},
|
|
1335
|
+
}, Vt = 10, H = (e, t, n) => {
|
|
1336
1336
|
if (t.length === 0) return;
|
|
1337
1337
|
console.log(`• ${e} (${t.length}):`);
|
|
1338
|
-
for (let e of t.slice(0,
|
|
1339
|
-
let r = t.length -
|
|
1338
|
+
for (let e of t.slice(0, Vt)) console.log(` ${e}`);
|
|
1339
|
+
let r = t.length - Vt;
|
|
1340
1340
|
r > 0 && console.log(` (+${r} more not shown — \`voltro doctor --json\` prints every one.)`), console.log(` → ${n}`);
|
|
1341
|
-
},
|
|
1341
|
+
}, Ht = (e) => {
|
|
1342
1342
|
console.log("");
|
|
1343
1343
|
let t = v(e, "src", "pages");
|
|
1344
1344
|
if (!S(t)) return console.log("• page-convention scan: no src/pages here — nothing to check (web apps only)."), 0;
|
|
1345
|
-
let n =
|
|
1345
|
+
let n = V(e);
|
|
1346
1346
|
if (n.length === 0) return console.log("✓ page-convention scan: every route is a page.tsx in its own directory, with a test beside it."), 0;
|
|
1347
1347
|
let r = (e) => n.filter((t) => t.kind === e).map((e) => e.file);
|
|
1348
|
-
return
|
|
1349
|
-
},
|
|
1350
|
-
let t =
|
|
1348
|
+
return H("will NEVER route — page.tsx outside src/pages/", r("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."), H("pages with no test beside them", r("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."), H("routes whose FIRST segment is dynamic — they claim every URL of that depth", r("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."), H("pages with no `meta` export — they serve the APP name as their title", r("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."), n.length;
|
|
1349
|
+
}, Ut = "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.", Wt = /* @__PURE__ */ new Map(), U = (e) => {
|
|
1350
|
+
let t = Wt.get(e);
|
|
1351
1351
|
if (t !== void 0) return t;
|
|
1352
1352
|
let n = (async () => {
|
|
1353
|
-
let { walk: t, loadDiscovered: n } = await import("./dev-
|
|
1353
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-P4HyeY9W.js"), r = await t(e);
|
|
1354
1354
|
return {
|
|
1355
1355
|
files: r,
|
|
1356
1356
|
discovered: await n(r)
|
|
1357
1357
|
};
|
|
1358
1358
|
})();
|
|
1359
|
-
return
|
|
1360
|
-
},
|
|
1359
|
+
return Wt.set(e, n), n;
|
|
1360
|
+
}, Gt = async (e) => {
|
|
1361
1361
|
let t;
|
|
1362
1362
|
try {
|
|
1363
|
-
let { files: n, discovered: r } = await
|
|
1363
|
+
let { files: n, discovered: r } = await U(e), i = r.tables.map((e) => {
|
|
1364
1364
|
let t = e;
|
|
1365
1365
|
return {
|
|
1366
1366
|
name: t.tableName,
|
|
@@ -1373,7 +1373,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1373
1373
|
return;
|
|
1374
1374
|
}
|
|
1375
1375
|
t !== null && (console.log(""), console.log(`${t.includes("does not exist") ? "✗" : "✓"} ${t}`));
|
|
1376
|
-
},
|
|
1376
|
+
}, Kt = (e) => e.map((e) => {
|
|
1377
1377
|
let t = e, n = Object.entries(t.fields ?? {}).map(([e, t]) => ({
|
|
1378
1378
|
name: e,
|
|
1379
1379
|
type: typeof t?.type == "string" ? t.type : ""
|
|
@@ -1383,21 +1383,42 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1383
1383
|
columns: n,
|
|
1384
1384
|
primaryKey: t.appliedPrimaryKey ?? []
|
|
1385
1385
|
};
|
|
1386
|
-
}),
|
|
1386
|
+
}), qt = async (e) => {
|
|
1387
1387
|
try {
|
|
1388
|
-
let {
|
|
1389
|
-
|
|
1388
|
+
let { missingRelationSources: t } = await import("./doctorSourceRelations-CPjSwYuZ.js"), { sourceKeys: n } = await import("@voltro/protocol"), { readFile: r } = await import("node:fs/promises"), { discovered: i } = await U(e), a = [];
|
|
1389
|
+
for (let e of i.queries) {
|
|
1390
|
+
let i = n(e.descriptor.source);
|
|
1391
|
+
if (i.length === 0) continue;
|
|
1392
|
+
let o = Jt(e.file);
|
|
1393
|
+
if (o === void 0) continue;
|
|
1394
|
+
let s = await r(o, "utf8").catch(() => null);
|
|
1395
|
+
s !== null && a.push(...t(e.descriptor.name, i, s));
|
|
1396
|
+
}
|
|
1397
|
+
return a;
|
|
1390
1398
|
} catch {
|
|
1391
1399
|
return null;
|
|
1392
1400
|
}
|
|
1393
|
-
}, Yt = async (e) => {
|
|
1394
|
-
let t = await
|
|
1401
|
+
}, Jt = (e) => e.endsWith(".ts") && !e.endsWith(".server.ts") ? `${e.slice(0, -3)}.server.ts` : void 0, Yt = async (e) => {
|
|
1402
|
+
let t = await qt(e);
|
|
1403
|
+
if (t === null || t.length === 0) return;
|
|
1404
|
+
let { describeMissingRelationSource: n } = await import("./doctorSourceRelations-CPjSwYuZ.js");
|
|
1405
|
+
console.log(""), console.log(`\u2717 ${t.length} quer${t.length === 1 ? "y" : "ies"} load a relation they do not declare:`);
|
|
1406
|
+
for (let e of t) console.log(` ${n(e)}`);
|
|
1407
|
+
}, W = async (e) => {
|
|
1408
|
+
try {
|
|
1409
|
+
let { discovered: t } = await U(e);
|
|
1410
|
+
return ve(Kt(t.tables));
|
|
1411
|
+
} catch {
|
|
1412
|
+
return null;
|
|
1413
|
+
}
|
|
1414
|
+
}, Xt = async (e) => {
|
|
1415
|
+
let t = await W(e);
|
|
1395
1416
|
if (t === null || t.tablesChecked === 0) return;
|
|
1396
1417
|
let n = be(t);
|
|
1397
1418
|
n !== null && (console.log(""), console.log(`${t.issues.length > 0 ? "✗" : "✓"} ${n}`));
|
|
1398
|
-
},
|
|
1419
|
+
}, G = async (e) => {
|
|
1399
1420
|
try {
|
|
1400
|
-
let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await
|
|
1421
|
+
let { payloadPropertyNames: t } = await import("@voltro/runtime"), { discovered: n } = await U(e);
|
|
1401
1422
|
return we(n.events.map((e) => {
|
|
1402
1423
|
let n = e.descriptor, r = t(n.key);
|
|
1403
1424
|
return {
|
|
@@ -1410,19 +1431,19 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1410
1431
|
} catch {
|
|
1411
1432
|
return null;
|
|
1412
1433
|
}
|
|
1413
|
-
},
|
|
1414
|
-
let t = await
|
|
1434
|
+
}, Zt = async (e) => {
|
|
1435
|
+
let t = await G(e);
|
|
1415
1436
|
if (t === null || t.eventsChecked === 0) return;
|
|
1416
1437
|
let n = Te(t);
|
|
1417
1438
|
n !== null && (console.log(""), console.log(`• ${n}`));
|
|
1418
1439
|
let r = Ee(t);
|
|
1419
1440
|
r !== null && (console.log(""), console.log(`⚠️ ${r}`));
|
|
1420
|
-
},
|
|
1441
|
+
}, K = (e) => {
|
|
1421
1442
|
let t = e, n = typeof t?.message == "string" && t.message !== "" ? t.message : String(e), r = typeof t?.code == "string" ? t.code : void 0;
|
|
1422
1443
|
return r === void 0 ? n : `${r}: ${n}`;
|
|
1423
|
-
},
|
|
1444
|
+
}, q = async (e) => {
|
|
1424
1445
|
try {
|
|
1425
|
-
let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await
|
|
1446
|
+
let { formatServerOnlyLeaks: t } = await import("@voltro/runtime"), n = (await U(e)).discovered.serverOnlyLeaks, r = t(n);
|
|
1426
1447
|
return {
|
|
1427
1448
|
status: {
|
|
1428
1449
|
checked: !0,
|
|
@@ -1433,12 +1454,12 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1433
1454
|
} catch (e) {
|
|
1434
1455
|
return { status: {
|
|
1435
1456
|
checked: !1,
|
|
1436
|
-
reason:
|
|
1457
|
+
reason: K(e)
|
|
1437
1458
|
} };
|
|
1438
1459
|
}
|
|
1439
|
-
},
|
|
1460
|
+
}, J = async (r) => {
|
|
1440
1461
|
try {
|
|
1441
|
-
let { loadApiConfig: i } = await import("./dev-
|
|
1462
|
+
let { loadApiConfig: i } = await import("./dev-P4HyeY9W.js"), { discovered: a } = await U(r), o = n(await i(r)), s = {
|
|
1442
1463
|
queries: a.queries,
|
|
1443
1464
|
mutations: a.mutations,
|
|
1444
1465
|
actions: a.actions,
|
|
@@ -1454,26 +1475,26 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1454
1475
|
} catch (e) {
|
|
1455
1476
|
return {
|
|
1456
1477
|
checked: !1,
|
|
1457
|
-
reason:
|
|
1478
|
+
reason: K(e),
|
|
1458
1479
|
defaultDeny: !0,
|
|
1459
1480
|
undecided: [],
|
|
1460
1481
|
openAccess: []
|
|
1461
1482
|
};
|
|
1462
1483
|
}
|
|
1463
|
-
},
|
|
1464
|
-
let t = await
|
|
1484
|
+
}, Qt = async (e) => {
|
|
1485
|
+
let t = await J(e);
|
|
1465
1486
|
if (!t.checked) return console.log(""), console.log("• access decisions: NOT CHECKED — the app's descriptors could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), !1;
|
|
1466
1487
|
console.log(""), console.log(`access decisions · security.defaultDeny ${t.defaultDeny ? "ON" : "OFF"}`), console.log(` ✗ no access decision ${String(t.undecided.length).padStart(4)}`), console.log(` ✓ openAccess, declared on purpose ${String(t.openAccess.length).padStart(4)}`);
|
|
1467
1488
|
for (let e of t.openAccess) console.log(` ${e.tag} — ${e.openAccess ?? ""}`);
|
|
1468
1489
|
if (t.undecided.length === 0) return !1;
|
|
1469
1490
|
console.log("");
|
|
1470
1491
|
for (let e of t.undecided) console.log(` ✗ ${e.tag} (${e.kind})${e.file === void 0 ? "" : `\n ${e.file}`}`);
|
|
1471
|
-
return console.log(""), t.defaultDeny ? (console.log(" `voltro dev` and `voltro serve` REFUSE to boot on these. Give each a decision:"),
|
|
1472
|
-
},
|
|
1492
|
+
return console.log(""), t.defaultDeny ? (console.log(" `voltro dev` and `voltro serve` REFUSE to boot on these. Give each a decision:"), $t(), !0) : (console.log(" This app sets `security: { defaultDeny: false }`, so these BOOT — and each one is"), console.log(" callable by any authenticated session. Advisory here for that reason only."), $t(), !1);
|
|
1493
|
+
}, $t = () => {
|
|
1473
1494
|
console.log(" `guards: [{ scope: '…' }]` authority the SUBJECT holds globally"), console.log(" `guards: [{ action, resourceType, resource }]` authority per ROW / per resource"), console.log(" — backed by `defineResourcePolicy` + a tuple source you register. If your"), console.log(" relationships already live in your own tables (a `teamMembers` row), register"), console.log(" a tuple source over them; nothing is copied. Fail-closed without a resolver."), console.log(" Docs: Authentication → Authorization."), console.log(" `openAccess: '<why anyone may call it>'` deliberately unauthenticated");
|
|
1474
|
-
},
|
|
1495
|
+
}, Y = async (e) => {
|
|
1475
1496
|
try {
|
|
1476
|
-
let { files: t } = await
|
|
1497
|
+
let { files: t } = await U(e), { WEBHOOK_PATTERN: n, loadWebhookFiles: r } = await import("./webhookDiscovery-il9ti-HE.js"), { incomingWebhookVerification: i } = await import("@voltro/plugin-webhooks"), a = t.filter((e) => n.test(ie(e)));
|
|
1477
1498
|
if (a.length === 0) return {
|
|
1478
1499
|
checked: !0,
|
|
1479
1500
|
unverified: [],
|
|
@@ -1500,14 +1521,14 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1500
1521
|
} catch (e) {
|
|
1501
1522
|
return {
|
|
1502
1523
|
checked: !1,
|
|
1503
|
-
reason:
|
|
1524
|
+
reason: K(e),
|
|
1504
1525
|
unverified: [],
|
|
1505
1526
|
open: [],
|
|
1506
1527
|
verified: 0
|
|
1507
1528
|
};
|
|
1508
1529
|
}
|
|
1509
|
-
},
|
|
1510
|
-
let t = await
|
|
1530
|
+
}, en = async (e) => {
|
|
1531
|
+
let t = await Y(e);
|
|
1511
1532
|
if (!t.checked) return console.log(""), console.log("• webhook verification: NOT CHECKED — the app's webhooks could not be loaded (not a pass)"), console.log(` reason: ${t.reason ?? "unknown"}`), !1;
|
|
1512
1533
|
if (t.verified + t.open.length + t.unverified.length === 0) return !1;
|
|
1513
1534
|
console.log(""), console.log("incoming webhook verification"), console.log(` ✓ signature / provider verified ${String(t.verified).padStart(4)}`), console.log(` ! deliberately public (none) ${String(t.open.length).padStart(4)}`), console.log(` ✗ nothing verifies the caller ${String(t.unverified.length).padStart(4)}`);
|
|
@@ -1516,13 +1537,13 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1516
1537
|
console.log("");
|
|
1517
1538
|
for (let e of t.unverified) console.log(` ✗ ${e.id}\n ${e.file}`);
|
|
1518
1539
|
return console.log(""), console.log(" These are public POSTs that run your application code, and `voltro dev` /"), console.log(" `voltro serve` REFUSE to mount them. Declare one of: `provider:` (a preset),"), console.log(" `signature:` (your own HMAC scheme), `verification: 'provider'` (your handler"), console.log(" verifies), or `verification: 'none'` (deliberately public)."), !0;
|
|
1519
|
-
},
|
|
1520
|
-
let { status: t, message: n } = await
|
|
1540
|
+
}, tn = async (e) => {
|
|
1541
|
+
let { status: t, message: n } = await q(e);
|
|
1521
1542
|
return t.checked ? n !== void 0 && (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);
|
|
1522
|
-
},
|
|
1523
|
-
hasWorkflows: async () => (await
|
|
1543
|
+
}, nn = async (e) => nt({
|
|
1544
|
+
hasWorkflows: async () => (await U(e)).discovered.workflows.length > 0,
|
|
1524
1545
|
openStore: async () => {
|
|
1525
|
-
let { loadApiConfig: t, buildStore: n } = await import("./dev-
|
|
1546
|
+
let { loadApiConfig: t, buildStore: n } = await import("./dev-P4HyeY9W.js"), r = await t(e);
|
|
1526
1547
|
if (r === null) throw Error("no app.config.ts in this directory");
|
|
1527
1548
|
let i = await n(r, void 0);
|
|
1528
1549
|
return {
|
|
@@ -1536,13 +1557,13 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1536
1557
|
let { sweepStalledRuns: t } = await import("@voltro/workflow");
|
|
1537
1558
|
return t({ store: e });
|
|
1538
1559
|
}
|
|
1539
|
-
}),
|
|
1540
|
-
let t =
|
|
1560
|
+
}), rn = async (e) => {
|
|
1561
|
+
let t = it(await nn(e));
|
|
1541
1562
|
t !== null && (console.log(""), console.log(t));
|
|
1542
|
-
},
|
|
1563
|
+
}, an = async (e) => {
|
|
1543
1564
|
let t;
|
|
1544
1565
|
try {
|
|
1545
|
-
let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await
|
|
1566
|
+
let { payloadPropertyNames: n } = await import("@voltro/runtime"), { files: r, discovered: i } = await U(e);
|
|
1546
1567
|
t = ke(r, i.workflows.map((e) => {
|
|
1547
1568
|
let t = e.definition, r = t.payloadSchema === void 0 ? {
|
|
1548
1569
|
required: [],
|
|
@@ -1562,18 +1583,18 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1562
1583
|
console.log("");
|
|
1563
1584
|
let r = t.issues.length > 0 ? "✗" : t.unchecked.length > 0 ? "•" : "✓";
|
|
1564
1585
|
console.log(`${r} ${n}`);
|
|
1565
|
-
},
|
|
1586
|
+
}, X = "voltro-authz-allowlist.txt", on = (e, t = (e) => {
|
|
1566
1587
|
try {
|
|
1567
1588
|
return C(e, "utf8");
|
|
1568
1589
|
} catch {
|
|
1569
1590
|
return "";
|
|
1570
1591
|
}
|
|
1571
|
-
}) => /* @__PURE__ */ new Set([...
|
|
1592
|
+
}) => /* @__PURE__ */ new Set([...Be, ...Ve(F(e).map(t))]), sn = (e, t) => {
|
|
1572
1593
|
let n = t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1573
1594
|
return new RegExp(String.raw`(?:export\s+)?const\s+([A-Za-z_$][\w$]*)\s*=\s*define[A-Za-z]*Event\s*\(\s*\{[^}]*?name\s*:\s*['"\`]${n}['"\`]`, "s").exec(e)?.[1];
|
|
1574
|
-
},
|
|
1595
|
+
}, Z = async (e) => {
|
|
1575
1596
|
try {
|
|
1576
|
-
let { discovered: t } = await
|
|
1597
|
+
let { discovered: t } = await U(e), n = t.events.map((e) => ({
|
|
1577
1598
|
name: e.descriptor.name,
|
|
1578
1599
|
file: e.file
|
|
1579
1600
|
})).filter((e) => typeof e.name == "string");
|
|
@@ -1584,25 +1605,25 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1584
1605
|
} catch {
|
|
1585
1606
|
return "";
|
|
1586
1607
|
}
|
|
1587
|
-
}, a =
|
|
1608
|
+
}, a = F(e).filter((e) => !r.has(e)).map(i).join("\n");
|
|
1588
1609
|
return n.filter(({ name: e, file: t }) => {
|
|
1589
1610
|
if (a.includes(e)) return !1;
|
|
1590
|
-
let n =
|
|
1611
|
+
let n = sn(i(t), e);
|
|
1591
1612
|
return n === void 0 || !new RegExp(String.raw`\b${n}\b`).test(a);
|
|
1592
1613
|
}).map((e) => e.name).sort();
|
|
1593
1614
|
} catch {
|
|
1594
1615
|
return [];
|
|
1595
1616
|
}
|
|
1596
|
-
},
|
|
1597
|
-
let t = await
|
|
1617
|
+
}, cn = async (e) => {
|
|
1618
|
+
let t = await Z(e);
|
|
1598
1619
|
if (t.length !== 0) {
|
|
1599
1620
|
console.log(""), console.log(`• ${t.length} declared event(s) with no emit call site found:`);
|
|
1600
1621
|
for (let e of t) console.log(` ${e}`);
|
|
1601
1622
|
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 AND the identifier its"), console.log(" declaration binds it to, so `emit(ctx, apiKeyCreated, …)` counts. An"), console.log(" emit through an ASSEMBLED name still reads as missing here.");
|
|
1602
1623
|
}
|
|
1603
|
-
},
|
|
1624
|
+
}, ln = async (e) => {
|
|
1604
1625
|
try {
|
|
1605
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1626
|
+
let { loadApiConfig: t } = await import("./dev-P4HyeY9W.js"), n = (await t(e))?.doctor?.scopeVocabulary;
|
|
1606
1627
|
if (typeof n != "string") return [];
|
|
1607
1628
|
let [r, i] = n.split("#");
|
|
1608
1629
|
if (r === void 0 || i === void 0) return [];
|
|
@@ -1611,7 +1632,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1611
1632
|
} catch {
|
|
1612
1633
|
return [];
|
|
1613
1634
|
}
|
|
1614
|
-
},
|
|
1635
|
+
}, Q = async (e) => {
|
|
1615
1636
|
let t = (e) => ({
|
|
1616
1637
|
evaluated: !1,
|
|
1617
1638
|
notEvaluated: e,
|
|
@@ -1619,7 +1640,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1619
1640
|
findings: []
|
|
1620
1641
|
});
|
|
1621
1642
|
try {
|
|
1622
|
-
let { offlineManifest: n, toInput: r } = await import("./checkCommand-
|
|
1643
|
+
let { offlineManifest: n, toInput: r } = await import("./checkCommand-lrzwOzV1.js"), { buildAppGraph: i, checkAppGraph: a } = await import("./appGraph-zuMGKVYX.js"), o = await n(e), s = r(o.manifest, o.tables), c = await ln(e), l = [.../* @__PURE__ */ new Set([...s.scopes ?? [], ...c])];
|
|
1623
1644
|
if (l.length === 0) {
|
|
1624
1645
|
try {
|
|
1625
1646
|
let { loadAppSchemaInputs: t } = await import("./frameworkTableAssembly-DgylYh9_.js");
|
|
@@ -1646,8 +1667,8 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1646
1667
|
} catch {
|
|
1647
1668
|
return t("app-not-importable");
|
|
1648
1669
|
}
|
|
1649
|
-
},
|
|
1650
|
-
let { findings: t, evaluated: n, notEvaluated: r } = await
|
|
1670
|
+
}, un = async (e) => {
|
|
1671
|
+
let { findings: t, evaluated: n, notEvaluated: r } = await Q(e);
|
|
1651
1672
|
if (!n) {
|
|
1652
1673
|
if (console.log(""), r === "app-not-importable") {
|
|
1653
1674
|
console.log("• scope vocabulary: NOT EVALUATED — `app.config.ts` could not be imported."), console.log(" This is not a statement about your scopes: the rule never got to read"), console.log(" them. The commonest cause is a config that demands its environment while"), console.log(" it is evaluated — an auth strategy reading a secret, say — so it imports"), console.log(" inside the container and not on a workstation."), console.log(""), console.log(" Run doctor where that environment exists, or make the config importable"), console.log(" without it. The same import failure is reported above for plugin tables;"), console.log(" both sections have this one cause.");
|
|
@@ -1661,7 +1682,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1661
1682
|
for (let e of t) console.log(` ${e.node}${e.file === void 0 ? "" : ` ${e.file}`}`), console.log(` ${e.detail}`);
|
|
1662
1683
|
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}`);
|
|
1663
1684
|
}
|
|
1664
|
-
},
|
|
1685
|
+
}, dn = async (e) => {
|
|
1665
1686
|
let t = ["src/locales", "locales"], n, r = [];
|
|
1666
1687
|
for (let i of t) {
|
|
1667
1688
|
let t = v(e, i);
|
|
@@ -1673,7 +1694,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1673
1694
|
if (n === void 0 || r.length === 0) return;
|
|
1674
1695
|
let i = [];
|
|
1675
1696
|
try {
|
|
1676
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1697
|
+
let { loadApiConfig: t } = await import("./dev-P4HyeY9W.js");
|
|
1677
1698
|
i = (await t(e))?.locales ?? [];
|
|
1678
1699
|
} catch {
|
|
1679
1700
|
return;
|
|
@@ -1686,7 +1707,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1686
1707
|
console.log("");
|
|
1687
1708
|
for (let e of Fe(a, n)) console.log(e);
|
|
1688
1709
|
}
|
|
1689
|
-
},
|
|
1710
|
+
}, fn = async (e) => {
|
|
1690
1711
|
let t = v(e, "src", "pages");
|
|
1691
1712
|
if (!S(t)) return !1;
|
|
1692
1713
|
let n = [];
|
|
@@ -1701,10 +1722,10 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1701
1722
|
console.log("");
|
|
1702
1723
|
for (let e of Re(r)) console.log(e);
|
|
1703
1724
|
return r.problems.length > 0;
|
|
1704
|
-
},
|
|
1705
|
-
let { discovered: t } = await
|
|
1725
|
+
}, pn = async (e) => {
|
|
1726
|
+
let { discovered: t } = await U(e), n = [];
|
|
1706
1727
|
try {
|
|
1707
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1728
|
+
let { loadApiConfig: t } = await import("./dev-P4HyeY9W.js");
|
|
1708
1729
|
n = ((await t(e))?.plugins ?? []).map((e) => {
|
|
1709
1730
|
let t = (e.extendSchema?.tables ?? []).map((e) => {
|
|
1710
1731
|
let t = e;
|
|
@@ -1717,8 +1738,8 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1717
1738
|
plugin: e.name,
|
|
1718
1739
|
tables: t,
|
|
1719
1740
|
rpcTags: n,
|
|
1720
|
-
canDisableTables:
|
|
1721
|
-
canAlias:
|
|
1741
|
+
canDisableTables: mn.has(r),
|
|
1742
|
+
canAlias: hn.has(r)
|
|
1722
1743
|
};
|
|
1723
1744
|
});
|
|
1724
1745
|
} catch {
|
|
@@ -1730,18 +1751,18 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1730
1751
|
...t.mutations,
|
|
1731
1752
|
...t.actions,
|
|
1732
1753
|
...t.streams ?? []
|
|
1733
|
-
].map((e) => String(e.descriptor.name)), i =
|
|
1754
|
+
].map((e) => String(e.descriptor.name)), i = et(n, {
|
|
1734
1755
|
tables: t.tables.map((e) => e.tableName),
|
|
1735
1756
|
rpcTags: r
|
|
1736
1757
|
});
|
|
1737
1758
|
console.log();
|
|
1738
|
-
for (let e of
|
|
1739
|
-
},
|
|
1759
|
+
for (let e of tt(n, i)) console.log(e);
|
|
1760
|
+
}, mn = /* @__PURE__ */ new Set([
|
|
1740
1761
|
"@voltro/plugin-rbac",
|
|
1741
1762
|
"@voltro/plugin-audit",
|
|
1742
1763
|
"@voltro/plugin-notifications",
|
|
1743
1764
|
"aiFlows"
|
|
1744
|
-
]),
|
|
1765
|
+
]), hn = /* @__PURE__ */ new Set([
|
|
1745
1766
|
"aiFlows",
|
|
1746
1767
|
"@voltro/plugin-audit",
|
|
1747
1768
|
"@voltro/plugin-billing",
|
|
@@ -1758,8 +1779,8 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1758
1779
|
"@voltro/plugin-sso-saml",
|
|
1759
1780
|
"@voltro/plugin-storage",
|
|
1760
1781
|
"@voltro/plugin-versioning"
|
|
1761
|
-
]),
|
|
1762
|
-
let t = await
|
|
1782
|
+
]), $ = 20, gn = async (e) => {
|
|
1783
|
+
let t = await _n(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;
|
|
1763
1784
|
return {
|
|
1764
1785
|
executors: t.executorCount,
|
|
1765
1786
|
guardVocabulary: [...t.vocabulary].sort(),
|
|
@@ -1771,15 +1792,15 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1771
1792
|
},
|
|
1772
1793
|
unchecked: t.result.unchecked
|
|
1773
1794
|
};
|
|
1774
|
-
},
|
|
1775
|
-
let { discovered: t } = await
|
|
1795
|
+
}, _n = async (e) => {
|
|
1796
|
+
let { discovered: t } = await U(e), n = /* @__PURE__ */ new Map(), r = (e) => {
|
|
1776
1797
|
if (!n.has(e)) try {
|
|
1777
1798
|
n.set(e, C(e, "utf8"));
|
|
1778
1799
|
} catch {
|
|
1779
1800
|
n.set(e, "");
|
|
1780
1801
|
}
|
|
1781
1802
|
return n.get(e);
|
|
1782
|
-
}, i =
|
|
1803
|
+
}, i = on(e, r), a = /* @__PURE__ */ new Set();
|
|
1783
1804
|
for (let e of t.tables) for (let t of Object.values(e.fields ?? {})) try {
|
|
1784
1805
|
let e = t.references?.();
|
|
1785
1806
|
e && a.add(e.tableName);
|
|
@@ -1811,12 +1832,12 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1811
1832
|
op: a?.op === "delete" || a?.op === "insert" ? a.op : t,
|
|
1812
1833
|
...a?.table === void 0 ? {} : { table: a.table }
|
|
1813
1834
|
};
|
|
1814
|
-
})), s = v(e,
|
|
1815
|
-
for (let t of
|
|
1835
|
+
})), s = v(e, X), c = S(s) ? j(C(s, "utf8")) : void 0, l = !1;
|
|
1836
|
+
for (let t of F(e)) if (/\bsetRowFilter\s*[<(]/.test(r(t))) {
|
|
1816
1837
|
l = !0;
|
|
1817
1838
|
break;
|
|
1818
1839
|
}
|
|
1819
|
-
let u =
|
|
1840
|
+
let u = qe({
|
|
1820
1841
|
executors: o,
|
|
1821
1842
|
guardVocabulary: i,
|
|
1822
1843
|
tenantScopedTables: t.tenantScopedTables,
|
|
@@ -1833,46 +1854,46 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1833
1854
|
executorCount: o.length,
|
|
1834
1855
|
allowPath: s
|
|
1835
1856
|
};
|
|
1836
|
-
},
|
|
1837
|
-
let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await
|
|
1857
|
+
}, vn = async (e, t) => {
|
|
1858
|
+
let { result: n, vocabulary: r, existing: i, reviewed: a, executorCount: o, allowPath: s, rowFilterRegistered: c } = await _n(e), l = n.counts;
|
|
1838
1859
|
console.log(`\nauthz scan · ${o} executor(s)`);
|
|
1839
|
-
let u = [...r].filter((e) => !
|
|
1860
|
+
let u = [...r].filter((e) => !Be.has(e)).sort();
|
|
1840
1861
|
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)}`);
|
|
1841
1862
|
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;
|
|
1842
|
-
if (console.log(` – accepted as recorded debt ${String(f).padStart(4)} (${
|
|
1843
|
-
let e = S(s) ? C(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r =
|
|
1844
|
-
return oe(s,
|
|
1863
|
+
if (console.log(` – accepted as recorded debt ${String(f).padStart(4)} (${X})`), 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) {
|
|
1864
|
+
let e = S(s) ? C(s, "utf8") : void 0, t = n.unchecked.map((e) => e.tag), r = Ze(e, t);
|
|
1865
|
+
return oe(s, Xe(e, t), "utf8"), console.log(`\n${X}: +${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;
|
|
1845
1866
|
}
|
|
1846
1867
|
if (n.unchecked.length === 0) return !1;
|
|
1847
1868
|
console.log("");
|
|
1848
|
-
for (let e of n.unchecked.slice(0,
|
|
1849
|
-
return n.unchecked.length >
|
|
1850
|
-
},
|
|
1851
|
-
if (e.includes("--help") || e.includes("-h")) return console.log(
|
|
1869
|
+
for (let e of n.unchecked.slice(0, $)) console.log(` ✗ ${e.tag} — ${e.why}\n ${e.path}`);
|
|
1870
|
+
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 ${X} 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 ${X}.`), 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);
|
|
1871
|
+
}, yn = async (e) => {
|
|
1872
|
+
if (e.includes("--help") || e.includes("-h")) return console.log(Ut), 0;
|
|
1852
1873
|
let t = e.includes("--strict"), n = e.find((e) => !e.startsWith("-")), o = b(n ?? process.cwd());
|
|
1853
1874
|
if (g(e)) return ee(), h({
|
|
1854
|
-
...
|
|
1855
|
-
spaCandidates: await
|
|
1856
|
-
pageConvention:
|
|
1875
|
+
...R(o),
|
|
1876
|
+
spaCandidates: await B(o),
|
|
1877
|
+
pageConvention: V(o),
|
|
1857
1878
|
fileTaxonomy: re(o).findings,
|
|
1858
|
-
junctionFks: (await
|
|
1859
|
-
eventDelivery: await
|
|
1879
|
+
junctionFks: (await W(o))?.issues ?? [],
|
|
1880
|
+
eventDelivery: await G(o),
|
|
1860
1881
|
duplicateInstances: i(o),
|
|
1861
1882
|
versionSkew: r(o) ?? null,
|
|
1862
|
-
serverOnly: (await
|
|
1863
|
-
accessDecisions: await
|
|
1864
|
-
webhookVerification: await
|
|
1865
|
-
authz: await
|
|
1866
|
-
ungrantedScopes: await
|
|
1867
|
-
neverEmittedEvents: await
|
|
1868
|
-
stalledRuns: await
|
|
1883
|
+
serverOnly: (await q(o)).status,
|
|
1884
|
+
accessDecisions: await J(o),
|
|
1885
|
+
webhookVerification: await Y(o),
|
|
1886
|
+
authz: await gn(o),
|
|
1887
|
+
ungrantedScopes: await Q(o),
|
|
1888
|
+
neverEmittedEvents: await Z(o),
|
|
1889
|
+
stalledRuns: await nn(o)
|
|
1869
1890
|
}), 0;
|
|
1870
|
-
let c =
|
|
1871
|
-
|
|
1872
|
-
let l = await
|
|
1891
|
+
let c = ct(o, t);
|
|
1892
|
+
z(o), At(o), Ht(o), ne(o), await It(o), await an(o), await rn(o), await Gt(o), await Xt(o), await Yt(o), await Zt(o), await pn(o), await un(o), await cn(o), await dn(o);
|
|
1893
|
+
let l = await tn(o), u = await vn(o, e.includes("--write-authz-allowlist")), d = await Qt(o), f = await en(o), p = await fn(o), m = s(r(o));
|
|
1873
1894
|
m !== void 0 && (console.log(""), console.log(m));
|
|
1874
1895
|
let _ = a(i(o));
|
|
1875
1896
|
return _ !== void 0 && console.log(`\n${_}`), l || u || d || p || f ? Math.max(c, 1) : c;
|
|
1876
1897
|
};
|
|
1877
1898
|
//#endregion
|
|
1878
|
-
export {
|
|
1899
|
+
export { B as C, Y as E, V as S, Q as T, Ht as _, gn as a, ct as b, G as c, L as d, ot as f, z as g, At as h, J as i, on as l, qt as m, st as n, Z as o, W as p, jt as r, sn as s, Ut as t, R as u, It as v, q as w, Tt as x, yn as y };
|