@voltro/cli 0.58.0 → 0.60.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 +113 -0
- package/dist/apiBuild-B9OvhITV.js +2 -0
- package/dist/{apiBuild-CkpsCqIu.js → apiBuild-BU5cd-Fn.js} +50 -48
- package/dist/bin.js +1 -1
- package/dist/{build-51qBWfYY.js → build-BxAsLzyU.js} +347 -258
- package/dist/{checkCommand-C1EbNmwl.js → checkCommand-C1CQc8lD.js} +1 -1
- package/dist/{checkCommand-C30J2F18.js → checkCommand-DC7k1_hP.js} +1 -1
- package/dist/{codemodRunner-BKjCwGiN.js → codemodRunner-ClUqkhvR.js} +523 -390
- package/dist/{commands-DowWkYtd.js → commands-Ro4hYBHD.js} +12 -12
- package/dist/{dashboardCommand-gG1y4PFG.js → dashboardCommand-t8Qsebjr.js} +1 -1
- package/dist/{doctorCommand-5ULMpL10.js → doctorCommand-CGjefPmk.js} +2 -2
- package/dist/doctorCommand-DXnNpKQT.js +2 -0
- package/dist/{evolveCommand-DTawtTxf.js → evolveCommand-CThb0EZZ.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{infoCommand-BFksHunl.js → infoCommand-a0WkKcUY.js} +1 -1
- package/dist/{runtimeTrace-BUk5zMXY.js → runtimeTrace-DDuKJgVi.js} +1 -1
- package/dist/{sdkgen-CAhmmbjx.js → sdkgen-vq1fF9D_.js} +1 -1
- package/dist/serveCommand-1R52mo6F.js +2 -0
- package/dist/{serveCommand-DhtC7WBq.js → serveCommand-Dr4KXmTS.js} +1 -1
- package/dist/serveEntry.js +1 -1
- package/dist/{start-C75w6ftA.js → start-BhoDQ25C.js} +1 -1
- package/dist/{start-DNtIlBcn.js → start-CcdPRG8L.js} +418 -367
- package/dist/startEntry.js +1 -1
- package/dist/{updateCommand-CtuD5r1t.js → updateCommand-D9avpQFT.js} +1 -1
- package/dist/updateCommand-QMOirvXC.js +2 -0
- package/package.json +37 -19
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/ai.md +50 -1
- package/templates/agent-docs/cli.md +7 -6
- package/templates/agent-docs/plugins/sentry.md +142 -16
- package/templates/agent-docs/whats-new.md +25 -168
- package/templates/apps/api-ai/package.json +6 -6
- 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 +9 -9
- 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-row-history/package.json +8 -8
- 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-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +7 -7
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +7 -7
- package/templates/apps/frontend-app/package.json +8 -8
- package/templates/apps/frontend-auth/package.json +7 -7
- package/templates/apps/frontend-blank/package.json +6 -6
- package/templates/apps/frontend-cms/package.json +8 -8
- 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 +6 -6
- package/templates/apps/frontend-docs/package.json +8 -8
- 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 +7 -7
- package/templates/apps/frontend-saas/package.json +7 -7
- package/templates/apps/frontend-spa/package.json +6 -6
- package/templates/apps/frontend-ssr/package.json +6 -6
- package/templates/apps/frontend-ssr-api/package.json +7 -7
- package/templates/apps/frontend-static-blog/package.json +8 -8
- package/templates/apps/frontend-status/package.json +7 -7
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/apiBuild-CDE4NXNi.js +0 -2
- package/dist/doctorCommand-B8H2MYCE.js +0 -2
- package/dist/serveCommand-BUXUtSF5.js +0 -2
- package/dist/updateCommand-eVKVHj3N.js +0 -2
|
@@ -2,9 +2,9 @@ import { A as e, D as t, I as n, O as r, _ as i, d as a, f as o, i as s, m as c,
|
|
|
2
2
|
import { t as d } from "./pageConvention-CMpfDN6r.js";
|
|
3
3
|
import { r as f } from "./tsconfigPaths-BWXBWgcl.js";
|
|
4
4
|
import { a as p, i as m, t as h } from "./fileTaxonomy-CbyMQYx_.js";
|
|
5
|
-
import { basename as g, dirname as _, join as v, relative as
|
|
6
|
-
import { existsSync as
|
|
7
|
-
import { execFileSync as
|
|
5
|
+
import { basename as g, dirname as _, join as v, relative as ee } from "node:path";
|
|
6
|
+
import { existsSync as y, readFileSync as te, statSync as ne } from "node:fs";
|
|
7
|
+
import { execFileSync as b } from "node:child_process";
|
|
8
8
|
import { Node as x, Project as re, QuoteKind as ie, SyntaxKind as S } from "ts-morph";
|
|
9
9
|
import { globSync as ae } from "tinyglobby";
|
|
10
10
|
//#region src/codemodHelpers.ts
|
|
@@ -504,20 +504,20 @@ var C = (e, t, n) => {
|
|
|
504
504
|
"read it now rather than waiting: `sourceKey` is almost always what a",
|
|
505
505
|
"\"parent\" relation means."
|
|
506
506
|
].join("\n")
|
|
507
|
-
}), Oe = "@voltro/plugin-atlassian", ke = "atlassianPlugin",
|
|
507
|
+
}), Oe = "@voltro/plugin-atlassian", ke = "atlassianPlugin", O = (e) => {
|
|
508
508
|
let t = [];
|
|
509
509
|
for (let n of e.getImportDeclarations()) if (n.getModuleSpecifierValue() === Oe) for (let e of n.getNamedImports()) e.getName() === ke && t.push(e.getAliasNode()?.getText() ?? e.getName());
|
|
510
510
|
return t;
|
|
511
|
-
},
|
|
511
|
+
}, Ae = T({
|
|
512
512
|
version: "0.6.0",
|
|
513
513
|
id: "0.6.0/05_atlassian-avatar-mode",
|
|
514
514
|
title: "atlassianPlugin's `avatar` config requires an explicit `mode: 'service' | 'perUser'`",
|
|
515
515
|
kind: "transform",
|
|
516
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
516
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => O(e).length > 0),
|
|
517
517
|
transform: ({ project: e, log: t }) => {
|
|
518
518
|
let n = 0;
|
|
519
519
|
for (let t of e.getSourceFiles()) {
|
|
520
|
-
let e =
|
|
520
|
+
let e = O(t);
|
|
521
521
|
if (e.length !== 0) for (let r of t.getDescendantsOfKind(S.CallExpression)) {
|
|
522
522
|
if (!e.includes(r.getExpression().getText())) continue;
|
|
523
523
|
let t = r.getArguments()[0];
|
|
@@ -533,7 +533,7 @@ var C = (e, t, n) => {
|
|
|
533
533
|
}
|
|
534
534
|
n > 0 && (t(`atlassian avatar: added mode:'service' to ${n} config${n === 1 ? "" : "s"}`), t(" → to use the viewing user's own PAT instead, switch to mode:'perUser' and add resolveSubject"));
|
|
535
535
|
}
|
|
536
|
-
}),
|
|
536
|
+
}), je = T({
|
|
537
537
|
version: "0.6.0",
|
|
538
538
|
id: "0.6.0/06_ui-strings-connect-account",
|
|
539
539
|
title: "UiStrings gained a required `connectAccount` section",
|
|
@@ -577,14 +577,14 @@ var C = (e, t, n) => {
|
|
|
577
577
|
"Alternatively, switch the annotation to `PartialUiStrings` if the object",
|
|
578
578
|
"was only ever an override bag."
|
|
579
579
|
].join("\n")
|
|
580
|
-
}),
|
|
580
|
+
}), Me = E("setRowFilter"), Ne = /\bresolveRowFilterScope\b/, Pe = T({
|
|
581
581
|
version: "0.7.0",
|
|
582
582
|
id: "0.7.0/01_row-filter-load-failure",
|
|
583
583
|
title: "A row filter that fails to load now errors instead of returning zero rows",
|
|
584
584
|
kind: "manual",
|
|
585
585
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
586
586
|
let t = e.getFullText();
|
|
587
|
-
return
|
|
587
|
+
return Me.test(t) || Ne.test(t);
|
|
588
588
|
}),
|
|
589
589
|
note: [
|
|
590
590
|
"Row-level security: a `load` failure is now an ERROR, and is retried first.",
|
|
@@ -655,7 +655,7 @@ var C = (e, t, n) => {
|
|
|
655
655
|
" \"every row you could see was just deleted\". Make sure your subscription",
|
|
656
656
|
" error handling surfaces this rather than swallowing it."
|
|
657
657
|
].join("\n")
|
|
658
|
-
}),
|
|
658
|
+
}), Fe = T({
|
|
659
659
|
version: "0.7.0",
|
|
660
660
|
id: "0.7.0/02_testing-invoke-effect-handlers",
|
|
661
661
|
title: "@voltro/testing: invoke() runs Effect handlers; executor types widened",
|
|
@@ -710,14 +710,14 @@ var C = (e, t, n) => {
|
|
|
710
710
|
"transaction, the deadlock replay, `afterCommit` and the plugin interceptor",
|
|
711
711
|
"chain wrap an Effect handler exactly as they wrap an async one."
|
|
712
712
|
].join("\n")
|
|
713
|
-
}),
|
|
713
|
+
}), Ie = /\bpasswordHash\b/, Le = /\b(UserStore|UserRecord|memoryUserStore|postgresUserStore)\b/, Re = T({
|
|
714
714
|
version: "0.8.0",
|
|
715
715
|
id: "0.8.0/01_optional-password-hash",
|
|
716
716
|
title: "`UserRecord.passwordHash` is optional — password-less identities are now first-class",
|
|
717
717
|
kind: "manual",
|
|
718
718
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
719
719
|
let t = e.getFullText();
|
|
720
|
-
return
|
|
720
|
+
return Ie.test(t) || Le.test(t);
|
|
721
721
|
}),
|
|
722
722
|
note: [
|
|
723
723
|
"`UserRecord.passwordHash` is now `string | null | undefined`, not `string`.",
|
|
@@ -788,7 +788,7 @@ var C = (e, t, n) => {
|
|
|
788
788
|
" to match and make sure your read path maps a NULL column to `null`/",
|
|
789
789
|
" `undefined` rather than to `''`-by-coercion."
|
|
790
790
|
].join("\n")
|
|
791
|
-
}),
|
|
791
|
+
}), ze = T({
|
|
792
792
|
version: "0.8.0",
|
|
793
793
|
id: "0.8.0/02_ssr-streams-and-loaderdata",
|
|
794
794
|
title: "`ssr` pages stream; `useLoaderData<T>()` returns `LoaderData<T>`",
|
|
@@ -840,13 +840,13 @@ var C = (e, t, n) => {
|
|
|
840
840
|
"docs. `defer()` requires `renderMode: 'ssr'` and `interactive: 'full'`;",
|
|
841
841
|
"every other combination is a hard error naming the page."
|
|
842
842
|
].join("\n")
|
|
843
|
-
}),
|
|
843
|
+
}), Be = /renderMode\s*[=:]\s*['"](spa|client)['"]/, Ve = /(^|[/\\])pages[/\\].*[/\\]?layout\.tsx$/, He = T({
|
|
844
844
|
version: "0.9.0",
|
|
845
845
|
id: "0.9.0/01_ssr-layout-shell-for-spa",
|
|
846
846
|
title: "A `renderMode:'spa'` page under a layout now server-renders that layout",
|
|
847
847
|
kind: "manual",
|
|
848
848
|
appliesTo: ({ project: e }) => {
|
|
849
|
-
let t = e.getSourceFiles(), n = t.some((e) =>
|
|
849
|
+
let t = e.getSourceFiles(), n = t.some((e) => Be.test(e.getFullText())), r = t.some((e) => Ve.test(e.getFilePath()));
|
|
850
850
|
return n && r;
|
|
851
851
|
},
|
|
852
852
|
note: [
|
|
@@ -885,35 +885,35 @@ var C = (e, t, n) => {
|
|
|
885
885
|
"Nothing changes for `static` / `ssr` / `isr` pages, or for a spa page that",
|
|
886
886
|
"has no layout (still a pure client mount)."
|
|
887
887
|
].join("\n")
|
|
888
|
-
}),
|
|
888
|
+
}), k = "client", Ue = "spa", We = (e) => {
|
|
889
889
|
if (!e) return null;
|
|
890
890
|
let t = x.isAsExpression(e) ? e.getExpression() : e;
|
|
891
891
|
return x.isStringLiteral(t) ? t : null;
|
|
892
|
-
},
|
|
892
|
+
}, A = (e) => {
|
|
893
893
|
let t = [];
|
|
894
894
|
for (let n of e.getDescendantsOfKind(S.VariableDeclaration)) {
|
|
895
895
|
if (n.getName() !== "renderMode") continue;
|
|
896
|
-
let e =
|
|
896
|
+
let e = We(n.getInitializer());
|
|
897
897
|
e && t.push(e);
|
|
898
898
|
}
|
|
899
899
|
for (let n of e.getDescendantsOfKind(S.PropertyAssignment)) {
|
|
900
900
|
if (n.getName() !== "renderMode") continue;
|
|
901
|
-
let e =
|
|
901
|
+
let e = We(n.getInitializer());
|
|
902
902
|
e && t.push(e);
|
|
903
903
|
}
|
|
904
904
|
return t;
|
|
905
|
-
},
|
|
905
|
+
}, Ge = T({
|
|
906
906
|
version: "0.10.0",
|
|
907
907
|
id: "0.10.0/01_render-mode-client-to-spa",
|
|
908
908
|
title: "renderMode is a closed set — `'client'` becomes `'spa'`",
|
|
909
909
|
kind: "transform",
|
|
910
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
910
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => A(e).some((e) => e.getLiteralValue() === k)),
|
|
911
911
|
transform: ({ project: e, log: t }) => {
|
|
912
912
|
let n = 0, r = /* @__PURE__ */ new Set();
|
|
913
|
-
for (let t of e.getSourceFiles()) for (let e of
|
|
914
|
-
n > 0 && (t(`renderMode: rewrote ${n} \`'${
|
|
913
|
+
for (let t of e.getSourceFiles()) for (let e of A(t)) e.getLiteralValue() === k && (e.setLiteralValue(Ue), n++, r.add(t.getFilePath()));
|
|
914
|
+
n > 0 && (t(`renderMode: rewrote ${n} \`'${k}'\` → \`'${Ue}'\` in ${r.size} file${r.size === 1 ? "" : "s"}`), t(" → 'spa' is the mode those pages already behaved as: no prerender, client-rendered"), t(" → new in 0.9.0: if such a page sits under a layout, that layout now server-renders (see the note above)"));
|
|
915
915
|
}
|
|
916
|
-
}),
|
|
916
|
+
}), Ke = T({
|
|
917
917
|
version: "0.10.0",
|
|
918
918
|
id: "0.10.0/02_router-state-carries-its-path",
|
|
919
919
|
title: "`renderRouterStateScript` now requires the `path` it rendered",
|
|
@@ -950,7 +950,7 @@ var C = (e, t, n) => {
|
|
|
950
950
|
"Trailing slashes, a trailing `/index.html`, and percent-encoding are normalised",
|
|
951
951
|
"before the comparison, so the usual static-host shapes still hydrate."
|
|
952
952
|
].join("\n")
|
|
953
|
-
}),
|
|
953
|
+
}), qe = T({
|
|
954
954
|
version: "0.10.0",
|
|
955
955
|
id: "0.10.0/03_workflow-caller-context-resolved",
|
|
956
956
|
title: "workflow `buildContext` receives a RESOLVED caller context",
|
|
@@ -996,7 +996,7 @@ var C = (e, t, n) => {
|
|
|
996
996
|
"it receives the resolved context too, so `callerContext?.subject ?? …` there",
|
|
997
997
|
"becomes `callerContext.subject`."
|
|
998
998
|
].join("\n")
|
|
999
|
-
}),
|
|
999
|
+
}), Je = T({
|
|
1000
1000
|
version: "0.10.0",
|
|
1001
1001
|
id: "0.10.0/04_seed-run-status-skipped",
|
|
1002
1002
|
title: "seed run status gained `skipped`",
|
|
@@ -1037,7 +1037,7 @@ var C = (e, t, n) => {
|
|
|
1037
1037
|
"`Schema.Literal`, a zod enum, a DB check constraint), widen it there too — an",
|
|
1038
1038
|
"unlisted third state is a DECODE failure, not a rendering oddity."
|
|
1039
1039
|
].join("\n")
|
|
1040
|
-
}),
|
|
1040
|
+
}), Ye = T({
|
|
1041
1041
|
version: "0.10.0",
|
|
1042
1042
|
id: "0.10.0/05_subscription-idle-state",
|
|
1043
1043
|
title: "`useSubscription` gained an idle state for `skip`",
|
|
@@ -1089,7 +1089,7 @@ var C = (e, t, n) => {
|
|
|
1089
1089
|
"time's data), hold it in your own state — the subscription no longer claims to",
|
|
1090
1090
|
"have data it was told to stop fetching."
|
|
1091
1091
|
].join("\n")
|
|
1092
|
-
}),
|
|
1092
|
+
}), Xe = T({
|
|
1093
1093
|
version: "0.11.0",
|
|
1094
1094
|
id: "0.11.0/01_step-options-type-params",
|
|
1095
1095
|
title: "`StepOptions` takes the context type first",
|
|
@@ -1117,7 +1117,7 @@ var C = (e, t, n) => {
|
|
|
1117
1117
|
"If the step reads nothing from earlier steps, `StepOptions<Record<never, never>,",
|
|
1118
1118
|
"Result>` is the honest spelling."
|
|
1119
1119
|
].join("\n")
|
|
1120
|
-
}),
|
|
1120
|
+
}), Ze = T({
|
|
1121
1121
|
version: "0.12.0",
|
|
1122
1122
|
id: "0.12.0/01_outbound-http-ssrf-guard",
|
|
1123
1123
|
title: "Outbound HttpClient blocks internal targets by default (add `http.allowHosts` if you call one)",
|
|
@@ -1157,7 +1157,7 @@ var C = (e, t, n) => {
|
|
|
1157
1157
|
"private address (DNS rebinding) still passes. Pair with network-layer egress",
|
|
1158
1158
|
"control if that is in your threat model."
|
|
1159
1159
|
].join("\n")
|
|
1160
|
-
}),
|
|
1160
|
+
}), Qe = T({
|
|
1161
1161
|
version: "0.12.0",
|
|
1162
1162
|
id: "0.12.0/02_api-key-revoke-tenant-scope",
|
|
1163
1163
|
title: "apiKeyService.revoke/rotate now require the caller's tenantId",
|
|
@@ -1186,7 +1186,7 @@ var C = (e, t, n) => {
|
|
|
1186
1186
|
"The framework's own `/v1/api-keys/revoke` route already passes the caller's",
|
|
1187
1187
|
"tenant — no change needed if you only use the shipped routes."
|
|
1188
1188
|
].join("\n")
|
|
1189
|
-
}),
|
|
1189
|
+
}), $e = T({
|
|
1190
1190
|
version: "0.12.0",
|
|
1191
1191
|
id: "0.12.0/03_api-key-on-behalf-of",
|
|
1192
1192
|
title: "API keys: createdBy is provenance, onBehalfOf is ownership",
|
|
@@ -1220,7 +1220,7 @@ var C = (e, t, n) => {
|
|
|
1220
1220
|
"specific one against what the body asks for. Grant them in your role map. A key",
|
|
1221
1221
|
"can never carry scopes its issuer does not hold."
|
|
1222
1222
|
].join("\n")
|
|
1223
|
-
}),
|
|
1223
|
+
}), et = T({
|
|
1224
1224
|
version: "0.12.0",
|
|
1225
1225
|
id: "0.12.0/04_inspect-fail-closed",
|
|
1226
1226
|
title: "The inspect surface requires VOLTRO_INSPECT_TOKEN (previously open when unset)",
|
|
@@ -1249,7 +1249,7 @@ var C = (e, t, n) => {
|
|
|
1249
1249
|
"",
|
|
1250
1250
|
"To turn the surface off entirely instead, set `VOLTRO_INSPECT=off`."
|
|
1251
1251
|
].join("\n")
|
|
1252
|
-
}),
|
|
1252
|
+
}), tt = T({
|
|
1253
1253
|
version: "0.13.0",
|
|
1254
1254
|
id: "0.13.0/01_bearer-gates-fail-closed",
|
|
1255
1255
|
title: "checkBearer is fail-closed; scimPlugin refuses an empty token",
|
|
@@ -1286,7 +1286,7 @@ var C = (e, t, n) => {
|
|
|
1286
1286
|
" • `@voltro/plugin-prometheus` already passes `{ openWhenUnset: true }` — its",
|
|
1287
1287
|
" `PROMETHEUS_TOKEN` is documented as optional. Nothing to do there."
|
|
1288
1288
|
].join("\n")
|
|
1289
|
-
}),
|
|
1289
|
+
}), nt = T({
|
|
1290
1290
|
version: "0.13.0",
|
|
1291
1291
|
id: "0.13.0/02_storage-grants-owner-only",
|
|
1292
1292
|
title: "storage.share / revoke / listGrants require ownership",
|
|
@@ -1317,7 +1317,7 @@ var C = (e, t, n) => {
|
|
|
1317
1317
|
" returning the grant or null. `storage.revoke` is handed a grant id, so it has",
|
|
1318
1318
|
" to resolve the object before it can check the owner."
|
|
1319
1319
|
].join("\n")
|
|
1320
|
-
}),
|
|
1320
|
+
}), rt = T({
|
|
1321
1321
|
version: "0.13.0",
|
|
1322
1322
|
id: "0.13.0/03_apply-plan-convergence-proof",
|
|
1323
1323
|
title: "applyPlan requires a `replan` convergence proof",
|
|
@@ -1350,7 +1350,7 @@ var C = (e, t, n) => {
|
|
|
1350
1350
|
" • `AppliedMigration` gained `appliedOps` (operations actually EXECUTED, from",
|
|
1351
1351
|
" the per-op results). If you construct that value in a test fixture, add it."
|
|
1352
1352
|
].join("\n")
|
|
1353
|
-
}),
|
|
1353
|
+
}), it = T({
|
|
1354
1354
|
version: "0.14.0",
|
|
1355
1355
|
id: "0.14.0/01_resolve-scopes-store",
|
|
1356
1356
|
title: "auth.resolveScopes receives the app DataStore",
|
|
@@ -1388,19 +1388,19 @@ var C = (e, t, n) => {
|
|
|
1388
1388
|
" deliberately does not, because only you know how fast a role change must",
|
|
1389
1389
|
" take effect."
|
|
1390
1390
|
].join("\n")
|
|
1391
|
-
}),
|
|
1391
|
+
}), j = (e) => {
|
|
1392
1392
|
if (!x.isCallExpression(e)) return !1;
|
|
1393
1393
|
let t = e.getExpression();
|
|
1394
1394
|
return x.isPropertyAccessExpression(t) && t.getName() === "reactive" && e.getArguments().length === 0;
|
|
1395
|
-
},
|
|
1395
|
+
}, at = (e) => e.getDescendantsOfKind(S.CallExpression).some(j), ot = (e) => {
|
|
1396
1396
|
let t = 0, n = e.getDescendantsOfKind(S.CallExpression);
|
|
1397
1397
|
for (let e of n) {
|
|
1398
|
-
if (e.wasForgotten() || !
|
|
1398
|
+
if (e.wasForgotten() || !j(e)) continue;
|
|
1399
1399
|
let n = e.getExpression();
|
|
1400
1400
|
x.isPropertyAccessExpression(n) && (e.replaceWithText(n.getExpression().getText()), t++);
|
|
1401
1401
|
}
|
|
1402
1402
|
return t;
|
|
1403
|
-
},
|
|
1403
|
+
}, st = T({
|
|
1404
1404
|
version: "0.14.0",
|
|
1405
1405
|
id: "0.14.0/02_reactive-by-default",
|
|
1406
1406
|
title: "Reactivity is the default; .reactive() is removed",
|
|
@@ -1418,16 +1418,16 @@ var C = (e, t, n) => {
|
|
|
1418
1418
|
"real saving: REPLICA IDENTITY FULL widens every UPDATE/DELETE in the WAL.",
|
|
1419
1419
|
"`voltro dev` warns if you opt out a table a query still reads."
|
|
1420
1420
|
].join("\n"),
|
|
1421
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1421
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => at(e)),
|
|
1422
1422
|
transform: ({ project: e, log: t }) => {
|
|
1423
1423
|
let n = 0, r = 0;
|
|
1424
1424
|
for (let t of e.getSourceFiles()) {
|
|
1425
|
-
let e =
|
|
1425
|
+
let e = ot(t);
|
|
1426
1426
|
e !== 0 && (n += e, r++);
|
|
1427
1427
|
}
|
|
1428
1428
|
return n > 0 && t(`removed ${n} .reactive() call(s) across ${r} file(s) — reactivity is the default`), n > 0;
|
|
1429
1429
|
}
|
|
1430
|
-
}),
|
|
1430
|
+
}), ct = T({
|
|
1431
1431
|
version: "0.14.0",
|
|
1432
1432
|
id: "0.14.0/07_dev-remote-file-migrations",
|
|
1433
1433
|
title: "voltro dev refuses unattended file migrations against a remote database",
|
|
@@ -1470,19 +1470,19 @@ var C = (e, t, n) => {
|
|
|
1470
1470
|
"Unchanged: `voltro db files`, `voltro db apply` and `voltro serve`. This gates the",
|
|
1471
1471
|
"AUTOMATIC boot path only; an explicit command is already an explicit decision."
|
|
1472
1472
|
].join("\n")
|
|
1473
|
-
}),
|
|
1474
|
-
let r =
|
|
1473
|
+
}), lt = (e) => [...e.getImportDeclarations(), ...e.getExportDeclarations()], M = (e) => g(e).replace(/\.tsx?$/, ""), ut = (e, t, n) => {
|
|
1474
|
+
let r = M(t), i = M(n);
|
|
1475
1475
|
if (r === i) return;
|
|
1476
1476
|
let a = /\.tsx?$/.exec(e)?.[0] ?? "", o = a === "" ? e : e.slice(0, -a.length);
|
|
1477
1477
|
if (!o.endsWith(`/${r}`) && o !== r) return;
|
|
1478
1478
|
let s = a === "" ? "" : /\.tsx$/.test(n) ? ".tsx" : ".ts";
|
|
1479
1479
|
return `${o.slice(0, o.length - r.length)}${i}${s}`;
|
|
1480
|
-
},
|
|
1480
|
+
}, N = (e, t) => {
|
|
1481
1481
|
let n = e.getFilePath(), r = [];
|
|
1482
|
-
for (let i of e.getProject().getSourceFiles()) for (let e of
|
|
1482
|
+
for (let i of e.getProject().getSourceFiles()) for (let e of lt(i)) {
|
|
1483
1483
|
let i = e.getModuleSpecifierValue();
|
|
1484
1484
|
if (i === void 0 || i.startsWith(".") || e.getModuleSpecifierSourceFile()?.getFilePath() !== n) continue;
|
|
1485
|
-
let a =
|
|
1485
|
+
let a = ut(i, n, t);
|
|
1486
1486
|
a !== void 0 && r.push({
|
|
1487
1487
|
decl: e,
|
|
1488
1488
|
spec: a
|
|
@@ -1491,19 +1491,19 @@ var C = (e, t, n) => {
|
|
|
1491
1491
|
e.move(t);
|
|
1492
1492
|
for (let e of r) e.decl.setModuleSpecifier(e.spec);
|
|
1493
1493
|
return r.length;
|
|
1494
|
-
},
|
|
1494
|
+
}, dt = (e) => {
|
|
1495
1495
|
let t = e.getProject().getCompilerOptions().paths;
|
|
1496
1496
|
if (t === void 0) return;
|
|
1497
|
-
let n =
|
|
1497
|
+
let n = M(e.getFilePath()), r = e.getFilePath().slice(0, e.getFilePath().lastIndexOf("/"));
|
|
1498
1498
|
for (let [e, i] of Object.entries(t)) if (!e.endsWith("*")) for (let t of i ?? []) {
|
|
1499
1499
|
if (!/\.tsx?$/.test(t)) continue;
|
|
1500
|
-
let i =
|
|
1500
|
+
let i = M(t), a = t.slice(0, t.lastIndexOf("/"));
|
|
1501
1501
|
if (i === n && r.endsWith(a.replace(/^\.\//, ""))) return e;
|
|
1502
1502
|
}
|
|
1503
|
-
},
|
|
1503
|
+
}, ft = /\.page\.tsx$/, pt = (e) => {
|
|
1504
1504
|
let t = e.includes("\\src\\pages\\") ? "\\src\\pages\\" : "/src/pages/", n = e.indexOf(t);
|
|
1505
1505
|
return n === -1 ? null : e.slice(0, n);
|
|
1506
|
-
},
|
|
1506
|
+
}, mt = (e) => e.endsWith(".tsx") && !i.has(e) && !d(e) && !/\.island\.tsx$/.test(e) && !ft.test(e), ht = T({
|
|
1507
1507
|
version: "0.14.0",
|
|
1508
1508
|
id: "0.14.0/03_pages-suffix",
|
|
1509
1509
|
title: "Pages are declared with a .page.tsx suffix",
|
|
@@ -1518,8 +1518,8 @@ var C = (e, t, n) => {
|
|
|
1518
1518
|
transform: ({ project: e, log: t }) => {
|
|
1519
1519
|
let n = /* @__PURE__ */ new Map(), r = e.getSourceFiles().filter((t) => {
|
|
1520
1520
|
let r = t.getFilePath();
|
|
1521
|
-
if (!
|
|
1522
|
-
let i =
|
|
1521
|
+
if (!mt(g(r))) return !1;
|
|
1522
|
+
let i = pt(r);
|
|
1523
1523
|
if (i === null) return !1;
|
|
1524
1524
|
let a = n.get(i);
|
|
1525
1525
|
return a === void 0 && (a = e.getSourceFile(v(i, "app.config.ts")) !== void 0 || e.getSourceFile(v(i, "app.config.tsx")) !== void 0, n.set(i, a)), a;
|
|
@@ -1537,13 +1537,13 @@ var C = (e, t, n) => {
|
|
|
1537
1537
|
let n = t.getFilePath(), r = g(n), s = _(n), c = r.slice(0, -4);
|
|
1538
1538
|
for (let t of [".test.tsx", ".spec.tsx"]) {
|
|
1539
1539
|
let n = v(s, `${c}${t}`), r = e.getSourceFile(n);
|
|
1540
|
-
r !== void 0 && (
|
|
1540
|
+
r !== void 0 && (N(r, v(s, `${c}.page${t}`)), o += 1);
|
|
1541
1541
|
}
|
|
1542
|
-
|
|
1542
|
+
N(t, v(s, `${c}.page.tsx`));
|
|
1543
1543
|
let l = i.get(n);
|
|
1544
1544
|
if (l !== void 0 && l.length > 0 && !l.every((e) => d(g(e)))) {
|
|
1545
|
-
let e =
|
|
1546
|
-
a.push(`${
|
|
1545
|
+
let e = pt(n) ?? _(n), t = [...new Set(l)].map((t) => ee(e, t));
|
|
1546
|
+
a.push(`${ee(e, n)} ← imported by ${t.join(", ")}`);
|
|
1547
1547
|
}
|
|
1548
1548
|
}
|
|
1549
1549
|
if (t(`renamed ${r.length} route file(s) to *.page.tsx${o > 0 ? ` (+${o} co-located test file(s))` : ""}`), a.length > 0) {
|
|
@@ -1551,7 +1551,7 @@ var C = (e, t, n) => {
|
|
|
1551
1551
|
for (let e of a) t(` ${e}`);
|
|
1552
1552
|
}
|
|
1553
1553
|
}
|
|
1554
|
-
}),
|
|
1554
|
+
}), gt = [
|
|
1555
1555
|
/\.page\.tsx$/,
|
|
1556
1556
|
c,
|
|
1557
1557
|
s,
|
|
@@ -1562,10 +1562,10 @@ var C = (e, t, n) => {
|
|
|
1562
1562
|
a,
|
|
1563
1563
|
r,
|
|
1564
1564
|
t
|
|
1565
|
-
],
|
|
1565
|
+
], _t = (e) => {
|
|
1566
1566
|
let t = g(e);
|
|
1567
|
-
return !/\.tsx?$/.test(t) || i.has(t) || n(t) || t === "index.ts" || t === "index.tsx" || t === "app.config.ts" ? !1 : !
|
|
1568
|
-
},
|
|
1567
|
+
return !/\.tsx?$/.test(t) || i.has(t) || n(t) || t === "index.ts" || t === "index.tsx" || t === "app.config.ts" ? !1 : !gt.some((e) => e.test(t));
|
|
1568
|
+
}, vt = (e) => {
|
|
1569
1569
|
let t = [], n = [], r = [], i = [];
|
|
1570
1570
|
for (let [a, o] of e.getExportedDeclarations()) {
|
|
1571
1571
|
let e = o[0];
|
|
@@ -1592,10 +1592,10 @@ var C = (e, t, n) => {
|
|
|
1592
1592
|
others: r,
|
|
1593
1593
|
types: i
|
|
1594
1594
|
};
|
|
1595
|
-
},
|
|
1595
|
+
}, yt = (e, t) => {
|
|
1596
1596
|
let { components: n, hooks: r, others: i, types: a } = e;
|
|
1597
1597
|
return n.length + r.length + i.length === 0 ? a.length > 0 ? ".types" : null : t && h(n) && r.length === 0 && i.length === 0 ? ".component.tsx" : n.length === 0 && r.length === 1 && i.length === 0 ? ".hook" : null;
|
|
1598
|
-
},
|
|
1598
|
+
}, bt = T({
|
|
1599
1599
|
version: "0.14.0",
|
|
1600
1600
|
id: "0.14.0/04_file-taxonomy",
|
|
1601
1601
|
title: "Web files declare their contract (*.component.tsx / *.hook.ts / *.types.ts)",
|
|
@@ -1608,19 +1608,19 @@ var C = (e, t, n) => {
|
|
|
1608
1608
|
if (s.length > 0) for (let e of s) t(` exempt (not ours): ${e.dir} — ${e.source}`);
|
|
1609
1609
|
for (let t of e.getSourceFiles()) {
|
|
1610
1610
|
let e = t.getFilePath();
|
|
1611
|
-
if (!
|
|
1612
|
-
let o =
|
|
1611
|
+
if (!_t(e) || p(e, s)) continue;
|
|
1612
|
+
let o = dt(t);
|
|
1613
1613
|
if (o !== void 0) {
|
|
1614
1614
|
a.push(`${g(e)} (tsconfig paths: "${o}")`);
|
|
1615
1615
|
continue;
|
|
1616
1616
|
}
|
|
1617
|
-
let c = e.endsWith(".tsx"), l =
|
|
1617
|
+
let c = e.endsWith(".tsx"), l = vt(t), u = yt(l, c);
|
|
1618
1618
|
if (u === null) {
|
|
1619
1619
|
l.components.length > 0 && l.hooks.length > 0 && r.push(`${g(e)} (component ${l.components.join("/")} + hook ${l.hooks.join("/")})`);
|
|
1620
1620
|
continue;
|
|
1621
1621
|
}
|
|
1622
1622
|
let d = g(e).replace(/\.tsx?$/, ""), f = u === ".component.tsx" ? ".component.tsx" : `${u}${c ? ".tsx" : ".ts"}`;
|
|
1623
|
-
i +=
|
|
1623
|
+
i += N(t, v(_(e), `${d}${f}`)), n.push(`${d}${f}`);
|
|
1624
1624
|
}
|
|
1625
1625
|
if (n.length > 0 && (t(`declared ${n.length} file(s): component / hook / types`), i > 0 && t(` rewrote ${i} aliased import specifier(s) (@/… and friends)`)), a.length > 0) {
|
|
1626
1626
|
t(""), t(`left alone — a tsconfig \`paths\` entry names ${a.length} of these files directly:`);
|
|
@@ -1633,7 +1633,7 @@ var C = (e, t, n) => {
|
|
|
1633
1633
|
r.length > 20 && t(` (+${r.length - 20} more)`);
|
|
1634
1634
|
}
|
|
1635
1635
|
}
|
|
1636
|
-
}),
|
|
1636
|
+
}), xt = T({
|
|
1637
1637
|
version: "0.14.0",
|
|
1638
1638
|
id: "0.14.0/05_typed-tracking",
|
|
1639
1639
|
title: "Tracking catalogues are typed against the component props",
|
|
@@ -1670,7 +1670,7 @@ var C = (e, t, n) => {
|
|
|
1670
1670
|
"Read each one before changing it: a cast that no longer compiles is sometimes",
|
|
1671
1671
|
"a real type disagreement the old signature was hiding."
|
|
1672
1672
|
].join("\n")
|
|
1673
|
-
}),
|
|
1673
|
+
}), St = T({
|
|
1674
1674
|
version: "0.14.0",
|
|
1675
1675
|
id: "0.14.0/06_voltro-test-skips-e2e",
|
|
1676
1676
|
title: "`voltro test` leaves `e2e/` to `voltro e2e`",
|
|
@@ -1692,13 +1692,13 @@ var C = (e, t, n) => {
|
|
|
1692
1692
|
" code it tests, or",
|
|
1693
1693
|
" • pass your own `--exclude`, which overrides the framework default outright."
|
|
1694
1694
|
].join("\n")
|
|
1695
|
-
}),
|
|
1695
|
+
}), Ct = (e) => {
|
|
1696
1696
|
let t = e.replace(/\.component(\.ui)?(\.tsx?)$/, "$2");
|
|
1697
1697
|
return t === e ? null : n(t) ? t : null;
|
|
1698
|
-
},
|
|
1698
|
+
}, wt = (e) => {
|
|
1699
1699
|
for (let [, t] of e.getExportedDeclarations()) if (t[0] !== void 0) return !1;
|
|
1700
1700
|
return e.getExportDeclarations().length === 0 && e.getExportAssignments().length === 0;
|
|
1701
|
-
},
|
|
1701
|
+
}, Tt = T({
|
|
1702
1702
|
version: "0.15.0",
|
|
1703
1703
|
id: "0.15.0/01_undo-mistaken-taxonomy-renames",
|
|
1704
1704
|
title: "Undo the two file renames 0.14.0 got wrong (framework primitives, side-effect modules)",
|
|
@@ -1715,14 +1715,14 @@ var C = (e, t, n) => {
|
|
|
1715
1715
|
transform: ({ project: e, log: t }) => {
|
|
1716
1716
|
let n = [], r = [];
|
|
1717
1717
|
for (let t of e.getSourceFiles()) {
|
|
1718
|
-
let e = t.getFilePath(), i = g(e), a =
|
|
1718
|
+
let e = t.getFilePath(), i = g(e), a = Ct(i);
|
|
1719
1719
|
if (a !== null) {
|
|
1720
|
-
|
|
1720
|
+
N(t, v(_(e), a)), n.push(`${i} → ${a}`);
|
|
1721
1721
|
continue;
|
|
1722
1722
|
}
|
|
1723
|
-
if (/\.types\.tsx?$/.test(i) &&
|
|
1723
|
+
if (/\.types\.tsx?$/.test(i) && wt(t)) {
|
|
1724
1724
|
let n = i.replace(/\.types(\.tsx?)$/, "$1");
|
|
1725
|
-
|
|
1725
|
+
N(t, v(_(e), n)), r.push(`${i} → ${n}`);
|
|
1726
1726
|
}
|
|
1727
1727
|
}
|
|
1728
1728
|
if (n.length > 0) {
|
|
@@ -1736,16 +1736,16 @@ var C = (e, t, n) => {
|
|
|
1736
1736
|
}
|
|
1737
1737
|
n.length === 0 && r.length === 0 && t("nothing to undo — 0.14.0 renamed neither a framework file nor a side-effect module here.");
|
|
1738
1738
|
}
|
|
1739
|
-
}),
|
|
1739
|
+
}), Et = ["@voltro/client", "@voltro/web"], P = "@voltro/protocol", Dt = T({
|
|
1740
1740
|
version: "0.15.0",
|
|
1741
1741
|
id: "0.15.0/02_error-tag-in-protocol",
|
|
1742
1742
|
title: "`errorTag` is imported from @voltro/protocol",
|
|
1743
1743
|
kind: "transform",
|
|
1744
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) =>
|
|
1744
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => Et.includes(e.getModuleSpecifierValue()) && e.getNamedImports().some((e) => e.getName() === "errorTag"))),
|
|
1745
1745
|
transform: ({ project: e, log: t }) => {
|
|
1746
1746
|
let n = 0;
|
|
1747
1747
|
for (let t of e.getSourceFiles()) for (let e of t.getImportDeclarations()) {
|
|
1748
|
-
if (!
|
|
1748
|
+
if (!Et.includes(e.getModuleSpecifierValue())) continue;
|
|
1749
1749
|
let r = e.getNamedImports().find((e) => e.getName() === "errorTag");
|
|
1750
1750
|
if (r === void 0) continue;
|
|
1751
1751
|
let i = r.getAliasNode()?.getText(), a = e.isTypeOnly() || r.isTypeOnly();
|
|
@@ -1802,7 +1802,7 @@ var C = (e, t, n) => {
|
|
|
1802
1802
|
}
|
|
1803
1803
|
}
|
|
1804
1804
|
let l = [], u = 0;
|
|
1805
|
-
for (let e of r) s.has(e.from) || (u +=
|
|
1805
|
+
for (let e of r) s.has(e.from) || (u += N(e.sf, e.to), e.isTest || l.push(o(e.to)));
|
|
1806
1806
|
if (l.length > 0 && (t(`moved ${l.length} route(s) into their own directory`), u > 0 && t(` rewrote ${u} aliased import specifier(s)`)), c.length > 0) {
|
|
1807
1807
|
t(""), t(`LEFT ALONE — ${c.length} case(s) where two files claim one route:`);
|
|
1808
1808
|
for (let e of c) t(` ${e}`);
|
|
@@ -2388,19 +2388,19 @@ var C = (e, t, n) => {
|
|
|
2388
2388
|
}), cn = (e) => e.getDescendantsOfKind(S.CallExpression).filter((e) => {
|
|
2389
2389
|
let t = e.getExpression().getText();
|
|
2390
2390
|
return t === "broadcast" || t === "broadcastPlugin";
|
|
2391
|
-
}),
|
|
2391
|
+
}), ln = (e) => {
|
|
2392
2392
|
let t = e.getArguments()[0];
|
|
2393
2393
|
if (!(t === void 0 || !t.isKind(S.ObjectLiteralExpression))) return t.getProperties().filter((e) => e.isKind(S.PropertyAssignment)).map((e) => e.asKindOrThrow(S.PropertyAssignment)).find((e) => e.getName() === "channel");
|
|
2394
|
-
},
|
|
2394
|
+
}, un = T({
|
|
2395
2395
|
version: "0.25.0",
|
|
2396
2396
|
id: "0.25.0/03_broadcast-channel-to-namespace",
|
|
2397
2397
|
title: "`broadcast({ channel })` → `broadcast({ namespace })`",
|
|
2398
2398
|
kind: "transform",
|
|
2399
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => cn(e).some((e) =>
|
|
2399
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => cn(e).some((e) => ln(e) !== void 0)),
|
|
2400
2400
|
transform: ({ project: e, log: t }) => {
|
|
2401
2401
|
let n = 0, r = [], i = [], a = /* @__PURE__ */ new Set();
|
|
2402
2402
|
for (let t of e.getSourceFiles()) for (let e of cn(t)) {
|
|
2403
|
-
let o =
|
|
2403
|
+
let o = ln(e);
|
|
2404
2404
|
if (o === void 0) continue;
|
|
2405
2405
|
let s = o.getInitializer();
|
|
2406
2406
|
if (s === void 0) continue;
|
|
@@ -2417,7 +2417,7 @@ var C = (e, t, n) => {
|
|
|
2417
2417
|
for (let e of i) t(` ! ${e} — carried verbatim; CHECK IT: the value is now a PREFIX the framework`), t(" appends ':changes' / ':events:<name>' / ':members' / ':presence' to.");
|
|
2418
2418
|
}
|
|
2419
2419
|
}
|
|
2420
|
-
}),
|
|
2420
|
+
}), dn = T({
|
|
2421
2421
|
version: "0.26.0",
|
|
2422
2422
|
id: "0.26.0/01_event-webhook-retry-removed",
|
|
2423
2423
|
title: "`defineEvent({ webhook: { retry } })` is gone — it never did anything",
|
|
@@ -2451,7 +2451,7 @@ var C = (e, t, n) => {
|
|
|
2451
2451
|
"If you were relying on the declared value to take effect, note that it never",
|
|
2452
2452
|
"did — your deliveries have been using the target default all along."
|
|
2453
2453
|
].join("\n")
|
|
2454
|
-
}),
|
|
2454
|
+
}), fn = T({
|
|
2455
2455
|
version: "0.26.0",
|
|
2456
2456
|
id: "0.26.0/02_step-retry-enforced",
|
|
2457
2457
|
title: "workflow step `retry:` is now ENFORCED (was metadata) — drop any redundant manual retry",
|
|
@@ -2504,12 +2504,12 @@ var C = (e, t, n) => {
|
|
|
2504
2504
|
"(retry transient, fail permanent), `maxElapsed: '5 minutes'` (a total time budget,",
|
|
2505
2505
|
"not just a count), `jitter` (on by default), and `respectRetryAfter` (honor a 429)."
|
|
2506
2506
|
].join("\n")
|
|
2507
|
-
}),
|
|
2507
|
+
}), pn = /\bmakeSubjectId\b/, mn = T({
|
|
2508
2508
|
version: "0.28.0",
|
|
2509
2509
|
id: "0.28.0/01_notifications-resolve-subject-id-async",
|
|
2510
2510
|
title: "`makeSubjectId` returns a Promise; `resolveSubjectId` may be async",
|
|
2511
2511
|
kind: "manual",
|
|
2512
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2512
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => pn.test(e.getFullText())),
|
|
2513
2513
|
note: [
|
|
2514
2514
|
"`makeSubjectId` from @voltro/plugin-notifications now returns a Promise.",
|
|
2515
2515
|
"",
|
|
@@ -2541,12 +2541,12 @@ var C = (e, t, n) => {
|
|
|
2541
2541
|
" reconnect. Memoise inside your own resolver if that trade suits your app —",
|
|
2542
2542
|
" you know your invalidation and we do not."
|
|
2543
2543
|
].join("\n")
|
|
2544
|
-
}),
|
|
2544
|
+
}), hn = /\bPluginRefChange\b|\bisSoftDelete\s*\(|\bapplyPluginRefRules\s*\(/, gn = T({
|
|
2545
2545
|
version: "0.28.0",
|
|
2546
2546
|
id: "0.28.0/02_plugin-ref-change-event",
|
|
2547
2547
|
title: "`PluginRefChange` is removed — the change channel's `ChangeEvent` is the one shape",
|
|
2548
2548
|
kind: "manual",
|
|
2549
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2549
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => hn.test(e.getFullText())),
|
|
2550
2550
|
note: [
|
|
2551
2551
|
"`PluginRefChange` no longer exists. `isSoftDelete` and `applyPluginRefRules`",
|
|
2552
2552
|
"take `ChangeEvent` from @voltro/database — the type the change channel actually",
|
|
@@ -2588,12 +2588,12 @@ var C = (e, t, n) => {
|
|
|
2588
2588
|
" not know that writes a delete, and the test passes against a stream the",
|
|
2589
2589
|
" framework never emits. That is the defect this change removes."
|
|
2590
2590
|
].join("\n")
|
|
2591
|
-
}),
|
|
2591
|
+
}), _n = /credentialsResolver\s*:/, vn = T({
|
|
2592
2592
|
version: "0.28.0",
|
|
2593
2593
|
id: "0.28.0/03_atlassian-credentials-context",
|
|
2594
2594
|
title: "`credentialsResolver` receives `{ subject, store }` instead of a bare Subject",
|
|
2595
2595
|
kind: "manual",
|
|
2596
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2596
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => _n.test(e.getFullText())),
|
|
2597
2597
|
note: [
|
|
2598
2598
|
"@voltro/plugin-atlassian: `credentialsResolver` now takes a context object.",
|
|
2599
2599
|
"",
|
|
@@ -2663,12 +2663,12 @@ var C = (e, t, n) => {
|
|
|
2663
2663
|
"",
|
|
2664
2664
|
"and rotate anything you find — a redacted future does not un-leak a past row."
|
|
2665
2665
|
].join("\n")
|
|
2666
|
-
}),
|
|
2666
|
+
}), yn = /auditPlugin\s*\(/, bn = T({
|
|
2667
2667
|
version: "0.28.0",
|
|
2668
2668
|
id: "0.28.0/04_audit-redacts-subject-metadata",
|
|
2669
2669
|
title: "`auditPlugin` redacts `subject.metadata` by default",
|
|
2670
2670
|
kind: "manual",
|
|
2671
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2671
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => yn.test(e.getFullText())),
|
|
2672
2672
|
note: [
|
|
2673
2673
|
"`auditPlugin` now redacts `subject.metadata` before the sink sees the event.",
|
|
2674
2674
|
"",
|
|
@@ -2724,12 +2724,12 @@ var C = (e, t, n) => {
|
|
|
2724
2724
|
" keeps the token in the framework vault, and the resolver's new `store`",
|
|
2725
2725
|
" handle covers an app with its own token table."
|
|
2726
2726
|
].join("\n")
|
|
2727
|
-
}),
|
|
2727
|
+
}), xn = E("useLoaderData"), Sn = T({
|
|
2728
2728
|
version: "0.29.0",
|
|
2729
2729
|
id: "0.29.0/01_loader-data-absence",
|
|
2730
2730
|
title: "`useLoaderData()` throws at a level that declares no `loader`",
|
|
2731
2731
|
kind: "manual",
|
|
2732
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2732
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => xn.test(e.getFullText())),
|
|
2733
2733
|
note: [
|
|
2734
2734
|
"`useLoaderData()` used to return `undefined` at a level with no `loader`,",
|
|
2735
2735
|
"which then died at `Cannot destructure property 'x' of undefined` — a",
|
|
@@ -2765,24 +2765,24 @@ var C = (e, t, n) => {
|
|
|
2765
2765
|
"that legitimately resolves to `undefined` does not throw — only a missing",
|
|
2766
2766
|
"`loader` does."
|
|
2767
2767
|
].join("\n")
|
|
2768
|
-
}),
|
|
2768
|
+
}), I = "@voltro/ui-shadcn", L = "voltro:lang", Cn = "voltro:locale", R = "parsePreferenceCookies", wn = (e, t) => {
|
|
2769
2769
|
let n = [];
|
|
2770
|
-
for (let r of e.getImportDeclarations()) if (r.getModuleSpecifierValue() ===
|
|
2770
|
+
for (let r of e.getImportDeclarations()) if (r.getModuleSpecifierValue() === I) for (let e of r.getNamedImports()) e.getName() === t && n.push(e.getAliasNode()?.getText() ?? e.getName());
|
|
2771
2771
|
return n;
|
|
2772
|
-
},
|
|
2772
|
+
}, Tn = (e) => {
|
|
2773
2773
|
let t = 0;
|
|
2774
|
-
for (let n of e.getSourceFiles()) n.getFullText().includes(
|
|
2774
|
+
for (let n of e.getSourceFiles()) n.getFullText().includes(L) && n.forEachDescendant((e) => {
|
|
2775
2775
|
if (x.isStringLiteral(e) || x.isNoSubstitutionTemplateLiteral(e) || x.isTemplateHead(e) || x.isTemplateMiddle(e) || x.isTemplateTail(e) || x.isRegularExpressionLiteral(e)) {
|
|
2776
2776
|
let n = e.getText();
|
|
2777
|
-
if (!n.includes(
|
|
2778
|
-
e.replaceWithText(n.split(
|
|
2777
|
+
if (!n.includes(L)) return;
|
|
2778
|
+
e.replaceWithText(n.split(L).join(Cn)), t++;
|
|
2779
2779
|
}
|
|
2780
2780
|
});
|
|
2781
2781
|
return t;
|
|
2782
|
-
},
|
|
2782
|
+
}, En = (e) => {
|
|
2783
2783
|
let t = 0, n = 0;
|
|
2784
2784
|
for (let r of e.getSourceFiles()) {
|
|
2785
|
-
let e =
|
|
2785
|
+
let e = wn(r, R);
|
|
2786
2786
|
e.length !== 0 && r.forEachDescendant((r) => {
|
|
2787
2787
|
if (!x.isCallExpression(r) || !e.includes(r.getExpression().getText())) return;
|
|
2788
2788
|
let i = r.getParent();
|
|
@@ -2805,29 +2805,29 @@ var C = (e, t, n) => {
|
|
|
2805
2805
|
access: t,
|
|
2806
2806
|
destructured: n
|
|
2807
2807
|
};
|
|
2808
|
-
},
|
|
2808
|
+
}, Dn = T({
|
|
2809
2809
|
version: "0.30.0",
|
|
2810
2810
|
id: "0.30.0/01_locale-cookie-rename",
|
|
2811
2811
|
title: "the language-preference cookie is `voltro:locale` (was `voltro:lang`)",
|
|
2812
2812
|
kind: "transform",
|
|
2813
2813
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
2814
2814
|
let t = e.getFullText();
|
|
2815
|
-
return t.includes(
|
|
2815
|
+
return t.includes(L) || t.includes(I) && (t.includes("LANG_COOKIE") || t.includes(R));
|
|
2816
2816
|
}),
|
|
2817
2817
|
transform: ({ project: e, helpers: t, log: n }) => {
|
|
2818
2818
|
let r = t.renameImport(e, {
|
|
2819
|
-
module:
|
|
2819
|
+
module: I,
|
|
2820
2820
|
from: "LANG_COOKIE",
|
|
2821
2821
|
to: "LOCALE_COOKIE"
|
|
2822
|
-
}), i =
|
|
2822
|
+
}), i = Tn(e), { access: a, destructured: o } = En(e), s = [];
|
|
2823
2823
|
r > 0 && s.push(`LANG_COOKIE → LOCALE_COOKIE (${r} import(s))`), i > 0 && s.push(`'voltro:lang' → 'voltro:locale' (${i} literal(s))`), a + o > 0 && s.push(`parsePreferenceCookies().lang → .locale (${a + o} site(s))`), s.length !== 0 && n(`locale cookie rename: ${s.join("; ")}. Your SOURCE is migrated. Your USERS' cookies are not — the old \`voltro:lang\` cookie in an already-visited browser is no longer read, so each user falls back to Accept-Language / defaultLocale once and re-picks their language. Nothing errors. If that reset is unacceptable, copy the old value forward at your own boot — the codemod file has the three-line bridge.` + (o > 0 ? ` ${o} destructure(s) were rewritten as \`{ locale: lang }\` to keep the local name safe from a scope collision — rename the binding yourself if you want the vocabulary to match.` : ""));
|
|
2824
2824
|
}
|
|
2825
|
-
}),
|
|
2825
|
+
}), On = /auditPlugin\s*\(|versioningPlugin\s*\(|atlassianPlugin\s*\(/, kn = T({
|
|
2826
2826
|
version: "0.30.0",
|
|
2827
2827
|
id: "0.30.0/02_audit-purge-query-recheck",
|
|
2828
2828
|
title: "re-run the credential-purge query — the 0.28.0 spelling under-reported on MySQL/MariaDB",
|
|
2829
2829
|
kind: "manual",
|
|
2830
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2830
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => On.test(e.getFullText())),
|
|
2831
2831
|
note: [
|
|
2832
2832
|
"IF YOU ALREADY RAN THE 0.28.0 PURGE CHECK ON MySQL OR MariaDB, RUN IT AGAIN.",
|
|
2833
2833
|
"The query that note shipped under-reported, and it under-reported by",
|
|
@@ -2874,14 +2874,14 @@ var C = (e, t, n) => {
|
|
|
2874
2874
|
" `connectionCredentials(...)` keeps it in the framework vault",
|
|
2875
2875
|
" (see `0.28.0/03_atlassian-credentials-context`)."
|
|
2876
2876
|
].join("\n")
|
|
2877
|
-
}),
|
|
2877
|
+
}), An = /\.webhooks\s*\.\s*emit\s*\(|useWebhooks\s*\(/, jn = T({
|
|
2878
2878
|
version: "0.30.0",
|
|
2879
2879
|
id: "0.30.0/03_webhook-emit-durable-deferral",
|
|
2880
2880
|
title: "a deferred `webhooks.emit` rides the transactional outbox; `{ immediate: true }` opts out",
|
|
2881
2881
|
kind: "manual",
|
|
2882
2882
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
2883
2883
|
let t = e.getFullText();
|
|
2884
|
-
return
|
|
2884
|
+
return An.test(t) || E("emit").test(t);
|
|
2885
2885
|
}),
|
|
2886
2886
|
note: [
|
|
2887
2887
|
"A `ctx.webhooks.emit(...)` inside a MUTATION now enqueues a transactional",
|
|
@@ -2931,14 +2931,14 @@ var C = (e, t, n) => {
|
|
|
2931
2931
|
"created by the declarative differ on the next `voltro dev` boot or",
|
|
2932
2932
|
"`voltro db apply` — there is nothing to run by hand."
|
|
2933
2933
|
].join("\n")
|
|
2934
|
-
}),
|
|
2934
|
+
}), Mn = /\.executionId\b|workflows\s*\.\s*start\s*\(|workflows\s*\.\s*child\s*\(/, Nn = T({
|
|
2935
2935
|
version: "0.30.0",
|
|
2936
2936
|
id: "0.30.0/04_workflow-run-handle-nullable-execution",
|
|
2937
2937
|
title: "`WorkflowRunHandle.executionId` is `string | null`; `status` gains queued/dropped/skipped",
|
|
2938
2938
|
kind: "manual",
|
|
2939
2939
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
2940
2940
|
let t = e.getFullText();
|
|
2941
|
-
return
|
|
2941
|
+
return Mn.test(t) || E("start").test(t);
|
|
2942
2942
|
}),
|
|
2943
2943
|
note: [
|
|
2944
2944
|
"A workflow start no longer always becomes a run. With declarative flow",
|
|
@@ -3003,12 +3003,12 @@ var C = (e, t, n) => {
|
|
|
3003
3003
|
" and `singleton: { mode: 'skip' }` throws `WorkflowSingletonHeldError`",
|
|
3004
3004
|
" carrying the incumbent's execution id, so you can wait on THAT run."
|
|
3005
3005
|
].join("\n")
|
|
3006
|
-
}),
|
|
3006
|
+
}), Pn = /auditPlugin\s*\(|versioningPlugin\s*\(|atlassianPlugin\s*\(/, Fn = T({
|
|
3007
3007
|
version: "0.31.0",
|
|
3008
3008
|
id: "0.31.0/01_rerun-credential-scan",
|
|
3009
3009
|
title: "re-run `voltro db scan-credentials` — on 0.30.0–0.30.2 it skipped the column credentials land in",
|
|
3010
3010
|
kind: "manual",
|
|
3011
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
3011
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Pn.test(e.getFullText())),
|
|
3012
3012
|
note: [
|
|
3013
3013
|
"IF YOU RAN `voltro db scan-credentials` ON 0.30.0, 0.30.1 OR 0.30.2, RUN IT",
|
|
3014
3014
|
"AGAIN. Its answer did not cover the column a leaked credential is most",
|
|
@@ -3042,7 +3042,7 @@ var C = (e, t, n) => {
|
|
|
3042
3042
|
"credential on the Subject — `connectionCredentials(...)` keeps it in the",
|
|
3043
3043
|
"framework vault."
|
|
3044
3044
|
].join("\n")
|
|
3045
|
-
}),
|
|
3045
|
+
}), In = T({
|
|
3046
3046
|
version: "0.32.0",
|
|
3047
3047
|
id: "0.32.0/01_audit-redacts-outcome",
|
|
3048
3048
|
title: "`auditPlugin` now redacts `outcome` by default — opt out if your trail reads it",
|
|
@@ -3083,7 +3083,7 @@ var C = (e, t, n) => {
|
|
|
3083
3083
|
"purge the rows AND rotate the credentials — assume anything written to a",
|
|
3084
3084
|
"log table has been read."
|
|
3085
3085
|
].join("\n")
|
|
3086
|
-
}),
|
|
3086
|
+
}), Ln = T({
|
|
3087
3087
|
version: "0.33.0",
|
|
3088
3088
|
id: "0.33.0/01_opentelemetry-optional-peer",
|
|
3089
3089
|
title: "`@effect/opentelemetry` is now an optional peer — install it if you use tracing",
|
|
@@ -3115,7 +3115,7 @@ var C = (e, t, n) => {
|
|
|
3115
3115
|
"never wrote down. It is a startup failure, not a silent loss of traces —",
|
|
3116
3116
|
"losing telemetry quietly would be the worse outcome."
|
|
3117
3117
|
].join("\n")
|
|
3118
|
-
}),
|
|
3118
|
+
}), Rn = T({
|
|
3119
3119
|
version: "0.33.0",
|
|
3120
3120
|
id: "0.33.0/02_coordinated-handle-gained-wake",
|
|
3121
3121
|
title: "`CoordinatedScheduleHandle` gained `wake()`, `currentIntervalMs()` and `isArmed()` — update hand-written test doubles",
|
|
@@ -3165,7 +3165,7 @@ var C = (e, t, n) => {
|
|
|
3165
3165
|
"Reporting nothing is the conservative default on purpose — a task that",
|
|
3166
3166
|
"cannot tell whether it was idle must not be slowed down on a guess."
|
|
3167
3167
|
].join("\n")
|
|
3168
|
-
}),
|
|
3168
|
+
}), zn = T({
|
|
3169
3169
|
version: "0.34.0",
|
|
3170
3170
|
id: "0.34.0/01_serve-does-mount-inspect",
|
|
3171
3171
|
title: "Correction: `voltro serve` DOES mount an inspect surface (the 0.12.0 note said it mounts none)",
|
|
@@ -3206,12 +3206,12 @@ var C = (e, t, n) => {
|
|
|
3206
3206
|
"place, everyone already past 0.12.0 — which is everyone the wrong sentence",
|
|
3207
3207
|
"could have misled — would never have seen it."
|
|
3208
3208
|
].join("\n")
|
|
3209
|
-
}),
|
|
3209
|
+
}), Bn = (e) => /\.with\(\s*[\w.]*tenant\(/.test(e) || /\.serverOnly\(\s*\)/.test(e), Vn = T({
|
|
3210
3210
|
version: "0.34.0",
|
|
3211
3211
|
id: "0.34.0/02_keyed-writes-are-tenant-scoped",
|
|
3212
3212
|
title: "Keyed-by-pk writes are tenant-enforced, and `crud` refuses `.serverOnly()` input",
|
|
3213
3213
|
kind: "manual",
|
|
3214
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
3214
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Bn(e.getFullText())),
|
|
3215
3215
|
note: [
|
|
3216
3216
|
"TWO WRITE-SIDE REFUSALS ARE NEW. Neither changes a type, so `tsc` will not",
|
|
3217
3217
|
"point at the call sites — these are runtime behaviour changes.",
|
|
@@ -3275,12 +3275,12 @@ var C = (e, t, n) => {
|
|
|
3275
3275
|
" an attack look like a no-op and leaves an honest caller debugging a",
|
|
3276
3276
|
" value that quietly did not land."
|
|
3277
3277
|
].join("\n")
|
|
3278
|
-
}),
|
|
3278
|
+
}), Hn = /* @__PURE__ */ new Set([
|
|
3279
3279
|
"defineQuery",
|
|
3280
3280
|
"defineMutation",
|
|
3281
3281
|
"defineAction",
|
|
3282
3282
|
"defineStream"
|
|
3283
|
-
]),
|
|
3283
|
+
]), Un = (e) => {
|
|
3284
3284
|
let t = e.getArguments()[0];
|
|
3285
3285
|
if (t === void 0 || !t.isKind(S.ObjectLiteralExpression)) return /* @__PURE__ */ new Set();
|
|
3286
3286
|
let n = /* @__PURE__ */ new Set();
|
|
@@ -3289,16 +3289,16 @@ var C = (e, t, n) => {
|
|
|
3289
3289
|
t !== void 0 && n.add(t);
|
|
3290
3290
|
}
|
|
3291
3291
|
return n;
|
|
3292
|
-
},
|
|
3293
|
-
if (!
|
|
3294
|
-
let t =
|
|
3292
|
+
}, Wn = (e, t) => /define(Query|Mutation|Action|Stream)\s*\(/.test(e) ? t.some((e) => {
|
|
3293
|
+
if (!Hn.has(e.getExpression().getText())) return !1;
|
|
3294
|
+
let t = Un(e);
|
|
3295
3295
|
return !t.has("internal") && !t.has("guards") && !t.has("openAccess");
|
|
3296
|
-
}) : !1,
|
|
3296
|
+
}) : !1, Gn = T({
|
|
3297
3297
|
version: "0.34.0",
|
|
3298
3298
|
id: "0.34.0/03_procedure-access-decision",
|
|
3299
3299
|
title: "Every wire-exposed procedure declares an access decision (`guards:` or `openAccess:`)",
|
|
3300
3300
|
kind: "manual",
|
|
3301
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
3301
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Wn(e.getFullText(), e.getDescendantsOfKind(S.CallExpression))),
|
|
3302
3302
|
note: [
|
|
3303
3303
|
"YOUR APP WILL NOT BOOT UNTIL EVERY WIRE-EXPOSED PROCEDURE DECIDES WHO MAY",
|
|
3304
3304
|
"CALL IT. This is the single largest behaviour change in this release, and it",
|
|
@@ -3343,18 +3343,18 @@ var C = (e, t, n) => {
|
|
|
3343
3343
|
"procedures your PLUGINS declare — the gate reads your app's own discovered",
|
|
3344
3344
|
"files only, so adopting this does not turn into a plugin bug report."
|
|
3345
3345
|
].join("\n")
|
|
3346
|
-
}),
|
|
3346
|
+
}), Kn = [
|
|
3347
3347
|
"workosAuthorizationUrl",
|
|
3348
3348
|
"workosAuthenticateWithCode",
|
|
3349
3349
|
"workosBeginLogin"
|
|
3350
|
-
],
|
|
3350
|
+
], qn = T({
|
|
3351
3351
|
version: "0.34.0",
|
|
3352
3352
|
id: "0.34.0/04_workos-oauth-state-pkce",
|
|
3353
3353
|
title: "WorkOS hosted login: `workosAuthorizationUrl` → `workosBeginLogin`, with mandatory `state` + PKCE",
|
|
3354
3354
|
kind: "manual",
|
|
3355
3355
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
3356
3356
|
let t = e.getFullText();
|
|
3357
|
-
return t.includes("@voltro/plugin-auth-workos") &&
|
|
3357
|
+
return t.includes("@voltro/plugin-auth-workos") && Kn.some((e) => t.includes(e));
|
|
3358
3358
|
}),
|
|
3359
3359
|
note: [
|
|
3360
3360
|
"YOUR WORKOS HOSTED-LOGIN FLOW HAD NO CSRF PROTECTION BY DEFAULT, AND NO PKCE.",
|
|
@@ -3412,12 +3412,12 @@ var C = (e, t, n) => {
|
|
|
3412
3412
|
"are accepted on the existing endpoints; your registered redirect URI is",
|
|
3413
3413
|
"unchanged."
|
|
3414
3414
|
].join("\n")
|
|
3415
|
-
}),
|
|
3415
|
+
}), Jn = /mirrorTables|_?voltro_mirror_/, Yn = T({
|
|
3416
3416
|
version: "0.34.0",
|
|
3417
3417
|
id: "0.34.0/05_analytics-mirror-versioned-writes",
|
|
3418
3418
|
title: "Analytics CDC-mirror: version-ordered writes, tombstoned deletes, retry + repair",
|
|
3419
3419
|
kind: "manual",
|
|
3420
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
3420
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Jn.test(e.getFullText())),
|
|
3421
3421
|
note: [
|
|
3422
3422
|
"The analytics CDC-mirror (`mirrorTables`) now orders every write and",
|
|
3423
3423
|
"retries the ones that fail. Three things to do.",
|
|
@@ -3472,7 +3472,7 @@ var C = (e, t, n) => {
|
|
|
3472
3472
|
" VOLTRO_ANALYTICS_MIRROR_REPAIR_INTERVAL_MS (60000, 0 disables)",
|
|
3473
3473
|
" VOLTRO_ANALYTICS_MIRROR_REPAIR_QUEUE_LIMIT (10000)"
|
|
3474
3474
|
].join("\n")
|
|
3475
|
-
}),
|
|
3475
|
+
}), Xn = T({
|
|
3476
3476
|
version: "0.34.0",
|
|
3477
3477
|
id: "0.34.0/06_origin-guard-and-trusted-proxies",
|
|
3478
3478
|
title: "Cross-site protection, trusted proxies and security headers are ON by default on the api listener",
|
|
@@ -3596,7 +3596,7 @@ var C = (e, t, n) => {
|
|
|
3596
3596
|
" a `Transfer-Encoding: chunked` body skipped it and was buffered without",
|
|
3597
3597
|
" bound. No action needed; VOLTRO_MAX_RPC_BODY_BYTES still tunes it."
|
|
3598
3598
|
].join("\n")
|
|
3599
|
-
}),
|
|
3599
|
+
}), Zn = T({
|
|
3600
3600
|
version: "0.34.0",
|
|
3601
3601
|
id: "0.34.0/07_incoming-webhook-declares-verification",
|
|
3602
3602
|
title: "An incoming webhook with no signature scheme now refuses to boot",
|
|
@@ -3645,7 +3645,7 @@ var C = (e, t, n) => {
|
|
|
3645
3645
|
"value — the sender holds the other half of it, so a generated one would",
|
|
3646
3646
|
"authenticate nobody."
|
|
3647
3647
|
].join("\n")
|
|
3648
|
-
}),
|
|
3648
|
+
}), Qn = T({
|
|
3649
3649
|
version: "0.34.0",
|
|
3650
3650
|
id: "0.34.0/08_init-initialises-the-workspace",
|
|
3651
3651
|
title: "`voltro init` initialises the workspace root; scaffolding is `create-project` only",
|
|
@@ -3697,20 +3697,20 @@ var C = (e, t, n) => {
|
|
|
3697
3697
|
"all 18 of its scripts — including the `pnpm db:up` the CLI then printed as a",
|
|
3698
3698
|
"next step. Run `voltro init` in the root first."
|
|
3699
3699
|
].join("\n")
|
|
3700
|
-
}),
|
|
3700
|
+
}), $n = (e, t) => (e.getProperty(t)?.asKind(S.PropertyAssignment))?.getInitializer()?.asKind(S.ObjectLiteralExpression), er = (e) => {
|
|
3701
3701
|
if (e.getExpression().getText() !== "workflow") return !1;
|
|
3702
3702
|
let t = e.getArguments()[0]?.asKind(S.ObjectLiteralExpression);
|
|
3703
3703
|
if (t === void 0) return !1;
|
|
3704
|
-
let n =
|
|
3704
|
+
let n = $n(t, "messages");
|
|
3705
3705
|
return n !== void 0 && n.getProperty("queries") !== void 0;
|
|
3706
|
-
},
|
|
3706
|
+
}, tr = T({
|
|
3707
3707
|
version: "0.34.0",
|
|
3708
3708
|
id: "0.34.0/09_workflow-messages-queries-removed",
|
|
3709
3709
|
title: "`workflow({ messages: { queries } })` is removed — it never had a send path",
|
|
3710
3710
|
kind: "manual",
|
|
3711
3711
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
3712
3712
|
let t = e.getFullText();
|
|
3713
|
-
return !t.includes("queries") || !/workflow\s*\(/.test(t) ? !1 : e.getDescendantsOfKind(S.CallExpression).some(
|
|
3713
|
+
return !t.includes("queries") || !/workflow\s*\(/.test(t) ? !1 : e.getDescendantsOfKind(S.CallExpression).some(er);
|
|
3714
3714
|
}),
|
|
3715
3715
|
note: [
|
|
3716
3716
|
"YOU DECLARED `messages: { queries: { … } }` ON A WORKFLOW. That channel is",
|
|
@@ -3753,7 +3753,7 @@ var C = (e, t, n) => {
|
|
|
3753
3753
|
"in-flight runs finish on the old path after a deploy. See the Versioning",
|
|
3754
3754
|
"page in the docs."
|
|
3755
3755
|
].join("\n")
|
|
3756
|
-
}),
|
|
3756
|
+
}), nr = T({
|
|
3757
3757
|
version: "0.34.0",
|
|
3758
3758
|
id: "0.34.0/11_ai-flows-per-step-human-signal",
|
|
3759
3759
|
title: "`HUMAN_RESPONSE_SIGNAL` removed — a human step's signal name is now per-step",
|
|
@@ -3797,23 +3797,23 @@ var C = (e, t, n) => {
|
|
|
3797
3797
|
"per flow (`humanTimeoutMs`), per app (`aiFlowsPlugin({ humanReviewTimeoutMs })`)",
|
|
3798
3798
|
"or per deploy (`VOLTRO_AI_FLOW_HUMAN_REVIEW_TIMEOUT_HOURS`). `0` = wait forever."
|
|
3799
3799
|
].join("\n")
|
|
3800
|
-
}),
|
|
3800
|
+
}), rr = /* @__PURE__ */ new Set([
|
|
3801
3801
|
"@voltro/plugin-auth",
|
|
3802
3802
|
"@voltro/protocol/session",
|
|
3803
3803
|
"@voltro/plugin-sso-saml"
|
|
3804
|
-
]),
|
|
3804
|
+
]), ir = /* @__PURE__ */ new Set(["issueSession", "signSession"]), ar = (e) => {
|
|
3805
3805
|
let t = e.getFullText();
|
|
3806
3806
|
if (!/issueSession|signSession|resolveScopes|@voltro\/(plugin-auth|protocol\/session|plugin-sso-saml)/.test(t)) return !1;
|
|
3807
|
-
for (let t of e.getImportDeclarations()) if (
|
|
3808
|
-
for (let t of e.getDescendantsOfKind(S.CallExpression)) if (
|
|
3807
|
+
for (let t of e.getImportDeclarations()) if (rr.has(t.getModuleSpecifierValue())) return !0;
|
|
3808
|
+
for (let t of e.getDescendantsOfKind(S.CallExpression)) if (ir.has(t.getExpression().getText())) return !0;
|
|
3809
3809
|
for (let t of e.getDescendantsOfKind(S.PropertyAssignment)) if (t.getName() === "resolveScopes") return !0;
|
|
3810
3810
|
return !1;
|
|
3811
|
-
},
|
|
3811
|
+
}, or = T({
|
|
3812
3812
|
version: "0.34.0",
|
|
3813
3813
|
id: "0.34.0/12_session-cookie-carries-identity",
|
|
3814
3814
|
title: "The session cookie carries identity only — authority resolves per request",
|
|
3815
3815
|
kind: "manual",
|
|
3816
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
3816
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(ar),
|
|
3817
3817
|
note: [
|
|
3818
3818
|
"YOUR USERS WILL SIGN IN ONCE MORE, AND A SESSION COOKIE CAN NO LONGER",
|
|
3819
3819
|
"CARRY PERMISSIONS.",
|
|
@@ -3904,12 +3904,12 @@ var C = (e, t, n) => {
|
|
|
3904
3904
|
"not have: an authoritative resolver now overrides a token's own scope",
|
|
3905
3905
|
"claim, which union-only could never do."
|
|
3906
3906
|
].join("\n")
|
|
3907
|
-
}),
|
|
3907
|
+
}), sr = /\bMockEmail\b|\.email\.(sent|lastTo|clear)\b|\bSentEmail\b/, cr = T({
|
|
3908
3908
|
version: "0.34.0",
|
|
3909
3909
|
id: "0.34.0/10_testing-mail-is-a-service",
|
|
3910
3910
|
title: "`ctx.email` / `MockEmail` removed — assert mail through the mail plugin",
|
|
3911
3911
|
kind: "manual",
|
|
3912
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
3912
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => sr.test(e.getFullText())),
|
|
3913
3913
|
note: [
|
|
3914
3914
|
"`@voltro/testing` no longer ships `MockEmail`, and `makeTestContext()` no",
|
|
3915
3915
|
"longer returns `ctx.email`. Your tests that touch it will not compile.",
|
|
@@ -3978,12 +3978,12 @@ var C = (e, t, n) => {
|
|
|
3978
3978
|
" • `makeTestContext({ layers })` — your app's own `app.config.ts`",
|
|
3979
3979
|
" `layers:` now resolve for an Effect-mode handler under test."
|
|
3980
3980
|
].join("\n")
|
|
3981
|
-
}),
|
|
3981
|
+
}), lr = /from\s+['"]@voltro\/plugin-billing(?:\/[\w-]+)?['"]/, ur = T({
|
|
3982
3982
|
version: "0.34.0",
|
|
3983
3983
|
id: "0.34.0/13_billing-provider-dunning",
|
|
3984
3984
|
title: "Billing dunning — `BillingProvider.fetchSubscription` is required, and `plan()` now honours a grace period",
|
|
3985
3985
|
kind: "manual",
|
|
3986
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
3986
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => lr.test(e.getFullText())),
|
|
3987
3987
|
note: [
|
|
3988
3988
|
"BILLING GAINED A DUNNING SEQUENCE. TWO THINGS CHANGED UNDER YOU.",
|
|
3989
3989
|
"",
|
|
@@ -4059,12 +4059,12 @@ var C = (e, t, n) => {
|
|
|
4059
4059
|
"`pastDueSince` / `statusEventAt` columns ride the declarative differ — they",
|
|
4060
4060
|
"are applied by `voltro db apply` and by a `voltro dev` boot, on every dialect."
|
|
4061
4061
|
].join("\n")
|
|
4062
|
-
}),
|
|
4062
|
+
}), dr = /from\s+['"]@voltro\/plugin-search(?:\/[\w-]+)?['"]/, fr = T({
|
|
4063
4063
|
version: "0.34.0",
|
|
4064
4064
|
id: "0.34.0/14_search-memory-backend-refuses-production",
|
|
4065
4065
|
title: "`plugin-search` on the in-memory backend now refuses to boot in production",
|
|
4066
4066
|
kind: "manual",
|
|
4067
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4067
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => dr.test(e.getFullText())),
|
|
4068
4068
|
note: [
|
|
4069
4069
|
"THE ZERO-CONFIG SEARCH BACKEND NO LONGER BOOTS IN PRODUCTION.",
|
|
4070
4070
|
"",
|
|
@@ -4133,7 +4133,7 @@ var C = (e, t, n) => {
|
|
|
4133
4133
|
"(`ts_headline` / `snippet()` / …) that `SearchQuery` promises. Degrading",
|
|
4134
4134
|
"those silently would replace one lie with another."
|
|
4135
4135
|
].join("\n")
|
|
4136
|
-
}),
|
|
4136
|
+
}), pr = T({
|
|
4137
4137
|
version: "0.34.0",
|
|
4138
4138
|
id: "0.34.0/15_mysql-mssql-tls-honoured",
|
|
4139
4139
|
title: "mysql/mariadb and mssql connections honour ?ssl= / ?sslmode= — or refuse to boot",
|
|
@@ -4205,7 +4205,7 @@ var C = (e, t, n) => {
|
|
|
4205
4205
|
"spins in-tick and starves the event loop. Set it only if you know nothing in",
|
|
4206
4206
|
"your process does that, and set it well above their peak concurrency."
|
|
4207
4207
|
].join("\n")
|
|
4208
|
-
}),
|
|
4208
|
+
}), mr = T({
|
|
4209
4209
|
version: "0.34.0",
|
|
4210
4210
|
id: "0.34.0/16_declare-node-env-for-migration-commands",
|
|
4211
4211
|
title: "`voltro db apply` / `voltro migrate` now treat an unset NODE_ENV as production",
|
|
@@ -4269,12 +4269,12 @@ var C = (e, t, n) => {
|
|
|
4269
4269
|
"process environment if you want a non-production `voltro serve` without a",
|
|
4270
4270
|
"built bundle. Everything downstream of the launcher does honour `.env`."
|
|
4271
4271
|
].join("\n")
|
|
4272
|
-
}),
|
|
4272
|
+
}), hr = /\/(?:src\/)?pages\//, gr = /\bcacheInvalidatesOn\b/, _r = T({
|
|
4273
4273
|
version: "0.34.0",
|
|
4274
4274
|
id: "0.34.0/17_isr-postgres-refuses-without-a-database",
|
|
4275
4275
|
title: "The postgres ISR cache + CDC invalidator read DB_URL, and no longer fall back silently",
|
|
4276
4276
|
kind: "manual",
|
|
4277
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4277
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => gr.test(e.getFullText()) || hr.test(e.getFilePath())),
|
|
4278
4278
|
note: [
|
|
4279
4279
|
"YOUR WEB PROCESS MAY HAVE BEEN USING THE MEMORY ISR CACHE ALL ALONG.",
|
|
4280
4280
|
"",
|
|
@@ -4319,12 +4319,12 @@ var C = (e, t, n) => {
|
|
|
4319
4319
|
" until their `revalidate` window expires. Give the web process a `DB_URL`",
|
|
4320
4320
|
" or remove the declaration."
|
|
4321
4321
|
].join("\n")
|
|
4322
|
-
}),
|
|
4322
|
+
}), vr = /\.migration\.ts$/, yr = T({
|
|
4323
4323
|
version: "0.34.0",
|
|
4324
4324
|
id: "0.34.0/18_serve-refuses-pending-file-migrations",
|
|
4325
4325
|
title: "`voltro serve` refuses to boot with pending file-based migrations",
|
|
4326
4326
|
kind: "manual",
|
|
4327
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4327
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => vr.test(e.getFilePath())),
|
|
4328
4328
|
note: [
|
|
4329
4329
|
"YOUR DEPLOY MUST RUN `migrations/*.migration.ts` BEFORE `voltro serve`.",
|
|
4330
4330
|
"",
|
|
@@ -4367,11 +4367,11 @@ var C = (e, t, n) => {
|
|
|
4367
4367
|
"fingerprint check — it is the one switch for \"no boot-time schema checks\",",
|
|
4368
4368
|
"and it now covers both."
|
|
4369
4369
|
].join("\n")
|
|
4370
|
-
}),
|
|
4370
|
+
}), br = /* @__PURE__ */ new Set([
|
|
4371
4371
|
"@voltro/plugin-auth",
|
|
4372
4372
|
"@voltro/plugin-auth/schema",
|
|
4373
4373
|
"@voltro/plugin-auth/plugin"
|
|
4374
|
-
]),
|
|
4374
|
+
]), xr = /* @__PURE__ */ new Set([
|
|
4375
4375
|
"UserStore",
|
|
4376
4376
|
"authTables",
|
|
4377
4377
|
"SendEmail",
|
|
@@ -4379,20 +4379,20 @@ var C = (e, t, n) => {
|
|
|
4379
4379
|
"memoryUserStore",
|
|
4380
4380
|
"postgresUserStore",
|
|
4381
4381
|
"authRoutesPlugin"
|
|
4382
|
-
]),
|
|
4382
|
+
]), Sr = (e) => {
|
|
4383
4383
|
if (!e.getFullText().includes("@voltro/plugin-auth")) return !1;
|
|
4384
|
-
for (let t of e.getImportDeclarations()) if (
|
|
4385
|
-
for (let e of t.getNamedImports()) if (
|
|
4384
|
+
for (let t of e.getImportDeclarations()) if (br.has(t.getModuleSpecifierValue())) {
|
|
4385
|
+
for (let e of t.getNamedImports()) if (xr.has(e.getName())) return !0;
|
|
4386
4386
|
if (t.getNamespaceImport() !== void 0) return !0;
|
|
4387
4387
|
}
|
|
4388
4388
|
for (let t of e.getDescendantsOfKind(S.TypeReference)) if (t.getTypeName().getText() === "UserStore") return !0;
|
|
4389
4389
|
return !1;
|
|
4390
|
-
},
|
|
4390
|
+
}, Cr = T({
|
|
4391
4391
|
version: "0.34.0",
|
|
4392
4392
|
id: "0.34.0/20_user-store-auth-feature-methods",
|
|
4393
4393
|
title: "UserStore gained the email-verification, invitation and impersonation methods",
|
|
4394
4394
|
kind: "manual",
|
|
4395
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
4395
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(Sr),
|
|
4396
4396
|
note: [
|
|
4397
4397
|
"IF YOU USE memoryUserStore OR postgresUserStore, THERE IS NOTHING TO DO.",
|
|
4398
4398
|
"Both already implement everything below. Read on only if you wrote your",
|
|
@@ -4472,26 +4472,26 @@ var C = (e, t, n) => {
|
|
|
4472
4472
|
" is the difference between \"new signups must confirm\" and \"everyone is",
|
|
4473
4473
|
" locked out until they check their mail\"."
|
|
4474
4474
|
].join("\n")
|
|
4475
|
-
}),
|
|
4475
|
+
}), z = /* @__PURE__ */ new Set([
|
|
4476
4476
|
"bindConnectionSubject",
|
|
4477
4477
|
"getConnectionSubject",
|
|
4478
4478
|
"unbindConnectionSubject",
|
|
4479
4479
|
"onBindConnectionSubject",
|
|
4480
4480
|
"connectionSubjectsSnapshot"
|
|
4481
|
-
]),
|
|
4481
|
+
]), wr = (e) => {
|
|
4482
4482
|
let t = e.getFullText();
|
|
4483
4483
|
if (!/ConnectionSubject|connectionSubjectsSnapshot|rebind/.test(t)) return !1;
|
|
4484
|
-
for (let t of e.getDescendantsOfKind(S.CallExpression)) if (
|
|
4485
|
-
for (let t of e.getImportDeclarations()) for (let e of t.getNamedImports()) if (
|
|
4484
|
+
for (let t of e.getDescendantsOfKind(S.CallExpression)) if (z.has(t.getExpression().getText())) return !0;
|
|
4485
|
+
for (let t of e.getImportDeclarations()) for (let e of t.getNamedImports()) if (z.has(e.getName())) return !0;
|
|
4486
4486
|
for (let t of e.getDescendantsOfKind(S.PropertyAssignment)) if (t.getName() === "rebind") return !0;
|
|
4487
4487
|
for (let t of e.getDescendantsOfKind(S.ShorthandPropertyAssignment)) if (t.getName() === "rebind") return !0;
|
|
4488
4488
|
return !1;
|
|
4489
|
-
},
|
|
4489
|
+
}, Tr = T({
|
|
4490
4490
|
version: "0.34.0",
|
|
4491
4491
|
id: "0.34.0/19_connection-override-carries-a-credential",
|
|
4492
4492
|
title: "Soft re-auth presents a credential — it no longer hands the server a Subject",
|
|
4493
4493
|
kind: "manual",
|
|
4494
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
4494
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(wr),
|
|
4495
4495
|
note: [
|
|
4496
4496
|
"A LIVE CONNECTION CAN NO LONGER BE HANDED A SUBJECT. IT PRESENTS A",
|
|
4497
4497
|
"CREDENTIAL, AND THE SERVER RESOLVES IT LIKE ANY OTHER REQUEST.",
|
|
@@ -4576,19 +4576,19 @@ var C = (e, t, n) => {
|
|
|
4576
4576
|
"it behaves identically under `voltro dev` and `voltro serve`, because both",
|
|
4577
4577
|
"now build the middleware from one function (`makeAuthMiddlewareLayers`)."
|
|
4578
4578
|
].join("\n")
|
|
4579
|
-
}),
|
|
4579
|
+
}), Er = (e) => {
|
|
4580
4580
|
if (/\.workflow(\.server)?\.tsx?$/.test(e.getBaseName())) return !0;
|
|
4581
4581
|
let t = e.getFullText();
|
|
4582
4582
|
if (!/resolveScopes|defineWorkflow|ctx\.workflows/.test(t)) return !1;
|
|
4583
4583
|
for (let t of e.getDescendantsOfKind(S.PropertyAssignment)) if (t.getName() === "resolveScopes") return !0;
|
|
4584
4584
|
for (let t of e.getDescendantsOfKind(S.CallExpression)) if (t.getExpression().getText() === "defineWorkflow") return !0;
|
|
4585
4585
|
return !1;
|
|
4586
|
-
},
|
|
4586
|
+
}, Dr = T({
|
|
4587
4587
|
version: "0.34.0",
|
|
4588
4588
|
id: "0.34.0/20_workflow-authority-resolves-at-resume",
|
|
4589
4589
|
title: "A resumed workflow re-resolves its caller's authority instead of restoring it",
|
|
4590
4590
|
kind: "manual",
|
|
4591
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
4591
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(Er),
|
|
4592
4592
|
note: [
|
|
4593
4593
|
"A WORKFLOW NO LONGER CARRIES ITS CALLER'S PERMISSIONS FORWARD. IT CARRIES",
|
|
4594
4594
|
"THEIR IDENTITY, AND ASKS YOUR APP WHAT THEY MAY DO WHEN IT RUNS.",
|
|
@@ -4653,7 +4653,7 @@ var C = (e, t, n) => {
|
|
|
4653
4653
|
" contain scopes and are stripped on READ — a resumed run cannot re-assert",
|
|
4654
4654
|
" authority the old build persisted."
|
|
4655
4655
|
].join("\n")
|
|
4656
|
-
}),
|
|
4656
|
+
}), Or = /* @__PURE__ */ new Set([
|
|
4657
4657
|
"listTag",
|
|
4658
4658
|
"createTag",
|
|
4659
4659
|
"updateTag",
|
|
@@ -4661,21 +4661,21 @@ var C = (e, t, n) => {
|
|
|
4661
4661
|
"createScope",
|
|
4662
4662
|
"writeScope",
|
|
4663
4663
|
"deleteScope"
|
|
4664
|
-
]),
|
|
4664
|
+
]), kr = (e) => {
|
|
4665
4665
|
let t = e.getFullText();
|
|
4666
4666
|
if (!/EntityAdminSpec|deriveEntityAdmins|Tag\b|Scope\b/.test(t)) return !1;
|
|
4667
4667
|
for (let t of e.getImportDeclarations()) for (let e of t.getNamedImports()) {
|
|
4668
4668
|
let t = e.getName();
|
|
4669
4669
|
if (t === "EntityAdminSpec" || t === "deriveEntityAdmins") return !0;
|
|
4670
4670
|
}
|
|
4671
|
-
for (let t of e.getDescendantsOfKind(S.PropertyAccessExpression)) if (
|
|
4671
|
+
for (let t of e.getDescendantsOfKind(S.PropertyAccessExpression)) if (Or.has(t.getName())) return !0;
|
|
4672
4672
|
return !1;
|
|
4673
|
-
},
|
|
4673
|
+
}, Ar = T({
|
|
4674
4674
|
version: "0.34.0",
|
|
4675
4675
|
id: "0.34.0/21_admin-gates-on-declared-access",
|
|
4676
4676
|
title: "The derived admin gates on the api's DECLARED access — the invented `<table>:create` scopes are gone",
|
|
4677
4677
|
kind: "manual",
|
|
4678
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
4678
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(kr),
|
|
4679
4679
|
note: [
|
|
4680
4680
|
"YOUR ADMIN WAS GATING ON SCOPE STRINGS NOTHING PRODUCED.",
|
|
4681
4681
|
"",
|
|
@@ -4765,14 +4765,14 @@ var C = (e, t, n) => {
|
|
|
4765
4765
|
"from \"undeclared\", so an intentionally public action rendered as forbidden",
|
|
4766
4766
|
"to everybody."
|
|
4767
4767
|
].join("\n")
|
|
4768
|
-
}),
|
|
4768
|
+
}), jr = /\b(useMutation|useAction|useWorkflow|useWorkflowSignal|useWorkflowUpdate|useUpload)\b/, Mr = /FiberFailure|Cause\.squash|squashWith/, Nr = T({
|
|
4769
4769
|
version: "0.34.0",
|
|
4770
4770
|
id: "0.34.0/22_write-rejections-carry-the-typed-error",
|
|
4771
4771
|
title: "A rejected mutate/run/signal/upload carries the typed error, not a FiberFailure",
|
|
4772
4772
|
kind: "manual",
|
|
4773
4773
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
4774
4774
|
let t = e.getFullText();
|
|
4775
|
-
return
|
|
4775
|
+
return jr.test(t) || Mr.test(t);
|
|
4776
4776
|
}),
|
|
4777
4777
|
note: [
|
|
4778
4778
|
"WHAT CHANGED. A write hook that rejects now rejects with the typed error",
|
|
@@ -4825,12 +4825,12 @@ var C = (e, t, n) => {
|
|
|
4825
4825
|
"contract, reject from a real rpc client, or assert on the value your",
|
|
4826
4826
|
"component branches on rather than on the literal the test wrote."
|
|
4827
4827
|
].join("\n")
|
|
4828
|
-
}),
|
|
4828
|
+
}), Pr = /@voltro\/plugin-sso-saml|samlSsoPlugin/, Fr = T({
|
|
4829
4829
|
version: "0.34.0",
|
|
4830
4830
|
id: "0.34.0/23_saml-signature-and-replay-defaults",
|
|
4831
4831
|
title: "SAML: response-signature requirement relaxed + surfaced; replay protection ON by default",
|
|
4832
4832
|
kind: "manual",
|
|
4833
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4833
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Pr.test(e.getFullText())),
|
|
4834
4834
|
note: [
|
|
4835
4835
|
"Two defaults in `samlSsoPlugin` moved. Read both — they interact.",
|
|
4836
4836
|
"",
|
|
@@ -4921,24 +4921,24 @@ var C = (e, t, n) => {
|
|
|
4921
4921
|
"request, and the envelope is unauthenticated. If you must run unsolicited,",
|
|
4922
4922
|
"set `wantAuthnResponseSigned: true`."
|
|
4923
4923
|
].join("\n")
|
|
4924
|
-
}),
|
|
4924
|
+
}), Ir = /\b(signPayload|verifySignature)\s*\(/, Lr = T({
|
|
4925
4925
|
version: "0.34.0",
|
|
4926
4926
|
id: "0.34.0/24_webhook-signing-renders-headers",
|
|
4927
4927
|
title: "Webhook signing: `signPayload`/`verifySignature` → `signRequest`/`verifyRequest`",
|
|
4928
4928
|
kind: "manual",
|
|
4929
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4929
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Ir.test(e.getFullText())),
|
|
4930
4930
|
note: "A webhook signature scheme now renders a header MAP rather than one header,\nand verifies against the request's whole header map.\n\n - signPayload(scheme, rawBody, secret)\n → signRequest(scheme, { rawBody, secret, messageId })\n returns { headers } instead of { headerName, headerValue }\n\n - verifySignature(scheme, rawBody, secret, headerValue)\n → verifyRequest(scheme, { rawBody, secret, headers })\n\nRewrite each call site:\n\n // before\n const { headerName, headerValue } = signPayload(scheme, body, secret)\n await fetch(url, { headers: { [headerName]: headerValue }, body })\n\n // after\n const { headers } = signRequest(scheme, { rawBody: body, secret, messageId: deliveryId })\n await fetch(url, { headers, body })\n\nWHY `messageId` IS REQUIRED, AND WHY THIS IS NOT AUTOMATED:\n\n Standard Webhooks signs over `<messageId>.<timestamp>.<body>` and sends the\n id as `webhook-id` — which is also the value the spec tells consumers to\n use as their IDEMPOTENCY KEY. Pass the id that identifies the message to\n THAT receiver, stable across retries (the framework passes its delivery\n id). A fresh `randomUUID()` per attempt compiles and reads fine, and\n quietly makes every retry look like a new message to the receiver.\n\nTHE DEFAULT OUTGOING SCHEME CHANGED:\n\n `defaultOutgoingSignature()` now returns Standard Webhooks v1.0.0 —\n `webhook-id` / `webhook-timestamp` / `webhook-signature: v1,<base64>` — so\n a NEW subscription signs to an interoperable spec every conformant\n consumer library already verifies. Existing target rows are untouched:\n each stores the scheme it was created with.\n\n Its key serialization differs too: `whsec_` + base64 of 24..64 random\n bytes, HMAC-ing the DECODED bytes. `subscribe()` mints the right shape\n automatically; passing your own hex secret for a standard-webhooks target\n is REFUSED at subscribe rather than producing signatures no consumer\n accepts.\n\n To keep the previous house format on a new subscription, pass it\n explicitly: `webhooks.subscribe({ …, signing: genericHmacSignature() })`\n — the same shape as before, under a name that says it is a choice.\n\nALSO IN THIS RELEASE, no code change needed:\n\n - a 3xx response is a failure and redirects are no longer FOLLOWED (they\n were, by fetch's default — which also walked past the SSRF guard);\n - a `410 Gone` disables the target immediately, whatever the\n consecutive-failure threshold says;\n - each attempt has a 30s wire timeout (`VOLTRO_WEBHOOK_TIMEOUT_MS`, or\n `timeoutMs`). There was none, so a receiver that accepted the connection\n and never answered held the delivery workflow open indefinitely.\n\nAnd `slackSignature()` is now a REAL verifier. It shipped as a stub that\nreturned false unconditionally, workable only through a header-packing\nconvention in the route mounter. A scheme now receives the whole header map\nand reads `x-slack-request-timestamp` itself."
|
|
4931
|
-
}),
|
|
4931
|
+
}), Rr = /from\s+['"]@voltro\/plugin-presence(?:\/[a-z]+)?['"]/, zr = /\b(lastSeen|presenceTable|memoryPresenceStore|isOnline|filterOnline|staleKeys|PresenceStore|PresenceEntry|PresenceTracker)\b/, Br = /_voltro_presence/, Vr = T({
|
|
4932
4932
|
version: "0.34.0",
|
|
4933
4933
|
id: "0.34.0/25_presence-has-no-table",
|
|
4934
4934
|
title: "Presence: `_voltro_presence` is gone, and so is `lastSeen` on the roster",
|
|
4935
4935
|
kind: "manual",
|
|
4936
4936
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
4937
4937
|
let t = e.getFullText();
|
|
4938
|
-
return
|
|
4938
|
+
return Br.test(t) || Rr.test(t) && zr.test(t);
|
|
4939
4939
|
}),
|
|
4940
4940
|
note: "@voltro/plugin-presence no longer declares a table. Four things moved.\n\n1. A roster member is now { key, meta } — there is NO `lastSeen`.\n\n It was the OWNING replica's clock, so on more than one replica \"active 3\n minutes ago\" rendered from it was wrong by the skew between two pods, with\n nothing to say so. It was also the only field a plain heartbeat changed,\n which is what made the roster push on every beat instead of on every change.\n\n // before\n members.map((m) => `${m.key} — ${ago(m.lastSeen)}`)\n // after: put anything time-shaped you need into meta\n usePresence(channel, { meta: { joinedAt: Date.now() } })\n members.map((m) => `${m.key} — ${ago(m.meta?.joinedAt)}`)\n\n2. `PresenceTracker.track()` and `.untrack()` return { delta, changed }.\n\n // before\n bus.announce(tracker.track({ channel, tenantId, key }))\n // after — announce ALWAYS (a peer's sweep needs the liveness signal),\n // push only on a change\n const write = tracker.track({ channel, tenantId, key })\n bus.announce(write.delta)\n if (write.changed) publishReactivity(store, presenceRoster)\n\n Do not blind-append `.delta` and move on: dropping `changed` restores the\n per-heartbeat push this release removed, and nothing will report it.\n\n `attachPresenceBus` also takes an optional `onRosterChanged` now — call it\n if you drive the bus yourself, or a peer's join and a peer's death will\n update your tracker and push nobody.\n\n3. These exports are DELETED, with no replacement:\n\n presenceTable, PresenceStore, PresenceEntry,\n memoryPresenceStore, isOnline, filterOnline, staleKeys\n\n They were the table era's read model — an abstraction over rows plus the\n staleness filter a row needed because it outlived the client that wrote it.\n Presence has neither. Reading the roster is `presence.list` / `usePresence`;\n the staleness sweep is the plugin's own and needs nothing from you.\n\n4. If your `source:` names '_voltro_presence' as a string, point it at the\n channel object instead:\n\n import { presenceRoster } from '@voltro/plugin-presence'\n defineQuery({ name: 'room.summary', source: presenceRoster, ... })\n\n And to push it yourself:\n\n import { publishReactivity } from '@voltro/protocol'\n publishReactivity(ctx.store, presenceRoster)\n\nTHE TABLE IS NOT DROPPED FOR YOU. The declarative differ never plans a drop for\na framework table no app declares — deliberately, so a live `_voltro_*` table is\nnever destroyed by an app that simply does not know about it. So an existing\n`_voltro_presence` stays, empty, until you remove it:\n\n DROP TABLE IF EXISTS _voltro_presence;\n\nIt holds no data anyone can use: nothing has written a row to it since presence\nmoved into memory."
|
|
4941
|
-
}),
|
|
4941
|
+
}), Hr = (e) => {
|
|
4942
4942
|
let t = e.getArguments()[0];
|
|
4943
4943
|
if (t === void 0 || !t.isKind(S.ObjectLiteralExpression)) return /* @__PURE__ */ new Set();
|
|
4944
4944
|
let n = /* @__PURE__ */ new Set();
|
|
@@ -4947,32 +4947,32 @@ var C = (e, t, n) => {
|
|
|
4947
4947
|
t !== void 0 && n.add(t);
|
|
4948
4948
|
}
|
|
4949
4949
|
return n;
|
|
4950
|
-
},
|
|
4950
|
+
}, Ur = (e, t) => /defineEvent\s*\(/.test(e) ? t.some((e) => {
|
|
4951
4951
|
if (e.getExpression().getText() !== "defineEvent") return !1;
|
|
4952
|
-
let t =
|
|
4952
|
+
let t = Hr(e);
|
|
4953
4953
|
return !t.has("guards") && !t.has("openAccess");
|
|
4954
|
-
}) : !1,
|
|
4954
|
+
}) : !1, Wr = T({
|
|
4955
4955
|
version: "0.35.0",
|
|
4956
4956
|
id: "0.35.0/01_event-access-decision",
|
|
4957
4957
|
title: "Every declared event decides who may listen (`guards:` or `openAccess:`)",
|
|
4958
4958
|
kind: "manual",
|
|
4959
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4959
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Ur(e.getFullText(), e.getDescendantsOfKind(S.CallExpression))),
|
|
4960
4960
|
note: (/* @__PURE__ */ "YOUR APP WILL NOT BOOT UNTIL EVERY DECLARED EVENT DECIDES WHO MAY LISTEN.(This closes the sibling of 0.34.0's procedure gate: `defineEvent`'s `guards:`(was optional and enforcement skipped an empty list, so an event with no(decision was silently subscribable by ANY authenticated session that could(open the socket.((WHAT TO DO, IN THIS ORDER:((1) LIST THEM. `voltro doctor` prints every undecided event with its tag and( file — the same set, from the same function, that the boot refuses on.( `voltro doctor --json` carries it as `accessDecisions.undecided` for CI.((2) DECIDE EACH ONE. There are exactly two answers and they are not the same( claim:(( guards: [{ scope: 'display:read' }] a subscriber must hold a scope( openAccess: 'public scoreboard' anyone may listen — and why(( `openAccess` takes a REASON, not a boolean. It is what a reviewer reads( later, and it is what makes \"we decided this is open\" distinguishable( from \"nobody looked\".((3) DO NOT RUBBER-STAMP. Reaching for a scope every caller already holds( satisfies the gate, reads as protection, and enforces nothing. If the( event is open, say `openAccess`. If it should not be open, this gate just( found a real hole — an event often carries exactly the data its table( guards behind a scoped query.((IF YOU NEED TO SHIP FIRST. The same field that covers procedures covers(events, in `app.config.ts`:(( export default { security: { defaultDeny: false } }((That restores the old default-allow for the WHOLE app, in one place a(reviewer can see. There is no env var for it, on purpose. `voltro doctor`(keeps listing the undecided events while it is off, marked advisory.((NOT AFFECTED: apps already running `security: { defaultDeny: false }`, and(events your PLUGINS declare — the gate reads your app's own discovered(`*.event.ts` files only.".split("(")).join("\n")
|
|
4961
|
-
}),
|
|
4961
|
+
}), Gr = /\brouteHttp\s*\(/, Kr = T({
|
|
4962
4962
|
version: "0.34.0",
|
|
4963
4963
|
id: "0.34.0/26_route-http-is-async",
|
|
4964
4964
|
title: "`routeHttp` returns a Promise",
|
|
4965
4965
|
kind: "manual",
|
|
4966
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
4966
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Gr.test(e.getFullText())),
|
|
4967
4967
|
note: "`routeHttp` (@voltro/mcp) is async now:\n\n routeHttp(options): HttpOutcome // before\n routeHttp(options): Promise<HttpOutcome> // after\n\nAwait it, and make the enclosing function async if it is not already:\n\n // before\n const outcome = routeHttp({ method, url, body, tools })\n if (outcome.kind === 'json') respond(outcome)\n\n // after\n const outcome = await routeHttp({ method, url, body, tools })\n if (outcome.kind === 'json') respond(outcome)\n\nWhy it moved: `tools/list` now folds in the app's agent tools and `tools/call`\nexecutes one, so two of the methods reach the app. The rest still resolve without\ntouching anything, and the function is still pure in the sense that matters — it\nbinds no socket, and a test supplies a `live` double.\n\nIf you use the shipped `serveHttp` transport there is nothing to do; it already\nawaits."
|
|
4968
|
-
}),
|
|
4968
|
+
}), qr = /@voltro\/plugin-(billing|governance|storage)/, Jr = /* @__PURE__ */ RegExp("\\b(billing\\.(startCheckout|portalUrl|previewChange|changePlan|changeSeats|invoices|reportUsage)|governance\\.(export|erase)|storage\\.(mintUploadUrl|ingestUrl|listRefs))\\b"), Yr = /\bdefinePluginRoute\s*\(|\broutes\s*:\s*\[/, Xr = T({
|
|
4969
4969
|
version: "0.35.0",
|
|
4970
4970
|
id: "0.35.0/02_plugin-procedures-carry-access-decisions",
|
|
4971
4971
|
title: "First-party plugin procedures carry access decisions; twelve now require a scope",
|
|
4972
4972
|
kind: "manual",
|
|
4973
4973
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
4974
4974
|
let t = e.getFullText();
|
|
4975
|
-
return
|
|
4975
|
+
return qr.test(t) || Jr.test(t) || Yr.test(t) && /VoltroPlugin|definePlugin/.test(t);
|
|
4976
4976
|
}),
|
|
4977
4977
|
note: [
|
|
4978
4978
|
"Every first-party plugin rpc route now declares an access decision, and the",
|
|
@@ -5037,12 +5037,12 @@ var C = (e, t, n) => {
|
|
|
5037
5037
|
"`openAccess` with the reason each is safe (self-scoped rows, signed",
|
|
5038
5038
|
"subject-bound tickets, per-object grants), and behave exactly as before."
|
|
5039
5039
|
].join("\n")
|
|
5040
|
-
}),
|
|
5040
|
+
}), Zr = /AnalyticsMirrorImpl/, Qr = T({
|
|
5041
5041
|
version: "0.35.0",
|
|
5042
5042
|
id: "0.35.0/03_analytics-mirror-max-version",
|
|
5043
5043
|
title: "Custom analytics mirror sinks answer `maxVersion` (fleet-scope seed read)",
|
|
5044
5044
|
kind: "manual",
|
|
5045
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
5045
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Zr.test(e.getFullText())),
|
|
5046
5046
|
note: [
|
|
5047
5047
|
"The analytics CDC-mirror now derives its version from the CHANGE under",
|
|
5048
5048
|
"`changeScope: 'fleet'` (postgres CDC, mysql binlog): warehouse baseline +",
|
|
@@ -5067,44 +5067,44 @@ var C = (e, t, n) => {
|
|
|
5067
5067
|
"",
|
|
5068
5068
|
"The read is issued at most once per key per process, off the commit path."
|
|
5069
5069
|
].join("\n")
|
|
5070
|
-
}),
|
|
5070
|
+
}), $r = (e) => /RunStepStatus/.test(e) || /['"]succeeded['"]/.test(e) && /['"]waiting['"]/.test(e) && /RunStep|runStep|flow/i.test(e), ei = T({
|
|
5071
5071
|
version: "0.35.0",
|
|
5072
5072
|
id: "0.35.0/04_flow-run-step-skipped",
|
|
5073
5073
|
title: "A flow run step can now be 'skipped' — handle it where you render a run timeline",
|
|
5074
5074
|
kind: "manual",
|
|
5075
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
5075
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => $r(e.getFullText())),
|
|
5076
5076
|
note: (/* @__PURE__ */ "A FLOW RUN STEP CAN NOW BE 'skipped'.((`when:` on a flow step gates it on a prior value, and a step whose condition(is false is SKIPPED rather than run. That is a sixth member of(`RunStepStatus`, so an exhaustive switch over it no longer compiles, and a(lookup keyed by status now has a hole.((WHAT TO DO:((1) FIND IT. Anywhere you render or branch on a run step status — a timeline( component, a status badge map, a progress calculation.((2) DECIDE WHAT A SKIPPED STEP LOOKS LIKE. It is NOT a failure and NOT a( success: it did not run, on purpose, and it produced no output. The( step carries `skipReason` — the rendered condition, e.g.( `{{mode}} equals \"full\"` — so the timeline can say WHY.((3) DO NOT DEFAULT IT TO INVISIBLE. Dropping the row compiles and reads fine( in review, and it reproduces exactly the problem `skipReason` exists to( prevent: a step that vanished is indistinguishable from a step nobody( declared, which is the first thing a user reports as a bug.((A PROGRESS COUNT probably needs a second look too: `succeeded / total` now(under-reports a completed run that skipped a step. Counting(`succeeded + skipped` against the total is usually what was meant.((If your app does not render a flow timeline, there is nothing to do — this(note fires on any file that names the status type or its literals.".split("(")).join("\n")
|
|
5077
|
-
}),
|
|
5077
|
+
}), ti = T({
|
|
5078
5078
|
version: "0.35.0",
|
|
5079
5079
|
id: "0.35.0/05_declared-schema-drops-runtime-flags",
|
|
5080
5080
|
title: "The declared schema no longer reads `CDC` / `VOLTRO_UNDO` / `VOLTRO_TRACING_PERSIST`",
|
|
5081
5081
|
kind: "manual",
|
|
5082
5082
|
appliesTo: () => !0,
|
|
5083
5083
|
note: (/* @__PURE__ */ "The set of framework tables your app DECLARES is hashed into the schema(fingerprint. A pre-deploy `voltro db apply` records that hash; every serving(container recomputes it and refuses to boot if it differs. Until this release(three RUNTIME flags fed into that set:(( CDC=0 removed `_voltro_cdc_offsets`( VOLTRO_UNDO=on added `_voltro_undo_log`( VOLTRO_TRACING_PERSIST=all added `_voltro_traces`((All three read as pure runtime knobs, so they tend to live on the PODS and(not on the pre-upgrade migrate Job — which is a green migrate followed by(every pod in CrashLoopBackOff. This was reported against a Helm deployment(where `CDC: \"0\"` was in all three overlays' pod blocks and none of their(jobs; it had been latent for months and would have fired on the next deploy.((WHAT YOU MUST DO — only if you set one of these to turn a table ON in(production:(( * `VOLTRO_UNDO=on` in production → add to app.config.ts:( export default { schema: { undo: true }, … }( * `VOLTRO_TRACING_PERSIST` keeping trace history in production → add:( export default { schema: { traces: true }, … }(( Without the declaration, `voltro serve` now REFUSES to boot and names the( field. That refusal is the point: before, the same configuration either( wrote to a table nobody created or produced a fingerprint the migrate job( could not reproduce.(( Turning capture OFF still needs no declaration and never will — a declared( table nobody writes to is harmless. Only turning it ON is a schema claim.((WHAT HAPPENS WITHOUT ANY ACTION:(( * On mariadb or mssql you will see ONE additive `create-table` in your next( plan: `_voltro_cdc_offsets` is now declared by the DIALECT rather than by( `CDC`, so it exists whether or not that process drives CDC. It is an( offsets table — a handful of rows — and the alternative was leaving a( runtime flag able to split your fleet.( * On postgres/sqlite nothing changes: those dialects have no offsets table.((AND ONE THING WORTH DOING ANYWAY: if you are upgrading a deployment that has(a separate migrate job, diff that job's `env:` against your pods' once. The(framework can now guarantee its OWN tables do not depend on a runtime flag;(it cannot make the same guarantee for a plugin's `extendSchema.tables`, which(is app code and may read anything. A `prod-mismatch` refusal now prints which(tables this process decided and from which input, so the comparison is quick.".split("(")).join("\n")
|
|
5084
|
-
}),
|
|
5084
|
+
}), B = "session_expired", ni = T({
|
|
5085
5085
|
version: "0.35.1",
|
|
5086
5086
|
id: "0.35.1/01_unauthorized-replaces-session-expired",
|
|
5087
5087
|
title: "A 401 is `code: 'unauthorized'`; the vault's own failure is `'credential_unusable'`",
|
|
5088
5088
|
kind: "transform",
|
|
5089
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getFullText().includes(
|
|
5089
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getFullText().includes(B)),
|
|
5090
5090
|
transform: ({ project: e, log: t }) => {
|
|
5091
5091
|
let n = [];
|
|
5092
5092
|
for (let t of e.getSourceFiles()) {
|
|
5093
|
-
if (!t.getFullText().includes(
|
|
5093
|
+
if (!t.getFullText().includes(B)) continue;
|
|
5094
5094
|
let e = !1;
|
|
5095
|
-
for (let n of t.getDescendantsOfKind(11)) n.getLiteralValue() ===
|
|
5095
|
+
for (let n of t.getDescendantsOfKind(11)) n.getLiteralValue() === B && (n.setLiteralValue("unauthorized"), e = !0);
|
|
5096
5096
|
e && n.push(t.getFilePath());
|
|
5097
5097
|
}
|
|
5098
|
-
n.length !== 0 && t(`rewrote '${
|
|
5098
|
+
n.length !== 0 && t(`rewrote '${B}' to 'unauthorized' in ${n.length} file(s).\n A 401 now means only "the credential was refused" — expired, revoked, wrong\n scope and MALFORMED all produce that status, and the old name asserted the\n first one. If a rewritten branch was meant to catch a credential your\n CONNECTION VAULT could not produce (no grant, revoked grant, failed refresh),\n change it to 'credential_unusable' — that is the code the vault raises, and it\n is the one where re-auth is genuinely the right action.\n A health check that logs the user out on this code should read 'unauthorized'\n as "ask again", not as "the session is gone".\n` + n.map((e) => ` ${e}`).join("\n"));
|
|
5099
5099
|
}
|
|
5100
|
-
}),
|
|
5100
|
+
}), ri = /\(\s*\{[^}]*\.\.\./, ii = /\bquery\??\.?\(\s*['"`]/, ai = T({
|
|
5101
5101
|
version: "0.37.0",
|
|
5102
5102
|
id: "0.37.0/01_procedure-input-rejects-undeclared-fields",
|
|
5103
5103
|
title: "a procedure input rejects a field it does not declare (it used to drop it)",
|
|
5104
5104
|
kind: "manual",
|
|
5105
5105
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
5106
5106
|
let t = e.getFullText();
|
|
5107
|
-
return
|
|
5107
|
+
return ri.test(t) || ii.test(t) || E("query").test(t);
|
|
5108
5108
|
}),
|
|
5109
5109
|
note: [
|
|
5110
5110
|
"A procedure call whose input carries a field the schema does not declare",
|
|
@@ -5166,33 +5166,33 @@ var C = (e, t, n) => {
|
|
|
5166
5166
|
"two, the only safe direction is to refuse — and a warning would have to be",
|
|
5167
5167
|
"read by someone, in a log, after the wrong rows were already served."
|
|
5168
5168
|
].join("\n")
|
|
5169
|
-
}),
|
|
5169
|
+
}), V = "@voltro/plugin-auth", H = "@voltro/protocol", U = "IMPERSONATION_METADATA_KEY", oi = T({
|
|
5170
5170
|
version: "0.38.0",
|
|
5171
5171
|
id: "0.38.0/01_impersonation-key-in-protocol",
|
|
5172
|
-
title: `\`${
|
|
5172
|
+
title: `\`${U}\` is imported from @voltro/protocol`,
|
|
5173
5173
|
kind: "transform",
|
|
5174
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue() ===
|
|
5174
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue() === V && e.getNamedImports().some((e) => e.getName() === U))),
|
|
5175
5175
|
transform: ({ project: e, log: t }) => {
|
|
5176
5176
|
let n = 0;
|
|
5177
5177
|
for (let t of e.getSourceFiles()) for (let e of t.getImportDeclarations()) {
|
|
5178
|
-
if (e.getModuleSpecifierValue() !==
|
|
5179
|
-
let r = e.getNamedImports().find((e) => e.getName() ===
|
|
5178
|
+
if (e.getModuleSpecifierValue() !== V) continue;
|
|
5179
|
+
let r = e.getNamedImports().find((e) => e.getName() === U);
|
|
5180
5180
|
if (r === void 0) continue;
|
|
5181
5181
|
let i = r.getAliasNode()?.getText(), a = e.isTypeOnly() || r.isTypeOnly();
|
|
5182
5182
|
r.remove();
|
|
5183
|
-
let o = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() ===
|
|
5184
|
-
name:
|
|
5183
|
+
let o = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() === H && e.isTypeOnly() === a), s = {
|
|
5184
|
+
name: U,
|
|
5185
5185
|
...i === void 0 ? {} : { alias: i }
|
|
5186
5186
|
};
|
|
5187
5187
|
o === void 0 ? t.addImportDeclaration({
|
|
5188
|
-
moduleSpecifier:
|
|
5188
|
+
moduleSpecifier: H,
|
|
5189
5189
|
isTypeOnly: a,
|
|
5190
5190
|
namedImports: [s]
|
|
5191
5191
|
}) : o.addNamedImport(s), e.getNamedImports().length === 0 && e.getDefaultImport() === void 0 && e.getNamespaceImport() === void 0 && e.remove(), n += 1;
|
|
5192
5192
|
}
|
|
5193
|
-
n > 0 && t(`${
|
|
5193
|
+
n > 0 && t(`${U}: ${n} import(s) repointed to ${H}`);
|
|
5194
5194
|
}
|
|
5195
|
-
}),
|
|
5195
|
+
}), si = T({
|
|
5196
5196
|
version: "0.38.0",
|
|
5197
5197
|
id: "0.38.0/02_startup-failure-refuses-boot",
|
|
5198
5198
|
title: "a `*.startup.ts` that fails refuses the boot (it used to warn and continue)",
|
|
@@ -5277,12 +5277,12 @@ var C = (e, t, n) => {
|
|
|
5277
5277
|
"long work after, so a failure in the long half cannot hide a missing",
|
|
5278
5278
|
"registration."
|
|
5279
5279
|
].join("\n")
|
|
5280
|
-
}),
|
|
5280
|
+
}), ci = /\bStruct\(\s*\{\s*\}\s*\)/, li = T({
|
|
5281
5281
|
version: "0.39.0",
|
|
5282
5282
|
id: "0.39.0/01_empty-input-schema-rejects-every-field",
|
|
5283
5283
|
title: "a procedure declaring `Schema.Struct({})` used to accept every field and now accepts none",
|
|
5284
5284
|
kind: "manual",
|
|
5285
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
5285
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => ci.test(e.getFullText())),
|
|
5286
5286
|
note: [
|
|
5287
5287
|
"CHECK YOUR `Schema.Struct({})` PROCEDURES FIRST. They have been accepting",
|
|
5288
5288
|
"every field anyone sent them, and they now accept none — the one jump in",
|
|
@@ -5336,7 +5336,7 @@ var C = (e, t, n) => {
|
|
|
5336
5336
|
"A procedure that genuinely takes no input keeps `Schema.Struct({})` and is",
|
|
5337
5337
|
"correct as it stands — callers must send `{}` or nothing."
|
|
5338
5338
|
].join("\n")
|
|
5339
|
-
}),
|
|
5339
|
+
}), ui = T({
|
|
5340
5340
|
version: "0.40.0",
|
|
5341
5341
|
id: "0.40.0/01_cold-start-failure-is-its-own-state",
|
|
5342
5342
|
title: "a failed cold start is `failed: true`, not `loading: true`",
|
|
@@ -5401,7 +5401,7 @@ var C = (e, t, n) => {
|
|
|
5401
5401
|
" reconnect discards the error and re-subscribes, so the entry returns to",
|
|
5402
5402
|
" pending on its own."
|
|
5403
5403
|
].join("\n")
|
|
5404
|
-
}),
|
|
5404
|
+
}), di = T({
|
|
5405
5405
|
version: "0.40.0",
|
|
5406
5406
|
id: "0.40.0/02_rejected-credential-widens-guard-results",
|
|
5407
5407
|
title: "a rejected credential answers `Unauthenticated`, widening three guard results",
|
|
@@ -5437,7 +5437,7 @@ var C = (e, t, n) => {
|
|
|
5437
5437
|
"`openAccess` procedures are untouched: the stamp only travels, and only a",
|
|
5438
5438
|
"guard that actually refuses ever spends it."
|
|
5439
5439
|
].join("\n")
|
|
5440
|
-
}),
|
|
5440
|
+
}), W = "@voltro/web/middleware", fi = /(^|[\\/])middleware\.tsx?$/, pi = T({
|
|
5441
5441
|
version: "0.41.0",
|
|
5442
5442
|
id: "0.41.0/01_middleware-defines-where-it-runs",
|
|
5443
5443
|
title: "`middleware.ts` exports `defineMiddleware(...)` and can say where it runs",
|
|
@@ -5457,9 +5457,9 @@ var C = (e, t, n) => {
|
|
|
5457
5457
|
let r = e.getText().replace(/^\s*export\s+default\s+/, "");
|
|
5458
5458
|
e.replaceWithText(`export default defineMiddleware({ run: ${r} })`), n += 1;
|
|
5459
5459
|
}
|
|
5460
|
-
let r = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() ===
|
|
5460
|
+
let r = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() === W);
|
|
5461
5461
|
r === void 0 ? t.insertImportDeclaration(0, {
|
|
5462
|
-
moduleSpecifier:
|
|
5462
|
+
moduleSpecifier: W,
|
|
5463
5463
|
namedImports: [{ name: "defineMiddleware" }]
|
|
5464
5464
|
}) : r.getNamedImports().some((e) => e.getName() === "defineMiddleware") || r.addNamedImport({ name: "defineMiddleware" });
|
|
5465
5465
|
}
|
|
@@ -5821,24 +5821,24 @@ var C = (e, t, n) => {
|
|
|
5821
5821
|
"with `totalBytes` and `objectBytes` beside them), so a report can state all",
|
|
5822
5822
|
"three rather than implying one."
|
|
5823
5823
|
].join("\n")
|
|
5824
|
-
}),
|
|
5824
|
+
}), Ai = "@voltro/i18n", ji = "I18nProvider", Mi = (e) => {
|
|
5825
5825
|
let t = [];
|
|
5826
5826
|
for (let n of e.getImportDeclarations()) {
|
|
5827
5827
|
let e = n.getModuleSpecifierValue();
|
|
5828
|
-
if (e ===
|
|
5828
|
+
if (e === Ai || e === `${Ai}/server`) for (let e of n.getNamedImports()) e.getName() === ji && t.push(e.getAliasNode()?.getText() ?? e.getName());
|
|
5829
5829
|
}
|
|
5830
5830
|
return t;
|
|
5831
|
-
},
|
|
5831
|
+
}, Ni = (e, t) => [...e.getDescendantsOfKind(S.JsxOpeningElement), ...e.getDescendantsOfKind(S.JsxSelfClosingElement)].filter((e) => t.includes(e.getTagNameNode().getText())), Pi = T({
|
|
5832
5832
|
version: "0.51.0",
|
|
5833
5833
|
id: "0.51.0/04_i18n-timezone-prop",
|
|
5834
5834
|
title: "`<I18nProvider>`: `timeZone` is its own prop, not an `intlConfig` member",
|
|
5835
5835
|
kind: "transform",
|
|
5836
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
5836
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Mi(e).length > 0),
|
|
5837
5837
|
transform: ({ project: e, log: t }) => {
|
|
5838
5838
|
let n = 0, r = 0;
|
|
5839
5839
|
for (let i of e.getSourceFiles()) {
|
|
5840
|
-
let e =
|
|
5841
|
-
if (e.length !== 0) for (let a of
|
|
5840
|
+
let e = Mi(i);
|
|
5841
|
+
if (e.length !== 0) for (let a of Ni(i, e)) {
|
|
5842
5842
|
let e = a.getAttribute("intlConfig");
|
|
5843
5843
|
if (!e || !x.isJsxAttribute(e)) continue;
|
|
5844
5844
|
let o = e.getInitializer();
|
|
@@ -5863,28 +5863,28 @@ var C = (e, t, n) => {
|
|
|
5863
5863
|
}
|
|
5864
5864
|
n > 0 && (t(`I18nProvider: moved ${n} \`timeZone\` out of \`intlConfig\` onto its own prop`), t(" → it now reaches useFormatDate/useRelativeTime too, not only react-intl")), r > 0 && t(`I18nProvider: ${r} \`intlConfig\` value(s) could not be read — listed above`), n === 0 && r === 0 && (t("I18nProvider: no `intlConfig.timeZone` found — nothing to move"), t(" → if this app renders dates under SSR, set `timeZone` in the web app.config.ts"));
|
|
5865
5865
|
}
|
|
5866
|
-
}),
|
|
5866
|
+
}), K = "@voltro/plugin-versioning", q = "@voltro/plugin-row-history", Fi = T({
|
|
5867
5867
|
version: "0.52.0",
|
|
5868
5868
|
id: "0.52.0/01_plugin-versioning-to-row-history",
|
|
5869
5869
|
title: "@voltro/plugin-versioning → @voltro/plugin-row-history (the name now says what it does)",
|
|
5870
5870
|
kind: "transform",
|
|
5871
|
-
appliesTo: ({ project: e, text: t }) => t.find(
|
|
5871
|
+
appliesTo: ({ project: e, text: t }) => t.find(K).length > 0 || e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue() === K)),
|
|
5872
5872
|
transform: ({ project: e, helpers: t, log: n }) => {
|
|
5873
5873
|
let r = t.renameImport(e, {
|
|
5874
|
-
module:
|
|
5874
|
+
module: K,
|
|
5875
5875
|
from: "versioningPlugin",
|
|
5876
5876
|
to: "rowHistoryPlugin"
|
|
5877
5877
|
}) + t.renameImport(e, {
|
|
5878
|
-
module:
|
|
5878
|
+
module: K,
|
|
5879
5879
|
from: "VersioningPluginOptions",
|
|
5880
5880
|
to: "RowHistoryPluginOptions"
|
|
5881
5881
|
});
|
|
5882
|
-
n(`${
|
|
5883
|
-
from:
|
|
5884
|
-
to:
|
|
5885
|
-
})} import(s)` + (r > 0 ? `, renamed ${r} versioningPlugin call site(s) to rowHistoryPlugin` : "") + `. Replace the dependency in package.json ("${
|
|
5882
|
+
n(`${K} → ${q}: repointed ${t.renameModuleSpecifier(e, {
|
|
5883
|
+
from: K,
|
|
5884
|
+
to: q
|
|
5885
|
+
})} import(s)` + (r > 0 ? `, renamed ${r} versioningPlugin call site(s) to rowHistoryPlugin` : "") + `. Replace the dependency in package.json ("${K}" → "${q}") and reinstall — the table (_voltro_row_history) and VOLTRO_ROW_HISTORY_TTL_HOURS already carry the new name, so nothing else changes. If you passed an explicit alias: to the plugin it is kept as-is; only the DEFAULT alias moved from 'versioning' to 'row-history' (inspect endpoint paths + boot log lines).`);
|
|
5886
5886
|
}
|
|
5887
|
-
}),
|
|
5887
|
+
}), Ii = T({
|
|
5888
5888
|
version: "0.52.0",
|
|
5889
5889
|
id: "0.52.0/02_http-interceptor-fail-closed",
|
|
5890
5890
|
title: "A throwing `onHttpRequest` interceptor now refuses the request (500) instead of being ignored",
|
|
@@ -5909,7 +5909,7 @@ var C = (e, t, n) => {
|
|
|
5909
5909
|
" (that is what plugin-ratelimit's httpShield does now — a Redis outage",
|
|
5910
5910
|
" must not become a self-inflicted API outage)."
|
|
5911
5911
|
].join("\n")
|
|
5912
|
-
}),
|
|
5912
|
+
}), Li = T({
|
|
5913
5913
|
version: "0.53.0",
|
|
5914
5914
|
id: "0.53.0/01_conflict-columns-take-the-table",
|
|
5915
5915
|
title: "`missingConflictColumns` takes the table and classifies absent vs NULL",
|
|
@@ -5933,7 +5933,7 @@ var C = (e, t, n) => {
|
|
|
5933
5933
|
"always INSERT; use a plain insert for NULL-keyed rows, or make the column",
|
|
5934
5934
|
"NOT NULL)."
|
|
5935
5935
|
].join("\n")
|
|
5936
|
-
}),
|
|
5936
|
+
}), Ri = T({
|
|
5937
5937
|
version: "0.53.0",
|
|
5938
5938
|
id: "0.53.0/02_empty-struct-input-flipped",
|
|
5939
5939
|
title: "`input: Schema.Struct({})` procedures flipped from accept-everything to reject-everything in 0.37.0",
|
|
@@ -5956,7 +5956,7 @@ var C = (e, t, n) => {
|
|
|
5956
5956
|
"struct is the strongest declaration a procedure can make), or a caller",
|
|
5957
5957
|
"sends fields the schema must now declare."
|
|
5958
5958
|
].join("\n")
|
|
5959
|
-
}),
|
|
5959
|
+
}), zi = T({
|
|
5960
5960
|
version: "0.53.0",
|
|
5961
5961
|
id: "0.53.0/03_validation-messages-are-ids",
|
|
5962
5962
|
title: "Form validation messages are ids + catalog now, not effect developer text",
|
|
@@ -5984,7 +5984,7 @@ var C = (e, t, n) => {
|
|
|
5984
5984
|
"- `validateFields` also returns `issues` — `{ path, id, params, fallback }`",
|
|
5985
5985
|
" per failure — for widget kits that resolve messages themselves."
|
|
5986
5986
|
].join("\n")
|
|
5987
|
-
}),
|
|
5987
|
+
}), Bi = T({
|
|
5988
5988
|
version: "0.53.0",
|
|
5989
5989
|
id: "0.53.0/04_widget-kind-gained-array",
|
|
5990
5990
|
title: "WidgetKind gained 'array' and 'reference' — total widget registries need two new entries",
|
|
@@ -6003,7 +6003,7 @@ var C = (e, t, n) => {
|
|
|
6003
6003
|
"Partial registries (`Partial<Record<WidgetKind, …>>` or per-kind lookups)",
|
|
6004
6004
|
"need nothing."
|
|
6005
6005
|
].join("\n")
|
|
6006
|
-
}),
|
|
6006
|
+
}), Vi = T({
|
|
6007
6007
|
version: "0.55.0",
|
|
6008
6008
|
id: "0.55.0/01_target-relations-declare-columns",
|
|
6009
6009
|
title: "A target's `relations:` names the junction's two columns now, not just the table",
|
|
@@ -6038,7 +6038,7 @@ var C = (e, t, n) => {
|
|
|
6038
6038
|
"the server compares them against the junction's real reference columns and",
|
|
6039
6039
|
"refuses — naming the correct pair — if they disagree."
|
|
6040
6040
|
].join("\n")
|
|
6041
|
-
}),
|
|
6041
|
+
}), Hi = T({
|
|
6042
6042
|
version: "0.55.0",
|
|
6043
6043
|
id: "0.55.0/02_widget-kind-gained-rich-text",
|
|
6044
6044
|
title: "WidgetKind gained 'rich-text' — total widget registries need one new entry",
|
|
@@ -6056,7 +6056,7 @@ var C = (e, t, n) => {
|
|
|
6056
6056
|
"Partial registries (`Partial<Record<WidgetKind, …>>` or per-kind lookups)",
|
|
6057
6057
|
"need nothing."
|
|
6058
6058
|
].join("\n")
|
|
6059
|
-
}),
|
|
6059
|
+
}), Ui = T({
|
|
6060
6060
|
version: "0.56.0",
|
|
6061
6061
|
id: "0.56.0/01_inspect_answers_are_observations",
|
|
6062
6062
|
title: "inspect answers are `Observation`s — the payload is `.data`",
|
|
@@ -6095,7 +6095,7 @@ var C = (e, t, n) => {
|
|
|
6095
6095
|
"looking for first, because `undefined` and \"zero\" render the same in most",
|
|
6096
6096
|
"alerting rules."
|
|
6097
6097
|
].join("\n")
|
|
6098
|
-
}),
|
|
6098
|
+
}), Wi = T({
|
|
6099
6099
|
version: "0.56.0",
|
|
6100
6100
|
id: "0.56.0/02_broadcast_gap_is_one_object",
|
|
6101
6101
|
title: "attachBroadcastBus's onGap now receives a single BroadcastGap object",
|
|
@@ -6126,7 +6126,7 @@ var C = (e, t, n) => {
|
|
|
6126
6126
|
"unsubscribed as a gap. If you wrapped the call in a try/catch to survive a",
|
|
6127
6127
|
"restarting broker, that catch is now dead code."
|
|
6128
6128
|
].join("\n")
|
|
6129
|
-
}),
|
|
6129
|
+
}), Gi = T({
|
|
6130
6130
|
version: "0.56.0",
|
|
6131
6131
|
id: "0.56.0/03_outbox_drain_needs_an_identity",
|
|
6132
6132
|
title: "drainOutbox now requires claimedBy — the fleet-wide exactly-once gate",
|
|
@@ -6158,7 +6158,7 @@ var C = (e, t, n) => {
|
|
|
6158
6158
|
"If you do NOT call `drainOutbox` yourself, there is nothing to do: `voltro",
|
|
6159
6159
|
"dev` and `voltro serve` pass the identity for you."
|
|
6160
6160
|
].join("\n")
|
|
6161
|
-
}),
|
|
6161
|
+
}), Ki = T({
|
|
6162
6162
|
version: "0.56.0",
|
|
6163
6163
|
id: "0.56.0/04_reaction_dedupe_is_one_claim",
|
|
6164
6164
|
title: "runReaction's dedupe is a single atomic claim",
|
|
@@ -6192,7 +6192,7 @@ var C = (e, t, n) => {
|
|
|
6192
6192
|
"(`_voltro_change_claims`), so a reaction acts once across the whole fleet",
|
|
6193
6193
|
"instead of once per replica — no code change on your side."
|
|
6194
6194
|
].join("\n")
|
|
6195
|
-
}),
|
|
6195
|
+
}), qi = T({
|
|
6196
6196
|
version: "0.56.0",
|
|
6197
6197
|
id: "0.56.0/05_plugin_bind_context_claims_a_change",
|
|
6198
6198
|
title: "PluginBindContext requires claimChange; change identity moved to @voltro/database",
|
|
@@ -6235,7 +6235,7 @@ var C = (e, t, n) => {
|
|
|
6235
6235
|
" it is internal to the digest, and `@voltro/runtime` already exports a",
|
|
6236
6236
|
" different function of that name."
|
|
6237
6237
|
].join("\n")
|
|
6238
|
-
}),
|
|
6238
|
+
}), Ji = T({
|
|
6239
6239
|
version: "0.56.0",
|
|
6240
6240
|
id: "0.56.0/06_serve_is_api_only",
|
|
6241
6241
|
title: "`voltro serve` on a WEB app now refuses — use `voltro start`",
|
|
@@ -6272,12 +6272,12 @@ var C = (e, t, n) => {
|
|
|
6272
6272
|
"`node .framework/dist-api/serveBundle/serveEntry.js` for an api — which is",
|
|
6273
6273
|
"faster still and needs no CLI in the runtime image.)"
|
|
6274
6274
|
].join("\n")
|
|
6275
|
-
}),
|
|
6275
|
+
}), Yi = (e) => /\brunAsSystem\b/.test(e.getFullText()), Xi = T({
|
|
6276
6276
|
version: "0.58.0",
|
|
6277
6277
|
id: "0.58.0/01_system_writes_stamp_no_actor",
|
|
6278
6278
|
title: "A `runAsSystem` write stamps no actor id instead of \"system\"",
|
|
6279
6279
|
kind: "manual",
|
|
6280
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6280
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(Yi),
|
|
6281
6281
|
note: [
|
|
6282
6282
|
"A WRITE MADE BY THE FRAMEWORK ACTING AS ITSELF NOW ATTRIBUTES TO NOBODY.",
|
|
6283
6283
|
"",
|
|
@@ -6310,12 +6310,12 @@ var C = (e, t, n) => {
|
|
|
6310
6310
|
" resolve, it is no longer referenced by new writes. Keep it for the",
|
|
6311
6311
|
" historical rows above, or drop it once those are gone."
|
|
6312
6312
|
].join("\n")
|
|
6313
|
-
}),
|
|
6313
|
+
}), Zi = (e) => /\bResolvedWorkflowCallerContext\b/.test(e.getFullText()), Qi = T({
|
|
6314
6314
|
version: "0.58.0",
|
|
6315
6315
|
id: "0.58.0/02_workflow_caller_context_carries_a_scope",
|
|
6316
6316
|
title: "ResolvedWorkflowCallerContext carries the run's resolved row-filter scope",
|
|
6317
6317
|
kind: "manual",
|
|
6318
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6318
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(Zi),
|
|
6319
6319
|
note: [
|
|
6320
6320
|
"A WORKFLOW RUN'S CALLER CONTEXT NOW CARRIES THE ROW-FILTER SCOPE ITS STEPS",
|
|
6321
6321
|
"READ THROUGH.",
|
|
@@ -6346,19 +6346,19 @@ var C = (e, t, n) => {
|
|
|
6346
6346
|
"Reaching for `NO_ROW_FILTER` in the second case makes the test assert",
|
|
6347
6347
|
"unfiltered reads while claiming to cover a filtered run."
|
|
6348
6348
|
].join("\n")
|
|
6349
|
-
}),
|
|
6349
|
+
}), $i = (e) => /\bFleetMergeResult\b|\bfleetObservations\b/.test(e.getFullText()), ea = T({
|
|
6350
6350
|
version: "0.58.0",
|
|
6351
6351
|
id: "0.58.0/03_fleet_view_reports_departed_replicas",
|
|
6352
6352
|
title: "A fleet view separates DEPARTED replicas from stale ones",
|
|
6353
6353
|
kind: "manual",
|
|
6354
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6354
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some($i),
|
|
6355
6355
|
note: (/* @__PURE__ */ "A FLEET VIEW NOW SEPARATES ROWS LEFT BY PROCESSES THAT ARE GONE FROM(ANSWERS THAT ARE MERELY OLD.((WHAT CHANGED. `FleetMergeResult` has a required `departed`, and the(`/_voltro/inspect/...?scope=fleet` envelope carries it beside `stale`.((WHY THEY ARE NOT THE SAME FACT. A STALE row belongs to a replica the(membership roster still lists: it is running and has stopped refreshing,(which is a fault worth reporting and a reason for `complete: false`. A(DEPARTED row belongs to a replica the roster no longer lists: that process(is gone, which is what a scale-down looks like, and it is not a reason for(anything. Counting the second as the first made `complete` unreachable(after any replica had ever exited, and — worse — let a dead process's(framework version report a version SPLIT across a fleet that had none.((They are still REPORTED. Dropping them would leave a reader unable to tell(a fleet that scaled down from a table being written by something nobody is(tracking.((WHAT TO DO. Only code that CONSTRUCTS a fleet result needs a change — in(practice a test double for `fleetObservations`. Add `departed: []`, or a(row when that is what the double is there to exercise:(( { byReplica, missing: [], responded: 2, expected: 2, stale: [],( departed: [], versions: undefined }((If you assert on `complete` or on `stale` in a test that leaves a replica(out of its membership roster, that replica is now DEPARTED and those(assertions move accordingly.".split("(")).join("\n")
|
|
6356
|
-
}),
|
|
6356
|
+
}), ta = (e) => /\bsubscribeClientErrors\b|\bClientErrorEvent\b/.test(e.getFullText()), na = T({
|
|
6357
6357
|
version: "0.58.0",
|
|
6358
6358
|
id: "0.58.0/04_rpc_errors_reach_reporters",
|
|
6359
6359
|
title: "rpc failures are published on the client error bus",
|
|
6360
6360
|
kind: "manual",
|
|
6361
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6361
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(ta),
|
|
6362
6362
|
note: [
|
|
6363
6363
|
"AN RPC CALL THAT FAILS IN THE CLIENT NOW REACHES YOUR ERROR REPORTERS.",
|
|
6364
6364
|
"",
|
|
@@ -6388,12 +6388,12 @@ var C = (e, t, n) => {
|
|
|
6388
6388
|
" If that is too loud for your reporter, gate it in the subscriber — where",
|
|
6389
6389
|
" you can see which failures matter to you."
|
|
6390
6390
|
].join("\n")
|
|
6391
|
-
}),
|
|
6391
|
+
}), ra = (e) => /\bsentryPlugin\b|@voltro\/plugin-sentry/.test(e.getFullText()), ia = T({
|
|
6392
6392
|
version: "0.58.0",
|
|
6393
6393
|
id: "0.58.0/05_sentry_traces_on_by_default",
|
|
6394
6394
|
title: "Sentry performance traces are on by default",
|
|
6395
6395
|
kind: "manual",
|
|
6396
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6396
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(ra),
|
|
6397
6397
|
note: [
|
|
6398
6398
|
"SENTRY PERFORMANCE TRACES ARE NOW ON BY DEFAULT ON THE API.",
|
|
6399
6399
|
"",
|
|
@@ -6431,12 +6431,12 @@ var C = (e, t, n) => {
|
|
|
6431
6431
|
"or `VOLTRO_PUBLIC_SENTRY_DSN`, the init returns immediately, so this changes",
|
|
6432
6432
|
"nothing for an app that has not set one."
|
|
6433
6433
|
].join("\n")
|
|
6434
|
-
}),
|
|
6434
|
+
}), aa = (e) => /\bjwtSecret\b/.test(e.getFullText()), oa = T({
|
|
6435
6435
|
version: "0.58.0",
|
|
6436
6436
|
id: "0.58.0/06_jwt_secret_may_be_a_function",
|
|
6437
6437
|
title: "jwtSecret may be a function, so a build needs no production credential",
|
|
6438
6438
|
kind: "manual",
|
|
6439
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6439
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(aa),
|
|
6440
6440
|
note: [
|
|
6441
6441
|
"`jwtSecret` NOW ACCEPTS A FUNCTION — AND YOU PROBABLY WANT ONE.",
|
|
6442
6442
|
"",
|
|
@@ -6467,7 +6467,138 @@ var C = (e, t, n) => {
|
|
|
6467
6467
|
"the config along instead of the field. A `jwtSecret: 'literal'` you wrote",
|
|
6468
6468
|
"yourself is unaffected — its own inferred type never widened."
|
|
6469
6469
|
].join("\n")
|
|
6470
|
-
}),
|
|
6470
|
+
}), sa = (e) => /\brerank\s*\(/.test(e.getFullText()), ca = T({
|
|
6471
|
+
version: "0.58.0",
|
|
6472
|
+
id: "0.58.0/07_rerank_takes_a_provider_config",
|
|
6473
|
+
title: "rerank reaches the gateway through a ProviderConfig",
|
|
6474
|
+
kind: "manual",
|
|
6475
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(sa),
|
|
6476
|
+
note: [
|
|
6477
|
+
"`rerank` NOW TAKES A `ProviderConfig`, LIKE EVERY OTHER PRIMITIVE.",
|
|
6478
|
+
"",
|
|
6479
|
+
"WHY. Its `provider` was `'mock' | 'cohere' | 'voyage'` — the same two",
|
|
6480
|
+
"vendors the gateway serves, addressed by their OWN keys, with no way to say",
|
|
6481
|
+
"\"through the gateway\". So five reranking models in the catalog",
|
|
6482
|
+
"(`cohere/rerank-v3.5`, `-v4-fast`, `-v4-pro`, `voyage/rerank-2.5`,",
|
|
6483
|
+
"`-2.5-lite`) were unreachable with a gateway key.",
|
|
6484
|
+
"",
|
|
6485
|
+
"WHAT TO WRITE, if you want the gateway route:",
|
|
6486
|
+
"",
|
|
6487
|
+
" rerank({ query, documents, provider: {",
|
|
6488
|
+
" name: 'gateway', model: 'cohere/rerank-v4-pro',",
|
|
6489
|
+
" }})",
|
|
6490
|
+
"",
|
|
6491
|
+
"The string shorthands stay for the direct-key route, and are deliberately",
|
|
6492
|
+
"NOT folded into `ProviderConfig`: that union is shared with `generateText`,",
|
|
6493
|
+
"and adding `cohere` there would let you name a provider with no language",
|
|
6494
|
+
"model — a config error the type currently catches.",
|
|
6495
|
+
"",
|
|
6496
|
+
"WHAT MIGHT STOP COMPILING. Only code that READS the field off a typed",
|
|
6497
|
+
"options object, which is now `string | ProviderConfig`. Narrow it where you",
|
|
6498
|
+
"read it (`typeof p === 'string'`)."
|
|
6499
|
+
].join("\n")
|
|
6500
|
+
}), la = (e) => {
|
|
6501
|
+
for (let t of e.getDescendantsOfKind(S.ObjectLiteralExpression)) {
|
|
6502
|
+
let e = t.getProperty("web");
|
|
6503
|
+
if (e === void 0 || !x.isPropertyAssignment(e)) continue;
|
|
6504
|
+
let n = e.getInitializer();
|
|
6505
|
+
if (n !== void 0 && x.isObjectLiteralExpression(n)) return n;
|
|
6506
|
+
}
|
|
6507
|
+
}, ua = (e) => {
|
|
6508
|
+
let t = e.getParent()?.getParent();
|
|
6509
|
+
return t !== void 0 && x.isObjectLiteralExpression(t) ? t : void 0;
|
|
6510
|
+
}, da = (e) => e.getBaseName() === "app.config.ts", fa = T({
|
|
6511
|
+
version: "0.59.0",
|
|
6512
|
+
id: "0.59.0/01_sourcemaps_moved_to_the_top_level",
|
|
6513
|
+
title: "`web.sourcemaps` moved to the top level of app.config.ts",
|
|
6514
|
+
kind: "transform",
|
|
6515
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().filter(da).some((e) => {
|
|
6516
|
+
let t = la(e);
|
|
6517
|
+
return t !== void 0 && t.getProperty("sourcemaps") !== void 0;
|
|
6518
|
+
}),
|
|
6519
|
+
transform: ({ project: e, log: t }) => {
|
|
6520
|
+
let n = 0, r = 0;
|
|
6521
|
+
for (let i of e.getSourceFiles().filter(da)) {
|
|
6522
|
+
let e = la(i);
|
|
6523
|
+
if (e === void 0) continue;
|
|
6524
|
+
let a = e.getProperty("sourcemaps");
|
|
6525
|
+
if (a === void 0) {
|
|
6526
|
+
e.getProperties().some((e) => x.isSpreadAssignment(e)) && (r += 1, t?.(`${i.getBaseName()}: \`web:\` spreads another object — if it carries \`sourcemaps\`, move it to the top level by hand.`));
|
|
6527
|
+
continue;
|
|
6528
|
+
}
|
|
6529
|
+
if (!x.isPropertyAssignment(a)) continue;
|
|
6530
|
+
let o = ua(e);
|
|
6531
|
+
if (o === void 0) {
|
|
6532
|
+
r += 1, t?.(`${i.getBaseName()}: found \`web.sourcemaps\` but not the object it belongs to — move it by hand.`);
|
|
6533
|
+
continue;
|
|
6534
|
+
}
|
|
6535
|
+
if (o.getProperty("sourcemaps") !== void 0) {
|
|
6536
|
+
r += 1, t?.(`${i.getBaseName()}: both \`sourcemaps\` and \`web.sourcemaps\` are set — delete the one you do not want.`);
|
|
6537
|
+
continue;
|
|
6538
|
+
}
|
|
6539
|
+
let s = a.getInitializer()?.getText();
|
|
6540
|
+
if (s !== void 0) {
|
|
6541
|
+
if (o.addPropertyAssignment({
|
|
6542
|
+
name: "sourcemaps",
|
|
6543
|
+
initializer: s
|
|
6544
|
+
}), a.remove(), e.getProperties().length === 0) {
|
|
6545
|
+
let t = e.getParent();
|
|
6546
|
+
t !== void 0 && x.isPropertyAssignment(t) && t.remove();
|
|
6547
|
+
}
|
|
6548
|
+
n += 1;
|
|
6549
|
+
}
|
|
6550
|
+
}
|
|
6551
|
+
n > 0 && (t?.(`sourcemaps: moved out of \`web:\` in ${n} config file(s)`), t?.(" → it now covers the SSR, start and serve bundles too, not only the browser bundle")), r > 0 && t?.(`sourcemaps: ${r} case(s) left for you — listed above`), n === 0 && r === 0 && t?.("sourcemaps: no `web.sourcemaps` found — nothing to move");
|
|
6552
|
+
}
|
|
6553
|
+
}), pa = (e) => /\bsentryPlugin\b|@voltro\/plugin-sentry/.test(e.getFullText()), ma = T({
|
|
6554
|
+
version: "0.60.0",
|
|
6555
|
+
id: "0.60.0/01_declared_failures_are_not_incidents",
|
|
6556
|
+
title: "Sentry no longer reports declared failures by default",
|
|
6557
|
+
kind: "manual",
|
|
6558
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(pa),
|
|
6559
|
+
note: [
|
|
6560
|
+
"A DECLARED FAILURE IS NO LONGER A SENTRY ISSUE BY DEFAULT.",
|
|
6561
|
+
"",
|
|
6562
|
+
"WHAT CHANGED. The rpc interceptor skipped only clean interrupts; every",
|
|
6563
|
+
"other cause went to `captureException`, so a failure declared in a",
|
|
6564
|
+
"procedure's `error:` union arrived as `level: error`. It now skips a cause",
|
|
6565
|
+
"that is failures-ONLY. Defects are reported exactly as before, including a",
|
|
6566
|
+
"defect that travelled beside a failure.",
|
|
6567
|
+
"",
|
|
6568
|
+
"WHY. A declared failure is a contract: somebody wrote the outcome down, the",
|
|
6569
|
+
"client gets it typed and branches on it, and it describes a state of the",
|
|
6570
|
+
"world. `AccessDeniedError` on a team you are not in is the system working.",
|
|
6571
|
+
"A defect is the opposite — nobody foresaw it — and that is what Sentry is",
|
|
6572
|
+
"built for. Effect separates the two, this framework leans on that split",
|
|
6573
|
+
"deliberately, and a descriptor carries it in `error:`; reporting both as an",
|
|
6574
|
+
"incident discarded it one layer up. A deployment measured the result: its",
|
|
6575
|
+
"first server-side issue was a person clicking a team they are not in.",
|
|
6576
|
+
"",
|
|
6577
|
+
"THE BROWSER HALF MOVED WITH IT. A rejected call is an rpc error on the",
|
|
6578
|
+
"client too, so `initSentryBrowser` applies the same rule to `rpc.*` events",
|
|
6579
|
+
"that carry a `_tag`. Route render failures and `reportClientError` calls",
|
|
6580
|
+
"are never filtered — nobody declared those.",
|
|
6581
|
+
"",
|
|
6582
|
+
"WHAT TO DO — one of these, deliberately:",
|
|
6583
|
+
"",
|
|
6584
|
+
"1) NOTHING, if Sentry is where you look for the unforeseen. Your issue list",
|
|
6585
|
+
" gets quieter; the trace still shows the failure.",
|
|
6586
|
+
"",
|
|
6587
|
+
"2) KEEP THEM, if Sentry is where you see errors at all:",
|
|
6588
|
+
"",
|
|
6589
|
+
" sentryPlugin({ captureFailures: true })",
|
|
6590
|
+
" initSentryBrowser({ captureFailures: true })",
|
|
6591
|
+
"",
|
|
6592
|
+
"3) KEEP THE ONES THAT ARE SIGNAL:",
|
|
6593
|
+
"",
|
|
6594
|
+
" sentryPlugin({",
|
|
6595
|
+
" captureFailures: (e) => e._tag === 'PaymentDeclined',",
|
|
6596
|
+
" })",
|
|
6597
|
+
"",
|
|
6598
|
+
"The boot line now names the setting — `sentry active … captureFailures=false`",
|
|
6599
|
+
"— so the choice is visible where the decision takes effect."
|
|
6600
|
+
].join("\n")
|
|
6601
|
+
}), ha = (e) => /\bcostSource\b|\bCostBreakdown\b|\bestimateCostUsd\b|\b_voltro_ai_usage\b|\bMeteredUsage\b/.test(e.getFullText()), ga = [
|
|
6471
6602
|
he,
|
|
6472
6603
|
ge,
|
|
6473
6604
|
ve,
|
|
@@ -6477,13 +6608,14 @@ var C = (e, t, n) => {
|
|
|
6477
6608
|
Te,
|
|
6478
6609
|
Ee,
|
|
6479
6610
|
De,
|
|
6611
|
+
Ae,
|
|
6480
6612
|
je,
|
|
6481
|
-
|
|
6613
|
+
Pe,
|
|
6482
6614
|
Fe,
|
|
6483
|
-
|
|
6615
|
+
Re,
|
|
6484
6616
|
ze,
|
|
6485
|
-
|
|
6486
|
-
|
|
6617
|
+
He,
|
|
6618
|
+
Ge,
|
|
6487
6619
|
Ke,
|
|
6488
6620
|
qe,
|
|
6489
6621
|
Je,
|
|
@@ -6496,15 +6628,14 @@ var C = (e, t, n) => {
|
|
|
6496
6628
|
tt,
|
|
6497
6629
|
nt,
|
|
6498
6630
|
rt,
|
|
6631
|
+
ct,
|
|
6499
6632
|
it,
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
gt,
|
|
6633
|
+
st,
|
|
6634
|
+
ht,
|
|
6635
|
+
bt,
|
|
6504
6636
|
xt,
|
|
6505
6637
|
St,
|
|
6506
|
-
|
|
6507
|
-
Et,
|
|
6638
|
+
Tt,
|
|
6508
6639
|
Dt,
|
|
6509
6640
|
Mt,
|
|
6510
6641
|
Pt,
|
|
@@ -6520,61 +6651,61 @@ var C = (e, t, n) => {
|
|
|
6520
6651
|
en,
|
|
6521
6652
|
nn,
|
|
6522
6653
|
sn,
|
|
6523
|
-
ln,
|
|
6524
6654
|
un,
|
|
6525
6655
|
dn,
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6656
|
+
fn,
|
|
6657
|
+
mn,
|
|
6658
|
+
gn,
|
|
6659
|
+
vn,
|
|
6660
|
+
bn,
|
|
6661
|
+
Sn,
|
|
6662
|
+
Dn,
|
|
6663
|
+
kn,
|
|
6664
|
+
jn,
|
|
6665
|
+
Nn,
|
|
6536
6666
|
Fn,
|
|
6537
6667
|
In,
|
|
6538
6668
|
Ln,
|
|
6539
6669
|
Rn,
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6670
|
+
zn,
|
|
6671
|
+
Vn,
|
|
6672
|
+
Gn,
|
|
6673
|
+
qn,
|
|
6544
6674
|
Yn,
|
|
6545
6675
|
Xn,
|
|
6546
6676
|
Zn,
|
|
6547
|
-
|
|
6548
|
-
sr,
|
|
6677
|
+
Qn,
|
|
6549
6678
|
tr,
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6679
|
+
cr,
|
|
6680
|
+
nr,
|
|
6681
|
+
or,
|
|
6682
|
+
ur,
|
|
6553
6683
|
fr,
|
|
6554
6684
|
pr,
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6685
|
+
mr,
|
|
6686
|
+
_r,
|
|
6687
|
+
yr,
|
|
6688
|
+
Tr,
|
|
6689
|
+
Dr,
|
|
6690
|
+
Cr,
|
|
6691
|
+
Ar,
|
|
6692
|
+
Nr,
|
|
6693
|
+
Fr,
|
|
6694
|
+
Lr,
|
|
6695
|
+
Vr,
|
|
6696
|
+
Kr,
|
|
6697
|
+
Wr,
|
|
6698
|
+
Xr,
|
|
6699
|
+
Qr,
|
|
6570
6700
|
ei,
|
|
6571
6701
|
ti,
|
|
6572
|
-
|
|
6702
|
+
ni,
|
|
6573
6703
|
ai,
|
|
6574
6704
|
oi,
|
|
6575
|
-
|
|
6705
|
+
si,
|
|
6576
6706
|
li,
|
|
6577
6707
|
ui,
|
|
6708
|
+
di,
|
|
6578
6709
|
pi,
|
|
6579
6710
|
mi,
|
|
6580
6711
|
hi,
|
|
@@ -6588,7 +6719,6 @@ var C = (e, t, n) => {
|
|
|
6588
6719
|
Di,
|
|
6589
6720
|
Oi,
|
|
6590
6721
|
ki,
|
|
6591
|
-
Ni,
|
|
6592
6722
|
Pi,
|
|
6593
6723
|
Fi,
|
|
6594
6724
|
Ii,
|
|
@@ -6603,44 +6733,47 @@ var C = (e, t, n) => {
|
|
|
6603
6733
|
Gi,
|
|
6604
6734
|
Ki,
|
|
6605
6735
|
qi,
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6736
|
+
Ji,
|
|
6737
|
+
Xi,
|
|
6738
|
+
Qi,
|
|
6739
|
+
ea,
|
|
6740
|
+
na,
|
|
6741
|
+
ia,
|
|
6742
|
+
oa,
|
|
6743
|
+
ca,
|
|
6744
|
+
fa,
|
|
6745
|
+
ma,
|
|
6612
6746
|
T({
|
|
6613
|
-
version: "0.
|
|
6614
|
-
id: "0.
|
|
6615
|
-
title: "
|
|
6747
|
+
version: "0.59.0",
|
|
6748
|
+
id: "0.59.0/02_costsource_gained_unpriced",
|
|
6749
|
+
title: "`costSource` gained `unpriced`, and AI usage is counted in a unit",
|
|
6616
6750
|
kind: "manual",
|
|
6617
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some(
|
|
6751
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some(ha),
|
|
6618
6752
|
note: [
|
|
6619
|
-
"
|
|
6753
|
+
"AI COST NOW HAS A THIRD SOURCE, AND USAGE HAS A UNIT.",
|
|
6620
6754
|
"",
|
|
6621
|
-
"
|
|
6622
|
-
"
|
|
6623
|
-
"
|
|
6624
|
-
"
|
|
6625
|
-
"
|
|
6755
|
+
"WHAT CHANGED. `CostBreakdown[\"costSource\"]` gained `\"unpriced\"`, and",
|
|
6756
|
+
"`_voltro_ai_usage` gained a `unit` column. Speech vendors meter characters",
|
|
6757
|
+
"or seconds, never tokens, so a ledger that only knew tokens could not hold a",
|
|
6758
|
+
"speech call at all. A non-token unit with no supplied price is written with",
|
|
6759
|
+
"the REAL count and a zero cost, rather than a fabricated one.",
|
|
6626
6760
|
"",
|
|
6627
|
-
"WHAT TO
|
|
6761
|
+
"WHAT TO DO:",
|
|
6628
6762
|
"",
|
|
6629
|
-
"
|
|
6630
|
-
"
|
|
6631
|
-
"
|
|
6763
|
+
"1) IF YOU NARROWED `costSource` — a union of two members in your own type,",
|
|
6764
|
+
" or an exhaustive switch — add `\"unpriced\"`. The compiler points at it.",
|
|
6765
|
+
" Decide what it means for you: it is a real usage row whose price we do",
|
|
6766
|
+
" not know, not a free call.",
|
|
6632
6767
|
"",
|
|
6633
|
-
"
|
|
6634
|
-
"NOT folded into `ProviderConfig`: that union is shared with `generateText`,",
|
|
6635
|
-
"and adding `cohere` there would let you name a provider with no language",
|
|
6636
|
-
"model — a config error the type currently catches.",
|
|
6768
|
+
"2) IF YOU READ `estimateCostUsd` POSITIONALLY, read it by name instead.",
|
|
6637
6769
|
"",
|
|
6638
|
-
"
|
|
6639
|
-
"
|
|
6640
|
-
"
|
|
6770
|
+
"3) CHECK YOUR USAGE QUERIES — this one does not fail, it answers wrongly.",
|
|
6771
|
+
" `sum(input_tokens)` over `_voltro_ai_usage` now adds character counts to",
|
|
6772
|
+
" token counts and returns a number that looks fine. Group by `unit`, and",
|
|
6773
|
+
" never sum across it."
|
|
6641
6774
|
].join("\n")
|
|
6642
6775
|
})
|
|
6643
|
-
],
|
|
6776
|
+
], J = /* @__PURE__ */ new Set([
|
|
6644
6777
|
"node_modules",
|
|
6645
6778
|
".git",
|
|
6646
6779
|
"dist",
|
|
@@ -6652,42 +6785,42 @@ var C = (e, t, n) => {
|
|
|
6652
6785
|
".turbo",
|
|
6653
6786
|
".cache",
|
|
6654
6787
|
".output"
|
|
6655
|
-
]),
|
|
6788
|
+
]), _a = () => [...[...J].map((e) => `**/${e}/**`), "**/.voltro-*/**"], Y = /(?:from|import)\s*\(?\s*['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, X = /\.(?:tsx?|jsx?|mjs|cjs)$/, va = (e) => g(e).replace(X, ""), ya = (e) => {
|
|
6656
6789
|
let t = e.split("/").filter((e) => e.length > 0).pop();
|
|
6657
6790
|
if (t === void 0 || t === "." || t === "..") return;
|
|
6658
|
-
let n = t.replace(
|
|
6791
|
+
let n = t.replace(X, "");
|
|
6659
6792
|
return n.length > 0 ? n : void 0;
|
|
6660
|
-
},
|
|
6793
|
+
}, ba = (e) => {
|
|
6661
6794
|
let t = /* @__PURE__ */ new Map();
|
|
6662
6795
|
for (let n of e) {
|
|
6663
6796
|
let e;
|
|
6664
6797
|
try {
|
|
6665
|
-
e =
|
|
6798
|
+
e = te(n, "utf8");
|
|
6666
6799
|
} catch {
|
|
6667
6800
|
continue;
|
|
6668
6801
|
}
|
|
6669
|
-
|
|
6670
|
-
for (let r =
|
|
6671
|
-
let e =
|
|
6802
|
+
Y.lastIndex = 0;
|
|
6803
|
+
for (let r = Y.exec(e); r !== null; r = Y.exec(e)) {
|
|
6804
|
+
let e = ya(r[1] ?? r[2] ?? "");
|
|
6672
6805
|
if (e === void 0) continue;
|
|
6673
6806
|
let i = t.get(e);
|
|
6674
6807
|
i === void 0 ? t.set(e, /* @__PURE__ */ new Set([n])) : i.add(n);
|
|
6675
6808
|
}
|
|
6676
6809
|
}
|
|
6677
6810
|
return t;
|
|
6678
|
-
},
|
|
6811
|
+
}, xa = (e, t) => {
|
|
6679
6812
|
let n = new Set(e);
|
|
6680
|
-
for (let r of e) for (let e of [
|
|
6813
|
+
for (let r of e) for (let e of [va(r), g(_(r))]) {
|
|
6681
6814
|
let r = t.get(e);
|
|
6682
6815
|
if (r !== void 0) for (let e of r) n.add(e);
|
|
6683
6816
|
}
|
|
6684
6817
|
return n;
|
|
6685
|
-
},
|
|
6818
|
+
}, Sa = /* @__PURE__ */ ".ts,.tsx,.mts,.cts,.js,.jsx,.mjs,.cjs,.yml,.yaml,.toml,.json,.jsonc,.ini,.cfg,.conf,.sh,.bash,.zsh,.fish,.ps1,.bat,.cmd,.md,.mdx,.rst,.txt,.adoc,Makefile,makefile,GNUmakefile,Justfile,justfile,Dockerfile,Containerfile,Procfile,Jenkinsfile,Rakefile,Taskfile".split(","), Ca = 2097152, wa = 4e4, Ta = (e) => {
|
|
6686
6819
|
let t = e.slice(e.lastIndexOf("/") + 1);
|
|
6687
|
-
return
|
|
6688
|
-
},
|
|
6820
|
+
return Sa.some((e) => e.startsWith(".") ? t.endsWith(e) : t === e);
|
|
6821
|
+
}, Ea = (e) => {
|
|
6689
6822
|
try {
|
|
6690
|
-
let t =
|
|
6823
|
+
let t = b("git", [
|
|
6691
6824
|
"ls-files",
|
|
6692
6825
|
"--cached",
|
|
6693
6826
|
"--others",
|
|
@@ -6706,23 +6839,23 @@ var C = (e, t, n) => {
|
|
|
6706
6839
|
} catch {
|
|
6707
6840
|
return;
|
|
6708
6841
|
}
|
|
6709
|
-
}, Z = (e, t =
|
|
6842
|
+
}, Z = (e, t = Ea) => {
|
|
6710
6843
|
let n = t(e);
|
|
6711
|
-
if (n === void 0) return
|
|
6844
|
+
if (n === void 0) return Da;
|
|
6712
6845
|
let r = /* @__PURE__ */ new Map(), i = [];
|
|
6713
6846
|
for (let t of n) {
|
|
6714
|
-
if (t.split("/").some((e) =>
|
|
6715
|
-
if (r.size >=
|
|
6847
|
+
if (t.split("/").some((e) => J.has(e)) || !Ta(t)) continue;
|
|
6848
|
+
if (r.size >= wa) {
|
|
6716
6849
|
i.push(t);
|
|
6717
6850
|
continue;
|
|
6718
6851
|
}
|
|
6719
6852
|
let n = v(e, t);
|
|
6720
6853
|
try {
|
|
6721
|
-
if (
|
|
6854
|
+
if (ne(n).size > Ca) {
|
|
6722
6855
|
i.push(t);
|
|
6723
6856
|
continue;
|
|
6724
6857
|
}
|
|
6725
|
-
let e =
|
|
6858
|
+
let e = te(n, "utf8");
|
|
6726
6859
|
if (e.includes("\0")) {
|
|
6727
6860
|
i.push(t);
|
|
6728
6861
|
continue;
|
|
@@ -6742,47 +6875,47 @@ var C = (e, t, n) => {
|
|
|
6742
6875
|
scanned: r.size,
|
|
6743
6876
|
skipped: i
|
|
6744
6877
|
};
|
|
6745
|
-
},
|
|
6878
|
+
}, Da = {
|
|
6746
6879
|
find: () => [],
|
|
6747
6880
|
scanned: 0,
|
|
6748
6881
|
skipped: []
|
|
6749
|
-
},
|
|
6882
|
+
}, Oa = [
|
|
6750
6883
|
"**/*.ts",
|
|
6751
6884
|
"**/*.tsx",
|
|
6752
6885
|
"!**/node_modules/**",
|
|
6753
6886
|
"!**/dist/**",
|
|
6754
6887
|
"!**/.framework/**",
|
|
6755
6888
|
"!**/*.d.ts"
|
|
6756
|
-
], Q = (e, t, n =
|
|
6889
|
+
], Q = (e, t, n = ja) => {
|
|
6757
6890
|
let r = /* @__PURE__ */ new Set();
|
|
6758
|
-
for (let e of t) for (let t of e.scope ??
|
|
6891
|
+
for (let e of t) for (let t of e.scope ?? Oa) r.add(t);
|
|
6759
6892
|
let i = n(e);
|
|
6760
6893
|
if (i !== void 0) {
|
|
6761
|
-
let t = [...r].filter((e) => !e.startsWith("!")).map((e) =>
|
|
6894
|
+
let t = [...r].filter((e) => !e.startsWith("!")).map((e) => Aa(e)), n = [...r].filter((e) => e.startsWith("!")).map((e) => Aa(e.slice(1))), a = [...J], o = [];
|
|
6762
6895
|
for (let r of i) {
|
|
6763
6896
|
if (a.some((e) => r === e || r.startsWith(`${e}/`) || r.includes(`/${e}/`)) || !t.some((e) => e(r)) || n.some((e) => e(r))) continue;
|
|
6764
6897
|
let i = v(e, r);
|
|
6765
|
-
|
|
6898
|
+
y(i) && o.push(i);
|
|
6766
6899
|
}
|
|
6767
|
-
return
|
|
6900
|
+
return ka(o.length, e), o;
|
|
6768
6901
|
}
|
|
6769
6902
|
let a = ae([...r], {
|
|
6770
6903
|
cwd: e,
|
|
6771
6904
|
absolute: !0,
|
|
6772
6905
|
expandDirectories: !1,
|
|
6773
6906
|
followSymbolicLinks: !1,
|
|
6774
|
-
ignore: [...
|
|
6907
|
+
ignore: [..._a()]
|
|
6775
6908
|
});
|
|
6776
|
-
return
|
|
6777
|
-
},
|
|
6778
|
-
let n =
|
|
6909
|
+
return ka(a.length, e), a;
|
|
6910
|
+
}, ka = (e, t) => {
|
|
6911
|
+
let n = Ma();
|
|
6779
6912
|
if (!(e <= n)) throw Error(`voltro update: the codemod scan matched ${e} files under ${t}, past the ${n} ceiling.\n Every matched file is parsed into one ts-morph project, so the heap needed grows with\n this number — past the ceiling it runs out of memory, and V8 aborts without naming a\n limit, which is why this stops here instead. Three ways out, in order:\n • put non-source directories in .gitignore (inside a git repo the scan then never\n sees them at all — a build cache, a data dump, a virtualenv),\n • run \`voltro update\` from the app directory rather than the workspace root, or\n • take one codemod at a time: \`voltro update --dry-run\` lists the ids, then\n \`voltro update --codemods-only --only <id>\` runs a single one.\n If every one of those files really is source this pass must rewrite, raise the ceiling\n with VOLTRO_CODEMOD_MAX_FILES and give node room: NODE_OPTIONS=--max-old-space-size=8192.`);
|
|
6780
|
-
},
|
|
6913
|
+
}, Aa = (e) => {
|
|
6781
6914
|
let t = e.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "\0").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\u0000/g, "(?:.*/)?").replace(/\\\{([^}]*)\\\}/g, (e, t) => `(?:${t.split(",").join("|")})`);
|
|
6782
6915
|
return (e) => RegExp(`^${t}$`).test(e);
|
|
6783
|
-
},
|
|
6916
|
+
}, ja = (e) => {
|
|
6784
6917
|
try {
|
|
6785
|
-
let t =
|
|
6918
|
+
let t = b("git", [
|
|
6786
6919
|
"ls-files",
|
|
6787
6920
|
"--cached",
|
|
6788
6921
|
"--others",
|
|
@@ -6801,7 +6934,7 @@ var C = (e, t, n) => {
|
|
|
6801
6934
|
} catch {
|
|
6802
6935
|
return;
|
|
6803
6936
|
}
|
|
6804
|
-
},
|
|
6937
|
+
}, Ma = () => {
|
|
6805
6938
|
let e = Number(process.env.VOLTRO_CODEMOD_MAX_FILES);
|
|
6806
6939
|
return Number.isInteger(e) && e > 0 ? e : 2e4;
|
|
6807
6940
|
}, $ = (e, t) => {
|
|
@@ -6811,7 +6944,7 @@ var C = (e, t, n) => {
|
|
|
6811
6944
|
if (t !== 0) return t;
|
|
6812
6945
|
}
|
|
6813
6946
|
return 0;
|
|
6814
|
-
},
|
|
6947
|
+
}, Na = (e, t, n = ga) => n.filter((n) => $(e, n.version) < 0 && $(n.version, t) <= 0).slice().sort(me), Pa = (e, t, n = () => {}, r = Da) => {
|
|
6815
6948
|
let i = [], a = [], o = [];
|
|
6816
6949
|
for (let s of t) {
|
|
6817
6950
|
let t = !s.appliesTo || s.appliesTo({
|
|
@@ -6862,8 +6995,8 @@ var C = (e, t, n) => {
|
|
|
6862
6995
|
manual: a,
|
|
6863
6996
|
skipped: o
|
|
6864
6997
|
};
|
|
6865
|
-
},
|
|
6866
|
-
let t = e.log ?? (() => {}), n =
|
|
6998
|
+
}, Fa = async (e) => {
|
|
6999
|
+
let t = e.log ?? (() => {}), n = Na(e.from, e.to, e.codemods ?? ga), r = e.only === void 0 || e.only.length === 0 ? n : (() => {
|
|
6867
7000
|
let t = n.filter((t) => e.only.includes(t.id)), r = e.only.filter((e) => !n.some((t) => t.id === e));
|
|
6868
7001
|
if (r.length > 0) throw Error(`voltro update --only: no codemod in ${e.from} → ${e.to} has id ${r.map((e) => `"${e}"`).join(", ")}.\n Available for this jump:\n${n.map((e) => ` ${e.id}`).join("\n")}`);
|
|
6869
7002
|
return t;
|
|
@@ -6890,24 +7023,24 @@ var C = (e, t, n) => {
|
|
|
6890
7023
|
get skipped() {
|
|
6891
7024
|
return (p ??= Z(e.root)).skipped;
|
|
6892
7025
|
}
|
|
6893
|
-
}, h = c.length > 0 ?
|
|
7026
|
+
}, h = c.length > 0 ? ba(Q(e.root, [{
|
|
6894
7027
|
...c[0],
|
|
6895
|
-
scope:
|
|
7028
|
+
scope: Oa
|
|
6896
7029
|
}])) : void 0;
|
|
6897
7030
|
for (let n of r) {
|
|
6898
7031
|
if (c.includes(n)) {
|
|
6899
7032
|
let r = a(), i = Q(e.root, [n]);
|
|
6900
|
-
for (let e of
|
|
6901
|
-
let s =
|
|
7033
|
+
for (let e of xa(i, h)) y(e) && r.addSourceFileAtPath(e);
|
|
7034
|
+
let s = Pa(r, [n], t, m);
|
|
6902
7035
|
e.dryRun || await r.save(), l.push(...s.applied), u.push(...s.manual), d.push(...s.skipped), o = void 0;
|
|
6903
7036
|
continue;
|
|
6904
7037
|
}
|
|
6905
7038
|
o ??= (() => {
|
|
6906
7039
|
let e = a();
|
|
6907
|
-
for (let t of s)
|
|
7040
|
+
for (let t of s) y(t) && e.addSourceFileAtPath(t);
|
|
6908
7041
|
return e;
|
|
6909
7042
|
})();
|
|
6910
|
-
let r =
|
|
7043
|
+
let r = Pa(o, [n], t, m);
|
|
6911
7044
|
e.dryRun || await o.save(), l.push(...r.applied), u.push(...r.manual), d.push(...r.skipped);
|
|
6912
7045
|
}
|
|
6913
7046
|
return {
|
|
@@ -6917,4 +7050,4 @@ var C = (e, t, n) => {
|
|
|
6917
7050
|
};
|
|
6918
7051
|
};
|
|
6919
7052
|
//#endregion
|
|
6920
|
-
export { T as i,
|
|
7053
|
+
export { T as i, Fa as n, J as r, $ as t };
|