@voltro/cli 0.48.0 → 0.49.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 +67 -0
- package/dist/{apiBuild-Dz8TJSxp.js → apiBuild-QmYHaCF4.js} +1 -1
- package/dist/apiBuild-dZbHdqMg.js +2 -0
- package/dist/bin.js +1 -1
- package/dist/{build-DLme2ppa.js → build-Bi4O_g7T.js} +6 -6
- package/dist/{checkCommand-Dals7g-I.js → checkCommand-D8vjQXQt.js} +3 -3
- package/dist/{checkCommand-BUBqPBlI.js → checkCommand-udbQpphy.js} +1 -1
- package/dist/{codegenCommand-L6vacVRW.js → codegenCommand-DApSH7hK.js} +39 -47
- package/dist/{codemodRunner-DSZjgyCL.js → codemodRunner-De1_316I.js} +562 -492
- package/dist/{commands-CAxFLqG4.js → commands-a5PxCaIg.js} +68 -60
- package/dist/{dashboardCommand-CJC8Kg-s.js → dashboardCommand-DaoUUqJS.js} +1 -1
- package/dist/dataCommand-CJv_OMoS.js +1156 -0
- package/dist/dataProfile-Du3ztYxv.js +51 -0
- package/dist/{dbCommand-ZGNItjoJ.js → dbCommand-Bf7Cy0mn.js} +2 -2
- package/dist/dbCommand-Bnl7MSGC.js +2 -0
- package/dist/{dev-lvnVq5RD.js → dev-C31Nvlbv.js} +1 -1
- package/dist/{dev-cGGsLNn6.js → dev-DFVuzOj7.js} +1 -1
- package/dist/{doctorCommand-BK0qu7eD.js → doctorCommand-B3uraeAe.js} +12 -12
- package/dist/doctorCommand-CPL6EhrW.js +2 -0
- package/dist/{dormancyCommand-CyIk-zq4.js → dormancyCommand-QUXQ9yoz.js} +1 -1
- package/dist/{embeddingsCommand-D7TLklps.js → embeddingsCommand-Zw1-rYSF.js} +1 -1
- package/dist/{envCommand-BHxKkGXq.js → envCommand-DtaJ4xEf.js} +1 -1
- package/dist/{evolveCommand-CQh6dw21.js → evolveCommand-JDD3hE1i.js} +2 -2
- package/dist/{frameworkTableAssembly-BNod_DKN.js → frameworkTableAssembly-BwJVEKLr.js} +3 -3
- package/dist/frameworkTableAssembly-CVDB2hCq.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-CuNl9cbh.js → infoCommand-COsUC1DB.js} +1 -1
- package/dist/{migrate-CL5Ed01M.js → migrate-D3MK9BpK.js} +2 -2
- package/dist/{runtimeTrace-C0SlIoQY.js → runtimeTrace-Di6fcndp.js} +1 -1
- package/dist/{sdkgen-BXm7zx7F.js → sdkgen-CIi5gM17.js} +1 -1
- package/dist/serveCommand-CzSDngKm.js +2 -0
- package/dist/serveCommand-N3udT49p.js +2362 -0
- package/dist/serveEntry.js +5 -5
- package/dist/{subcommandNames-CKG5Dz3a.js → subcommandNames-DpYs3DXr.js} +12 -2
- package/dist/{updateCommand-BlyXavoG.js → updateCommand-2BfbeMvp.js} +1 -1
- package/dist/updateCommand-CtYm7aKH.js +2 -0
- package/dist/{webhooksCommand-QlAk_tED.js → webhooksCommand-CwX9IzvJ.js} +1 -1
- package/package.json +29 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +71 -13
- package/templates/agent-docs/whats-new.md +34 -47
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +9 -9
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +10 -10
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/apiBuild-DOnvi2zm.js +0 -2
- package/dist/dataCommand-hIaq2iKY.js +0 -1052
- package/dist/dataProfile-Cm0YVKSy.js +0 -18
- package/dist/dbCommand-D1Q33ktl.js +0 -2
- package/dist/doctorCommand-CWgUPye-.js +0 -2
- package/dist/frameworkTableAssembly-Rft-DPUg.js +0 -2
- package/dist/serveCommand-CV3YO9L3.js +0 -2035
- package/dist/serveCommand-ZP_Cb-yz.js +0 -2
- package/dist/updateCommand-CT5AvVg7.js +0 -2
|
@@ -2,13 +2,13 @@ import { E as e, N as t, O as n, T as r, d as i, f as a, h as o, i as s, l as c,
|
|
|
2
2
|
import { t as d } from "./pageConvention-cEiRxdab.js";
|
|
3
3
|
import { r as f } from "./tsconfigPaths-BWXBWgcl.js";
|
|
4
4
|
import { a as p, i as ee, t as te } from "./fileTaxonomy-CJfgOllU.js";
|
|
5
|
-
import { basename as m, dirname as h, join as g, relative as
|
|
6
|
-
import { existsSync as
|
|
7
|
-
import { execFileSync as
|
|
8
|
-
import { Node as
|
|
9
|
-
import { globSync as
|
|
5
|
+
import { basename as m, dirname as h, join as g, relative as _ } from "node:path";
|
|
6
|
+
import { existsSync as v, readFileSync as ne } from "node:fs";
|
|
7
|
+
import { execFileSync as re } from "node:child_process";
|
|
8
|
+
import { Node as y, Project as ie, QuoteKind as ae, SyntaxKind as b } from "ts-morph";
|
|
9
|
+
import { globSync as oe } from "tinyglobby";
|
|
10
10
|
//#region src/codemodHelpers.ts
|
|
11
|
-
var
|
|
11
|
+
var x = (e, t, n) => {
|
|
12
12
|
let r = [];
|
|
13
13
|
for (let i of e.getImportDeclarations()) if (i.getModuleSpecifierValue() === t) for (let e of i.getNamedImports()) {
|
|
14
14
|
if (e.getName() !== n) continue;
|
|
@@ -16,70 +16,70 @@ var b = (e, t, n) => {
|
|
|
16
16
|
r.push(t ? t.getText() : e.getName());
|
|
17
17
|
}
|
|
18
18
|
return r;
|
|
19
|
-
},
|
|
19
|
+
}, S = (e, t) => {
|
|
20
20
|
let n = e.getExpression();
|
|
21
|
-
return
|
|
22
|
-
},
|
|
21
|
+
return y.isIdentifier(n) && t.includes(n.getText());
|
|
22
|
+
}, se = (e, { module: t, from: n, to: r }) => {
|
|
23
23
|
let i = 0;
|
|
24
24
|
for (let a of e.getSourceFiles()) for (let e of a.getImportDeclarations()) if (e.getModuleSpecifierValue() === t) for (let t of e.getNamedImports()) {
|
|
25
25
|
if (t.getName() !== n) continue;
|
|
26
26
|
let e = t.getNameNode();
|
|
27
|
-
!t.getAliasNode() &&
|
|
27
|
+
!t.getAliasNode() && y.isIdentifier(e) ? e.rename(r) : e.replaceWithText(r), i++;
|
|
28
28
|
}
|
|
29
29
|
return i;
|
|
30
|
-
},
|
|
30
|
+
}, ce = (e, { from: t, to: n }) => {
|
|
31
31
|
let r = 0;
|
|
32
32
|
for (let i of e.getSourceFiles()) {
|
|
33
33
|
for (let e of i.getImportDeclarations()) e.getModuleSpecifierValue() === t && (e.setModuleSpecifier(n), r++);
|
|
34
34
|
for (let e of i.getExportDeclarations()) e.getModuleSpecifierValue() === t && (e.setModuleSpecifier(n), r++);
|
|
35
|
-
for (let e of i.getDescendantsOfKind(
|
|
36
|
-
if (e.getExpression().getKind() !==
|
|
35
|
+
for (let e of i.getDescendantsOfKind(b.CallExpression)) {
|
|
36
|
+
if (e.getExpression().getKind() !== b.ImportKeyword) continue;
|
|
37
37
|
let i = e.getArguments()[0];
|
|
38
|
-
i &&
|
|
38
|
+
i && y.isStringLiteral(i) && i.getLiteralValue() === t && (i.replaceWithText(JSON.stringify(n)), r++);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
return r;
|
|
42
|
-
},
|
|
42
|
+
}, le = (e, { component: t, from: n, to: r }) => {
|
|
43
43
|
let i = 0;
|
|
44
44
|
for (let a of e.getSourceFiles()) {
|
|
45
|
-
let e = [...a.getDescendantsOfKind(
|
|
46
|
-
for (let a of e) if (a.getTagNameNode().getText() === t) for (let e of a.getAttributes())
|
|
45
|
+
let e = [...a.getDescendantsOfKind(b.JsxOpeningElement), ...a.getDescendantsOfKind(b.JsxSelfClosingElement)];
|
|
46
|
+
for (let a of e) if (a.getTagNameNode().getText() === t) for (let e of a.getAttributes()) y.isJsxAttribute(e) && e.getNameNode().getText() === n && (e.getNameNode().replaceWithText(r), i++);
|
|
47
47
|
}
|
|
48
48
|
return i;
|
|
49
|
-
},
|
|
49
|
+
}, ue = (e, { inCallTo: t, module: n, from: r, to: i }) => {
|
|
50
50
|
let a = 0;
|
|
51
51
|
for (let o of e.getSourceFiles()) {
|
|
52
|
-
let e =
|
|
53
|
-
if (e.length !== 0) for (let t of o.getDescendantsOfKind(
|
|
54
|
-
if (!
|
|
52
|
+
let e = x(o, n, t);
|
|
53
|
+
if (e.length !== 0) for (let t of o.getDescendantsOfKind(b.CallExpression).reverse()) {
|
|
54
|
+
if (!S(t, e)) continue;
|
|
55
55
|
let n = t.getArguments()[0];
|
|
56
|
-
if (!(!n || !
|
|
57
|
-
if (!
|
|
56
|
+
if (!(!n || !y.isObjectLiteralExpression(n))) for (let e of n.getProperties()) {
|
|
57
|
+
if (!y.isPropertyAssignment(e) && !y.isShorthandPropertyAssignment(e)) continue;
|
|
58
58
|
let t = e.getNameNode();
|
|
59
|
-
t.getText() === r && (
|
|
59
|
+
t.getText() === r && (y.isShorthandPropertyAssignment(e) ? e.replaceWithText(`${i}: ${r}`) : t.replaceWithText(i), a++);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
return a;
|
|
64
|
-
},
|
|
64
|
+
}, de = (e, { module: t, name: n }) => {
|
|
65
65
|
let r = 0;
|
|
66
66
|
for (let i of e.getSourceFiles()) {
|
|
67
67
|
let e = i.getImportDeclaration((e) => e.getModuleSpecifierValue() === t);
|
|
68
68
|
e && (e.getNamedImports().some((e) => e.getName() === n) || (e.addNamedImport(n), r++));
|
|
69
69
|
}
|
|
70
70
|
return r;
|
|
71
|
-
},
|
|
71
|
+
}, fe = (e, t, n) => {
|
|
72
72
|
let r = e.getImportDeclaration((e) => e.getModuleSpecifierValue() === t);
|
|
73
73
|
r ? r.getNamedImports().some((e) => e.getName() === n) || r.addNamedImport(n) : e.addImportDeclaration({
|
|
74
74
|
moduleSpecifier: t,
|
|
75
75
|
namedImports: [n]
|
|
76
76
|
});
|
|
77
|
-
},
|
|
78
|
-
renameImport:
|
|
79
|
-
renameModuleSpecifier:
|
|
80
|
-
renameJsxProp:
|
|
81
|
-
renameObjectKey:
|
|
82
|
-
addImport:
|
|
77
|
+
}, pe = {
|
|
78
|
+
renameImport: se,
|
|
79
|
+
renameModuleSpecifier: ce,
|
|
80
|
+
renameJsxProp: le,
|
|
81
|
+
renameObjectKey: ue,
|
|
82
|
+
addImport: de,
|
|
83
83
|
removeImport: (e, { module: t, name: n }) => {
|
|
84
84
|
let r = 0;
|
|
85
85
|
for (let i of e.getSourceFiles()) for (let e of i.getImportDeclarations()) {
|
|
@@ -92,9 +92,9 @@ var b = (e, t, n) => {
|
|
|
92
92
|
changeCallArgs: (e, { module: t, callee: n, reorder: r, drop: i, toObject: a }) => {
|
|
93
93
|
let o = 0;
|
|
94
94
|
for (let s of e.getSourceFiles()) {
|
|
95
|
-
let e =
|
|
96
|
-
if (e.length !== 0) for (let t of s.getDescendantsOfKind(
|
|
97
|
-
if (!
|
|
95
|
+
let e = x(s, t, n);
|
|
96
|
+
if (e.length !== 0) for (let t of s.getDescendantsOfKind(b.CallExpression).reverse()) {
|
|
97
|
+
if (!S(t, e)) continue;
|
|
98
98
|
let n = t.getArguments().map((e) => e.getText());
|
|
99
99
|
if (r && (n = r.map((e) => n[e]).filter((e) => e !== void 0)), i) {
|
|
100
100
|
let e = new Set(i);
|
|
@@ -113,31 +113,31 @@ var b = (e, t, n) => {
|
|
|
113
113
|
wrapCall: (e, { module: t, callee: n, wrapper: r, wrapperModule: i }) => {
|
|
114
114
|
let a = 0;
|
|
115
115
|
for (let o of e.getSourceFiles()) {
|
|
116
|
-
let e =
|
|
116
|
+
let e = x(o, t, n);
|
|
117
117
|
if (e.length === 0) continue;
|
|
118
118
|
let s = !1;
|
|
119
|
-
for (let t of o.getDescendantsOfKind(
|
|
120
|
-
s &&
|
|
119
|
+
for (let t of o.getDescendantsOfKind(b.CallExpression).reverse()) S(t, e) && (t.replaceWithText(`${r}(${t.getText()})`), s = !0, a++);
|
|
120
|
+
s && fe(o, i, r);
|
|
121
121
|
}
|
|
122
122
|
return a;
|
|
123
123
|
},
|
|
124
124
|
annotate: (e, { module: t, symbol: n, comment: r }) => {
|
|
125
125
|
let i = 0;
|
|
126
126
|
for (let a of e.getSourceFiles()) {
|
|
127
|
-
let e =
|
|
127
|
+
let e = x(a, t, n);
|
|
128
128
|
if (e.length === 0) continue;
|
|
129
129
|
let o = /* @__PURE__ */ new Map();
|
|
130
|
-
for (let t of a.getDescendantsOfKind(
|
|
130
|
+
for (let t of a.getDescendantsOfKind(b.Identifier)) {
|
|
131
131
|
if (!e.includes(t.getText())) continue;
|
|
132
|
-
let n = t.getFirstAncestorByKind(
|
|
132
|
+
let n = t.getFirstAncestorByKind(b.ExpressionStatement) ?? t.getFirstAncestorByKind(b.VariableStatement) ?? t.getFirstAncestorByKind(b.ReturnStatement);
|
|
133
133
|
n && o.set(n.getStart(), n);
|
|
134
134
|
}
|
|
135
135
|
for (let e of [...o.values()].sort((e, t) => t.getStart() - e.getStart())) e.replaceWithText(`// TODO(voltro-migration): ${r}\n${e.getText()}`), i++;
|
|
136
136
|
}
|
|
137
137
|
return i;
|
|
138
138
|
}
|
|
139
|
-
},
|
|
140
|
-
if (!
|
|
139
|
+
}, me = /^\d+\.\d+\.\d+$/, C = (e) => {
|
|
140
|
+
if (!me.test(e.version)) throw Error(`codemod "${e.id}": version must be x.y.z (got "${e.version}")`);
|
|
141
141
|
if (!e.id.startsWith(`${e.version}/`)) throw Error(`codemod "${e.id}": id must start with "${e.version}/" (the version it migrates to)`);
|
|
142
142
|
if (e.kind === "transform" && typeof e.transform != "function") throw Error(`codemod "${e.id}": kind:'transform' requires a transform() function`);
|
|
143
143
|
if (e.kind === "manual" && (e.note === void 0 || e.note.trim() === "")) throw Error(`codemod "${e.id}": kind:'manual' requires a non-empty note`);
|
|
@@ -147,14 +147,14 @@ var b = (e, t, n) => {
|
|
|
147
147
|
__codemod: !0,
|
|
148
148
|
seq: n
|
|
149
149
|
};
|
|
150
|
-
},
|
|
150
|
+
}, w = (e) => RegExp(`\\b${e}\\s*(?:<[^()]*>)?\\s*\\(`), he = (e, t) => {
|
|
151
151
|
let n = e.version.split(".").map(Number), r = t.version.split(".").map(Number);
|
|
152
152
|
for (let e = 0; e < 3; e++) {
|
|
153
153
|
let t = (n[e] ?? 0) - (r[e] ?? 0);
|
|
154
154
|
if (t !== 0) return t;
|
|
155
155
|
}
|
|
156
156
|
return e.seq === t.seq ? e.id < t.id ? -1 : +(e.id > t.id) : e.seq - t.seq;
|
|
157
|
-
},
|
|
157
|
+
}, ge = C({
|
|
158
158
|
version: "0.3.0",
|
|
159
159
|
id: "0.3.0/01_prod-serve-requires-build",
|
|
160
160
|
title: "Production `voltro serve` requires a precompiled bundle (build before serve)",
|
|
@@ -174,7 +174,7 @@ var b = (e, t, n) => {
|
|
|
174
174
|
"",
|
|
175
175
|
"`voltro dev` and a non-production local `voltro serve` are unchanged (still tsx)."
|
|
176
176
|
].join("\n")
|
|
177
|
-
}),
|
|
177
|
+
}), _e = C({
|
|
178
178
|
version: "0.4.0",
|
|
179
179
|
id: "0.4.0/01_rbac-forbidden-to-scopeerror",
|
|
180
180
|
title: "@voltro/plugin-rbac: `Forbidden` → protocol `ScopeError` (one denial tag)",
|
|
@@ -200,36 +200,36 @@ var b = (e, t, n) => {
|
|
|
200
200
|
let a = r + i;
|
|
201
201
|
a > 0 && n(`rbac Forbidden → ScopeError: rewrote ${a} import site(s). Check any \`new Forbidden({ reason })\` (→ \`new ScopeError({ message })\`) and \`catchTag('Forbidden')\` / \`_tag === 'Forbidden'\` (→ 'ScopeError') by hand.`);
|
|
202
202
|
}
|
|
203
|
-
}),
|
|
203
|
+
}), T = "@voltro/plugin-rbac/web", ve = "@voltro/client", ye = C({
|
|
204
204
|
version: "0.4.0",
|
|
205
205
|
id: "0.4.0/02_rbac-web-to-client-permissions",
|
|
206
206
|
title: "@voltro/plugin-rbac/web removed — the UI gate lives in @voltro/client",
|
|
207
207
|
kind: "transform",
|
|
208
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue() ===
|
|
208
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue() === T)),
|
|
209
209
|
transform: ({ project: e, helpers: t, log: n }) => {
|
|
210
210
|
let r = t.annotate(e, {
|
|
211
|
-
module:
|
|
211
|
+
module: T,
|
|
212
212
|
symbol: "RbacScopeContext",
|
|
213
213
|
comment: "voltro 0.4.0: RbacScopeContext is gone. Read scopes with `usePermissions()` from '@voltro/client' — it returns { scopes }, not the bare array."
|
|
214
214
|
}), i = t.renameImport(e, {
|
|
215
|
-
module:
|
|
215
|
+
module: T,
|
|
216
216
|
from: "RbacScopeProvider",
|
|
217
217
|
to: "PermissionProvider"
|
|
218
218
|
}) + t.renameImport(e, {
|
|
219
|
-
module:
|
|
219
|
+
module: T,
|
|
220
220
|
from: "canFromScopes",
|
|
221
221
|
to: "canCall"
|
|
222
222
|
}) + t.renameImport(e, {
|
|
223
|
-
module:
|
|
223
|
+
module: T,
|
|
224
224
|
from: "canAnyFromScopes",
|
|
225
225
|
to: "canCallAny"
|
|
226
226
|
}), a = t.renameModuleSpecifier(e, {
|
|
227
|
-
from:
|
|
228
|
-
to:
|
|
227
|
+
from: T,
|
|
228
|
+
to: ve
|
|
229
229
|
});
|
|
230
230
|
a > 0 && n(`@voltro/plugin-rbac/web → @voltro/client: repointed ${a} import(s)` + (i > 0 ? `, renamed ${i} symbol(s)` : "") + ". Mount <PermissionProvider scopes={…}> where <RbacScopeProvider> was — same prop, and it now feeds useCan across the whole app." + (r > 0 ? ` ${r} RbacScopeContext site(s) were annotated: switch them to usePermissions().` : ""));
|
|
231
231
|
}
|
|
232
|
-
}),
|
|
232
|
+
}), be = C({
|
|
233
233
|
version: "0.5.0",
|
|
234
234
|
id: "0.5.0/01_one-terminal-exactly-one",
|
|
235
235
|
title: ".one() now fails on MORE than one row; NoRowFound is a declarable typed error",
|
|
@@ -262,7 +262,7 @@ var b = (e, t, n) => {
|
|
|
262
262
|
" new OptimisticLockError({ table: 'notes', expected: 3 })",
|
|
263
263
|
" • `instanceof` and `err._tag === 'NoRowFound'` checks are unaffected."
|
|
264
264
|
].join("\n")
|
|
265
|
-
}),
|
|
265
|
+
}), xe = C({
|
|
266
266
|
version: "0.5.0",
|
|
267
267
|
id: "0.5.0/02_typed-store-rows",
|
|
268
268
|
title: "store.query() now returns the row type — casts on row fields may stop compiling",
|
|
@@ -301,14 +301,14 @@ var b = (e, t, n) => {
|
|
|
301
301
|
"A hand-built descriptor still resolves to `Row`, so untyped call sites are",
|
|
302
302
|
"unaffected."
|
|
303
303
|
].join("\n")
|
|
304
|
-
}),
|
|
304
|
+
}), Se = /VOLTRO_DEV_SESSION_SECRET|voltro-dev-session-secret/, Ce = /VOLTRO_SESSION_SECRET\s*(?:\?\?|\|\|)\s*['"`]/, we = C({
|
|
305
305
|
version: "0.6.0",
|
|
306
306
|
id: "0.6.0/01_no-dev-session-secret",
|
|
307
307
|
title: "The built-in dev session secret is removed; VOLTRO_SESSION_SECRET is required",
|
|
308
308
|
kind: "manual",
|
|
309
309
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
310
310
|
let t = e.getFullText();
|
|
311
|
-
return
|
|
311
|
+
return Se.test(t) || Ce.test(t);
|
|
312
312
|
}),
|
|
313
313
|
note: [
|
|
314
314
|
"The framework no longer has a built-in fallback session secret.",
|
|
@@ -352,14 +352,14 @@ var b = (e, t, n) => {
|
|
|
352
352
|
" voltro secret generate session",
|
|
353
353
|
" `voltro dev` minting one for you locally does NOT cover your deployment."
|
|
354
354
|
].join("\n")
|
|
355
|
-
}),
|
|
355
|
+
}), Te = /computeProration|roundHalfAwayFromZero|ProrationInput|ProrationResult|DunningState|DunningCycleResult|DunningSchedule|DEFAULT_DUNNING_SCHEDULE|validateDunningSchedule|retryTimeFor|openDunning|recoverDunning|advanceDunning|runDunningCycle|recordPaymentFailure|recordPaymentSuccess|dunningSchedule|DunningStore|memoryDunningStore|dataStoreDunningStore/, Ee = C({
|
|
356
356
|
version: "0.6.0",
|
|
357
357
|
id: "0.6.0/03_billing-on-stripe-sdk",
|
|
358
358
|
title: "Billing moved onto the Stripe SDK; proration + dunning are now Stripe’s",
|
|
359
359
|
kind: "manual",
|
|
360
360
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
361
361
|
let t = e.getFullText();
|
|
362
|
-
return
|
|
362
|
+
return Te.test(t) || /@voltro\/plugin-billing/.test(t);
|
|
363
363
|
}),
|
|
364
364
|
note: [
|
|
365
365
|
"`@voltro/plugin-billing` now talks to Stripe through the official SDK, and two",
|
|
@@ -415,7 +415,7 @@ var b = (e, t, n) => {
|
|
|
415
415
|
" Set a `priceId` on every paid plan. A subscription created in the Stripe",
|
|
416
416
|
" Dashboard is now recognised via its price id, which requires the mapping."
|
|
417
417
|
].join("\n")
|
|
418
|
-
}),
|
|
418
|
+
}), De = C({
|
|
419
419
|
version: "0.6.0",
|
|
420
420
|
id: "0.6.0/02_subscription-state-union",
|
|
421
421
|
title: "SubscriptionState is a discriminated union — `loading` now narrows `data`",
|
|
@@ -462,7 +462,7 @@ var b = (e, t, n) => {
|
|
|
462
462
|
"`error` set. If you branch only on `loading`, check `error` too, or that",
|
|
463
463
|
"case renders a skeleton forever."
|
|
464
464
|
].join("\n")
|
|
465
|
-
}),
|
|
465
|
+
}), Oe = C({
|
|
466
466
|
version: "0.6.0",
|
|
467
467
|
id: "0.6.0/04_relation-key-validation",
|
|
468
468
|
title: "relation key options are validated at boot; `one` now fails on more than one match",
|
|
@@ -503,28 +503,28 @@ var b = (e, t, n) => {
|
|
|
503
503
|
"read it now rather than waiting: `sourceKey` is almost always what a",
|
|
504
504
|
"\"parent\" relation means."
|
|
505
505
|
].join("\n")
|
|
506
|
-
}),
|
|
506
|
+
}), ke = "@voltro/plugin-atlassian", Ae = "atlassianPlugin", E = (e) => {
|
|
507
507
|
let t = [];
|
|
508
|
-
for (let n of e.getImportDeclarations()) if (n.getModuleSpecifierValue() ===
|
|
508
|
+
for (let n of e.getImportDeclarations()) if (n.getModuleSpecifierValue() === ke) for (let e of n.getNamedImports()) e.getName() === Ae && t.push(e.getAliasNode()?.getText() ?? e.getName());
|
|
509
509
|
return t;
|
|
510
|
-
},
|
|
510
|
+
}, je = C({
|
|
511
511
|
version: "0.6.0",
|
|
512
512
|
id: "0.6.0/05_atlassian-avatar-mode",
|
|
513
513
|
title: "atlassianPlugin's `avatar` config requires an explicit `mode: 'service' | 'perUser'`",
|
|
514
514
|
kind: "transform",
|
|
515
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
515
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => E(e).length > 0),
|
|
516
516
|
transform: ({ project: e, log: t }) => {
|
|
517
517
|
let n = 0;
|
|
518
518
|
for (let t of e.getSourceFiles()) {
|
|
519
|
-
let e =
|
|
520
|
-
if (e.length !== 0) for (let r of t.getDescendantsOfKind(
|
|
519
|
+
let e = E(t);
|
|
520
|
+
if (e.length !== 0) for (let r of t.getDescendantsOfKind(b.CallExpression)) {
|
|
521
521
|
if (!e.includes(r.getExpression().getText())) continue;
|
|
522
522
|
let t = r.getArguments()[0];
|
|
523
|
-
if (!t || !
|
|
523
|
+
if (!t || !y.isObjectLiteralExpression(t)) continue;
|
|
524
524
|
let i = t.getProperty("avatar");
|
|
525
|
-
if (!i || !
|
|
525
|
+
if (!i || !y.isPropertyAssignment(i)) continue;
|
|
526
526
|
let a = i.getInitializer();
|
|
527
|
-
!a || !
|
|
527
|
+
!a || !y.isObjectLiteralExpression(a) || a.getProperty("mode") || (a.insertPropertyAssignment(0, {
|
|
528
528
|
name: "mode",
|
|
529
529
|
initializer: "'service'"
|
|
530
530
|
}), n++);
|
|
@@ -532,7 +532,7 @@ var b = (e, t, n) => {
|
|
|
532
532
|
}
|
|
533
533
|
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"));
|
|
534
534
|
}
|
|
535
|
-
}),
|
|
535
|
+
}), Me = C({
|
|
536
536
|
version: "0.6.0",
|
|
537
537
|
id: "0.6.0/06_ui-strings-connect-account",
|
|
538
538
|
title: "UiStrings gained a required `connectAccount` section",
|
|
@@ -576,14 +576,14 @@ var b = (e, t, n) => {
|
|
|
576
576
|
"Alternatively, switch the annotation to `PartialUiStrings` if the object",
|
|
577
577
|
"was only ever an override bag."
|
|
578
578
|
].join("\n")
|
|
579
|
-
}),
|
|
579
|
+
}), Ne = w("setRowFilter"), Pe = /\bresolveRowFilterScope\b/, Fe = C({
|
|
580
580
|
version: "0.7.0",
|
|
581
581
|
id: "0.7.0/01_row-filter-load-failure",
|
|
582
582
|
title: "A row filter that fails to load now errors instead of returning zero rows",
|
|
583
583
|
kind: "manual",
|
|
584
584
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
585
585
|
let t = e.getFullText();
|
|
586
|
-
return
|
|
586
|
+
return Ne.test(t) || Pe.test(t);
|
|
587
587
|
}),
|
|
588
588
|
note: [
|
|
589
589
|
"Row-level security: a `load` failure is now an ERROR, and is retried first.",
|
|
@@ -654,14 +654,14 @@ var b = (e, t, n) => {
|
|
|
654
654
|
" \"every row you could see was just deleted\". Make sure your subscription",
|
|
655
655
|
" error handling surfaces this rather than swallowing it."
|
|
656
656
|
].join("\n")
|
|
657
|
-
}),
|
|
657
|
+
}), Ie = C({
|
|
658
658
|
version: "0.7.0",
|
|
659
659
|
id: "0.7.0/02_testing-invoke-effect-handlers",
|
|
660
660
|
title: "@voltro/testing: invoke() runs Effect handlers; executor types widened",
|
|
661
661
|
kind: "manual",
|
|
662
662
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
663
663
|
let t = e.getFullText();
|
|
664
|
-
return t.includes("@voltro/testing") ?
|
|
664
|
+
return t.includes("@voltro/testing") ? w("invoke").test(t) || /\bProcedureExecutor\b/.test(t) : !1;
|
|
665
665
|
}),
|
|
666
666
|
note: [
|
|
667
667
|
"`invoke(descriptor, executor, input, ctx)` now DETECTS an Effect-returning",
|
|
@@ -709,14 +709,14 @@ var b = (e, t, n) => {
|
|
|
709
709
|
"transaction, the deadlock replay, `afterCommit` and the plugin interceptor",
|
|
710
710
|
"chain wrap an Effect handler exactly as they wrap an async one."
|
|
711
711
|
].join("\n")
|
|
712
|
-
}),
|
|
712
|
+
}), Le = /\bpasswordHash\b/, Re = /\b(UserStore|UserRecord|memoryUserStore|postgresUserStore)\b/, ze = C({
|
|
713
713
|
version: "0.8.0",
|
|
714
714
|
id: "0.8.0/01_optional-password-hash",
|
|
715
715
|
title: "`UserRecord.passwordHash` is optional — password-less identities are now first-class",
|
|
716
716
|
kind: "manual",
|
|
717
717
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
718
718
|
let t = e.getFullText();
|
|
719
|
-
return
|
|
719
|
+
return Le.test(t) || Re.test(t);
|
|
720
720
|
}),
|
|
721
721
|
note: [
|
|
722
722
|
"`UserRecord.passwordHash` is now `string | null | undefined`, not `string`.",
|
|
@@ -787,7 +787,7 @@ var b = (e, t, n) => {
|
|
|
787
787
|
" to match and make sure your read path maps a NULL column to `null`/",
|
|
788
788
|
" `undefined` rather than to `''`-by-coercion."
|
|
789
789
|
].join("\n")
|
|
790
|
-
}),
|
|
790
|
+
}), Be = C({
|
|
791
791
|
version: "0.8.0",
|
|
792
792
|
id: "0.8.0/02_ssr-streams-and-loaderdata",
|
|
793
793
|
title: "`ssr` pages stream; `useLoaderData<T>()` returns `LoaderData<T>`",
|
|
@@ -839,13 +839,13 @@ var b = (e, t, n) => {
|
|
|
839
839
|
"docs. `defer()` requires `renderMode: 'ssr'` and `interactive: 'full'`;",
|
|
840
840
|
"every other combination is a hard error naming the page."
|
|
841
841
|
].join("\n")
|
|
842
|
-
}),
|
|
842
|
+
}), Ve = /renderMode\s*[=:]\s*['"](spa|client)['"]/, He = /(^|[/\\])pages[/\\].*[/\\]?layout\.tsx$/, Ue = C({
|
|
843
843
|
version: "0.9.0",
|
|
844
844
|
id: "0.9.0/01_ssr-layout-shell-for-spa",
|
|
845
845
|
title: "A `renderMode:'spa'` page under a layout now server-renders that layout",
|
|
846
846
|
kind: "manual",
|
|
847
847
|
appliesTo: ({ project: e }) => {
|
|
848
|
-
let t = e.getSourceFiles(), n = t.some((e) =>
|
|
848
|
+
let t = e.getSourceFiles(), n = t.some((e) => Ve.test(e.getFullText())), r = t.some((e) => He.test(e.getFilePath()));
|
|
849
849
|
return n && r;
|
|
850
850
|
},
|
|
851
851
|
note: [
|
|
@@ -884,35 +884,35 @@ var b = (e, t, n) => {
|
|
|
884
884
|
"Nothing changes for `static` / `ssr` / `isr` pages, or for a spa page that",
|
|
885
885
|
"has no layout (still a pure client mount)."
|
|
886
886
|
].join("\n")
|
|
887
|
-
}),
|
|
887
|
+
}), D = "client", We = "spa", O = (e) => {
|
|
888
888
|
if (!e) return null;
|
|
889
|
-
let t =
|
|
890
|
-
return
|
|
891
|
-
},
|
|
889
|
+
let t = y.isAsExpression(e) ? e.getExpression() : e;
|
|
890
|
+
return y.isStringLiteral(t) ? t : null;
|
|
891
|
+
}, k = (e) => {
|
|
892
892
|
let t = [];
|
|
893
|
-
for (let n of e.getDescendantsOfKind(
|
|
893
|
+
for (let n of e.getDescendantsOfKind(b.VariableDeclaration)) {
|
|
894
894
|
if (n.getName() !== "renderMode") continue;
|
|
895
|
-
let e =
|
|
895
|
+
let e = O(n.getInitializer());
|
|
896
896
|
e && t.push(e);
|
|
897
897
|
}
|
|
898
|
-
for (let n of e.getDescendantsOfKind(
|
|
898
|
+
for (let n of e.getDescendantsOfKind(b.PropertyAssignment)) {
|
|
899
899
|
if (n.getName() !== "renderMode") continue;
|
|
900
|
-
let e =
|
|
900
|
+
let e = O(n.getInitializer());
|
|
901
901
|
e && t.push(e);
|
|
902
902
|
}
|
|
903
903
|
return t;
|
|
904
|
-
},
|
|
904
|
+
}, Ge = C({
|
|
905
905
|
version: "0.10.0",
|
|
906
906
|
id: "0.10.0/01_render-mode-client-to-spa",
|
|
907
907
|
title: "renderMode is a closed set — `'client'` becomes `'spa'`",
|
|
908
908
|
kind: "transform",
|
|
909
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
909
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => k(e).some((e) => e.getLiteralValue() === D)),
|
|
910
910
|
transform: ({ project: e, log: t }) => {
|
|
911
911
|
let n = 0, r = /* @__PURE__ */ new Set();
|
|
912
|
-
for (let t of e.getSourceFiles()) for (let e of
|
|
913
|
-
n > 0 && (t(`renderMode: rewrote ${n} \`'${
|
|
912
|
+
for (let t of e.getSourceFiles()) for (let e of k(t)) e.getLiteralValue() === D && (e.setLiteralValue(We), n++, r.add(t.getFilePath()));
|
|
913
|
+
n > 0 && (t(`renderMode: rewrote ${n} \`'${D}'\` → \`'${We}'\` 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)"));
|
|
914
914
|
}
|
|
915
|
-
}),
|
|
915
|
+
}), Ke = C({
|
|
916
916
|
version: "0.10.0",
|
|
917
917
|
id: "0.10.0/02_router-state-carries-its-path",
|
|
918
918
|
title: "`renderRouterStateScript` now requires the `path` it rendered",
|
|
@@ -949,7 +949,7 @@ var b = (e, t, n) => {
|
|
|
949
949
|
"Trailing slashes, a trailing `/index.html`, and percent-encoding are normalised",
|
|
950
950
|
"before the comparison, so the usual static-host shapes still hydrate."
|
|
951
951
|
].join("\n")
|
|
952
|
-
}),
|
|
952
|
+
}), qe = C({
|
|
953
953
|
version: "0.10.0",
|
|
954
954
|
id: "0.10.0/03_workflow-caller-context-resolved",
|
|
955
955
|
title: "workflow `buildContext` receives a RESOLVED caller context",
|
|
@@ -995,7 +995,7 @@ var b = (e, t, n) => {
|
|
|
995
995
|
"it receives the resolved context too, so `callerContext?.subject ?? …` there",
|
|
996
996
|
"becomes `callerContext.subject`."
|
|
997
997
|
].join("\n")
|
|
998
|
-
}),
|
|
998
|
+
}), Je = C({
|
|
999
999
|
version: "0.10.0",
|
|
1000
1000
|
id: "0.10.0/04_seed-run-status-skipped",
|
|
1001
1001
|
title: "seed run status gained `skipped`",
|
|
@@ -1036,7 +1036,7 @@ var b = (e, t, n) => {
|
|
|
1036
1036
|
"`Schema.Literal`, a zod enum, a DB check constraint), widen it there too — an",
|
|
1037
1037
|
"unlisted third state is a DECODE failure, not a rendering oddity."
|
|
1038
1038
|
].join("\n")
|
|
1039
|
-
}),
|
|
1039
|
+
}), Ye = C({
|
|
1040
1040
|
version: "0.10.0",
|
|
1041
1041
|
id: "0.10.0/05_subscription-idle-state",
|
|
1042
1042
|
title: "`useSubscription` gained an idle state for `skip`",
|
|
@@ -1088,7 +1088,7 @@ var b = (e, t, n) => {
|
|
|
1088
1088
|
"time's data), hold it in your own state — the subscription no longer claims to",
|
|
1089
1089
|
"have data it was told to stop fetching."
|
|
1090
1090
|
].join("\n")
|
|
1091
|
-
}),
|
|
1091
|
+
}), Xe = C({
|
|
1092
1092
|
version: "0.11.0",
|
|
1093
1093
|
id: "0.11.0/01_step-options-type-params",
|
|
1094
1094
|
title: "`StepOptions` takes the context type first",
|
|
@@ -1116,7 +1116,7 @@ var b = (e, t, n) => {
|
|
|
1116
1116
|
"If the step reads nothing from earlier steps, `StepOptions<Record<never, never>,",
|
|
1117
1117
|
"Result>` is the honest spelling."
|
|
1118
1118
|
].join("\n")
|
|
1119
|
-
}),
|
|
1119
|
+
}), Ze = C({
|
|
1120
1120
|
version: "0.12.0",
|
|
1121
1121
|
id: "0.12.0/01_outbound-http-ssrf-guard",
|
|
1122
1122
|
title: "Outbound HttpClient blocks internal targets by default (add `http.allowHosts` if you call one)",
|
|
@@ -1156,7 +1156,7 @@ var b = (e, t, n) => {
|
|
|
1156
1156
|
"private address (DNS rebinding) still passes. Pair with network-layer egress",
|
|
1157
1157
|
"control if that is in your threat model."
|
|
1158
1158
|
].join("\n")
|
|
1159
|
-
}),
|
|
1159
|
+
}), Qe = C({
|
|
1160
1160
|
version: "0.12.0",
|
|
1161
1161
|
id: "0.12.0/02_api-key-revoke-tenant-scope",
|
|
1162
1162
|
title: "apiKeyService.revoke/rotate now require the caller's tenantId",
|
|
@@ -1185,7 +1185,7 @@ var b = (e, t, n) => {
|
|
|
1185
1185
|
"The framework's own `/v1/api-keys/revoke` route already passes the caller's",
|
|
1186
1186
|
"tenant — no change needed if you only use the shipped routes."
|
|
1187
1187
|
].join("\n")
|
|
1188
|
-
}),
|
|
1188
|
+
}), $e = C({
|
|
1189
1189
|
version: "0.12.0",
|
|
1190
1190
|
id: "0.12.0/03_api-key-on-behalf-of",
|
|
1191
1191
|
title: "API keys: createdBy is provenance, onBehalfOf is ownership",
|
|
@@ -1219,7 +1219,7 @@ var b = (e, t, n) => {
|
|
|
1219
1219
|
"specific one against what the body asks for. Grant them in your role map. A key",
|
|
1220
1220
|
"can never carry scopes its issuer does not hold."
|
|
1221
1221
|
].join("\n")
|
|
1222
|
-
}),
|
|
1222
|
+
}), et = C({
|
|
1223
1223
|
version: "0.12.0",
|
|
1224
1224
|
id: "0.12.0/04_inspect-fail-closed",
|
|
1225
1225
|
title: "The inspect surface requires VOLTRO_INSPECT_TOKEN (previously open when unset)",
|
|
@@ -1248,7 +1248,7 @@ var b = (e, t, n) => {
|
|
|
1248
1248
|
"",
|
|
1249
1249
|
"To turn the surface off entirely instead, set `VOLTRO_INSPECT=off`."
|
|
1250
1250
|
].join("\n")
|
|
1251
|
-
}),
|
|
1251
|
+
}), tt = C({
|
|
1252
1252
|
version: "0.13.0",
|
|
1253
1253
|
id: "0.13.0/01_bearer-gates-fail-closed",
|
|
1254
1254
|
title: "checkBearer is fail-closed; scimPlugin refuses an empty token",
|
|
@@ -1285,7 +1285,7 @@ var b = (e, t, n) => {
|
|
|
1285
1285
|
" • `@voltro/plugin-prometheus` already passes `{ openWhenUnset: true }` — its",
|
|
1286
1286
|
" `PROMETHEUS_TOKEN` is documented as optional. Nothing to do there."
|
|
1287
1287
|
].join("\n")
|
|
1288
|
-
}),
|
|
1288
|
+
}), nt = C({
|
|
1289
1289
|
version: "0.13.0",
|
|
1290
1290
|
id: "0.13.0/02_storage-grants-owner-only",
|
|
1291
1291
|
title: "storage.share / revoke / listGrants require ownership",
|
|
@@ -1316,7 +1316,7 @@ var b = (e, t, n) => {
|
|
|
1316
1316
|
" returning the grant or null. `storage.revoke` is handed a grant id, so it has",
|
|
1317
1317
|
" to resolve the object before it can check the owner."
|
|
1318
1318
|
].join("\n")
|
|
1319
|
-
}),
|
|
1319
|
+
}), rt = C({
|
|
1320
1320
|
version: "0.13.0",
|
|
1321
1321
|
id: "0.13.0/03_apply-plan-convergence-proof",
|
|
1322
1322
|
title: "applyPlan requires a `replan` convergence proof",
|
|
@@ -1349,7 +1349,7 @@ var b = (e, t, n) => {
|
|
|
1349
1349
|
" • `AppliedMigration` gained `appliedOps` (operations actually EXECUTED, from",
|
|
1350
1350
|
" the per-op results). If you construct that value in a test fixture, add it."
|
|
1351
1351
|
].join("\n")
|
|
1352
|
-
}),
|
|
1352
|
+
}), it = C({
|
|
1353
1353
|
version: "0.14.0",
|
|
1354
1354
|
id: "0.14.0/01_resolve-scopes-store",
|
|
1355
1355
|
title: "auth.resolveScopes receives the app DataStore",
|
|
@@ -1387,19 +1387,19 @@ var b = (e, t, n) => {
|
|
|
1387
1387
|
" deliberately does not, because only you know how fast a role change must",
|
|
1388
1388
|
" take effect."
|
|
1389
1389
|
].join("\n")
|
|
1390
|
-
}),
|
|
1391
|
-
if (!
|
|
1390
|
+
}), A = (e) => {
|
|
1391
|
+
if (!y.isCallExpression(e)) return !1;
|
|
1392
1392
|
let t = e.getExpression();
|
|
1393
|
-
return
|
|
1394
|
-
},
|
|
1395
|
-
let t = 0, n = e.getDescendantsOfKind(
|
|
1393
|
+
return y.isPropertyAccessExpression(t) && t.getName() === "reactive" && e.getArguments().length === 0;
|
|
1394
|
+
}, at = (e) => e.getDescendantsOfKind(b.CallExpression).some(A), ot = (e) => {
|
|
1395
|
+
let t = 0, n = e.getDescendantsOfKind(b.CallExpression);
|
|
1396
1396
|
for (let e of n) {
|
|
1397
|
-
if (e.wasForgotten() || !
|
|
1397
|
+
if (e.wasForgotten() || !A(e)) continue;
|
|
1398
1398
|
let n = e.getExpression();
|
|
1399
|
-
|
|
1399
|
+
y.isPropertyAccessExpression(n) && (e.replaceWithText(n.getExpression().getText()), t++);
|
|
1400
1400
|
}
|
|
1401
1401
|
return t;
|
|
1402
|
-
},
|
|
1402
|
+
}, st = C({
|
|
1403
1403
|
version: "0.14.0",
|
|
1404
1404
|
id: "0.14.0/02_reactive-by-default",
|
|
1405
1405
|
title: "Reactivity is the default; .reactive() is removed",
|
|
@@ -1417,16 +1417,16 @@ var b = (e, t, n) => {
|
|
|
1417
1417
|
"real saving: REPLICA IDENTITY FULL widens every UPDATE/DELETE in the WAL.",
|
|
1418
1418
|
"`voltro dev` warns if you opt out a table a query still reads."
|
|
1419
1419
|
].join("\n"),
|
|
1420
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1420
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => at(e)),
|
|
1421
1421
|
transform: ({ project: e, log: t }) => {
|
|
1422
1422
|
let n = 0, r = 0;
|
|
1423
1423
|
for (let t of e.getSourceFiles()) {
|
|
1424
|
-
let e =
|
|
1424
|
+
let e = ot(t);
|
|
1425
1425
|
e !== 0 && (n += e, r++);
|
|
1426
1426
|
}
|
|
1427
1427
|
return n > 0 && t(`removed ${n} .reactive() call(s) across ${r} file(s) — reactivity is the default`), n > 0;
|
|
1428
1428
|
}
|
|
1429
|
-
}),
|
|
1429
|
+
}), ct = C({
|
|
1430
1430
|
version: "0.14.0",
|
|
1431
1431
|
id: "0.14.0/07_dev-remote-file-migrations",
|
|
1432
1432
|
title: "voltro dev refuses unattended file migrations against a remote database",
|
|
@@ -1469,19 +1469,19 @@ var b = (e, t, n) => {
|
|
|
1469
1469
|
"Unchanged: `voltro db files`, `voltro db apply` and `voltro serve`. This gates the",
|
|
1470
1470
|
"AUTOMATIC boot path only; an explicit command is already an explicit decision."
|
|
1471
1471
|
].join("\n")
|
|
1472
|
-
}),
|
|
1473
|
-
let r =
|
|
1472
|
+
}), lt = (e) => [...e.getImportDeclarations(), ...e.getExportDeclarations()], j = (e) => m(e).replace(/\.tsx?$/, ""), ut = (e, t, n) => {
|
|
1473
|
+
let r = j(t), i = j(n);
|
|
1474
1474
|
if (r === i) return;
|
|
1475
1475
|
let a = /\.tsx?$/.exec(e)?.[0] ?? "", o = a === "" ? e : e.slice(0, -a.length);
|
|
1476
1476
|
if (!o.endsWith(`/${r}`) && o !== r) return;
|
|
1477
1477
|
let s = a === "" ? "" : /\.tsx$/.test(n) ? ".tsx" : ".ts";
|
|
1478
1478
|
return `${o.slice(0, o.length - r.length)}${i}${s}`;
|
|
1479
|
-
},
|
|
1479
|
+
}, M = (e, t) => {
|
|
1480
1480
|
let n = e.getFilePath(), r = [];
|
|
1481
|
-
for (let i of e.getProject().getSourceFiles()) for (let e of
|
|
1481
|
+
for (let i of e.getProject().getSourceFiles()) for (let e of lt(i)) {
|
|
1482
1482
|
let i = e.getModuleSpecifierValue();
|
|
1483
1483
|
if (i === void 0 || i.startsWith(".") || e.getModuleSpecifierSourceFile()?.getFilePath() !== n) continue;
|
|
1484
|
-
let a =
|
|
1484
|
+
let a = ut(i, n, t);
|
|
1485
1485
|
a !== void 0 && r.push({
|
|
1486
1486
|
decl: e,
|
|
1487
1487
|
spec: a
|
|
@@ -1490,19 +1490,19 @@ var b = (e, t, n) => {
|
|
|
1490
1490
|
e.move(t);
|
|
1491
1491
|
for (let e of r) e.decl.setModuleSpecifier(e.spec);
|
|
1492
1492
|
return r.length;
|
|
1493
|
-
},
|
|
1493
|
+
}, dt = (e) => {
|
|
1494
1494
|
let t = e.getProject().getCompilerOptions().paths;
|
|
1495
1495
|
if (t === void 0) return;
|
|
1496
|
-
let n =
|
|
1496
|
+
let n = j(e.getFilePath()), r = e.getFilePath().slice(0, e.getFilePath().lastIndexOf("/"));
|
|
1497
1497
|
for (let [e, i] of Object.entries(t)) if (!e.endsWith("*")) for (let t of i ?? []) {
|
|
1498
1498
|
if (!/\.tsx?$/.test(t)) continue;
|
|
1499
|
-
let i =
|
|
1499
|
+
let i = j(t), a = t.slice(0, t.lastIndexOf("/"));
|
|
1500
1500
|
if (i === n && r.endsWith(a.replace(/^\.\//, ""))) return e;
|
|
1501
1501
|
}
|
|
1502
|
-
},
|
|
1502
|
+
}, ft = /\.page\.tsx$/, N = (e) => {
|
|
1503
1503
|
let t = e.includes("\\src\\pages\\") ? "\\src\\pages\\" : "/src/pages/", n = e.indexOf(t);
|
|
1504
1504
|
return n === -1 ? null : e.slice(0, n);
|
|
1505
|
-
},
|
|
1505
|
+
}, pt = (e) => e.endsWith(".tsx") && !o.has(e) && !d(e) && !/\.island\.tsx$/.test(e) && !ft.test(e), mt = C({
|
|
1506
1506
|
version: "0.14.0",
|
|
1507
1507
|
id: "0.14.0/03_pages-suffix",
|
|
1508
1508
|
title: "Pages are declared with a .page.tsx suffix",
|
|
@@ -1517,8 +1517,8 @@ var b = (e, t, n) => {
|
|
|
1517
1517
|
transform: ({ project: e, log: t }) => {
|
|
1518
1518
|
let n = /* @__PURE__ */ new Map(), r = e.getSourceFiles().filter((t) => {
|
|
1519
1519
|
let r = t.getFilePath();
|
|
1520
|
-
if (!
|
|
1521
|
-
let i =
|
|
1520
|
+
if (!pt(m(r))) return !1;
|
|
1521
|
+
let i = N(r);
|
|
1522
1522
|
if (i === null) return !1;
|
|
1523
1523
|
let a = n.get(i);
|
|
1524
1524
|
return a === void 0 && (a = e.getSourceFile(g(i, "app.config.ts")) !== void 0 || e.getSourceFile(g(i, "app.config.tsx")) !== void 0, n.set(i, a)), a;
|
|
@@ -1536,13 +1536,13 @@ var b = (e, t, n) => {
|
|
|
1536
1536
|
let n = t.getFilePath(), r = m(n), s = h(n), c = r.slice(0, -4);
|
|
1537
1537
|
for (let t of [".test.tsx", ".spec.tsx"]) {
|
|
1538
1538
|
let n = g(s, `${c}${t}`), r = e.getSourceFile(n);
|
|
1539
|
-
r !== void 0 && (
|
|
1539
|
+
r !== void 0 && (M(r, g(s, `${c}.page${t}`)), o += 1);
|
|
1540
1540
|
}
|
|
1541
|
-
|
|
1541
|
+
M(t, g(s, `${c}.page.tsx`));
|
|
1542
1542
|
let l = i.get(n);
|
|
1543
1543
|
if (l !== void 0 && l.length > 0 && !l.every((e) => d(m(e)))) {
|
|
1544
|
-
let e =
|
|
1545
|
-
a.push(`${
|
|
1544
|
+
let e = N(n) ?? h(n), t = [...new Set(l)].map((t) => _(e, t));
|
|
1545
|
+
a.push(`${_(e, n)} ← imported by ${t.join(", ")}`);
|
|
1546
1546
|
}
|
|
1547
1547
|
}
|
|
1548
1548
|
if (t(`renamed ${r.length} route file(s) to *.page.tsx${o > 0 ? ` (+${o} co-located test file(s))` : ""}`), a.length > 0) {
|
|
@@ -1550,7 +1550,7 @@ var b = (e, t, n) => {
|
|
|
1550
1550
|
for (let e of a) t(` ${e}`);
|
|
1551
1551
|
}
|
|
1552
1552
|
}
|
|
1553
|
-
}),
|
|
1553
|
+
}), ht = [
|
|
1554
1554
|
/\.page\.tsx$/,
|
|
1555
1555
|
a,
|
|
1556
1556
|
s,
|
|
@@ -1561,24 +1561,24 @@ var b = (e, t, n) => {
|
|
|
1561
1561
|
c,
|
|
1562
1562
|
e,
|
|
1563
1563
|
r
|
|
1564
|
-
],
|
|
1564
|
+
], gt = (e) => {
|
|
1565
1565
|
let n = m(e);
|
|
1566
|
-
return !/\.tsx?$/.test(n) || o.has(n) || t(n) || n === "index.ts" || n === "index.tsx" || n === "app.config.ts" ? !1 : !
|
|
1567
|
-
},
|
|
1566
|
+
return !/\.tsx?$/.test(n) || o.has(n) || t(n) || n === "index.ts" || n === "index.tsx" || n === "app.config.ts" ? !1 : !ht.some((e) => e.test(n));
|
|
1567
|
+
}, _t = (e) => {
|
|
1568
1568
|
let t = [], n = [], r = [], i = [];
|
|
1569
1569
|
for (let [a, o] of e.getExportedDeclarations()) {
|
|
1570
1570
|
let e = o[0];
|
|
1571
1571
|
if (e === void 0) continue;
|
|
1572
|
-
if (
|
|
1572
|
+
if (y.isInterfaceDeclaration(e) || y.isTypeAliasDeclaration(e)) {
|
|
1573
1573
|
i.push(a);
|
|
1574
1574
|
continue;
|
|
1575
1575
|
}
|
|
1576
1576
|
if (a === "default") {
|
|
1577
|
-
if (!(
|
|
1577
|
+
if (!(y.isFunctionDeclaration(e) || y.isClassDeclaration(e) || y.isArrowFunction(e) || y.isFunctionExpression(e))) {
|
|
1578
1578
|
r.push("default");
|
|
1579
1579
|
continue;
|
|
1580
1580
|
}
|
|
1581
|
-
let n =
|
|
1581
|
+
let n = y.isFunctionDeclaration(e) || y.isClassDeclaration(e) ? e.getName() : void 0;
|
|
1582
1582
|
t.push(n ?? "Default");
|
|
1583
1583
|
continue;
|
|
1584
1584
|
}
|
|
@@ -1591,10 +1591,10 @@ var b = (e, t, n) => {
|
|
|
1591
1591
|
others: r,
|
|
1592
1592
|
types: i
|
|
1593
1593
|
};
|
|
1594
|
-
},
|
|
1594
|
+
}, vt = (e, t) => {
|
|
1595
1595
|
let { components: n, hooks: r, others: i, types: a } = e;
|
|
1596
1596
|
return n.length + r.length + i.length === 0 ? a.length > 0 ? ".types" : null : t && te(n) && r.length === 0 && i.length === 0 ? ".component.tsx" : n.length === 0 && r.length === 1 && i.length === 0 ? ".hook" : null;
|
|
1597
|
-
},
|
|
1597
|
+
}, yt = C({
|
|
1598
1598
|
version: "0.14.0",
|
|
1599
1599
|
id: "0.14.0/04_file-taxonomy",
|
|
1600
1600
|
title: "Web files declare their contract (*.component.tsx / *.hook.ts / *.types.ts)",
|
|
@@ -1607,19 +1607,19 @@ var b = (e, t, n) => {
|
|
|
1607
1607
|
if (s.length > 0) for (let e of s) t(` exempt (not ours): ${e.dir} — ${e.source}`);
|
|
1608
1608
|
for (let t of e.getSourceFiles()) {
|
|
1609
1609
|
let e = t.getFilePath();
|
|
1610
|
-
if (!
|
|
1611
|
-
let o =
|
|
1610
|
+
if (!gt(e) || p(e, s)) continue;
|
|
1611
|
+
let o = dt(t);
|
|
1612
1612
|
if (o !== void 0) {
|
|
1613
1613
|
a.push(`${m(e)} (tsconfig paths: "${o}")`);
|
|
1614
1614
|
continue;
|
|
1615
1615
|
}
|
|
1616
|
-
let c = e.endsWith(".tsx"), l =
|
|
1616
|
+
let c = e.endsWith(".tsx"), l = _t(t), u = vt(l, c);
|
|
1617
1617
|
if (u === null) {
|
|
1618
1618
|
l.components.length > 0 && l.hooks.length > 0 && r.push(`${m(e)} (component ${l.components.join("/")} + hook ${l.hooks.join("/")})`);
|
|
1619
1619
|
continue;
|
|
1620
1620
|
}
|
|
1621
1621
|
let d = m(e).replace(/\.tsx?$/, ""), f = u === ".component.tsx" ? ".component.tsx" : `${u}${c ? ".tsx" : ".ts"}`;
|
|
1622
|
-
i +=
|
|
1622
|
+
i += M(t, g(h(e), `${d}${f}`)), n.push(`${d}${f}`);
|
|
1623
1623
|
}
|
|
1624
1624
|
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) {
|
|
1625
1625
|
t(""), t(`left alone — a tsconfig \`paths\` entry names ${a.length} of these files directly:`);
|
|
@@ -1632,7 +1632,7 @@ var b = (e, t, n) => {
|
|
|
1632
1632
|
r.length > 20 && t(` (+${r.length - 20} more)`);
|
|
1633
1633
|
}
|
|
1634
1634
|
}
|
|
1635
|
-
}),
|
|
1635
|
+
}), bt = C({
|
|
1636
1636
|
version: "0.14.0",
|
|
1637
1637
|
id: "0.14.0/05_typed-tracking",
|
|
1638
1638
|
title: "Tracking catalogues are typed against the component props",
|
|
@@ -1669,7 +1669,7 @@ var b = (e, t, n) => {
|
|
|
1669
1669
|
"Read each one before changing it: a cast that no longer compiles is sometimes",
|
|
1670
1670
|
"a real type disagreement the old signature was hiding."
|
|
1671
1671
|
].join("\n")
|
|
1672
|
-
}),
|
|
1672
|
+
}), xt = C({
|
|
1673
1673
|
version: "0.14.0",
|
|
1674
1674
|
id: "0.14.0/06_voltro-test-skips-e2e",
|
|
1675
1675
|
title: "`voltro test` leaves `e2e/` to `voltro e2e`",
|
|
@@ -1691,13 +1691,13 @@ var b = (e, t, n) => {
|
|
|
1691
1691
|
" code it tests, or",
|
|
1692
1692
|
" • pass your own `--exclude`, which overrides the framework default outright."
|
|
1693
1693
|
].join("\n")
|
|
1694
|
-
}),
|
|
1694
|
+
}), St = (e) => {
|
|
1695
1695
|
let n = e.replace(/\.component(\.ui)?(\.tsx?)$/, "$2");
|
|
1696
1696
|
return n === e ? null : t(n) ? n : null;
|
|
1697
|
-
},
|
|
1697
|
+
}, Ct = (e) => {
|
|
1698
1698
|
for (let [, t] of e.getExportedDeclarations()) if (t[0] !== void 0) return !1;
|
|
1699
1699
|
return e.getExportDeclarations().length === 0 && e.getExportAssignments().length === 0;
|
|
1700
|
-
},
|
|
1700
|
+
}, wt = C({
|
|
1701
1701
|
version: "0.15.0",
|
|
1702
1702
|
id: "0.15.0/01_undo-mistaken-taxonomy-renames",
|
|
1703
1703
|
title: "Undo the two file renames 0.14.0 got wrong (framework primitives, side-effect modules)",
|
|
@@ -1714,14 +1714,14 @@ var b = (e, t, n) => {
|
|
|
1714
1714
|
transform: ({ project: e, log: t }) => {
|
|
1715
1715
|
let n = [], r = [];
|
|
1716
1716
|
for (let t of e.getSourceFiles()) {
|
|
1717
|
-
let e = t.getFilePath(), i = m(e), a =
|
|
1717
|
+
let e = t.getFilePath(), i = m(e), a = St(i);
|
|
1718
1718
|
if (a !== null) {
|
|
1719
|
-
|
|
1719
|
+
M(t, g(h(e), a)), n.push(`${i} → ${a}`);
|
|
1720
1720
|
continue;
|
|
1721
1721
|
}
|
|
1722
|
-
if (/\.types\.tsx?$/.test(i) &&
|
|
1722
|
+
if (/\.types\.tsx?$/.test(i) && Ct(t)) {
|
|
1723
1723
|
let n = i.replace(/\.types(\.tsx?)$/, "$1");
|
|
1724
|
-
|
|
1724
|
+
M(t, g(h(e), n)), r.push(`${i} → ${n}`);
|
|
1725
1725
|
}
|
|
1726
1726
|
}
|
|
1727
1727
|
if (n.length > 0) {
|
|
@@ -1735,54 +1735,54 @@ var b = (e, t, n) => {
|
|
|
1735
1735
|
}
|
|
1736
1736
|
n.length === 0 && r.length === 0 && t("nothing to undo — 0.14.0 renamed neither a framework file nor a side-effect module here.");
|
|
1737
1737
|
}
|
|
1738
|
-
}),
|
|
1738
|
+
}), P = ["@voltro/client", "@voltro/web"], F = "@voltro/protocol", Tt = C({
|
|
1739
1739
|
version: "0.15.0",
|
|
1740
1740
|
id: "0.15.0/02_error-tag-in-protocol",
|
|
1741
1741
|
title: "`errorTag` is imported from @voltro/protocol",
|
|
1742
1742
|
kind: "transform",
|
|
1743
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) =>
|
|
1743
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => P.includes(e.getModuleSpecifierValue()) && e.getNamedImports().some((e) => e.getName() === "errorTag"))),
|
|
1744
1744
|
transform: ({ project: e, log: t }) => {
|
|
1745
1745
|
let n = 0;
|
|
1746
1746
|
for (let t of e.getSourceFiles()) for (let e of t.getImportDeclarations()) {
|
|
1747
|
-
if (!
|
|
1747
|
+
if (!P.includes(e.getModuleSpecifierValue())) continue;
|
|
1748
1748
|
let r = e.getNamedImports().find((e) => e.getName() === "errorTag");
|
|
1749
1749
|
if (r === void 0) continue;
|
|
1750
1750
|
let i = r.getAliasNode()?.getText(), a = e.isTypeOnly() || r.isTypeOnly();
|
|
1751
1751
|
r.remove();
|
|
1752
|
-
let o = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() ===
|
|
1752
|
+
let o = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() === F && e.isTypeOnly() === a), s = {
|
|
1753
1753
|
name: "errorTag",
|
|
1754
1754
|
...i === void 0 ? {} : { alias: i }
|
|
1755
1755
|
};
|
|
1756
1756
|
o === void 0 ? t.addImportDeclaration({
|
|
1757
|
-
moduleSpecifier:
|
|
1757
|
+
moduleSpecifier: F,
|
|
1758
1758
|
isTypeOnly: a,
|
|
1759
1759
|
namedImports: [s]
|
|
1760
1760
|
}) : o.addNamedImport(s), e.getNamedImports().length === 0 && e.getDefaultImport() === void 0 && e.getNamespaceImport() === void 0 && e.remove(), n += 1;
|
|
1761
1761
|
}
|
|
1762
|
-
n > 0 && t(`errorTag: ${n} import(s) repointed to ${
|
|
1762
|
+
n > 0 && t(`errorTag: ${n} import(s) repointed to ${F}`);
|
|
1763
1763
|
}
|
|
1764
|
-
}),
|
|
1765
|
-
let t = h(e), n = m(e).replace(
|
|
1764
|
+
}), I = /\.page\.tsx$/, Et = /\.page\.(test|spec)\.tsx$/, Dt = (e) => /(^|\/)src\/pages\//.test(e), Ot = (e) => {
|
|
1765
|
+
let t = h(e), n = m(e).replace(I, "");
|
|
1766
1766
|
return n === "index" ? g(t, "page.tsx") : g(t, n, "page.tsx");
|
|
1767
|
-
},
|
|
1768
|
-
let t = h(e), n = m(e), r = /\.page\.spec\.tsx$/.test(n) ? "spec" : "test", i = n.replace(
|
|
1767
|
+
}, kt = (e) => {
|
|
1768
|
+
let t = h(e), n = m(e), r = /\.page\.spec\.tsx$/.test(n) ? "spec" : "test", i = n.replace(Et, "");
|
|
1769
1769
|
return i === "index" ? g(t, `page.${r}.tsx`) : g(t, i, `page.${r}.tsx`);
|
|
1770
|
-
},
|
|
1770
|
+
}, At = C({
|
|
1771
1771
|
version: "0.17.0",
|
|
1772
1772
|
id: "0.17.0/01_pages-are-directories",
|
|
1773
1773
|
title: "A directory is a route segment; its route is page.tsx",
|
|
1774
1774
|
kind: "transform",
|
|
1775
1775
|
scope: ["**/src/pages/**/*.ts", "**/src/pages/**/*.tsx"],
|
|
1776
1776
|
needsImporters: !0,
|
|
1777
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1777
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Dt(e.getFilePath()) && I.test(m(e.getFilePath()))),
|
|
1778
1778
|
transform: ({ project: e, log: t }) => {
|
|
1779
1779
|
let n = e.getSourceFiles(), r = [];
|
|
1780
1780
|
for (let e of n) {
|
|
1781
1781
|
let t = String(e.getFilePath());
|
|
1782
|
-
if (!
|
|
1783
|
-
let n = m(t), i =
|
|
1784
|
-
if (!i && !
|
|
1785
|
-
let a = i ?
|
|
1782
|
+
if (!Dt(t)) continue;
|
|
1783
|
+
let n = m(t), i = Et.test(n);
|
|
1784
|
+
if (!i && !I.test(n)) continue;
|
|
1785
|
+
let a = i ? kt(t) : Ot(t);
|
|
1786
1786
|
a !== t && r.push({
|
|
1787
1787
|
sf: e,
|
|
1788
1788
|
from: t,
|
|
@@ -1801,7 +1801,7 @@ var b = (e, t, n) => {
|
|
|
1801
1801
|
}
|
|
1802
1802
|
}
|
|
1803
1803
|
let l = [], u = 0;
|
|
1804
|
-
for (let e of r) s.has(e.from) || (u +=
|
|
1804
|
+
for (let e of r) s.has(e.from) || (u += M(e.sf, e.to), e.isTest || l.push(o(e.to)));
|
|
1805
1805
|
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) {
|
|
1806
1806
|
t(""), t(`LEFT ALONE — ${c.length} case(s) where two files claim one route:`);
|
|
1807
1807
|
for (let e of c) t(` ${e}`);
|
|
@@ -1809,12 +1809,12 @@ var b = (e, t, n) => {
|
|
|
1809
1809
|
}
|
|
1810
1810
|
l.length === 0 && c.length === 0 && t("every route already lives in its own directory — nothing to move.");
|
|
1811
1811
|
}
|
|
1812
|
-
}),
|
|
1812
|
+
}), jt = /,\s*(['"])like\1\s*,/, Mt = C({
|
|
1813
1813
|
version: "0.18.0",
|
|
1814
1814
|
id: "0.18.0/01_where-like-removed",
|
|
1815
1815
|
title: "the `'like'` where-operator is removed — pick `contains` or `startsWith`",
|
|
1816
1816
|
kind: "manual",
|
|
1817
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1817
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => jt.test(e.getFullText())),
|
|
1818
1818
|
note: [
|
|
1819
1819
|
"The `'like'` operator is removed from the ergonomic `.where(col, op, value)` form.",
|
|
1820
1820
|
"",
|
|
@@ -1852,12 +1852,12 @@ var b = (e, t, n) => {
|
|
|
1852
1852
|
"in a raw query (`ctx.store.raw`); the DSL has no arbitrary-pattern operator, and",
|
|
1853
1853
|
"adding one that cannot use an index is not on the roadmap."
|
|
1854
1854
|
].join("\n")
|
|
1855
|
-
}),
|
|
1855
|
+
}), Nt = /\.serverOnly\s*\(\s*\)/, Pt = C({
|
|
1856
1856
|
version: "0.19.0",
|
|
1857
1857
|
id: "0.19.0/01_server-only-gates-the-boot",
|
|
1858
1858
|
title: "`.serverOnly()` now FAILS the boot under `voltro serve` — it used to only warn",
|
|
1859
1859
|
kind: "manual",
|
|
1860
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1860
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Nt.test(e.getFullText())),
|
|
1861
1861
|
note: [
|
|
1862
1862
|
"`.serverOnly()` now GATES. Before 0.19.0 it emitted one `log.warn` and let the",
|
|
1863
1863
|
"boot continue — in every command, including `voltro serve`.",
|
|
@@ -1904,12 +1904,12 @@ var b = (e, t, n) => {
|
|
|
1904
1904
|
"hatch is that people delete the marker instead — and a check whose only way out",
|
|
1905
1905
|
"is to disable it gets disabled."
|
|
1906
1906
|
].join("\n")
|
|
1907
|
-
}),
|
|
1907
|
+
}), Ft = /\bauditPlugin\s*\(/, It = C({
|
|
1908
1908
|
version: "0.19.0",
|
|
1909
1909
|
id: "0.19.0/02_audit-redact-input-default",
|
|
1910
1910
|
title: "`auditPlugin` now redacts mutation input by default (`redactInput: 'all'`)",
|
|
1911
1911
|
kind: "manual",
|
|
1912
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1912
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Ft.test(e.getFullText())),
|
|
1913
1913
|
note: [
|
|
1914
1914
|
"`auditPlugin`'s `redactInput` now defaults to `'all'`. Audit rows written from",
|
|
1915
1915
|
"now on carry `input: { __redacted: 'all' }` — which still proves a payload",
|
|
@@ -1945,12 +1945,12 @@ var b = (e, t, n) => {
|
|
|
1945
1945
|
"those markers live on TABLE COLUMNS, and this is a mutation's INPUT.",
|
|
1946
1946
|
"`changePassword({ oldPassword, newPassword })` has no column to consult."
|
|
1947
1947
|
].join("\n")
|
|
1948
|
-
}),
|
|
1948
|
+
}), Lt = w("registerWriteRecorder"), Rt = C({
|
|
1949
1949
|
version: "0.20.0",
|
|
1950
1950
|
id: "0.20.0/01_write-recorder-port",
|
|
1951
1951
|
title: "`WriteRecorder` takes a port (`{ append, maxOf }`) instead of a bare `append`",
|
|
1952
1952
|
kind: "manual",
|
|
1953
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1953
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Lt.test(e.getFullText())),
|
|
1954
1954
|
note: [
|
|
1955
1955
|
"If you wrote your own in-transaction write recorder, its first parameter is",
|
|
1956
1956
|
"now an object rather than a function:",
|
|
@@ -1989,12 +1989,12 @@ var b = (e, t, n) => {
|
|
|
1989
1989
|
"nested transaction, and a throw from either operation still rolls the",
|
|
1990
1990
|
"caller's write back. That is the guarantee the timing exists for."
|
|
1991
1991
|
].join("\n")
|
|
1992
|
-
}),
|
|
1992
|
+
}), zt = /\.maxLength\s*\(/, Bt = C({
|
|
1993
1993
|
version: "0.21.0",
|
|
1994
1994
|
id: "0.21.0/01_maxlength-now-migrates",
|
|
1995
1995
|
title: "`text().maxLength(n)` now migrates EXISTING columns — plan before you apply",
|
|
1996
1996
|
kind: "manual",
|
|
1997
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
1997
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => zt.test(e.getFullText())),
|
|
1998
1998
|
note: [
|
|
1999
1999
|
"Your source does not change. `text().maxLength(n)` compiles exactly as before",
|
|
2000
2000
|
"and every bound you already declared stays as written.",
|
|
@@ -2036,12 +2036,12 @@ var b = (e, t, n) => {
|
|
|
2036
2036
|
"framework guarantees, and an upgrade-time ALTER that fails on your data is a",
|
|
2037
2037
|
"worse outcome than the index-size concern it would fix."
|
|
2038
2038
|
].join("\n")
|
|
2039
|
-
}),
|
|
2039
|
+
}), Vt = /\bMigrationOperation\b|\bPlannedOperation\b|\bInspectMigrationOperationKind\b|\bOperationKind\b/, Ht = C({
|
|
2040
2040
|
version: "0.22.0",
|
|
2041
2041
|
id: "0.22.0/01_rename-index-op",
|
|
2042
2042
|
title: "`MigrationOperation` gained a `rename-index` kind",
|
|
2043
2043
|
kind: "manual",
|
|
2044
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2044
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Vt.test(e.getFullText())),
|
|
2045
2045
|
note: [
|
|
2046
2046
|
"The migration planner can now emit a `rename-index` operation:",
|
|
2047
2047
|
"",
|
|
@@ -2073,12 +2073,12 @@ var b = (e, t, n) => {
|
|
|
2073
2073
|
"match where two same-shaped indexes were renamed at once. Those still plan",
|
|
2074
2074
|
"as drop + create, exactly as before."
|
|
2075
2075
|
].join("\n")
|
|
2076
|
-
}),
|
|
2076
|
+
}), Ut = /@voltro\/plugin-(notifications|scim|ai-flows)/, Wt = C({
|
|
2077
2077
|
version: "0.22.0",
|
|
2078
2078
|
id: "0.22.0/02_plugin-tables-voltro-prefixed",
|
|
2079
2079
|
title: "plugin-owned tables are `_voltro_`-prefixed (the rows move themselves)",
|
|
2080
2080
|
kind: "manual",
|
|
2081
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2081
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Ut.test(e.getFullText())),
|
|
2082
2082
|
note: [
|
|
2083
2083
|
"Ten tables owned by @voltro/plugin-notifications, @voltro/plugin-scim and",
|
|
2084
2084
|
"@voltro/plugin-ai-flows moved out of your table namespace and into the",
|
|
@@ -2128,12 +2128,12 @@ var b = (e, t, n) => {
|
|
|
2128
2128
|
"gained a `rename-table` kind. An exhaustive `switch` needs an arm; don't add",
|
|
2129
2129
|
"a `default:`, which would silence this and every future kind."
|
|
2130
2130
|
].join("\n")
|
|
2131
|
-
}),
|
|
2131
|
+
}), Gt = /QueryCacheScope|QueryCacheConfig|scope\s*:\s*['"](?:subject|global)['"]/, Kt = C({
|
|
2132
2132
|
version: "0.22.0",
|
|
2133
2133
|
id: "0.22.0/03_cache-scope-gained-tenant",
|
|
2134
2134
|
title: "`cache.scope` gained 'tenant' — an exhaustive switch over it needs a branch",
|
|
2135
2135
|
kind: "manual",
|
|
2136
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2136
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Gt.test(e.getFullText())),
|
|
2137
2137
|
note: [
|
|
2138
2138
|
"`cache: { scope }` now accepts a third value, `'tenant'`: one cache entry per",
|
|
2139
2139
|
"org, none shared across orgs.",
|
|
@@ -2162,12 +2162,12 @@ var b = (e, t, n) => {
|
|
|
2162
2162
|
"Rubric: does the resolved predicate depend on the caller? On the PERSON →",
|
|
2163
2163
|
"`subject`; on their ORG only → `tenant`; on neither → `global`."
|
|
2164
2164
|
].join("\n")
|
|
2165
|
-
}),
|
|
2165
|
+
}), qt = /envTokenAuthResolver|InspectAuthResolver|authResolver/, Jt = C({
|
|
2166
2166
|
version: "0.22.0",
|
|
2167
2167
|
id: "0.22.0/04_inspect-write-credential",
|
|
2168
2168
|
title: "Mutating `/_voltro/inspect/*` endpoints need VOLTRO_INSPECT_WRITE_TOKEN",
|
|
2169
2169
|
kind: "manual",
|
|
2170
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2170
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => qt.test(e.getFullText())),
|
|
2171
2171
|
note: [
|
|
2172
2172
|
"A POST / PATCH / PUT / DELETE to `/_voltro/inspect/*` now needs a SECOND",
|
|
2173
2173
|
"credential: `VOLTRO_INSPECT_WRITE_TOKEN`, sent as the `x-voltro-inspect-write`",
|
|
@@ -2205,12 +2205,12 @@ var b = (e, t, n) => {
|
|
|
2205
2205
|
"IMPLEMENTING a resolver is unaffected — `(headers) => …` still satisfies the",
|
|
2206
2206
|
"type. Only callers are obliged."
|
|
2207
2207
|
].join("\n")
|
|
2208
|
-
}),
|
|
2208
|
+
}), Yt = /versioningPlugin\s*\(/, Xt = C({
|
|
2209
2209
|
version: "0.23.0",
|
|
2210
2210
|
id: "0.23.0/01_versioning-is-opt-out",
|
|
2211
2211
|
title: "versioningPlugin: `tables: string[]` → opt-out by default, `include` / `exclude` by value",
|
|
2212
2212
|
kind: "manual",
|
|
2213
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2213
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Yt.test(e.getFullText())),
|
|
2214
2214
|
note: [
|
|
2215
2215
|
"`versioningPlugin({ tables: [...] })` no longer compiles. Row history is now",
|
|
2216
2216
|
"ON by default for every table your app declares.",
|
|
@@ -2250,12 +2250,12 @@ var b = (e, t, n) => {
|
|
|
2250
2250
|
"surprises you, `exclude` is the knob, and the retention sweep",
|
|
2251
2251
|
"(`VOLTRO_ROW_HISTORY_TTL_HOURS`) still bounds age."
|
|
2252
2252
|
].join("\n")
|
|
2253
|
-
}),
|
|
2253
|
+
}), Zt = /@voltro\/ai|\.agent\.tsx|agent_(threads|messages)/, Qt = C({
|
|
2254
2254
|
version: "0.24.0",
|
|
2255
2255
|
id: "0.24.0/01_agent-tables-voltro-prefixed",
|
|
2256
2256
|
title: "the two agent tables are `_voltro_`-prefixed (the rows move themselves)",
|
|
2257
2257
|
kind: "manual",
|
|
2258
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2258
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Zt.test(e.getFullText())),
|
|
2259
2259
|
note: [
|
|
2260
2260
|
"The two tables owned by @voltro/ai moved out of your table namespace and",
|
|
2261
2261
|
"into the framework's:",
|
|
@@ -2308,12 +2308,12 @@ var b = (e, t, n) => {
|
|
|
2308
2308
|
"declared by something. You get a fresh empty `_voltro_…` table alongside it,",
|
|
2309
2309
|
"which is the collision this ends."
|
|
2310
2310
|
].join("\n")
|
|
2311
|
-
}),
|
|
2311
|
+
}), $t = /\.events\s*\.\s*emit\s*\(/, en = C({
|
|
2312
2312
|
version: "0.25.0",
|
|
2313
2313
|
id: "0.25.0/01_events-emit-to-publish",
|
|
2314
2314
|
title: "`ctx.events.emit(name, data)` → `ctx.events.publish(descriptor, key, payload)`",
|
|
2315
2315
|
kind: "manual",
|
|
2316
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2316
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => $t.test(e.getFullText())),
|
|
2317
2317
|
note: [
|
|
2318
2318
|
"`ctx.events.emit('name', data)` is gone. Declare the event and publish it:",
|
|
2319
2319
|
"",
|
|
@@ -2357,53 +2357,53 @@ var b = (e, t, n) => {
|
|
|
2357
2357
|
"",
|
|
2358
2358
|
"Docs: https://docs.voltro.dev/docs/data/events"
|
|
2359
2359
|
].join("\n")
|
|
2360
|
-
}),
|
|
2360
|
+
}), tn = /* @__PURE__ */ new Set([
|
|
2361
2361
|
"description",
|
|
2362
2362
|
"version",
|
|
2363
2363
|
"globalRateLimit"
|
|
2364
|
-
]),
|
|
2364
|
+
]), nn = ["defaultRetry", "defaultSigning"], rn = (e) => e.getDescendantsOfKind(b.CallExpression).filter((e) => e.getExpression().getText() === "defineOutgoingEvent"), an = C({
|
|
2365
2365
|
version: "0.25.0",
|
|
2366
2366
|
id: "0.25.0/02_outgoing-event-to-define-event",
|
|
2367
2367
|
title: "`defineOutgoingEvent` → `defineEvent({ …, webhook: { … } })`",
|
|
2368
2368
|
kind: "transform",
|
|
2369
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2369
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => rn(e).length > 0),
|
|
2370
2370
|
transform: ({ project: e, log: t }) => {
|
|
2371
2371
|
let n = 0, r = /* @__PURE__ */ new Set(), i = [];
|
|
2372
|
-
for (let t of e.getSourceFiles()) for (let e of
|
|
2372
|
+
for (let t of e.getSourceFiles()) for (let e of rn(t)) {
|
|
2373
2373
|
let a = e.getArguments()[0];
|
|
2374
|
-
if (a === void 0 || !a.isKind(
|
|
2375
|
-
let o = a.getProperties().filter((e) => e.isKind(
|
|
2374
|
+
if (a === void 0 || !a.isKind(b.ObjectLiteralExpression)) continue;
|
|
2375
|
+
let o = a.getProperties().filter((e) => e.isKind(b.PropertyAssignment)), s = (e) => o.find((t) => t.asKindOrThrow(b.PropertyAssignment).getName() === e)?.asKindOrThrow(b.PropertyAssignment).getInitializer()?.getText(), c = s("id"), l = s("payload");
|
|
2376
2376
|
if (c === void 0 || l === void 0) continue;
|
|
2377
|
-
let u = [...
|
|
2377
|
+
let u = [...tn].map((e) => {
|
|
2378
2378
|
let t = s(e);
|
|
2379
2379
|
if (t !== void 0) return `${e === "globalRateLimit" ? "rateLimit" : e}: ${t}`;
|
|
2380
2380
|
}).filter((e) => e !== void 0);
|
|
2381
|
-
for (let e of
|
|
2381
|
+
for (let e of nn) s(e) !== void 0 && i.push(`${t.getBaseName()}: ${e}`);
|
|
2382
2382
|
let d = u.length > 0 ? `, webhook: { ${u.join(", ")} }` : ", webhook: {}";
|
|
2383
2383
|
e.replaceWithText(`defineEvent({ name: ${c}, key: Schema.Struct({}), payload: ${l}${d} })`), n++, r.add(t.getFilePath());
|
|
2384
2384
|
}
|
|
2385
2385
|
n !== 0 && (t(`webhooks: rewrote ${n} \`defineOutgoingEvent\` → \`defineEvent\` in ${r.size} file${r.size === 1 ? "" : "s"}`), t(" → `key: Schema.Struct({})` is CORRECT, not a placeholder: a webhook event goes to"), t(" subscribed targets, not to a routing key. Give it a key only if you also want"), t(" connected clients to subscribe per-something with `useEvent`."), t(" → import `defineEvent` from `@voltro/protocol` and `Schema` from `effect`;"), t(" the file is now a declaration, so `*.event.ts` is its home."), t(" → `ctx.webhooks.emit(descriptor, payload)` still works, and"), t(" `ctx.events.publish(descriptor, key, payload)` now reaches the HTTP targets too."), i.length > 0 && (t(` → NOT carried across (${i.length}): ${[...new Set(i)].join(", ")}`), t(" The plugin's retry/signing shapes are richer than the declared event can hold,"), t(" so they are left in place as a compile error rather than dropped silently."), t(" Configure them at subscribe time, where the full shape is typed.")));
|
|
2386
2386
|
}
|
|
2387
|
-
}),
|
|
2387
|
+
}), on = (e) => e.getDescendantsOfKind(b.CallExpression).filter((e) => {
|
|
2388
2388
|
let t = e.getExpression().getText();
|
|
2389
2389
|
return t === "broadcast" || t === "broadcastPlugin";
|
|
2390
2390
|
}), L = (e) => {
|
|
2391
2391
|
let t = e.getArguments()[0];
|
|
2392
|
-
if (!(t === void 0 || !t.isKind(
|
|
2393
|
-
}, sn =
|
|
2392
|
+
if (!(t === void 0 || !t.isKind(b.ObjectLiteralExpression))) return t.getProperties().filter((e) => e.isKind(b.PropertyAssignment)).map((e) => e.asKindOrThrow(b.PropertyAssignment)).find((e) => e.getName() === "channel");
|
|
2393
|
+
}, sn = C({
|
|
2394
2394
|
version: "0.25.0",
|
|
2395
2395
|
id: "0.25.0/03_broadcast-channel-to-namespace",
|
|
2396
2396
|
title: "`broadcast({ channel })` → `broadcast({ namespace })`",
|
|
2397
2397
|
kind: "transform",
|
|
2398
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
2398
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => on(e).some((e) => L(e) !== void 0)),
|
|
2399
2399
|
transform: ({ project: e, log: t }) => {
|
|
2400
2400
|
let n = 0, r = [], i = [], a = /* @__PURE__ */ new Set();
|
|
2401
|
-
for (let t of e.getSourceFiles()) for (let e of
|
|
2401
|
+
for (let t of e.getSourceFiles()) for (let e of on(t)) {
|
|
2402
2402
|
let o = L(e);
|
|
2403
2403
|
if (o === void 0) continue;
|
|
2404
2404
|
let s = o.getInitializer();
|
|
2405
2405
|
if (s === void 0) continue;
|
|
2406
|
-
let c = s.getText(), l = s.isKind(
|
|
2406
|
+
let c = s.getText(), l = s.isKind(b.StringLiteral) ? s.getLiteralValue() : void 0;
|
|
2407
2407
|
if (l !== void 0 && l.endsWith(":changes")) {
|
|
2408
2408
|
let e = l.slice(0, -8);
|
|
2409
2409
|
o.replaceWithText(`namespace: '${e}'`), r.push(`${t.getBaseName()}: '${l}' → '${e}'`);
|
|
@@ -2416,7 +2416,7 @@ var b = (e, t, n) => {
|
|
|
2416
2416
|
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.");
|
|
2417
2417
|
}
|
|
2418
2418
|
}
|
|
2419
|
-
}), cn =
|
|
2419
|
+
}), cn = C({
|
|
2420
2420
|
version: "0.26.0",
|
|
2421
2421
|
id: "0.26.0/01_event-webhook-retry-removed",
|
|
2422
2422
|
title: "`defineEvent({ webhook: { retry } })` is gone — it never did anything",
|
|
@@ -2450,7 +2450,7 @@ var b = (e, t, n) => {
|
|
|
2450
2450
|
"If you were relying on the declared value to take effect, note that it never",
|
|
2451
2451
|
"did — your deliveries have been using the target default all along."
|
|
2452
2452
|
].join("\n")
|
|
2453
|
-
}), ln =
|
|
2453
|
+
}), ln = C({
|
|
2454
2454
|
version: "0.26.0",
|
|
2455
2455
|
id: "0.26.0/02_step-retry-enforced",
|
|
2456
2456
|
title: "workflow step `retry:` is now ENFORCED (was metadata) — drop any redundant manual retry",
|
|
@@ -2503,7 +2503,7 @@ var b = (e, t, n) => {
|
|
|
2503
2503
|
"(retry transient, fail permanent), `maxElapsed: '5 minutes'` (a total time budget,",
|
|
2504
2504
|
"not just a count), `jitter` (on by default), and `respectRetryAfter` (honor a 429)."
|
|
2505
2505
|
].join("\n")
|
|
2506
|
-
}), un = /\bmakeSubjectId\b/, dn =
|
|
2506
|
+
}), un = /\bmakeSubjectId\b/, dn = C({
|
|
2507
2507
|
version: "0.28.0",
|
|
2508
2508
|
id: "0.28.0/01_notifications-resolve-subject-id-async",
|
|
2509
2509
|
title: "`makeSubjectId` returns a Promise; `resolveSubjectId` may be async",
|
|
@@ -2540,7 +2540,7 @@ var b = (e, t, n) => {
|
|
|
2540
2540
|
" reconnect. Memoise inside your own resolver if that trade suits your app —",
|
|
2541
2541
|
" you know your invalidation and we do not."
|
|
2542
2542
|
].join("\n")
|
|
2543
|
-
}), fn = /\bPluginRefChange\b|\bisSoftDelete\s*\(|\bapplyPluginRefRules\s*\(/, pn =
|
|
2543
|
+
}), fn = /\bPluginRefChange\b|\bisSoftDelete\s*\(|\bapplyPluginRefRules\s*\(/, pn = C({
|
|
2544
2544
|
version: "0.28.0",
|
|
2545
2545
|
id: "0.28.0/02_plugin-ref-change-event",
|
|
2546
2546
|
title: "`PluginRefChange` is removed — the change channel's `ChangeEvent` is the one shape",
|
|
@@ -2587,7 +2587,7 @@ var b = (e, t, n) => {
|
|
|
2587
2587
|
" not know that writes a delete, and the test passes against a stream the",
|
|
2588
2588
|
" framework never emits. That is the defect this change removes."
|
|
2589
2589
|
].join("\n")
|
|
2590
|
-
}), mn = /credentialsResolver\s*:/, hn =
|
|
2590
|
+
}), mn = /credentialsResolver\s*:/, hn = C({
|
|
2591
2591
|
version: "0.28.0",
|
|
2592
2592
|
id: "0.28.0/03_atlassian-credentials-context",
|
|
2593
2593
|
title: "`credentialsResolver` receives `{ subject, store }` instead of a bare Subject",
|
|
@@ -2662,7 +2662,7 @@ var b = (e, t, n) => {
|
|
|
2662
2662
|
"",
|
|
2663
2663
|
"and rotate anything you find — a redacted future does not un-leak a past row."
|
|
2664
2664
|
].join("\n")
|
|
2665
|
-
}), gn = /auditPlugin\s*\(/, _n =
|
|
2665
|
+
}), gn = /auditPlugin\s*\(/, _n = C({
|
|
2666
2666
|
version: "0.28.0",
|
|
2667
2667
|
id: "0.28.0/04_audit-redacts-subject-metadata",
|
|
2668
2668
|
title: "`auditPlugin` redacts `subject.metadata` by default",
|
|
@@ -2723,7 +2723,7 @@ var b = (e, t, n) => {
|
|
|
2723
2723
|
" keeps the token in the framework vault, and the resolver's new `store`",
|
|
2724
2724
|
" handle covers an app with its own token table."
|
|
2725
2725
|
].join("\n")
|
|
2726
|
-
}), vn =
|
|
2726
|
+
}), vn = w("useLoaderData"), yn = C({
|
|
2727
2727
|
version: "0.29.0",
|
|
2728
2728
|
id: "0.29.0/01_loader-data-absence",
|
|
2729
2729
|
title: "`useLoaderData()` throws at a level that declares no `loader`",
|
|
@@ -2771,7 +2771,7 @@ var b = (e, t, n) => {
|
|
|
2771
2771
|
}, Sn = (e) => {
|
|
2772
2772
|
let t = 0;
|
|
2773
2773
|
for (let n of e.getSourceFiles()) n.getFullText().includes(z) && n.forEachDescendant((e) => {
|
|
2774
|
-
if (
|
|
2774
|
+
if (y.isStringLiteral(e) || y.isNoSubstitutionTemplateLiteral(e) || y.isTemplateHead(e) || y.isTemplateMiddle(e) || y.isTemplateTail(e) || y.isRegularExpressionLiteral(e)) {
|
|
2775
2775
|
let n = e.getText();
|
|
2776
2776
|
if (!n.includes(z)) return;
|
|
2777
2777
|
e.replaceWithText(n.split(z).join(bn)), t++;
|
|
@@ -2783,19 +2783,19 @@ var b = (e, t, n) => {
|
|
|
2783
2783
|
for (let r of e.getSourceFiles()) {
|
|
2784
2784
|
let e = xn(r, B);
|
|
2785
2785
|
e.length !== 0 && r.forEachDescendant((r) => {
|
|
2786
|
-
if (!
|
|
2786
|
+
if (!y.isCallExpression(r) || !e.includes(r.getExpression().getText())) return;
|
|
2787
2787
|
let i = r.getParent();
|
|
2788
|
-
if (
|
|
2788
|
+
if (y.isPropertyAccessExpression(i) && i.getName() === "lang") {
|
|
2789
2789
|
i.getNameNode().replaceWithText("locale"), t++;
|
|
2790
2790
|
return;
|
|
2791
2791
|
}
|
|
2792
|
-
if (
|
|
2792
|
+
if (y.isVariableDeclaration(i)) {
|
|
2793
2793
|
let e = i.getNameNode();
|
|
2794
|
-
if (!
|
|
2794
|
+
if (!y.isObjectBindingPattern(e)) return;
|
|
2795
2795
|
for (let t of e.getElements()) {
|
|
2796
2796
|
if (t.getPropertyNameNode() !== void 0) continue;
|
|
2797
2797
|
let e = t.getNameNode();
|
|
2798
|
-
!
|
|
2798
|
+
!y.isIdentifier(e) || e.getText() !== "lang" || (t.replaceWithText(`locale: ${t.getText()}`), n++);
|
|
2799
2799
|
}
|
|
2800
2800
|
}
|
|
2801
2801
|
});
|
|
@@ -2804,7 +2804,7 @@ var b = (e, t, n) => {
|
|
|
2804
2804
|
access: t,
|
|
2805
2805
|
destructured: n
|
|
2806
2806
|
};
|
|
2807
|
-
}, wn =
|
|
2807
|
+
}, wn = C({
|
|
2808
2808
|
version: "0.30.0",
|
|
2809
2809
|
id: "0.30.0/01_locale-cookie-rename",
|
|
2810
2810
|
title: "the language-preference cookie is `voltro:locale` (was `voltro:lang`)",
|
|
@@ -2821,7 +2821,7 @@ var b = (e, t, n) => {
|
|
|
2821
2821
|
}), i = Sn(e), { access: a, destructured: o } = Cn(e), s = [];
|
|
2822
2822
|
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.` : ""));
|
|
2823
2823
|
}
|
|
2824
|
-
}), Tn = /auditPlugin\s*\(|versioningPlugin\s*\(|atlassianPlugin\s*\(/, En =
|
|
2824
|
+
}), Tn = /auditPlugin\s*\(|versioningPlugin\s*\(|atlassianPlugin\s*\(/, En = C({
|
|
2825
2825
|
version: "0.30.0",
|
|
2826
2826
|
id: "0.30.0/02_audit-purge-query-recheck",
|
|
2827
2827
|
title: "re-run the credential-purge query — the 0.28.0 spelling under-reported on MySQL/MariaDB",
|
|
@@ -2873,14 +2873,14 @@ var b = (e, t, n) => {
|
|
|
2873
2873
|
" `connectionCredentials(...)` keeps it in the framework vault",
|
|
2874
2874
|
" (see `0.28.0/03_atlassian-credentials-context`)."
|
|
2875
2875
|
].join("\n")
|
|
2876
|
-
}), Dn = /\.webhooks\s*\.\s*emit\s*\(|useWebhooks\s*\(/, On =
|
|
2876
|
+
}), Dn = /\.webhooks\s*\.\s*emit\s*\(|useWebhooks\s*\(/, On = C({
|
|
2877
2877
|
version: "0.30.0",
|
|
2878
2878
|
id: "0.30.0/03_webhook-emit-durable-deferral",
|
|
2879
2879
|
title: "a deferred `webhooks.emit` rides the transactional outbox; `{ immediate: true }` opts out",
|
|
2880
2880
|
kind: "manual",
|
|
2881
2881
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
2882
2882
|
let t = e.getFullText();
|
|
2883
|
-
return Dn.test(t) ||
|
|
2883
|
+
return Dn.test(t) || w("emit").test(t);
|
|
2884
2884
|
}),
|
|
2885
2885
|
note: [
|
|
2886
2886
|
"A `ctx.webhooks.emit(...)` inside a MUTATION now enqueues a transactional",
|
|
@@ -2930,14 +2930,14 @@ var b = (e, t, n) => {
|
|
|
2930
2930
|
"created by the declarative differ on the next `voltro dev` boot or",
|
|
2931
2931
|
"`voltro db apply` — there is nothing to run by hand."
|
|
2932
2932
|
].join("\n")
|
|
2933
|
-
}), kn = /\.executionId\b|workflows\s*\.\s*start\s*\(|workflows\s*\.\s*child\s*\(/, An =
|
|
2933
|
+
}), kn = /\.executionId\b|workflows\s*\.\s*start\s*\(|workflows\s*\.\s*child\s*\(/, An = C({
|
|
2934
2934
|
version: "0.30.0",
|
|
2935
2935
|
id: "0.30.0/04_workflow-run-handle-nullable-execution",
|
|
2936
2936
|
title: "`WorkflowRunHandle.executionId` is `string | null`; `status` gains queued/dropped/skipped",
|
|
2937
2937
|
kind: "manual",
|
|
2938
2938
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
2939
2939
|
let t = e.getFullText();
|
|
2940
|
-
return kn.test(t) ||
|
|
2940
|
+
return kn.test(t) || w("start").test(t);
|
|
2941
2941
|
}),
|
|
2942
2942
|
note: [
|
|
2943
2943
|
"A workflow start no longer always becomes a run. With declarative flow",
|
|
@@ -3002,7 +3002,7 @@ var b = (e, t, n) => {
|
|
|
3002
3002
|
" and `singleton: { mode: 'skip' }` throws `WorkflowSingletonHeldError`",
|
|
3003
3003
|
" carrying the incumbent's execution id, so you can wait on THAT run."
|
|
3004
3004
|
].join("\n")
|
|
3005
|
-
}), jn = /auditPlugin\s*\(|versioningPlugin\s*\(|atlassianPlugin\s*\(/, Mn =
|
|
3005
|
+
}), jn = /auditPlugin\s*\(|versioningPlugin\s*\(|atlassianPlugin\s*\(/, Mn = C({
|
|
3006
3006
|
version: "0.31.0",
|
|
3007
3007
|
id: "0.31.0/01_rerun-credential-scan",
|
|
3008
3008
|
title: "re-run `voltro db scan-credentials` — on 0.30.0–0.30.2 it skipped the column credentials land in",
|
|
@@ -3041,7 +3041,7 @@ var b = (e, t, n) => {
|
|
|
3041
3041
|
"credential on the Subject — `connectionCredentials(...)` keeps it in the",
|
|
3042
3042
|
"framework vault."
|
|
3043
3043
|
].join("\n")
|
|
3044
|
-
}), Nn =
|
|
3044
|
+
}), Nn = C({
|
|
3045
3045
|
version: "0.32.0",
|
|
3046
3046
|
id: "0.32.0/01_audit-redacts-outcome",
|
|
3047
3047
|
title: "`auditPlugin` now redacts `outcome` by default — opt out if your trail reads it",
|
|
@@ -3082,7 +3082,7 @@ var b = (e, t, n) => {
|
|
|
3082
3082
|
"purge the rows AND rotate the credentials — assume anything written to a",
|
|
3083
3083
|
"log table has been read."
|
|
3084
3084
|
].join("\n")
|
|
3085
|
-
}), Pn =
|
|
3085
|
+
}), Pn = C({
|
|
3086
3086
|
version: "0.33.0",
|
|
3087
3087
|
id: "0.33.0/01_opentelemetry-optional-peer",
|
|
3088
3088
|
title: "`@effect/opentelemetry` is now an optional peer — install it if you use tracing",
|
|
@@ -3114,7 +3114,7 @@ var b = (e, t, n) => {
|
|
|
3114
3114
|
"never wrote down. It is a startup failure, not a silent loss of traces —",
|
|
3115
3115
|
"losing telemetry quietly would be the worse outcome."
|
|
3116
3116
|
].join("\n")
|
|
3117
|
-
}), Fn =
|
|
3117
|
+
}), Fn = C({
|
|
3118
3118
|
version: "0.33.0",
|
|
3119
3119
|
id: "0.33.0/02_coordinated-handle-gained-wake",
|
|
3120
3120
|
title: "`CoordinatedScheduleHandle` gained `wake()`, `currentIntervalMs()` and `isArmed()` — update hand-written test doubles",
|
|
@@ -3164,7 +3164,7 @@ var b = (e, t, n) => {
|
|
|
3164
3164
|
"Reporting nothing is the conservative default on purpose — a task that",
|
|
3165
3165
|
"cannot tell whether it was idle must not be slowed down on a guess."
|
|
3166
3166
|
].join("\n")
|
|
3167
|
-
}), In =
|
|
3167
|
+
}), In = C({
|
|
3168
3168
|
version: "0.34.0",
|
|
3169
3169
|
id: "0.34.0/01_serve-does-mount-inspect",
|
|
3170
3170
|
title: "Correction: `voltro serve` DOES mount an inspect surface (the 0.12.0 note said it mounts none)",
|
|
@@ -3205,7 +3205,7 @@ var b = (e, t, n) => {
|
|
|
3205
3205
|
"place, everyone already past 0.12.0 — which is everyone the wrong sentence",
|
|
3206
3206
|
"could have misled — would never have seen it."
|
|
3207
3207
|
].join("\n")
|
|
3208
|
-
}), Ln = (e) => /\.with\(\s*[\w.]*tenant\(/.test(e) || /\.serverOnly\(\s*\)/.test(e), Rn =
|
|
3208
|
+
}), Ln = (e) => /\.with\(\s*[\w.]*tenant\(/.test(e) || /\.serverOnly\(\s*\)/.test(e), Rn = C({
|
|
3209
3209
|
version: "0.34.0",
|
|
3210
3210
|
id: "0.34.0/02_keyed-writes-are-tenant-scoped",
|
|
3211
3211
|
title: "Keyed-by-pk writes are tenant-enforced, and `crud` refuses `.serverOnly()` input",
|
|
@@ -3281,10 +3281,10 @@ var b = (e, t, n) => {
|
|
|
3281
3281
|
"defineStream"
|
|
3282
3282
|
]), Bn = (e) => {
|
|
3283
3283
|
let t = e.getArguments()[0];
|
|
3284
|
-
if (t === void 0 || !t.isKind(
|
|
3284
|
+
if (t === void 0 || !t.isKind(b.ObjectLiteralExpression)) return /* @__PURE__ */ new Set();
|
|
3285
3285
|
let n = /* @__PURE__ */ new Set();
|
|
3286
3286
|
for (let e of t.getProperties()) {
|
|
3287
|
-
let t = (e.asKind(
|
|
3287
|
+
let t = (e.asKind(b.PropertyAssignment) ?? e.asKind(b.ShorthandPropertyAssignment))?.getName?.();
|
|
3288
3288
|
t !== void 0 && n.add(t);
|
|
3289
3289
|
}
|
|
3290
3290
|
return n;
|
|
@@ -3292,12 +3292,12 @@ var b = (e, t, n) => {
|
|
|
3292
3292
|
if (!zn.has(e.getExpression().getText())) return !1;
|
|
3293
3293
|
let t = Bn(e);
|
|
3294
3294
|
return !t.has("internal") && !t.has("guards") && !t.has("openAccess");
|
|
3295
|
-
}) : !1, Hn =
|
|
3295
|
+
}) : !1, Hn = C({
|
|
3296
3296
|
version: "0.34.0",
|
|
3297
3297
|
id: "0.34.0/03_procedure-access-decision",
|
|
3298
3298
|
title: "Every wire-exposed procedure declares an access decision (`guards:` or `openAccess:`)",
|
|
3299
3299
|
kind: "manual",
|
|
3300
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Vn(e.getFullText(), e.getDescendantsOfKind(
|
|
3300
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Vn(e.getFullText(), e.getDescendantsOfKind(b.CallExpression))),
|
|
3301
3301
|
note: [
|
|
3302
3302
|
"YOUR APP WILL NOT BOOT UNTIL EVERY WIRE-EXPOSED PROCEDURE DECIDES WHO MAY",
|
|
3303
3303
|
"CALL IT. This is the single largest behaviour change in this release, and it",
|
|
@@ -3346,7 +3346,7 @@ var b = (e, t, n) => {
|
|
|
3346
3346
|
"workosAuthorizationUrl",
|
|
3347
3347
|
"workosAuthenticateWithCode",
|
|
3348
3348
|
"workosBeginLogin"
|
|
3349
|
-
], Wn =
|
|
3349
|
+
], Wn = C({
|
|
3350
3350
|
version: "0.34.0",
|
|
3351
3351
|
id: "0.34.0/04_workos-oauth-state-pkce",
|
|
3352
3352
|
title: "WorkOS hosted login: `workosAuthorizationUrl` → `workosBeginLogin`, with mandatory `state` + PKCE",
|
|
@@ -3411,7 +3411,7 @@ var b = (e, t, n) => {
|
|
|
3411
3411
|
"are accepted on the existing endpoints; your registered redirect URI is",
|
|
3412
3412
|
"unchanged."
|
|
3413
3413
|
].join("\n")
|
|
3414
|
-
}), Gn = /mirrorTables|_?voltro_mirror_/, Kn =
|
|
3414
|
+
}), Gn = /mirrorTables|_?voltro_mirror_/, Kn = C({
|
|
3415
3415
|
version: "0.34.0",
|
|
3416
3416
|
id: "0.34.0/05_analytics-mirror-versioned-writes",
|
|
3417
3417
|
title: "Analytics CDC-mirror: version-ordered writes, tombstoned deletes, retry + repair",
|
|
@@ -3471,7 +3471,7 @@ var b = (e, t, n) => {
|
|
|
3471
3471
|
" VOLTRO_ANALYTICS_MIRROR_REPAIR_INTERVAL_MS (60000, 0 disables)",
|
|
3472
3472
|
" VOLTRO_ANALYTICS_MIRROR_REPAIR_QUEUE_LIMIT (10000)"
|
|
3473
3473
|
].join("\n")
|
|
3474
|
-
}), qn =
|
|
3474
|
+
}), qn = C({
|
|
3475
3475
|
version: "0.34.0",
|
|
3476
3476
|
id: "0.34.0/06_origin-guard-and-trusted-proxies",
|
|
3477
3477
|
title: "Cross-site protection, trusted proxies and security headers are ON by default on the api listener",
|
|
@@ -3595,7 +3595,7 @@ var b = (e, t, n) => {
|
|
|
3595
3595
|
" a `Transfer-Encoding: chunked` body skipped it and was buffered without",
|
|
3596
3596
|
" bound. No action needed; VOLTRO_MAX_RPC_BODY_BYTES still tunes it."
|
|
3597
3597
|
].join("\n")
|
|
3598
|
-
}), Jn =
|
|
3598
|
+
}), Jn = C({
|
|
3599
3599
|
version: "0.34.0",
|
|
3600
3600
|
id: "0.34.0/07_incoming-webhook-declares-verification",
|
|
3601
3601
|
title: "An incoming webhook with no signature scheme now refuses to boot",
|
|
@@ -3644,7 +3644,7 @@ var b = (e, t, n) => {
|
|
|
3644
3644
|
"value — the sender holds the other half of it, so a generated one would",
|
|
3645
3645
|
"authenticate nobody."
|
|
3646
3646
|
].join("\n")
|
|
3647
|
-
}), Yn =
|
|
3647
|
+
}), Yn = C({
|
|
3648
3648
|
version: "0.34.0",
|
|
3649
3649
|
id: "0.34.0/08_init-initialises-the-workspace",
|
|
3650
3650
|
title: "`voltro init` initialises the workspace root; scaffolding is `create-project` only",
|
|
@@ -3696,20 +3696,20 @@ var b = (e, t, n) => {
|
|
|
3696
3696
|
"all 18 of its scripts — including the `pnpm db:up` the CLI then printed as a",
|
|
3697
3697
|
"next step. Run `voltro init` in the root first."
|
|
3698
3698
|
].join("\n")
|
|
3699
|
-
}), Xn = (e, t) => (e.getProperty(t)?.asKind(
|
|
3699
|
+
}), Xn = (e, t) => (e.getProperty(t)?.asKind(b.PropertyAssignment))?.getInitializer()?.asKind(b.ObjectLiteralExpression), Zn = (e) => {
|
|
3700
3700
|
if (e.getExpression().getText() !== "workflow") return !1;
|
|
3701
|
-
let t = e.getArguments()[0]?.asKind(
|
|
3701
|
+
let t = e.getArguments()[0]?.asKind(b.ObjectLiteralExpression);
|
|
3702
3702
|
if (t === void 0) return !1;
|
|
3703
3703
|
let n = Xn(t, "messages");
|
|
3704
3704
|
return n !== void 0 && n.getProperty("queries") !== void 0;
|
|
3705
|
-
}, Qn =
|
|
3705
|
+
}, Qn = C({
|
|
3706
3706
|
version: "0.34.0",
|
|
3707
3707
|
id: "0.34.0/09_workflow-messages-queries-removed",
|
|
3708
3708
|
title: "`workflow({ messages: { queries } })` is removed — it never had a send path",
|
|
3709
3709
|
kind: "manual",
|
|
3710
3710
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
3711
3711
|
let t = e.getFullText();
|
|
3712
|
-
return !t.includes("queries") || !/workflow\s*\(/.test(t) ? !1 : e.getDescendantsOfKind(
|
|
3712
|
+
return !t.includes("queries") || !/workflow\s*\(/.test(t) ? !1 : e.getDescendantsOfKind(b.CallExpression).some(Zn);
|
|
3713
3713
|
}),
|
|
3714
3714
|
note: [
|
|
3715
3715
|
"YOU DECLARED `messages: { queries: { … } }` ON A WORKFLOW. That channel is",
|
|
@@ -3752,7 +3752,7 @@ var b = (e, t, n) => {
|
|
|
3752
3752
|
"in-flight runs finish on the old path after a deploy. See the Versioning",
|
|
3753
3753
|
"page in the docs."
|
|
3754
3754
|
].join("\n")
|
|
3755
|
-
}), $n =
|
|
3755
|
+
}), $n = C({
|
|
3756
3756
|
version: "0.34.0",
|
|
3757
3757
|
id: "0.34.0/11_ai-flows-per-step-human-signal",
|
|
3758
3758
|
title: "`HUMAN_RESPONSE_SIGNAL` removed — a human step's signal name is now per-step",
|
|
@@ -3804,10 +3804,10 @@ var b = (e, t, n) => {
|
|
|
3804
3804
|
let t = e.getFullText();
|
|
3805
3805
|
if (!/issueSession|signSession|resolveScopes|@voltro\/(plugin-auth|protocol\/session|plugin-sso-saml)/.test(t)) return !1;
|
|
3806
3806
|
for (let t of e.getImportDeclarations()) if (er.has(t.getModuleSpecifierValue())) return !0;
|
|
3807
|
-
for (let t of e.getDescendantsOfKind(
|
|
3808
|
-
for (let t of e.getDescendantsOfKind(
|
|
3807
|
+
for (let t of e.getDescendantsOfKind(b.CallExpression)) if (tr.has(t.getExpression().getText())) return !0;
|
|
3808
|
+
for (let t of e.getDescendantsOfKind(b.PropertyAssignment)) if (t.getName() === "resolveScopes") return !0;
|
|
3809
3809
|
return !1;
|
|
3810
|
-
}, rr =
|
|
3810
|
+
}, rr = C({
|
|
3811
3811
|
version: "0.34.0",
|
|
3812
3812
|
id: "0.34.0/12_session-cookie-carries-identity",
|
|
3813
3813
|
title: "The session cookie carries identity only — authority resolves per request",
|
|
@@ -3903,7 +3903,7 @@ var b = (e, t, n) => {
|
|
|
3903
3903
|
"not have: an authoritative resolver now overrides a token's own scope",
|
|
3904
3904
|
"claim, which union-only could never do."
|
|
3905
3905
|
].join("\n")
|
|
3906
|
-
}), ir = /\bMockEmail\b|\.email\.(sent|lastTo|clear)\b|\bSentEmail\b/, ar =
|
|
3906
|
+
}), ir = /\bMockEmail\b|\.email\.(sent|lastTo|clear)\b|\bSentEmail\b/, ar = C({
|
|
3907
3907
|
version: "0.34.0",
|
|
3908
3908
|
id: "0.34.0/10_testing-mail-is-a-service",
|
|
3909
3909
|
title: "`ctx.email` / `MockEmail` removed — assert mail through the mail plugin",
|
|
@@ -3977,7 +3977,7 @@ var b = (e, t, n) => {
|
|
|
3977
3977
|
" • `makeTestContext({ layers })` — your app's own `app.config.ts`",
|
|
3978
3978
|
" `layers:` now resolve for an Effect-mode handler under test."
|
|
3979
3979
|
].join("\n")
|
|
3980
|
-
}), or = /from\s+['"]@voltro\/plugin-billing(?:\/[\w-]+)?['"]/, sr =
|
|
3980
|
+
}), or = /from\s+['"]@voltro\/plugin-billing(?:\/[\w-]+)?['"]/, sr = C({
|
|
3981
3981
|
version: "0.34.0",
|
|
3982
3982
|
id: "0.34.0/13_billing-provider-dunning",
|
|
3983
3983
|
title: "Billing dunning — `BillingProvider.fetchSubscription` is required, and `plan()` now honours a grace period",
|
|
@@ -4058,7 +4058,7 @@ var b = (e, t, n) => {
|
|
|
4058
4058
|
"`pastDueSince` / `statusEventAt` columns ride the declarative differ — they",
|
|
4059
4059
|
"are applied by `voltro db apply` and by a `voltro dev` boot, on every dialect."
|
|
4060
4060
|
].join("\n")
|
|
4061
|
-
}), cr = /from\s+['"]@voltro\/plugin-search(?:\/[\w-]+)?['"]/, lr =
|
|
4061
|
+
}), cr = /from\s+['"]@voltro\/plugin-search(?:\/[\w-]+)?['"]/, lr = C({
|
|
4062
4062
|
version: "0.34.0",
|
|
4063
4063
|
id: "0.34.0/14_search-memory-backend-refuses-production",
|
|
4064
4064
|
title: "`plugin-search` on the in-memory backend now refuses to boot in production",
|
|
@@ -4132,7 +4132,7 @@ var b = (e, t, n) => {
|
|
|
4132
4132
|
"(`ts_headline` / `snippet()` / …) that `SearchQuery` promises. Degrading",
|
|
4133
4133
|
"those silently would replace one lie with another."
|
|
4134
4134
|
].join("\n")
|
|
4135
|
-
}), ur =
|
|
4135
|
+
}), ur = C({
|
|
4136
4136
|
version: "0.34.0",
|
|
4137
4137
|
id: "0.34.0/15_mysql-mssql-tls-honoured",
|
|
4138
4138
|
title: "mysql/mariadb and mssql connections honour ?ssl= / ?sslmode= — or refuse to boot",
|
|
@@ -4204,7 +4204,7 @@ var b = (e, t, n) => {
|
|
|
4204
4204
|
"spins in-tick and starves the event loop. Set it only if you know nothing in",
|
|
4205
4205
|
"your process does that, and set it well above their peak concurrency."
|
|
4206
4206
|
].join("\n")
|
|
4207
|
-
}), dr =
|
|
4207
|
+
}), dr = C({
|
|
4208
4208
|
version: "0.34.0",
|
|
4209
4209
|
id: "0.34.0/16_declare-node-env-for-migration-commands",
|
|
4210
4210
|
title: "`voltro db apply` / `voltro migrate` now treat an unset NODE_ENV as production",
|
|
@@ -4268,7 +4268,7 @@ var b = (e, t, n) => {
|
|
|
4268
4268
|
"process environment if you want a non-production `voltro serve` without a",
|
|
4269
4269
|
"built bundle. Everything downstream of the launcher does honour `.env`."
|
|
4270
4270
|
].join("\n")
|
|
4271
|
-
}), fr = /\/(?:src\/)?pages\//, pr = /\bcacheInvalidatesOn\b/, mr =
|
|
4271
|
+
}), fr = /\/(?:src\/)?pages\//, pr = /\bcacheInvalidatesOn\b/, mr = C({
|
|
4272
4272
|
version: "0.34.0",
|
|
4273
4273
|
id: "0.34.0/17_isr-postgres-refuses-without-a-database",
|
|
4274
4274
|
title: "The postgres ISR cache + CDC invalidator read DB_URL, and no longer fall back silently",
|
|
@@ -4318,7 +4318,7 @@ var b = (e, t, n) => {
|
|
|
4318
4318
|
" until their `revalidate` window expires. Give the web process a `DB_URL`",
|
|
4319
4319
|
" or remove the declaration."
|
|
4320
4320
|
].join("\n")
|
|
4321
|
-
}), hr = /\.migration\.ts$/, gr =
|
|
4321
|
+
}), hr = /\.migration\.ts$/, gr = C({
|
|
4322
4322
|
version: "0.34.0",
|
|
4323
4323
|
id: "0.34.0/18_serve-refuses-pending-file-migrations",
|
|
4324
4324
|
title: "`voltro serve` refuses to boot with pending file-based migrations",
|
|
@@ -4384,9 +4384,9 @@ var b = (e, t, n) => {
|
|
|
4384
4384
|
for (let e of t.getNamedImports()) if (vr.has(e.getName())) return !0;
|
|
4385
4385
|
if (t.getNamespaceImport() !== void 0) return !0;
|
|
4386
4386
|
}
|
|
4387
|
-
for (let t of e.getDescendantsOfKind(
|
|
4387
|
+
for (let t of e.getDescendantsOfKind(b.TypeReference)) if (t.getTypeName().getText() === "UserStore") return !0;
|
|
4388
4388
|
return !1;
|
|
4389
|
-
}, br =
|
|
4389
|
+
}, br = C({
|
|
4390
4390
|
version: "0.34.0",
|
|
4391
4391
|
id: "0.34.0/20_user-store-auth-feature-methods",
|
|
4392
4392
|
title: "UserStore gained the email-verification, invitation and impersonation methods",
|
|
@@ -4480,12 +4480,12 @@ var b = (e, t, n) => {
|
|
|
4480
4480
|
]), xr = (e) => {
|
|
4481
4481
|
let t = e.getFullText();
|
|
4482
4482
|
if (!/ConnectionSubject|connectionSubjectsSnapshot|rebind/.test(t)) return !1;
|
|
4483
|
-
for (let t of e.getDescendantsOfKind(
|
|
4483
|
+
for (let t of e.getDescendantsOfKind(b.CallExpression)) if (V.has(t.getExpression().getText())) return !0;
|
|
4484
4484
|
for (let t of e.getImportDeclarations()) for (let e of t.getNamedImports()) if (V.has(e.getName())) return !0;
|
|
4485
|
-
for (let t of e.getDescendantsOfKind(
|
|
4486
|
-
for (let t of e.getDescendantsOfKind(
|
|
4485
|
+
for (let t of e.getDescendantsOfKind(b.PropertyAssignment)) if (t.getName() === "rebind") return !0;
|
|
4486
|
+
for (let t of e.getDescendantsOfKind(b.ShorthandPropertyAssignment)) if (t.getName() === "rebind") return !0;
|
|
4487
4487
|
return !1;
|
|
4488
|
-
}, Sr =
|
|
4488
|
+
}, Sr = C({
|
|
4489
4489
|
version: "0.34.0",
|
|
4490
4490
|
id: "0.34.0/19_connection-override-carries-a-credential",
|
|
4491
4491
|
title: "Soft re-auth presents a credential — it no longer hands the server a Subject",
|
|
@@ -4579,10 +4579,10 @@ var b = (e, t, n) => {
|
|
|
4579
4579
|
if (/\.workflow(\.server)?\.tsx?$/.test(e.getBaseName())) return !0;
|
|
4580
4580
|
let t = e.getFullText();
|
|
4581
4581
|
if (!/resolveScopes|defineWorkflow|ctx\.workflows/.test(t)) return !1;
|
|
4582
|
-
for (let t of e.getDescendantsOfKind(
|
|
4583
|
-
for (let t of e.getDescendantsOfKind(
|
|
4582
|
+
for (let t of e.getDescendantsOfKind(b.PropertyAssignment)) if (t.getName() === "resolveScopes") return !0;
|
|
4583
|
+
for (let t of e.getDescendantsOfKind(b.CallExpression)) if (t.getExpression().getText() === "defineWorkflow") return !0;
|
|
4584
4584
|
return !1;
|
|
4585
|
-
}, wr =
|
|
4585
|
+
}, wr = C({
|
|
4586
4586
|
version: "0.34.0",
|
|
4587
4587
|
id: "0.34.0/20_workflow-authority-resolves-at-resume",
|
|
4588
4588
|
title: "A resumed workflow re-resolves its caller's authority instead of restoring it",
|
|
@@ -4667,9 +4667,9 @@ var b = (e, t, n) => {
|
|
|
4667
4667
|
let t = e.getName();
|
|
4668
4668
|
if (t === "EntityAdminSpec" || t === "deriveEntityAdmins") return !0;
|
|
4669
4669
|
}
|
|
4670
|
-
for (let t of e.getDescendantsOfKind(
|
|
4670
|
+
for (let t of e.getDescendantsOfKind(b.PropertyAccessExpression)) if (Tr.has(t.getName())) return !0;
|
|
4671
4671
|
return !1;
|
|
4672
|
-
}, Dr =
|
|
4672
|
+
}, Dr = C({
|
|
4673
4673
|
version: "0.34.0",
|
|
4674
4674
|
id: "0.34.0/21_admin-gates-on-declared-access",
|
|
4675
4675
|
title: "The derived admin gates on the api's DECLARED access — the invented `<table>:create` scopes are gone",
|
|
@@ -4764,7 +4764,7 @@ var b = (e, t, n) => {
|
|
|
4764
4764
|
"from \"undeclared\", so an intentionally public action rendered as forbidden",
|
|
4765
4765
|
"to everybody."
|
|
4766
4766
|
].join("\n")
|
|
4767
|
-
}), Or = /\b(useMutation|useAction|useWorkflow|useWorkflowSignal|useWorkflowUpdate|useUpload)\b/, kr = /FiberFailure|Cause\.squash|squashWith/, Ar =
|
|
4767
|
+
}), Or = /\b(useMutation|useAction|useWorkflow|useWorkflowSignal|useWorkflowUpdate|useUpload)\b/, kr = /FiberFailure|Cause\.squash|squashWith/, Ar = C({
|
|
4768
4768
|
version: "0.34.0",
|
|
4769
4769
|
id: "0.34.0/22_write-rejections-carry-the-typed-error",
|
|
4770
4770
|
title: "A rejected mutate/run/signal/upload carries the typed error, not a FiberFailure",
|
|
@@ -4824,7 +4824,7 @@ var b = (e, t, n) => {
|
|
|
4824
4824
|
"contract, reject from a real rpc client, or assert on the value your",
|
|
4825
4825
|
"component branches on rather than on the literal the test wrote."
|
|
4826
4826
|
].join("\n")
|
|
4827
|
-
}), jr = /@voltro\/plugin-sso-saml|samlSsoPlugin/, Mr =
|
|
4827
|
+
}), jr = /@voltro\/plugin-sso-saml|samlSsoPlugin/, Mr = C({
|
|
4828
4828
|
version: "0.34.0",
|
|
4829
4829
|
id: "0.34.0/23_saml-signature-and-replay-defaults",
|
|
4830
4830
|
title: "SAML: response-signature requirement relaxed + surfaced; replay protection ON by default",
|
|
@@ -4920,14 +4920,14 @@ var b = (e, t, n) => {
|
|
|
4920
4920
|
"request, and the envelope is unauthenticated. If you must run unsolicited,",
|
|
4921
4921
|
"set `wantAuthnResponseSigned: true`."
|
|
4922
4922
|
].join("\n")
|
|
4923
|
-
}), Nr = /\b(signPayload|verifySignature)\s*\(/, Pr =
|
|
4923
|
+
}), Nr = /\b(signPayload|verifySignature)\s*\(/, Pr = C({
|
|
4924
4924
|
version: "0.34.0",
|
|
4925
4925
|
id: "0.34.0/24_webhook-signing-renders-headers",
|
|
4926
4926
|
title: "Webhook signing: `signPayload`/`verifySignature` → `signRequest`/`verifyRequest`",
|
|
4927
4927
|
kind: "manual",
|
|
4928
4928
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Nr.test(e.getFullText())),
|
|
4929
4929
|
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."
|
|
4930
|
-
}), Fr = /from\s+['"]@voltro\/plugin-presence(?:\/[a-z]+)?['"]/, Ir = /\b(lastSeen|presenceTable|memoryPresenceStore|isOnline|filterOnline|staleKeys|PresenceStore|PresenceEntry|PresenceTracker)\b/, Lr = /_voltro_presence/, Rr =
|
|
4930
|
+
}), Fr = /from\s+['"]@voltro\/plugin-presence(?:\/[a-z]+)?['"]/, Ir = /\b(lastSeen|presenceTable|memoryPresenceStore|isOnline|filterOnline|staleKeys|PresenceStore|PresenceEntry|PresenceTracker)\b/, Lr = /_voltro_presence/, Rr = C({
|
|
4931
4931
|
version: "0.34.0",
|
|
4932
4932
|
id: "0.34.0/25_presence-has-no-table",
|
|
4933
4933
|
title: "Presence: `_voltro_presence` is gone, and so is `lastSeen` on the roster",
|
|
@@ -4939,10 +4939,10 @@ var b = (e, t, n) => {
|
|
|
4939
4939
|
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."
|
|
4940
4940
|
}), zr = (e) => {
|
|
4941
4941
|
let t = e.getArguments()[0];
|
|
4942
|
-
if (t === void 0 || !t.isKind(
|
|
4942
|
+
if (t === void 0 || !t.isKind(b.ObjectLiteralExpression)) return /* @__PURE__ */ new Set();
|
|
4943
4943
|
let n = /* @__PURE__ */ new Set();
|
|
4944
4944
|
for (let e of t.getProperties()) {
|
|
4945
|
-
let t = (e.asKind(
|
|
4945
|
+
let t = (e.asKind(b.PropertyAssignment) ?? e.asKind(b.ShorthandPropertyAssignment))?.getName?.();
|
|
4946
4946
|
t !== void 0 && n.add(t);
|
|
4947
4947
|
}
|
|
4948
4948
|
return n;
|
|
@@ -4950,21 +4950,21 @@ var b = (e, t, n) => {
|
|
|
4950
4950
|
if (e.getExpression().getText() !== "defineEvent") return !1;
|
|
4951
4951
|
let t = zr(e);
|
|
4952
4952
|
return !t.has("guards") && !t.has("openAccess");
|
|
4953
|
-
}) : !1, Vr =
|
|
4953
|
+
}) : !1, Vr = C({
|
|
4954
4954
|
version: "0.35.0",
|
|
4955
4955
|
id: "0.35.0/01_event-access-decision",
|
|
4956
4956
|
title: "Every declared event decides who may listen (`guards:` or `openAccess:`)",
|
|
4957
4957
|
kind: "manual",
|
|
4958
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Br(e.getFullText(), e.getDescendantsOfKind(
|
|
4958
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Br(e.getFullText(), e.getDescendantsOfKind(b.CallExpression))),
|
|
4959
4959
|
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")
|
|
4960
|
-
}), Hr = /\brouteHttp\s*\(/, Ur =
|
|
4960
|
+
}), Hr = /\brouteHttp\s*\(/, Ur = C({
|
|
4961
4961
|
version: "0.34.0",
|
|
4962
4962
|
id: "0.34.0/26_route-http-is-async",
|
|
4963
4963
|
title: "`routeHttp` returns a Promise",
|
|
4964
4964
|
kind: "manual",
|
|
4965
4965
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Hr.test(e.getFullText())),
|
|
4966
4966
|
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."
|
|
4967
|
-
}), Wr = /@voltro\/plugin-(billing|governance|storage)/, Gr = /* @__PURE__ */ RegExp("\\b(billing\\.(startCheckout|portalUrl|previewChange|changePlan|changeSeats|invoices|reportUsage)|governance\\.(export|erase)|storage\\.(mintUploadUrl|ingestUrl|listRefs))\\b"), Kr = /\bdefinePluginRoute\s*\(|\broutes\s*:\s*\[/, qr =
|
|
4967
|
+
}), Wr = /@voltro\/plugin-(billing|governance|storage)/, Gr = /* @__PURE__ */ RegExp("\\b(billing\\.(startCheckout|portalUrl|previewChange|changePlan|changeSeats|invoices|reportUsage)|governance\\.(export|erase)|storage\\.(mintUploadUrl|ingestUrl|listRefs))\\b"), Kr = /\bdefinePluginRoute\s*\(|\broutes\s*:\s*\[/, qr = C({
|
|
4968
4968
|
version: "0.35.0",
|
|
4969
4969
|
id: "0.35.0/02_plugin-procedures-carry-access-decisions",
|
|
4970
4970
|
title: "First-party plugin procedures carry access decisions; twelve now require a scope",
|
|
@@ -5036,7 +5036,7 @@ var b = (e, t, n) => {
|
|
|
5036
5036
|
"`openAccess` with the reason each is safe (self-scoped rows, signed",
|
|
5037
5037
|
"subject-bound tickets, per-object grants), and behave exactly as before."
|
|
5038
5038
|
].join("\n")
|
|
5039
|
-
}), Jr = /AnalyticsMirrorImpl/, Yr =
|
|
5039
|
+
}), Jr = /AnalyticsMirrorImpl/, Yr = C({
|
|
5040
5040
|
version: "0.35.0",
|
|
5041
5041
|
id: "0.35.0/03_analytics-mirror-max-version",
|
|
5042
5042
|
title: "Custom analytics mirror sinks answer `maxVersion` (fleet-scope seed read)",
|
|
@@ -5066,21 +5066,21 @@ var b = (e, t, n) => {
|
|
|
5066
5066
|
"",
|
|
5067
5067
|
"The read is issued at most once per key per process, off the commit path."
|
|
5068
5068
|
].join("\n")
|
|
5069
|
-
}), Xr = (e) => /RunStepStatus/.test(e) || /['"]succeeded['"]/.test(e) && /['"]waiting['"]/.test(e) && /RunStep|runStep|flow/i.test(e), Zr =
|
|
5069
|
+
}), Xr = (e) => /RunStepStatus/.test(e) || /['"]succeeded['"]/.test(e) && /['"]waiting['"]/.test(e) && /RunStep|runStep|flow/i.test(e), Zr = C({
|
|
5070
5070
|
version: "0.35.0",
|
|
5071
5071
|
id: "0.35.0/04_flow-run-step-skipped",
|
|
5072
5072
|
title: "A flow run step can now be 'skipped' — handle it where you render a run timeline",
|
|
5073
5073
|
kind: "manual",
|
|
5074
5074
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => Xr(e.getFullText())),
|
|
5075
5075
|
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")
|
|
5076
|
-
}), Qr =
|
|
5076
|
+
}), Qr = C({
|
|
5077
5077
|
version: "0.35.0",
|
|
5078
5078
|
id: "0.35.0/05_declared-schema-drops-runtime-flags",
|
|
5079
5079
|
title: "The declared schema no longer reads `CDC` / `VOLTRO_UNDO` / `VOLTRO_TRACING_PERSIST`",
|
|
5080
5080
|
kind: "manual",
|
|
5081
5081
|
appliesTo: () => !0,
|
|
5082
5082
|
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")
|
|
5083
|
-
}), H = "session_expired", $r =
|
|
5083
|
+
}), H = "session_expired", $r = C({
|
|
5084
5084
|
version: "0.35.1",
|
|
5085
5085
|
id: "0.35.1/01_unauthorized-replaces-session-expired",
|
|
5086
5086
|
title: "A 401 is `code: 'unauthorized'`; the vault's own failure is `'credential_unusable'`",
|
|
@@ -5096,14 +5096,14 @@ var b = (e, t, n) => {
|
|
|
5096
5096
|
}
|
|
5097
5097
|
n.length !== 0 && t(`rewrote '${H}' 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"));
|
|
5098
5098
|
}
|
|
5099
|
-
}), ei = /\(\s*\{[^}]*\.\.\./, ti = /\bquery\??\.?\(\s*['"`]/, ni =
|
|
5099
|
+
}), ei = /\(\s*\{[^}]*\.\.\./, ti = /\bquery\??\.?\(\s*['"`]/, ni = C({
|
|
5100
5100
|
version: "0.37.0",
|
|
5101
5101
|
id: "0.37.0/01_procedure-input-rejects-undeclared-fields",
|
|
5102
5102
|
title: "a procedure input rejects a field it does not declare (it used to drop it)",
|
|
5103
5103
|
kind: "manual",
|
|
5104
5104
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
5105
5105
|
let t = e.getFullText();
|
|
5106
|
-
return ei.test(t) || ti.test(t) ||
|
|
5106
|
+
return ei.test(t) || ti.test(t) || w("query").test(t);
|
|
5107
5107
|
}),
|
|
5108
5108
|
note: [
|
|
5109
5109
|
"A procedure call whose input carries a field the schema does not declare",
|
|
@@ -5165,7 +5165,7 @@ var b = (e, t, n) => {
|
|
|
5165
5165
|
"two, the only safe direction is to refuse — and a warning would have to be",
|
|
5166
5166
|
"read by someone, in a log, after the wrong rows were already served."
|
|
5167
5167
|
].join("\n")
|
|
5168
|
-
}), U = "@voltro/plugin-auth", W = "@voltro/protocol", G = "IMPERSONATION_METADATA_KEY", ri =
|
|
5168
|
+
}), U = "@voltro/plugin-auth", W = "@voltro/protocol", G = "IMPERSONATION_METADATA_KEY", ri = C({
|
|
5169
5169
|
version: "0.38.0",
|
|
5170
5170
|
id: "0.38.0/01_impersonation-key-in-protocol",
|
|
5171
5171
|
title: `\`${G}\` is imported from @voltro/protocol`,
|
|
@@ -5191,7 +5191,7 @@ var b = (e, t, n) => {
|
|
|
5191
5191
|
}
|
|
5192
5192
|
n > 0 && t(`${G}: ${n} import(s) repointed to ${W}`);
|
|
5193
5193
|
}
|
|
5194
|
-
}), ii =
|
|
5194
|
+
}), ii = C({
|
|
5195
5195
|
version: "0.38.0",
|
|
5196
5196
|
id: "0.38.0/02_startup-failure-refuses-boot",
|
|
5197
5197
|
title: "a `*.startup.ts` that fails refuses the boot (it used to warn and continue)",
|
|
@@ -5276,7 +5276,7 @@ var b = (e, t, n) => {
|
|
|
5276
5276
|
"long work after, so a failure in the long half cannot hide a missing",
|
|
5277
5277
|
"registration."
|
|
5278
5278
|
].join("\n")
|
|
5279
|
-
}), ai = /\bStruct\(\s*\{\s*\}\s*\)/, oi =
|
|
5279
|
+
}), ai = /\bStruct\(\s*\{\s*\}\s*\)/, oi = C({
|
|
5280
5280
|
version: "0.39.0",
|
|
5281
5281
|
id: "0.39.0/01_empty-input-schema-rejects-every-field",
|
|
5282
5282
|
title: "a procedure declaring `Schema.Struct({})` used to accept every field and now accepts none",
|
|
@@ -5335,14 +5335,14 @@ var b = (e, t, n) => {
|
|
|
5335
5335
|
"A procedure that genuinely takes no input keeps `Schema.Struct({})` and is",
|
|
5336
5336
|
"correct as it stands — callers must send `{}` or nothing."
|
|
5337
5337
|
].join("\n")
|
|
5338
|
-
}), si =
|
|
5338
|
+
}), si = C({
|
|
5339
5339
|
version: "0.40.0",
|
|
5340
5340
|
id: "0.40.0/01_cold-start-failure-is-its-own-state",
|
|
5341
5341
|
title: "a failed cold start is `failed: true`, not `loading: true`",
|
|
5342
5342
|
kind: "manual",
|
|
5343
5343
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
5344
5344
|
let t = e.getFullText();
|
|
5345
|
-
return
|
|
5345
|
+
return w("useSubscription").test(t) || w("usePreloadedSubscription").test(t) || /\buseWorkflow\w*\(/.test(t);
|
|
5346
5346
|
}),
|
|
5347
5347
|
note: [
|
|
5348
5348
|
"A subscription whose COLD START failed no longer reports `loading: true`.",
|
|
@@ -5400,14 +5400,14 @@ var b = (e, t, n) => {
|
|
|
5400
5400
|
" reconnect discards the error and re-subscribes, so the entry returns to",
|
|
5401
5401
|
" pending on its own."
|
|
5402
5402
|
].join("\n")
|
|
5403
|
-
}), ci =
|
|
5403
|
+
}), ci = C({
|
|
5404
5404
|
version: "0.40.0",
|
|
5405
5405
|
id: "0.40.0/02_rejected-credential-widens-guard-results",
|
|
5406
5406
|
title: "a rejected credential answers `Unauthenticated`, widening three guard results",
|
|
5407
5407
|
kind: "manual",
|
|
5408
5408
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
5409
5409
|
let t = e.getFullText();
|
|
5410
|
-
return
|
|
5410
|
+
return w("checkGuards").test(t) || w("checkGuardsEffect").test(t) || w("bindEvent").test(t);
|
|
5411
5411
|
}),
|
|
5412
5412
|
note: [
|
|
5413
5413
|
"A guard refusing a caller whose CREDENTIAL was rejected now answers",
|
|
@@ -5436,23 +5436,213 @@ var b = (e, t, n) => {
|
|
|
5436
5436
|
"`openAccess` procedures are untouched: the stamp only travels, and only a",
|
|
5437
5437
|
"guard that actually refuses ever spends it."
|
|
5438
5438
|
].join("\n")
|
|
5439
|
-
}), K = "@voltro/web/middleware", q = /(^|[\\/])middleware\.tsx?$/,
|
|
5439
|
+
}), K = "@voltro/web/middleware", q = /(^|[\\/])middleware\.tsx?$/, li = C({
|
|
5440
|
+
version: "0.41.0",
|
|
5441
|
+
id: "0.41.0/01_middleware-defines-where-it-runs",
|
|
5442
|
+
title: "`middleware.ts` exports `defineMiddleware(...)` and can say where it runs",
|
|
5443
|
+
kind: "transform",
|
|
5444
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => q.test(e.getFilePath()) ? e.getExportAssignment((e) => !e.isExportEquals()) !== void 0 || e.getFunctions().some((e) => e.isDefaultExport()) : !1),
|
|
5445
|
+
transform: ({ project: e, log: t }) => {
|
|
5446
|
+
let n = 0;
|
|
5447
|
+
for (let t of e.getSourceFiles()) {
|
|
5448
|
+
if (!q.test(t.getFilePath()) || t.getFullText().includes("defineMiddleware")) continue;
|
|
5449
|
+
let e = t.getExportAssignment((e) => !e.isExportEquals());
|
|
5450
|
+
if (e !== void 0) {
|
|
5451
|
+
let t = e.getExpression().getText();
|
|
5452
|
+
e.replaceWithText(`export default defineMiddleware({ run: ${t} })`), n += 1;
|
|
5453
|
+
} else {
|
|
5454
|
+
let e = t.getFunctions().find((e) => e.isDefaultExport());
|
|
5455
|
+
if (e === void 0) continue;
|
|
5456
|
+
let r = e.getText().replace(/^\s*export\s+default\s+/, "");
|
|
5457
|
+
e.replaceWithText(`export default defineMiddleware({ run: ${r} })`), n += 1;
|
|
5458
|
+
}
|
|
5459
|
+
let r = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() === K);
|
|
5460
|
+
r === void 0 ? t.insertImportDeclaration(0, {
|
|
5461
|
+
moduleSpecifier: K,
|
|
5462
|
+
namedImports: [{ name: "defineMiddleware" }]
|
|
5463
|
+
}) : r.getNamedImports().some((e) => e.getName() === "defineMiddleware") || r.addNamedImport({ name: "defineMiddleware" });
|
|
5464
|
+
}
|
|
5465
|
+
n > 0 && (t(`middleware.ts: ${n} export(s) wrapped in defineMiddleware`), t("Add a `match` if the middleware should not run on every route — see the note."));
|
|
5466
|
+
},
|
|
5467
|
+
note: [
|
|
5468
|
+
"`middleware.ts` now exports `defineMiddleware(...)`. Your file was rewritten",
|
|
5469
|
+
"to the wrapped form, which behaves exactly as it did: no `match` means every",
|
|
5470
|
+
"server-rendered route.",
|
|
5471
|
+
"",
|
|
5472
|
+
"WHAT TO DO NEXT (optional, and worth a minute)",
|
|
5473
|
+
"",
|
|
5474
|
+
"If your middleware starts with a hand-written path gate, move it into `match`",
|
|
5475
|
+
"and delete the `if`:",
|
|
5476
|
+
"",
|
|
5477
|
+
" export const session = defineMiddleware({",
|
|
5478
|
+
" match: { under: '/app', except: ['/app/public'] },",
|
|
5479
|
+
" run: async (req) => { /* the body, without the guard clause */ },",
|
|
5480
|
+
" })",
|
|
5481
|
+
"",
|
|
5482
|
+
"WHY THIS IS BETTER THAN THE `if`",
|
|
5483
|
+
"",
|
|
5484
|
+
" • The hook no longer runs at all on routes it does not cover, so a public",
|
|
5485
|
+
" page stops paying for an IdP round trip it never used.",
|
|
5486
|
+
" • `under` / `routes` / `except` are checked against your ROUTES at boot. A",
|
|
5487
|
+
" path that matches nothing refuses the boot instead of silently never",
|
|
5488
|
+
" firing — the failure an `if` cannot report.",
|
|
5489
|
+
" • `voltro doctor` reports overlaps and dead matchers before you deploy.",
|
|
5490
|
+
"",
|
|
5491
|
+
"You can export SEVERAL middlewares now, each with its own `match`. At most",
|
|
5492
|
+
"one may match any given route: two hooks writing one `authorization` header",
|
|
5493
|
+
"have no defensible winner, so an overlap refuses the boot and names both.",
|
|
5494
|
+
"",
|
|
5495
|
+
"Non-page requests (assets, unknown paths) are NOT matched unless you ask with",
|
|
5496
|
+
"`assets: true`. There is no render there, so only `setCookies` takes effect."
|
|
5497
|
+
].join("\n")
|
|
5498
|
+
}), ui = C({
|
|
5499
|
+
version: "0.43.0",
|
|
5500
|
+
id: "0.43.0/01_dangling-reference-to-rows-refused",
|
|
5501
|
+
title: "`DanglingReferenceError` → `RowsRefusedError` (named for the outcome, not a guessed cause)",
|
|
5502
|
+
kind: "transform",
|
|
5503
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue().startsWith("@voltro/data-transfer") && e.getNamedImports().some((e) => e.getName() === "DanglingReferenceError"))),
|
|
5504
|
+
transform: ({ project: e, helpers: t, log: n }) => {
|
|
5505
|
+
let r = t.renameImport(e, {
|
|
5506
|
+
module: "@voltro/data-transfer",
|
|
5507
|
+
from: "DanglingReferenceError",
|
|
5508
|
+
to: "RowsRefusedError"
|
|
5509
|
+
});
|
|
5510
|
+
return r > 0 && n(`renamed ${r} import(s) of DanglingReferenceError → RowsRefusedError. A tag STRING (Effect.catchTag('DanglingReferenceError', …) or err._tag === '…') is NOT rewritten — change it to 'RowsRefusedError'. The payload also gained primaryCount, and each row a boolean derived.`), r;
|
|
5511
|
+
}
|
|
5512
|
+
}), di = C({
|
|
5513
|
+
version: "0.44.0",
|
|
5514
|
+
id: "0.44.0/01_import-outcome",
|
|
5515
|
+
title: "`runImport` returns an ImportOutcome — read `.manifest` for the bundle",
|
|
5516
|
+
kind: "manual",
|
|
5517
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue().startsWith("@voltro/data-transfer") && e.getNamedImports().some((e) => e.getName() === "runImport"))),
|
|
5518
|
+
note: [
|
|
5519
|
+
"`runImport(...)` now resolves to `{ manifest, tablesWritten, rowsWritten, tablesSkipped, rowsSkipped, fullyResumed }`",
|
|
5520
|
+
"instead of the bundle's `Manifest`.",
|
|
5521
|
+
"",
|
|
5522
|
+
" 1. Where you read the bundle — `.tables`, `.assets`, `.scope`, `.source` — read `.manifest.tables` and so on.",
|
|
5523
|
+
" 2. Where you REPORTED a row count, prefer `rowsWritten`. The manifest total is what the bundle CARRIES:",
|
|
5524
|
+
" a run that skipped every table (an earlier run of the same bundle directory had already applied them)",
|
|
5525
|
+
" carries the full count while writing nothing, which is exactly how a no-op used to read as a success.",
|
|
5526
|
+
" 3. `fullyResumed` is true precisely in that case.",
|
|
5527
|
+
"",
|
|
5528
|
+
"Same release, unrelated to the return type: `--mode replace` now runs in ONE transaction unless you pass",
|
|
5529
|
+
"`--no-atomic` (CLI) or `atomic: false` (API) — a replace that failed mid-load used to leave the target",
|
|
5530
|
+
"emptied of its old rows and holding part of the new ones. If you relied on per-table resume for a replace,",
|
|
5531
|
+
"that is the non-atomic path."
|
|
5532
|
+
].join("\n")
|
|
5533
|
+
}), fi = C({
|
|
5534
|
+
version: "0.45.0",
|
|
5535
|
+
id: "0.45.0/01_typed-source-table-name",
|
|
5536
|
+
title: "`source:` is typechecked against the app’s tables, from the next `voltro dev`",
|
|
5537
|
+
kind: "manual",
|
|
5538
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => /\bsource\s*:/.test(e.getFullText())),
|
|
5539
|
+
note: [
|
|
5540
|
+
"`source:` on a query or stream is now typed against your app’s own tables.",
|
|
5541
|
+
"A name no table carries is a COMPILE error instead of a subscription that",
|
|
5542
|
+
"silently never updates.",
|
|
5543
|
+
"",
|
|
5544
|
+
"WHEN IT STARTS APPLYING",
|
|
5545
|
+
"",
|
|
5546
|
+
"Not now — at your next `voltro dev` (or `voltro codegen`). Those write",
|
|
5547
|
+
"`voltro-tables.generated.d.ts` beside the generated rpc group, and that file",
|
|
5548
|
+
"is what narrows the type. Until it exists, `source:` is `string`, exactly as",
|
|
5549
|
+
"it is today. This note exists because the error appears one command later",
|
|
5550
|
+
"than the upgrade that caused it.",
|
|
5551
|
+
"",
|
|
5552
|
+
"WHAT TO DO",
|
|
5553
|
+
"",
|
|
5554
|
+
"Boot once, then read what `tsc` flags. Each site is one of two things:",
|
|
5555
|
+
"",
|
|
5556
|
+
" • a name that is misspelled, or was renamed away — a REAL defect this",
|
|
5557
|
+
" just surfaced. That query’s view was never updating. Fix the name.",
|
|
5558
|
+
"",
|
|
5559
|
+
" • a source computed at runtime — correct as written. Annotate it",
|
|
5560
|
+
" `ReactivitySourceValue` (exported from `@voltro/protocol`), which is the",
|
|
5561
|
+
" wide `string | ReactivityChannel` shape.",
|
|
5562
|
+
"",
|
|
5563
|
+
"Reach for the second only when the value genuinely is not a literal. Widening",
|
|
5564
|
+
"a name you could have spelled turns a found defect back into a quiet one.",
|
|
5565
|
+
"",
|
|
5566
|
+
"Eager-loaded relations are a common source of the first kind: a query that",
|
|
5567
|
+
"loads a relation must also declare that relation’s table (and, for a",
|
|
5568
|
+
"many-to-many, the junction). `voltro doctor` reports those.",
|
|
5569
|
+
"",
|
|
5570
|
+
"To opt out entirely, delete `voltro-tables.generated.d.ts` and exclude it",
|
|
5571
|
+
"from your tsconfig; `source:` widens back to `string`."
|
|
5572
|
+
].join("\n")
|
|
5573
|
+
}), pi = C({
|
|
5574
|
+
version: "0.46.0",
|
|
5575
|
+
id: "0.46.0/01_typed-aggregate-source",
|
|
5576
|
+
title: "an aggregate’s `incremental.source` is typechecked against the app’s tables",
|
|
5577
|
+
kind: "manual",
|
|
5578
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => /\bincremental\s*:/.test(e.getFullText())),
|
|
5579
|
+
note: (/* @__PURE__ */ "An aggregate that opts into incremental maintenance names the table whose(CDC deltas drive it:(( incremental: { source: 'tasks', op: 'count' }((That name is now checked against your app’s tables, the same way a query’s(`source:` has been since 0.45.0.((WHY IT MATTERS MORE HERE((A name matching no table does not error. The runner subscribes to something(nothing writes, no delta ever arrives, and the aggregate quietly stops(tracking its input — while every read of it still succeeds and still returns(a number. There is no failing request to notice.((WHEN IT STARTS APPLYING((At your next `voltro dev` or `voltro codegen`, not at this upgrade — those(write `voltro-tables.generated.d.ts`, and that file is what narrows the type.(Until it exists the field is `string`, exactly as it is today.((WHAT TO DO((Boot once and read what `tsc` flags. A flagged name is either misspelled or(renamed away — a real defect, and that aggregate has not been maintaining —(or it is computed at runtime, in which case annotate it `string`.((The boot also warns now: an aggregate whose CDC source resolves to no table(is named in the same stale-`source:` warning queries and streams appear in.".split("(")).join("\n")
|
|
5580
|
+
}), mi = C({
|
|
5581
|
+
version: "0.49.0",
|
|
5582
|
+
id: "0.49.0/01_data-imports-to-transfers",
|
|
5583
|
+
title: "`voltro data imports` → `voltro data transfers`",
|
|
5584
|
+
kind: "manual",
|
|
5585
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getFullText().includes("data imports")),
|
|
5586
|
+
note: [
|
|
5587
|
+
"The subcommand that reads the data-transfer history has been renamed:",
|
|
5588
|
+
"",
|
|
5589
|
+
" voltro data imports → voltro data transfers",
|
|
5590
|
+
"",
|
|
5591
|
+
"Two reasons, and the second is why it could not wait:",
|
|
5592
|
+
"",
|
|
5593
|
+
" - `import` and `imports` differ by one letter, and the neighbour is the most",
|
|
5594
|
+
" destructive command in the CLI.",
|
|
5595
|
+
" - it stopped being true. An EXPORT now writes to the same record, so the",
|
|
5596
|
+
" command shows both directions and \"imports\" named half of it.",
|
|
5597
|
+
"",
|
|
5598
|
+
"Update any scripts, CI jobs or runbooks that call it. THIS note is manual",
|
|
5599
|
+
"because a CLI invocation lives in your pipeline definitions, which `voltro",
|
|
5600
|
+
"update` cannot see — not because the release leaves your source alone. It",
|
|
5601
|
+
"does not: `@voltro/database` renamed the four run-history exports with it",
|
|
5602
|
+
"(`ImportRun`, `describeImportRun`, `IMPORT_RUNS_TABLE`,",
|
|
5603
|
+
"`_voltroImportRunsTable`). Those ARE rewritten for you, by the codemod",
|
|
5604
|
+
"beside this one — including a hand-spelled `_voltro_data_imports` in raw",
|
|
5605
|
+
"SQL, which is the half that would otherwise fail silently.",
|
|
5606
|
+
"",
|
|
5607
|
+
"The table behind it was renamed too, from `_voltro_data_imports` to",
|
|
5608
|
+
"`_voltro_data_transfers`. That half needs nothing from you: it carries a rename",
|
|
5609
|
+
"marker, so `voltro db apply` (or a `voltro dev` boot) moves it with its rows on",
|
|
5610
|
+
"every dialect. If you query it directly, the new name is the one to use."
|
|
5611
|
+
].join("\n")
|
|
5612
|
+
}), J = ["@voltro/database", "voltro/database"], hi = [
|
|
5613
|
+
["ImportRun", "DataTransferRun"],
|
|
5614
|
+
["describeImportRun", "describeTransferRun"],
|
|
5615
|
+
["IMPORT_RUNS_TABLE", "DATA_TRANSFERS_TABLE"],
|
|
5616
|
+
["_voltroImportRunsTable", "_voltroDataTransfersTable"]
|
|
5617
|
+
], Y = "_voltro_data_imports", gi = "_voltro_data_transfers", _i = (e) => {
|
|
5618
|
+
let t = 0;
|
|
5619
|
+
for (let n of e.getSourceFiles()) n.getFullText().includes(Y) && n.forEachDescendant((e) => {
|
|
5620
|
+
if (y.isStringLiteral(e) || y.isNoSubstitutionTemplateLiteral(e) || y.isTemplateHead(e) || y.isTemplateMiddle(e) || y.isTemplateTail(e) || y.isRegularExpressionLiteral(e)) {
|
|
5621
|
+
let n = e.getText();
|
|
5622
|
+
if (!n.includes(Y)) return;
|
|
5623
|
+
e.replaceWithText(n.split(Y).join(gi)), t++;
|
|
5624
|
+
}
|
|
5625
|
+
});
|
|
5626
|
+
return t;
|
|
5627
|
+
}, vi = [
|
|
5628
|
+
ge,
|
|
5440
5629
|
_e,
|
|
5441
|
-
|
|
5630
|
+
ye,
|
|
5442
5631
|
be,
|
|
5443
5632
|
xe,
|
|
5444
|
-
|
|
5445
|
-
|
|
5633
|
+
we,
|
|
5634
|
+
Ee,
|
|
5446
5635
|
De,
|
|
5447
5636
|
Oe,
|
|
5448
|
-
|
|
5637
|
+
je,
|
|
5449
5638
|
Me,
|
|
5450
|
-
|
|
5639
|
+
Fe,
|
|
5451
5640
|
Ie,
|
|
5452
|
-
|
|
5641
|
+
ze,
|
|
5453
5642
|
Be,
|
|
5454
|
-
|
|
5455
|
-
|
|
5643
|
+
Ue,
|
|
5644
|
+
Ge,
|
|
5645
|
+
Ke,
|
|
5456
5646
|
qe,
|
|
5457
5647
|
Je,
|
|
5458
5648
|
Ye,
|
|
@@ -5464,17 +5654,16 @@ var b = (e, t, n) => {
|
|
|
5464
5654
|
tt,
|
|
5465
5655
|
nt,
|
|
5466
5656
|
rt,
|
|
5657
|
+
ct,
|
|
5467
5658
|
it,
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
gt,
|
|
5659
|
+
st,
|
|
5660
|
+
mt,
|
|
5661
|
+
yt,
|
|
5662
|
+
bt,
|
|
5473
5663
|
xt,
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
Dt,
|
|
5664
|
+
wt,
|
|
5665
|
+
Tt,
|
|
5666
|
+
At,
|
|
5478
5667
|
Mt,
|
|
5479
5668
|
Pt,
|
|
5480
5669
|
It,
|
|
@@ -5487,8 +5676,7 @@ var b = (e, t, n) => {
|
|
|
5487
5676
|
Xt,
|
|
5488
5677
|
Qt,
|
|
5489
5678
|
en,
|
|
5490
|
-
|
|
5491
|
-
on,
|
|
5679
|
+
an,
|
|
5492
5680
|
sn,
|
|
5493
5681
|
cn,
|
|
5494
5682
|
ln,
|
|
@@ -5544,153 +5732,35 @@ var b = (e, t, n) => {
|
|
|
5544
5732
|
oi,
|
|
5545
5733
|
si,
|
|
5546
5734
|
ci,
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5735
|
+
li,
|
|
5736
|
+
ui,
|
|
5737
|
+
di,
|
|
5738
|
+
fi,
|
|
5739
|
+
pi,
|
|
5740
|
+
mi,
|
|
5741
|
+
C({
|
|
5742
|
+
version: "0.49.0",
|
|
5743
|
+
id: "0.49.0/02_import-run-symbols",
|
|
5744
|
+
title: "`ImportRun` / `describeImportRun` / `IMPORT_RUNS_TABLE` → their `…TransferRun` names",
|
|
5551
5745
|
kind: "transform",
|
|
5552
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) =>
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
if (!q.test(t.getFilePath()) || t.getFullText().includes("defineMiddleware")) continue;
|
|
5557
|
-
let e = t.getExportAssignment((e) => !e.isExportEquals());
|
|
5558
|
-
if (e !== void 0) {
|
|
5559
|
-
let t = e.getExpression().getText();
|
|
5560
|
-
e.replaceWithText(`export default defineMiddleware({ run: ${t} })`), n += 1;
|
|
5561
|
-
} else {
|
|
5562
|
-
let e = t.getFunctions().find((e) => e.isDefaultExport());
|
|
5563
|
-
if (e === void 0) continue;
|
|
5564
|
-
let r = e.getText().replace(/^\s*export\s+default\s+/, "");
|
|
5565
|
-
e.replaceWithText(`export default defineMiddleware({ run: ${r} })`), n += 1;
|
|
5566
|
-
}
|
|
5567
|
-
let r = t.getImportDeclarations().find((e) => e.getModuleSpecifierValue() === K);
|
|
5568
|
-
r === void 0 ? t.insertImportDeclaration(0, {
|
|
5569
|
-
moduleSpecifier: K,
|
|
5570
|
-
namedImports: [{ name: "defineMiddleware" }]
|
|
5571
|
-
}) : r.getNamedImports().some((e) => e.getName() === "defineMiddleware") || r.addNamedImport({ name: "defineMiddleware" });
|
|
5572
|
-
}
|
|
5573
|
-
n > 0 && (t(`middleware.ts: ${n} export(s) wrapped in defineMiddleware`), t("Add a `match` if the middleware should not run on every route — see the note."));
|
|
5574
|
-
},
|
|
5575
|
-
note: [
|
|
5576
|
-
"`middleware.ts` now exports `defineMiddleware(...)`. Your file was rewritten",
|
|
5577
|
-
"to the wrapped form, which behaves exactly as it did: no `match` means every",
|
|
5578
|
-
"server-rendered route.",
|
|
5579
|
-
"",
|
|
5580
|
-
"WHAT TO DO NEXT (optional, and worth a minute)",
|
|
5581
|
-
"",
|
|
5582
|
-
"If your middleware starts with a hand-written path gate, move it into `match`",
|
|
5583
|
-
"and delete the `if`:",
|
|
5584
|
-
"",
|
|
5585
|
-
" export const session = defineMiddleware({",
|
|
5586
|
-
" match: { under: '/app', except: ['/app/public'] },",
|
|
5587
|
-
" run: async (req) => { /* the body, without the guard clause */ },",
|
|
5588
|
-
" })",
|
|
5589
|
-
"",
|
|
5590
|
-
"WHY THIS IS BETTER THAN THE `if`",
|
|
5591
|
-
"",
|
|
5592
|
-
" • The hook no longer runs at all on routes it does not cover, so a public",
|
|
5593
|
-
" page stops paying for an IdP round trip it never used.",
|
|
5594
|
-
" • `under` / `routes` / `except` are checked against your ROUTES at boot. A",
|
|
5595
|
-
" path that matches nothing refuses the boot instead of silently never",
|
|
5596
|
-
" firing — the failure an `if` cannot report.",
|
|
5597
|
-
" • `voltro doctor` reports overlaps and dead matchers before you deploy.",
|
|
5598
|
-
"",
|
|
5599
|
-
"You can export SEVERAL middlewares now, each with its own `match`. At most",
|
|
5600
|
-
"one may match any given route: two hooks writing one `authorization` header",
|
|
5601
|
-
"have no defensible winner, so an overlap refuses the boot and names both.",
|
|
5602
|
-
"",
|
|
5603
|
-
"Non-page requests (assets, unknown paths) are NOT matched unless you ask with",
|
|
5604
|
-
"`assets: true`. There is no render there, so only `setCookies` takes effect."
|
|
5605
|
-
].join("\n")
|
|
5606
|
-
}),
|
|
5607
|
-
S({
|
|
5608
|
-
version: "0.43.0",
|
|
5609
|
-
id: "0.43.0/01_dangling-reference-to-rows-refused",
|
|
5610
|
-
title: "`DanglingReferenceError` → `RowsRefusedError` (named for the outcome, not a guessed cause)",
|
|
5611
|
-
kind: "transform",
|
|
5612
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue().startsWith("@voltro/data-transfer") && e.getNamedImports().some((e) => e.getName() === "DanglingReferenceError"))),
|
|
5746
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
5747
|
+
let t = e.getFullText();
|
|
5748
|
+
return t.includes(Y) ? !0 : J.some((e) => t.includes(e)) ? hi.some(([e]) => t.includes(e)) : !1;
|
|
5749
|
+
}),
|
|
5613
5750
|
transform: ({ project: e, helpers: t, log: n }) => {
|
|
5614
|
-
let r =
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5751
|
+
let r = 0;
|
|
5752
|
+
for (let n of J) for (let [i, a] of hi) r += t.renameImport(e, {
|
|
5753
|
+
module: n,
|
|
5754
|
+
from: i,
|
|
5755
|
+
to: a
|
|
5618
5756
|
});
|
|
5619
|
-
|
|
5757
|
+
let i = _i(e);
|
|
5758
|
+
if (r + i === 0) return;
|
|
5759
|
+
let a = [];
|
|
5760
|
+
r > 0 && a.push(`${r} import(s) renamed to their \`…TransferRun\` names`), i > 0 && a.push(`${i} hand-spelled \`${Y}\` → \`${gi}\``), n(`data-transfer run history: ${a.join("; ")}. An export writes to this record now, so the old names described half of what the table holds. The table itself carries a rename marker — \`voltro db apply\` (or a \`voltro dev\` boot) moves it with its rows on every dialect, so no data is lost and nothing is required of you there.`);
|
|
5620
5761
|
}
|
|
5621
|
-
}),
|
|
5622
|
-
S({
|
|
5623
|
-
version: "0.44.0",
|
|
5624
|
-
id: "0.44.0/01_import-outcome",
|
|
5625
|
-
title: "`runImport` returns an ImportOutcome — read `.manifest` for the bundle",
|
|
5626
|
-
kind: "manual",
|
|
5627
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => e.getImportDeclarations().some((e) => e.getModuleSpecifierValue().startsWith("@voltro/data-transfer") && e.getNamedImports().some((e) => e.getName() === "runImport"))),
|
|
5628
|
-
note: [
|
|
5629
|
-
"`runImport(...)` now resolves to `{ manifest, tablesWritten, rowsWritten, tablesSkipped, rowsSkipped, fullyResumed }`",
|
|
5630
|
-
"instead of the bundle's `Manifest`.",
|
|
5631
|
-
"",
|
|
5632
|
-
" 1. Where you read the bundle — `.tables`, `.assets`, `.scope`, `.source` — read `.manifest.tables` and so on.",
|
|
5633
|
-
" 2. Where you REPORTED a row count, prefer `rowsWritten`. The manifest total is what the bundle CARRIES:",
|
|
5634
|
-
" a run that skipped every table (an earlier run of the same bundle directory had already applied them)",
|
|
5635
|
-
" carries the full count while writing nothing, which is exactly how a no-op used to read as a success.",
|
|
5636
|
-
" 3. `fullyResumed` is true precisely in that case.",
|
|
5637
|
-
"",
|
|
5638
|
-
"Same release, unrelated to the return type: `--mode replace` now runs in ONE transaction unless you pass",
|
|
5639
|
-
"`--no-atomic` (CLI) or `atomic: false` (API) — a replace that failed mid-load used to leave the target",
|
|
5640
|
-
"emptied of its old rows and holding part of the new ones. If you relied on per-table resume for a replace,",
|
|
5641
|
-
"that is the non-atomic path."
|
|
5642
|
-
].join("\n")
|
|
5643
|
-
}),
|
|
5644
|
-
S({
|
|
5645
|
-
version: "0.45.0",
|
|
5646
|
-
id: "0.45.0/01_typed-source-table-name",
|
|
5647
|
-
title: "`source:` is typechecked against the app’s tables, from the next `voltro dev`",
|
|
5648
|
-
kind: "manual",
|
|
5649
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => /\bsource\s*:/.test(e.getFullText())),
|
|
5650
|
-
note: [
|
|
5651
|
-
"`source:` on a query or stream is now typed against your app’s own tables.",
|
|
5652
|
-
"A name no table carries is a COMPILE error instead of a subscription that",
|
|
5653
|
-
"silently never updates.",
|
|
5654
|
-
"",
|
|
5655
|
-
"WHEN IT STARTS APPLYING",
|
|
5656
|
-
"",
|
|
5657
|
-
"Not now — at your next `voltro dev` (or `voltro codegen`). Those write",
|
|
5658
|
-
"`voltro-tables.generated.d.ts` beside the generated rpc group, and that file",
|
|
5659
|
-
"is what narrows the type. Until it exists, `source:` is `string`, exactly as",
|
|
5660
|
-
"it is today. This note exists because the error appears one command later",
|
|
5661
|
-
"than the upgrade that caused it.",
|
|
5662
|
-
"",
|
|
5663
|
-
"WHAT TO DO",
|
|
5664
|
-
"",
|
|
5665
|
-
"Boot once, then read what `tsc` flags. Each site is one of two things:",
|
|
5666
|
-
"",
|
|
5667
|
-
" • a name that is misspelled, or was renamed away — a REAL defect this",
|
|
5668
|
-
" just surfaced. That query’s view was never updating. Fix the name.",
|
|
5669
|
-
"",
|
|
5670
|
-
" • a source computed at runtime — correct as written. Annotate it",
|
|
5671
|
-
" `ReactivitySourceValue` (exported from `@voltro/protocol`), which is the",
|
|
5672
|
-
" wide `string | ReactivityChannel` shape.",
|
|
5673
|
-
"",
|
|
5674
|
-
"Reach for the second only when the value genuinely is not a literal. Widening",
|
|
5675
|
-
"a name you could have spelled turns a found defect back into a quiet one.",
|
|
5676
|
-
"",
|
|
5677
|
-
"Eager-loaded relations are a common source of the first kind: a query that",
|
|
5678
|
-
"loads a relation must also declare that relation’s table (and, for a",
|
|
5679
|
-
"many-to-many, the junction). `voltro doctor` reports those.",
|
|
5680
|
-
"",
|
|
5681
|
-
"To opt out entirely, delete `voltro-tables.generated.d.ts` and exclude it",
|
|
5682
|
-
"from your tsconfig; `source:` widens back to `string`."
|
|
5683
|
-
].join("\n")
|
|
5684
|
-
}),
|
|
5685
|
-
S({
|
|
5686
|
-
version: "0.46.0",
|
|
5687
|
-
id: "0.46.0/01_typed-aggregate-source",
|
|
5688
|
-
title: "an aggregate’s `incremental.source` is typechecked against the app’s tables",
|
|
5689
|
-
kind: "manual",
|
|
5690
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => /\bincremental\s*:/.test(e.getFullText())),
|
|
5691
|
-
note: (/* @__PURE__ */ "An aggregate that opts into incremental maintenance names the table whose(CDC deltas drive it:(( incremental: { source: 'tasks', op: 'count' }((That name is now checked against your app’s tables, the same way a query’s(`source:` has been since 0.45.0.((WHY IT MATTERS MORE HERE((A name matching no table does not error. The runner subscribes to something(nothing writes, no delta ever arrives, and the aggregate quietly stops(tracking its input — while every read of it still succeeds and still returns(a number. There is no failing request to notice.((WHEN IT STARTS APPLYING((At your next `voltro dev` or `voltro codegen`, not at this upgrade — those(write `voltro-tables.generated.d.ts`, and that file is what narrows the type.(Until it exists the field is `string`, exactly as it is today.((WHAT TO DO((Boot once and read what `tsc` flags. A flagged name is either misspelled or(renamed away — a real defect, and that aggregate has not been maintaining —(or it is computed at runtime, in which case annotate it `string`.((The boot also warns now: an aggregate whose CDC source resolves to no table(is named in the same stale-`source:` warning queries and streams appear in.".split("(")).join("\n")
|
|
5692
5762
|
})
|
|
5693
|
-
],
|
|
5763
|
+
], X = /* @__PURE__ */ new Set([
|
|
5694
5764
|
"node_modules",
|
|
5695
5765
|
".git",
|
|
5696
5766
|
"dist",
|
|
@@ -5702,73 +5772,73 @@ var b = (e, t, n) => {
|
|
|
5702
5772
|
".turbo",
|
|
5703
5773
|
".cache",
|
|
5704
5774
|
".output"
|
|
5705
|
-
]),
|
|
5775
|
+
]), yi = () => [...[...X].map((e) => `**/${e}/**`), "**/.voltro-*/**"], Z = /(?:from|import)\s*\(?\s*['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\)/g, bi = /\.(?:tsx?|jsx?|mjs|cjs)$/, xi = (e) => m(e).replace(bi, ""), Si = (e) => {
|
|
5706
5776
|
let t = e.split("/").filter((e) => e.length > 0).pop();
|
|
5707
5777
|
if (t === void 0 || t === "." || t === "..") return;
|
|
5708
|
-
let n = t.replace(
|
|
5778
|
+
let n = t.replace(bi, "");
|
|
5709
5779
|
return n.length > 0 ? n : void 0;
|
|
5710
|
-
},
|
|
5780
|
+
}, Ci = (e) => {
|
|
5711
5781
|
let t = /* @__PURE__ */ new Map();
|
|
5712
5782
|
for (let n of e) {
|
|
5713
5783
|
let e;
|
|
5714
5784
|
try {
|
|
5715
|
-
e =
|
|
5785
|
+
e = ne(n, "utf8");
|
|
5716
5786
|
} catch {
|
|
5717
5787
|
continue;
|
|
5718
5788
|
}
|
|
5719
|
-
|
|
5720
|
-
for (let r =
|
|
5721
|
-
let e =
|
|
5789
|
+
Z.lastIndex = 0;
|
|
5790
|
+
for (let r = Z.exec(e); r !== null; r = Z.exec(e)) {
|
|
5791
|
+
let e = Si(r[1] ?? r[2] ?? "");
|
|
5722
5792
|
if (e === void 0) continue;
|
|
5723
5793
|
let i = t.get(e);
|
|
5724
5794
|
i === void 0 ? t.set(e, /* @__PURE__ */ new Set([n])) : i.add(n);
|
|
5725
5795
|
}
|
|
5726
5796
|
}
|
|
5727
5797
|
return t;
|
|
5728
|
-
},
|
|
5798
|
+
}, wi = (e, t) => {
|
|
5729
5799
|
let n = new Set(e);
|
|
5730
|
-
for (let r of e) for (let e of [
|
|
5800
|
+
for (let r of e) for (let e of [xi(r), m(h(r))]) {
|
|
5731
5801
|
let r = t.get(e);
|
|
5732
5802
|
if (r !== void 0) for (let e of r) n.add(e);
|
|
5733
5803
|
}
|
|
5734
5804
|
return n;
|
|
5735
|
-
},
|
|
5805
|
+
}, Ti = [
|
|
5736
5806
|
"**/*.ts",
|
|
5737
5807
|
"**/*.tsx",
|
|
5738
5808
|
"!**/node_modules/**",
|
|
5739
5809
|
"!**/dist/**",
|
|
5740
5810
|
"!**/.framework/**",
|
|
5741
5811
|
"!**/*.d.ts"
|
|
5742
|
-
], Q = (e, t, n =
|
|
5812
|
+
], Q = (e, t, n = Oi) => {
|
|
5743
5813
|
let r = /* @__PURE__ */ new Set();
|
|
5744
|
-
for (let e of t) for (let t of e.scope ??
|
|
5814
|
+
for (let e of t) for (let t of e.scope ?? Ti) r.add(t);
|
|
5745
5815
|
let i = n(e);
|
|
5746
5816
|
if (i !== void 0) {
|
|
5747
|
-
let t = [...r].filter((e) => !e.startsWith("!")).map((e) =>
|
|
5817
|
+
let t = [...r].filter((e) => !e.startsWith("!")).map((e) => Di(e)), n = [...r].filter((e) => e.startsWith("!")).map((e) => Di(e.slice(1))), a = [...X], o = [];
|
|
5748
5818
|
for (let r of i) {
|
|
5749
5819
|
if (a.some((e) => r === e || r.startsWith(`${e}/`) || r.includes(`/${e}/`)) || !t.some((e) => e(r)) || n.some((e) => e(r))) continue;
|
|
5750
5820
|
let i = g(e, r);
|
|
5751
|
-
|
|
5821
|
+
v(i) && o.push(i);
|
|
5752
5822
|
}
|
|
5753
|
-
return
|
|
5823
|
+
return Ei(o.length, e), o;
|
|
5754
5824
|
}
|
|
5755
|
-
let a =
|
|
5825
|
+
let a = oe([...r], {
|
|
5756
5826
|
cwd: e,
|
|
5757
5827
|
absolute: !0,
|
|
5758
5828
|
expandDirectories: !1,
|
|
5759
5829
|
followSymbolicLinks: !1,
|
|
5760
|
-
ignore: [...
|
|
5830
|
+
ignore: [...yi()]
|
|
5761
5831
|
});
|
|
5762
|
-
return
|
|
5763
|
-
},
|
|
5764
|
-
let n =
|
|
5832
|
+
return Ei(a.length, e), a;
|
|
5833
|
+
}, Ei = (e, t) => {
|
|
5834
|
+
let n = ki();
|
|
5765
5835
|
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.`);
|
|
5766
|
-
},
|
|
5836
|
+
}, Di = (e) => {
|
|
5767
5837
|
let t = e.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "\0").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\u0000/g, "(?:.*/)?").replace(/\\\{([^}]*)\\\}/g, (e, t) => `(?:${t.split(",").join("|")})`);
|
|
5768
5838
|
return (e) => RegExp(`^${t}$`).test(e);
|
|
5769
|
-
},
|
|
5839
|
+
}, Oi = (e) => {
|
|
5770
5840
|
try {
|
|
5771
|
-
let t =
|
|
5841
|
+
let t = re("git", [
|
|
5772
5842
|
"ls-files",
|
|
5773
5843
|
"--cached",
|
|
5774
5844
|
"--others",
|
|
@@ -5787,7 +5857,7 @@ var b = (e, t, n) => {
|
|
|
5787
5857
|
} catch {
|
|
5788
5858
|
return;
|
|
5789
5859
|
}
|
|
5790
|
-
},
|
|
5860
|
+
}, ki = () => {
|
|
5791
5861
|
let e = Number(process.env.VOLTRO_CODEMOD_MAX_FILES);
|
|
5792
5862
|
return Number.isInteger(e) && e > 0 ? e : 2e4;
|
|
5793
5863
|
}, $ = (e, t) => {
|
|
@@ -5797,7 +5867,7 @@ var b = (e, t, n) => {
|
|
|
5797
5867
|
if (t !== 0) return t;
|
|
5798
5868
|
}
|
|
5799
5869
|
return 0;
|
|
5800
|
-
},
|
|
5870
|
+
}, Ai = (e, t, n = vi) => n.filter((n) => $(e, n.version) < 0 && $(n.version, t) <= 0).slice().sort(he), ji = (e, t, n = () => {}) => {
|
|
5801
5871
|
let r = [], i = [], a = [];
|
|
5802
5872
|
for (let o of t) {
|
|
5803
5873
|
if (!(!o.appliesTo || o.appliesTo({ project: e }))) {
|
|
@@ -5815,7 +5885,7 @@ var b = (e, t, n) => {
|
|
|
5815
5885
|
let t = new Map(e.getSourceFiles().map((e) => [e.getFilePath(), e.getFullText()]));
|
|
5816
5886
|
o.transform?.({
|
|
5817
5887
|
project: e,
|
|
5818
|
-
helpers:
|
|
5888
|
+
helpers: pe,
|
|
5819
5889
|
log: n
|
|
5820
5890
|
});
|
|
5821
5891
|
let s = new Map(e.getSourceFiles().map((e) => [e.getFilePath(), e.getFullText()])), c = /* @__PURE__ */ new Map();
|
|
@@ -5843,8 +5913,8 @@ var b = (e, t, n) => {
|
|
|
5843
5913
|
manual: i,
|
|
5844
5914
|
skipped: a
|
|
5845
5915
|
};
|
|
5846
|
-
},
|
|
5847
|
-
let t = e.log ?? (() => {}), n =
|
|
5916
|
+
}, Mi = async (e) => {
|
|
5917
|
+
let t = e.log ?? (() => {}), n = Ai(e.from, e.to, e.codemods ?? vi), r = e.only === void 0 || e.only.length === 0 ? n : (() => {
|
|
5848
5918
|
let t = n.filter((t) => e.only.includes(t.id)), r = e.only.filter((e) => !n.some((t) => t.id === e));
|
|
5849
5919
|
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")}`);
|
|
5850
5920
|
return t;
|
|
@@ -5856,31 +5926,31 @@ var b = (e, t, n) => {
|
|
|
5856
5926
|
};
|
|
5857
5927
|
let i = f(e.root);
|
|
5858
5928
|
i !== void 0 && t(`path aliases: ${Object.keys(i.paths).join(", ")}`);
|
|
5859
|
-
let a = () => new
|
|
5929
|
+
let a = () => new ie({
|
|
5860
5930
|
skipAddingFilesFromTsConfig: !0,
|
|
5861
|
-
manipulationSettings: { quoteKind:
|
|
5931
|
+
manipulationSettings: { quoteKind: ae.Single },
|
|
5862
5932
|
...i === void 0 ? {} : { compilerOptions: {
|
|
5863
5933
|
baseUrl: i.baseUrl,
|
|
5864
5934
|
paths: i.paths
|
|
5865
5935
|
} }
|
|
5866
|
-
}), o, s = Q(e.root, r), c = r.filter((e) => e.needsImporters === !0 && e.scope !== void 0), l = [], u = [], d = [], p = c.length > 0 ?
|
|
5936
|
+
}), o, s = Q(e.root, r), c = r.filter((e) => e.needsImporters === !0 && e.scope !== void 0), l = [], u = [], d = [], p = c.length > 0 ? Ci(Q(e.root, [{
|
|
5867
5937
|
...c[0],
|
|
5868
|
-
scope:
|
|
5938
|
+
scope: Ti
|
|
5869
5939
|
}])) : void 0;
|
|
5870
5940
|
for (let n of r) {
|
|
5871
5941
|
if (c.includes(n)) {
|
|
5872
5942
|
let r = a(), i = Q(e.root, [n]);
|
|
5873
|
-
for (let e of
|
|
5874
|
-
let s =
|
|
5943
|
+
for (let e of wi(i, p)) v(e) && r.addSourceFileAtPath(e);
|
|
5944
|
+
let s = ji(r, [n], t);
|
|
5875
5945
|
e.dryRun || await r.save(), l.push(...s.applied), u.push(...s.manual), d.push(...s.skipped), o = void 0;
|
|
5876
5946
|
continue;
|
|
5877
5947
|
}
|
|
5878
5948
|
o ??= (() => {
|
|
5879
5949
|
let e = a();
|
|
5880
|
-
for (let t of s)
|
|
5950
|
+
for (let t of s) v(t) && e.addSourceFileAtPath(t);
|
|
5881
5951
|
return e;
|
|
5882
5952
|
})();
|
|
5883
|
-
let r =
|
|
5953
|
+
let r = ji(o, [n], t);
|
|
5884
5954
|
e.dryRun || await o.save(), l.push(...r.applied), u.push(...r.manual), d.push(...r.skipped);
|
|
5885
5955
|
}
|
|
5886
5956
|
return {
|
|
@@ -5890,4 +5960,4 @@ var b = (e, t, n) => {
|
|
|
5890
5960
|
};
|
|
5891
5961
|
};
|
|
5892
5962
|
//#endregion
|
|
5893
|
-
export {
|
|
5963
|
+
export { C as i, Mi as n, X as r, $ as t };
|