@voltro/cli 0.49.0 → 0.50.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 +58 -0
- package/dist/apiBuild-BWo8KI6n.js +2 -0
- package/dist/{apiBuild-QmYHaCF4.js → apiBuild-CFYXo06U.js} +1 -1
- package/dist/bin.js +1 -1
- package/dist/{build-Bi4O_g7T.js → build-CnSH-zru.js} +6 -6
- package/dist/{checkCommand-D8vjQXQt.js → checkCommand-Do3SQbLx.js} +2 -2
- package/dist/{checkCommand-udbQpphy.js → checkCommand-OL41BMIb.js} +1 -1
- package/dist/{codegenCommand-DApSH7hK.js → codegenCommand-BJzaRz6q.js} +1 -1
- package/dist/{codemodRunner-De1_316I.js → codemodRunner-De3k0pRd.js} +641 -481
- package/dist/{commands-a5PxCaIg.js → commands-By23Ljny.js} +19 -19
- package/dist/{dashboardCommand-DaoUUqJS.js → dashboardCommand-DN1rAABE.js} +1 -1
- package/dist/{dataCommand-CJv_OMoS.js → dataCommand-B93TUBIx.js} +473 -323
- package/dist/{dev-C31Nvlbv.js → dev-1yu42ubu.js} +1 -1
- package/dist/{dev-DFVuzOj7.js → dev-BWwE0QjK.js} +1 -1
- package/dist/doctorCommand-BmovAwb7.js +2 -0
- package/dist/{doctorCommand-B3uraeAe.js → doctorCommand-y-EbP8st.js} +10 -10
- package/dist/{dormancyCommand-QUXQ9yoz.js → dormancyCommand-Dc7KRNCG.js} +1 -1
- package/dist/{embeddingsCommand-Zw1-rYSF.js → embeddingsCommand-kPs132bB.js} +1 -1
- package/dist/{envCommand-DtaJ4xEf.js → envCommand-E12zSt51.js} +1 -1
- package/dist/{evolveCommand-JDD3hE1i.js → evolveCommand-B3nagPVc.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{infoCommand-COsUC1DB.js → infoCommand-Cq0Yz98u.js} +1 -1
- package/dist/{interruptedReplace-C1ZI84xi.js → interruptedReplace-C3O3M1MM.js} +2 -1
- package/dist/interruptedReplace-CvmiAM9K.js +2 -0
- package/dist/{runtimeTrace-Di6fcndp.js → runtimeTrace-BpLUcrfy.js} +1 -1
- package/dist/{sdkgen-CIi5gM17.js → sdkgen-dl4-WKF6.js} +1 -1
- package/dist/{serveCommand-N3udT49p.js → serveCommand-8CTzQCY0.js} +6 -6
- package/dist/serveCommand-C_WI4TTG.js +2 -0
- package/dist/serveEntry.js +1 -1
- package/dist/updateCommand-D91-TZ7E.js +2 -0
- package/dist/{updateCommand-2BfbeMvp.js → updateCommand-i8JbrLAA.js} +2 -1
- package/dist/{webhooksCommand-CwX9IzvJ.js → webhooksCommand-B0bdyuQ4.js} +1 -1
- package/package.json +35 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +53 -3
- package/templates/agent-docs/whats-new.md +28 -37
- 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-dZbHdqMg.js +0 -2
- package/dist/doctorCommand-CPL6EhrW.js +0 -2
- package/dist/interruptedReplace-DNJ7MKph.js +0 -2
- package/dist/serveCommand-CzSDngKm.js +0 -2
- package/dist/updateCommand-CtYm7aKH.js +0 -2
|
@@ -3,7 +3,7 @@ import { t } from "./frameworkInspectState-CX2250XB.js";
|
|
|
3
3
|
import { n } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
4
|
import { t as r } from "./bootRefusal-pgvDxlrU.js";
|
|
5
5
|
import { n as i, r as a } from "./startupRunner-CEqQq7ax.js";
|
|
6
|
-
import { t as o } from "./interruptedReplace-
|
|
6
|
+
import { t as o } from "./interruptedReplace-C3O3M1MM.js";
|
|
7
7
|
import { r as s } from "./appPort-B_HpJ_ck.js";
|
|
8
8
|
import { H as c, J as l, K as u, V as d, W as f, X as p, Y as m, Z as h, ct as g, ft as _, g as v, ht as ee, lt as y, pt as te, q as b, ut as x } from "./webDev-B4IEMB0n.js";
|
|
9
9
|
import { n as ne, r as S } from "./dialectDriver-czCHYpeH.js";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as e, d as t, f as n, i as r, u as i } from "./dev-
|
|
1
|
+
import { c as e, d as t, f as n, i as r, u as i } from "./dev-1yu42ubu.js";
|
|
2
2
|
import "./dialectDriver-czCHYpeH.js";
|
|
3
3
|
export { r as buildStore, e as loadApiConfig, i as loadDiscovered, t as runDev, n as walk };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Ht as e, Ut as t, Vt as n } from "./dev-
|
|
1
|
+
import { Ht as e, Ut as t, Vt as n } from "./dev-1yu42ubu.js";
|
|
2
2
|
import { at as r, it as i, ot as a, s as o, st as s, t as c, w as l, y as u } from "./webDev-B4IEMB0n.js";
|
|
3
3
|
import { x as d } from "./frameworkTableAssembly-BwJVEKLr.js";
|
|
4
4
|
import { n as f } from "./pageConvention-cEiRxdab.js";
|
|
5
|
-
import { r as p, u as m } from "./apiBuild-
|
|
5
|
+
import { r as p, u as m } from "./apiBuild-CFYXo06U.js";
|
|
6
6
|
import { n as h, r as g, t as ee } from "./cliOutput-D1tSBoRM.js";
|
|
7
7
|
import { n as _, t as te } from "./tsconfigPaths-BWXBWgcl.js";
|
|
8
8
|
import { n as ne, r as re } from "./fileTaxonomy-CJfgOllU.js";
|
|
@@ -1350,7 +1350,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1350
1350
|
let t = Wt.get(e);
|
|
1351
1351
|
if (t !== void 0) return t;
|
|
1352
1352
|
let n = (async () => {
|
|
1353
|
-
let { walk: t, loadDiscovered: n } = await import("./dev-
|
|
1353
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-BWwE0QjK.js"), r = await t(e);
|
|
1354
1354
|
return {
|
|
1355
1355
|
files: r,
|
|
1356
1356
|
discovered: await n(r)
|
|
@@ -1459,7 +1459,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1459
1459
|
}
|
|
1460
1460
|
}, J = async (r) => {
|
|
1461
1461
|
try {
|
|
1462
|
-
let { loadApiConfig: i } = await import("./dev-
|
|
1462
|
+
let { loadApiConfig: i } = await import("./dev-BWwE0QjK.js"), { discovered: a } = await U(r), o = e(await i(r)), s = {
|
|
1463
1463
|
queries: a.queries,
|
|
1464
1464
|
mutations: a.mutations,
|
|
1465
1465
|
actions: a.actions,
|
|
@@ -1543,7 +1543,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1543
1543
|
}, nn = async (e) => nt({
|
|
1544
1544
|
hasWorkflows: async () => (await U(e)).discovered.workflows.length > 0,
|
|
1545
1545
|
openStore: async () => {
|
|
1546
|
-
let { loadApiConfig: t, buildStore: n } = await import("./dev-
|
|
1546
|
+
let { loadApiConfig: t, buildStore: n } = await import("./dev-BWwE0QjK.js"), r = await t(e);
|
|
1547
1547
|
if (r === null) throw Error("no app.config.ts in this directory");
|
|
1548
1548
|
let i = await n(r, void 0);
|
|
1549
1549
|
return {
|
|
@@ -1623,7 +1623,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1623
1623
|
}
|
|
1624
1624
|
}, ln = async (e) => {
|
|
1625
1625
|
try {
|
|
1626
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1626
|
+
let { loadApiConfig: t } = await import("./dev-BWwE0QjK.js"), n = (await t(e))?.doctor?.scopeVocabulary;
|
|
1627
1627
|
if (typeof n != "string") return [];
|
|
1628
1628
|
let [r, i] = n.split("#");
|
|
1629
1629
|
if (r === void 0 || i === void 0) return [];
|
|
@@ -1640,7 +1640,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1640
1640
|
findings: []
|
|
1641
1641
|
});
|
|
1642
1642
|
try {
|
|
1643
|
-
let { offlineManifest: n, toInput: r } = await import("./checkCommand-
|
|
1643
|
+
let { offlineManifest: n, toInput: r } = await import("./checkCommand-OL41BMIb.js"), { buildAppGraph: i, checkAppGraph: a } = await import("./appGraph-zuMGKVYX.js"), o = await n(e), s = r(o.manifest, o.tables), c = await ln(e), l = [.../* @__PURE__ */ new Set([...s.scopes ?? [], ...c])];
|
|
1644
1644
|
if (l.length === 0) {
|
|
1645
1645
|
try {
|
|
1646
1646
|
let { loadAppSchemaInputs: t } = await import("./frameworkTableAssembly-CVDB2hCq.js");
|
|
@@ -1694,7 +1694,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1694
1694
|
if (n === void 0 || r.length === 0) return;
|
|
1695
1695
|
let i = [];
|
|
1696
1696
|
try {
|
|
1697
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1697
|
+
let { loadApiConfig: t } = await import("./dev-BWwE0QjK.js");
|
|
1698
1698
|
i = (await t(e))?.locales ?? [];
|
|
1699
1699
|
} catch {
|
|
1700
1700
|
return;
|
|
@@ -1725,7 +1725,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1725
1725
|
}, pn = async (e) => {
|
|
1726
1726
|
let { discovered: t } = await U(e), n = [];
|
|
1727
1727
|
try {
|
|
1728
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1728
|
+
let { loadApiConfig: t } = await import("./dev-BWwE0QjK.js");
|
|
1729
1729
|
n = ((await t(e))?.plugins ?? []).map((e) => {
|
|
1730
1730
|
let t = (e.extendSchema?.tables ?? []).map((e) => {
|
|
1731
1731
|
let t = e;
|
|
@@ -1870,7 +1870,7 @@ var le = /* @__PURE__ */ new Set([
|
|
|
1870
1870
|
return n.unchecked.length > $ && console.log(` … and ${n.unchecked.length - $} more — \`voltro doctor --json\` prints every one (\`authz.unchecked\`).`), i === void 0 ? (console.log(`\nNo ${X} yet, so this run is advisory. To start the ratchet:`), console.log("\n voltro doctor --write-authz-allowlist\n"), console.log("That records today's unchecked handlers as DEBT and fails every run after on"), console.log("anything NEW. Fix a handler and its line stops mattering — the scan reports it as"), console.log("guarded whether or not the line is still there."), !1) : (console.log(`\n${n.unchecked.length} executor(s) with no access check are not in ${X}.`), console.log("Add a guard, or add the tag to that file if it is genuinely open."), console.log("\nBefore hand-rolling another check: `guards: [{ action, resourceType, resource }]`"), console.log("answers \"may this subject act on THIS row\" declaratively, and an app whose"), console.log("relationships live in its own tables registers its own tuple source rather than"), console.log("copying data into a framework table. See the authorization docs."), !0);
|
|
1871
1871
|
}, yn = async (e) => {
|
|
1872
1872
|
try {
|
|
1873
|
-
let { loadApiConfig: t } = await import("./dev-
|
|
1873
|
+
let { loadApiConfig: t } = await import("./dev-BWwE0QjK.js"), { decidedSchemaReport: n } = await import("./doctorDecidedSchema-BlbWgCD_.js"), r = await t(e);
|
|
1874
1874
|
return r == null ? null : n({
|
|
1875
1875
|
...r.schema ? { declared: r.schema } : {},
|
|
1876
1876
|
...r.store === void 0 ? {} : { store: r.store },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as e } from "./cliOutput-D1tSBoRM.js";
|
|
2
|
-
import { t } from "./checkCommand-
|
|
3
|
-
import { i as n, n as r } from "./codemodRunner-
|
|
2
|
+
import { t } from "./checkCommand-Do3SQbLx.js";
|
|
3
|
+
import { i as n, n as r } from "./codemodRunner-De3k0pRd.js";
|
|
4
4
|
import { basename as i, join as a, resolve as o } from "node:path";
|
|
5
5
|
import { branchNamespaceName as s, planBranchProvision as c } from "@voltro/database";
|
|
6
6
|
import { readFile as l } from "node:fs/promises";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e, r as t, t as n } from "./cliOutput-D1tSBoRM.js";
|
|
2
|
-
import { o as r } from "./updateCommand-
|
|
2
|
+
import { o as r } from "./updateCommand-i8JbrLAA.js";
|
|
3
3
|
import { join as i, resolve as a } from "node:path";
|
|
4
4
|
import { readFileSync as o, readdirSync as s, statSync as c } from "node:fs";
|
|
5
5
|
//#region src/infoCommand.ts
|
|
@@ -14,7 +14,8 @@ var n = async (n) => {
|
|
|
14
14
|
let i = r.map((e) => ({
|
|
15
15
|
id: String(e.id ?? ""),
|
|
16
16
|
startedAt: e.startedAt instanceof Date ? e.startedAt : new Date(String(e.startedAt ?? "")),
|
|
17
|
-
|
|
17
|
+
kind: e.kind === void 0 || e.kind === null ? "replace" : String(e.kind),
|
|
18
|
+
tables: e.tables === null || e.tables === void 0 ? null : Number(e.tables),
|
|
18
19
|
capture: e.capture === null || e.capture === void 0 ? null : String(e.capture),
|
|
19
20
|
via: String(e.via ?? "unknown")
|
|
20
21
|
}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./apiBuild-
|
|
1
|
+
import { n as e } from "./apiBuild-CFYXo06U.js";
|
|
2
2
|
import { join as t, resolve as n, sep as r } from "node:path";
|
|
3
3
|
import { existsSync as i, promises as a } from "node:fs";
|
|
4
4
|
import { createLogger as o } from "@voltro/logger";
|
|
@@ -422,7 +422,7 @@ let package = Package(
|
|
|
422
422
|
await l.mkdir(o(e), { recursive: !0 }), await l.writeFile(e, n.content, "utf8");
|
|
423
423
|
}
|
|
424
424
|
}, X = async (e) => {
|
|
425
|
-
let { offlineManifest: t } = await import("./checkCommand-
|
|
425
|
+
let { offlineManifest: t } = await import("./checkCommand-OL41BMIb.js"), { manifest: n } = await t(e);
|
|
426
426
|
return n;
|
|
427
427
|
}, Z = async (e) => {
|
|
428
428
|
let t = J(await (e.manifestProvider ?? X)(e.root), {
|
|
@@ -3,8 +3,8 @@ import { t } from "./frameworkInspectState-CX2250XB.js";
|
|
|
3
3
|
import { r as n, t as r } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
4
|
import { t as i } from "./bootRefusal-pgvDxlrU.js";
|
|
5
5
|
import { n as a, r as o } from "./startupRunner-CEqQq7ax.js";
|
|
6
|
-
import { t as s } from "./interruptedReplace-
|
|
7
|
-
import { $ as c, $t as l, A as u, At as d, Bt as f, C as ee, Cn as te, Ct as ne, D as p, Dt as m, E as h, En as re, Et as g, F as ie, Ft as ae, G as oe, Gt as se, H as _, Ht as ce, I as le, It as ue, J as de, Jt as v, K as y, Kt as fe, L as b, Lt as pe, M as me, Mt as he, N as ge, Nt as _e, O as ve, Ot as ye, P as be, Pt as xe, Q as Se, Qt as Ce, R as x, Rt as we, S as Te, St as Ee, T as De, Tn as Oe, Tt as S, U as ke, V as Ae, W as je, Wt as Me, X as Ne, Xt as Pe, Y as Fe, Yt as C, Z as Ie, Zt as Le, _ as w, _n as Re, _t as T, an as ze, at as Be, b as Ve, bn as He, bt as Ue, c as We, cn as Ge, ct as Ke, dn as qe, dt as Je, en as Ye, et as Xe, f as Ze, fn as Qe, ft as $e, g as et, gt as tt, h as nt, hn as rt, ht as it, i as at, in as ot, it as st, j as ct, jt as lt, k as ut, kt as dt, ln as ft, lt as pt, m as mt, mn as ht, mt as gt, nn as _t, nt as E, o as D, on as vt, ot as O, p as k, pn as yt, pt as bt, q as xt, qt as St, r as Ct, rn as A, rt as wt, sn as j, st as Tt, t as Et, tn as Dt, tt as Ot, u as kt, un as At, ut as jt, v as Mt, vn as Nt, vt as M, w as N, wn as Pt, wt as Ft, x as It, xn as Lt, xt as Rt, y as zt, yn as Bt, yt as Vt, zt as Ht } from "./dev-
|
|
6
|
+
import { t as s } from "./interruptedReplace-C3O3M1MM.js";
|
|
7
|
+
import { $ as c, $t as l, A as u, At as d, Bt as f, C as ee, Cn as te, Ct as ne, D as p, Dt as m, E as h, En as re, Et as g, F as ie, Ft as ae, G as oe, Gt as se, H as _, Ht as ce, I as le, It as ue, J as de, Jt as v, K as y, Kt as fe, L as b, Lt as pe, M as me, Mt as he, N as ge, Nt as _e, O as ve, Ot as ye, P as be, Pt as xe, Q as Se, Qt as Ce, R as x, Rt as we, S as Te, St as Ee, T as De, Tn as Oe, Tt as S, U as ke, V as Ae, W as je, Wt as Me, X as Ne, Xt as Pe, Y as Fe, Yt as C, Z as Ie, Zt as Le, _ as w, _n as Re, _t as T, an as ze, at as Be, b as Ve, bn as He, bt as Ue, c as We, cn as Ge, ct as Ke, dn as qe, dt as Je, en as Ye, et as Xe, f as Ze, fn as Qe, ft as $e, g as et, gt as tt, h as nt, hn as rt, ht as it, i as at, in as ot, it as st, j as ct, jt as lt, k as ut, kt as dt, ln as ft, lt as pt, m as mt, mn as ht, mt as gt, nn as _t, nt as E, o as D, on as vt, ot as O, p as k, pn as yt, pt as bt, q as xt, qt as St, r as Ct, rn as A, rt as wt, sn as j, st as Tt, t as Et, tn as Dt, tt as Ot, u as kt, un as At, ut as jt, v as Mt, vn as Nt, vt as M, w as N, wn as Pt, wt as Ft, x as It, xn as Lt, xt as Rt, y as zt, yn as Bt, yt as Vt, zt as Ht } from "./dev-1yu42ubu.js";
|
|
8
8
|
import { n as Ut } from "./cliArgs-D4p8n7EE.js";
|
|
9
9
|
import { r as P } from "./appPort-B_HpJ_ck.js";
|
|
10
10
|
import { ht as Wt, pt as Gt } from "./webDev-B4IEMB0n.js";
|
|
@@ -18,7 +18,7 @@ import { h as pn, o as mn } from "./inspect-B7U7Cl_Z.js";
|
|
|
18
18
|
import { n as hn } from "./mssqlClusterPatch-_4cE_nun.js";
|
|
19
19
|
import { i as gn, n as _n, r as vn, t as yn } from "./webhookDiscovery-CphsQe59.js";
|
|
20
20
|
import { t as bn } from "./inspectMetrics-CfdKLh6t.js";
|
|
21
|
-
import { r as xn, u as Sn } from "./apiBuild-
|
|
21
|
+
import { r as xn, u as Sn } from "./apiBuild-CFYXo06U.js";
|
|
22
22
|
import { t as Cn } from "./bootTiming-BdyP9nYw.js";
|
|
23
23
|
import { a as wn, o as Tn, t as En } from "./dataProfile-Du3ztYxv.js";
|
|
24
24
|
import L, { basename as Dn, join as On } from "node:path";
|
|
@@ -97,7 +97,7 @@ var Zi = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy <
|
|
|
97
97
|
await a(e), await o();
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
|
-
}, ta = "/_voltro/admin/import", na = "/_voltro/admin/import/start", ra = "/_voltro/admin/export", ia = "/_voltro/admin/export/download", aa = "/_voltro/admin/
|
|
100
|
+
}, ta = "/_voltro/admin/import", na = "/_voltro/admin/import/start", ra = "/_voltro/admin/export", ia = "/_voltro/admin/export/download", aa = "/_voltro/admin/transfers", Z = (e, t) => ({
|
|
101
101
|
status: e,
|
|
102
102
|
contentType: "application/json; charset=utf-8",
|
|
103
103
|
body: JSON.stringify(t)
|
|
@@ -463,7 +463,7 @@ var Zi = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy <
|
|
|
463
463
|
atomic: r.atomic,
|
|
464
464
|
...r.dryRun ? { dryRun: !0 } : {},
|
|
465
465
|
recorded: f,
|
|
466
|
-
outcome: "poll /_voltro/admin/
|
|
466
|
+
outcome: "poll /_voltro/admin/transfers for this runId — a 202 means started, not finished"
|
|
467
467
|
});
|
|
468
468
|
}, La = async (e) => {
|
|
469
469
|
let t = await Wi(e, ["manifest.json"]).then((e) => e.get("manifest.json"), () => null);
|
|
@@ -679,7 +679,7 @@ var Zi = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy <
|
|
|
679
679
|
transport: c ? "storage" : "download",
|
|
680
680
|
...c ? { bundleKey: r.bundleKey } : {},
|
|
681
681
|
recorded: d,
|
|
682
|
-
outcome: "poll /_voltro/admin/
|
|
682
|
+
outcome: "poll /_voltro/admin/transfers for this runId; fetch the bytes from /_voltro/admin/export/download"
|
|
683
683
|
});
|
|
684
684
|
}, to = async (e, t) => {
|
|
685
685
|
try {
|
package/dist/serveEntry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e, r as t, t as n } from "./codemodRunner-
|
|
1
|
+
import { n as e, r as t, t as n } from "./codemodRunner-De3k0pRd.js";
|
|
2
2
|
import { basename as r, dirname as i, join as a, relative as o, resolve as s } from "node:path";
|
|
3
3
|
import { existsSync as c, readFileSync as l, readdirSync as u, statSync as d, writeFileSync as f } from "node:fs";
|
|
4
4
|
import { totalmem as p } from "node:os";
|
|
@@ -579,6 +579,7 @@ with \`--only\` / \`--root\`.`;
|
|
|
579
579
|
for (let e of r.manual) {
|
|
580
580
|
console.log(`\n▸ ${e.id} — ${e.title}`);
|
|
581
581
|
for (let t of e.note.split("\n")) console.log(` ${t}`);
|
|
582
|
+
e.certain || (console.log(""), console.log(" ── nothing in this repository matched. That is NOT a clean bill of health:"), console.log(" `voltro update` reads the files git tracks here, and a CLI call also lives"), console.log(" in places it cannot reach — an inline script in a CI runner, a CronJob"), console.log(" spec in another repo, a runbook, a deploy job. Search those by hand."));
|
|
582
583
|
}
|
|
583
584
|
}
|
|
584
585
|
return n.dryRun && console.log("\n(dry-run — no files written)"), 0;
|
|
@@ -222,7 +222,7 @@ createVerifier({ secret: [process.env.WEBHOOK_SECRET, process.env.WEBHOOK_SECRET
|
|
|
222
222
|
...t === void 0 ? {} : { payload: t }
|
|
223
223
|
};
|
|
224
224
|
}, S = u({ scope: "voltro:webhooks" }), C = ["--out", "--name"], w = async (e) => {
|
|
225
|
-
let { walk: t, loadDiscovered: n } = await import("./dev-
|
|
225
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-BWwE0QjK.js"), { outgoingFromEvents: r } = await import("./webhookDiscovery-il9ti-HE.js");
|
|
226
226
|
return r((await n(await t(e))).events.map((e) => ({
|
|
227
227
|
file: e.file,
|
|
228
228
|
descriptor: e.descriptor
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "The `voltro` CLI — dev server, codegen, migrations, project scaffolding, agent-docs seeding, and production serve.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -676,6 +676,24 @@
|
|
|
676
676
|
"title": "store.query() now returns the row type — casts on row fields may stop compiling",
|
|
677
677
|
"kind": "manual"
|
|
678
678
|
},
|
|
679
|
+
{
|
|
680
|
+
"version": "0.50.0",
|
|
681
|
+
"id": "0.50.0/01_transfer-runs-endpoint",
|
|
682
|
+
"title": "`GET /_voltro/admin/imports` → `GET /_voltro/admin/transfers`",
|
|
683
|
+
"kind": "manual"
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"version": "0.50.0",
|
|
687
|
+
"id": "0.50.0/02_reissue-data-imports-rename",
|
|
688
|
+
"title": "RE-CHECK: `voltro data imports` → `voltro data transfers` (0.49.0's note could not see your scripts)",
|
|
689
|
+
"kind": "manual"
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"version": "0.50.0",
|
|
693
|
+
"id": "0.50.0/03_interrupted-replace-tables-nullable",
|
|
694
|
+
"title": "`InterruptedReplace.tables` is `number | null`",
|
|
695
|
+
"kind": "manual"
|
|
696
|
+
},
|
|
679
697
|
{
|
|
680
698
|
"version": "0.6.0",
|
|
681
699
|
"id": "0.6.0/01_no-dev-session-secret",
|
|
@@ -751,22 +769,22 @@
|
|
|
751
769
|
"@effect/platform-node": "^0.108.0",
|
|
752
770
|
"@effect/sql": "^0.52.0",
|
|
753
771
|
"@effect/workflow": "^0.19.0",
|
|
754
|
-
"@voltro/ai": "0.
|
|
755
|
-
"@voltro/cache": "0.
|
|
756
|
-
"@voltro/data-transfer": "0.
|
|
757
|
-
"@voltro/database": "0.
|
|
758
|
-
"@voltro/env": "0.
|
|
759
|
-
"@voltro/kv": "0.
|
|
760
|
-
"@voltro/logger": "0.
|
|
761
|
-
"@voltro/plugin-auth": "0.
|
|
762
|
-
"@voltro/plugin-broadcast": "0.
|
|
763
|
-
"@voltro/plugin-mail": "0.
|
|
764
|
-
"@voltro/plugin-storage": "0.
|
|
765
|
-
"@voltro/plugin-webhooks": "0.
|
|
766
|
-
"@voltro/protocol": "0.
|
|
767
|
-
"@voltro/runtime": "0.
|
|
768
|
-
"@voltro/serverless": "0.
|
|
769
|
-
"@voltro/workflow": "0.
|
|
772
|
+
"@voltro/ai": "0.50.0",
|
|
773
|
+
"@voltro/cache": "0.50.0",
|
|
774
|
+
"@voltro/data-transfer": "0.50.0",
|
|
775
|
+
"@voltro/database": "0.50.0",
|
|
776
|
+
"@voltro/env": "0.50.0",
|
|
777
|
+
"@voltro/kv": "0.50.0",
|
|
778
|
+
"@voltro/logger": "0.50.0",
|
|
779
|
+
"@voltro/plugin-auth": "0.50.0",
|
|
780
|
+
"@voltro/plugin-broadcast": "0.50.0",
|
|
781
|
+
"@voltro/plugin-mail": "0.50.0",
|
|
782
|
+
"@voltro/plugin-storage": "0.50.0",
|
|
783
|
+
"@voltro/plugin-webhooks": "0.50.0",
|
|
784
|
+
"@voltro/protocol": "0.50.0",
|
|
785
|
+
"@voltro/runtime": "0.50.0",
|
|
786
|
+
"@voltro/serverless": "0.50.0",
|
|
787
|
+
"@voltro/workflow": "0.50.0",
|
|
770
788
|
"chokidar": "^5.0.0",
|
|
771
789
|
"ioredis": "^5.11.1",
|
|
772
790
|
"tinyglobby": "^0.2.17",
|
package/templates/AGENTS.md
CHANGED
|
@@ -707,7 +707,7 @@ each plugin's own README.
|
|
|
707
707
|
|
|
708
708
|
| Topic | Open | Summary |
|
|
709
709
|
|---|---|---|
|
|
710
|
-
| **What's new in 0.
|
|
710
|
+
| **What's new in 0.50.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
|
|
711
711
|
| AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
|
|
712
712
|
| Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
|
|
713
713
|
| Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
|
|
@@ -9,7 +9,7 @@ each plugin's own README.
|
|
|
9
9
|
|
|
10
10
|
| Topic | Open | Summary |
|
|
11
11
|
|---|---|---|
|
|
12
|
-
| **What's new in 0.
|
|
12
|
+
| **What's new in 0.50.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
|
|
13
13
|
| AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
|
|
14
14
|
| Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
|
|
15
15
|
| Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
|
|
@@ -2996,7 +2996,7 @@ $ voltro data transfers --target api --api-url https://app.example
|
|
|
2996
2996
|
2026-08-23T08:00:00.000Z · export all — 228866 row(s) across 104 table(s) · via api · from backups/nightly.vbundle
|
|
2997
2997
|
```
|
|
2998
2998
|
|
|
2999
|
-
Same data over `GET /_voltro/admin/
|
|
2999
|
+
Same data over `GET /_voltro/admin/transfers?limit=20`, behind the same
|
|
3000
3000
|
data-transfer secret (the row names bundles and schema fingerprints). It works
|
|
3001
3001
|
from a different machine than the one that started the import, and through
|
|
3002
3002
|
anything that forwards a GET.
|
|
@@ -3330,12 +3330,62 @@ yield* runImport({ store: target, bundleDir: './backup', targetSnapshot }).pipe(
|
|
|
3330
3330
|
## Native backup / restore
|
|
3331
3331
|
|
|
3332
3332
|
```bash
|
|
3333
|
-
voltro data backup ./backups/2026-07-01
|
|
3334
|
-
voltro data
|
|
3333
|
+
voltro data backup ./backups/2026-07-01 # pg_dump --format=custom / mariadb-dump --single-transaction / …
|
|
3334
|
+
voltro data backup ./backups/2026-07-01 --assets # rows AND the stored blobs
|
|
3335
|
+
voltro data restore ./backups/2026-07-01 --assets # pg_restore / mariadb / … + the blobs
|
|
3335
3336
|
```
|
|
3336
3337
|
|
|
3337
3338
|
These shell out to the vendor tools resolved from your `DB_DIALECT` + connection env. They produce a dialect-native artifact (`db.dump`, `db.sql`, `db.sqlite`, `db.bacpac`) that is lossless and point-in-time consistent for **same-dialect** restore — the right tool for disaster recovery. Secrets are passed via the tools' environment variables (`PGPASSWORD`, `MYSQL_PWD`), never on the command line, where the tool supports it. The named tool must be installed and on `PATH`.
|
|
3338
3339
|
|
|
3340
|
+
### `--assets` — the blobs are not in the dump
|
|
3341
|
+
|
|
3342
|
+
A vendor dump contains rows. Your blobs are in object storage, and no `pg_dump` has ever seen them. So a rows-only backup restores a database whose rows reference objects that are not there — and the reference and the object are checked at different times, which is why that state is discovered by a user, months later, rather than by the restore.
|
|
3343
|
+
|
|
3344
|
+
`--assets` captures them alongside the dump, through the same content-addressed pipeline `voltro data export --assets` uses: each blob is streamed (never buffered whole), stored under `assets/<sha256>` so identical content is stored once, and listed in `assets/index.ndjson`. `restore --assets` streams them back and **re-hashes on the way**, so a corrupted artifact can never silently overwrite good bytes.
|
|
3345
|
+
|
|
3346
|
+
```
|
|
3347
|
+
backups/2026-07-01/
|
|
3348
|
+
├─ db.dump # the vendor artifact (rows)
|
|
3349
|
+
├─ voltro-backup-stamp.json # provenance, incl. what --assets captured
|
|
3350
|
+
├─ assets/index.ndjson # key → sha256 → size → contentType
|
|
3351
|
+
└─ assets/<sha256> # the blob bodies, deduped by content
|
|
3352
|
+
```
|
|
3353
|
+
|
|
3354
|
+
Three refusals, each for a belief that is otherwise acted on silently:
|
|
3355
|
+
|
|
3356
|
+
- **`backup --assets` with no storage provider configured → refused.** There is nothing to capture, and a flag that is accepted and ignored lets you build a rollback story on an artifact that does not contain what you asked for.
|
|
3357
|
+
- **`restore --assets` on a rows-only backup → refused.** You believe the blobs are in there. Restoring the rows anyway produces exactly the dangling state this exists to prevent.
|
|
3358
|
+
- **restore *without* `--assets` on a backup that HAS them → warned, not refused.** Restoring rows without blobs is legitimate (a schema drill, a lower environment), and refusing it would push people at `--force`.
|
|
3359
|
+
|
|
3360
|
+
Resume is per blob key, so re-running a `--assets` capture that was interrupted transfers only what is missing. The **dump itself has no resume** — a vendor artifact is one opaque file with no offset to restart from. If you need a resumable, chunkable, observable transfer, that is the logical path (`export` / `import`), and it is why the logical path exists.
|
|
3361
|
+
|
|
3362
|
+
### A restore that is interrupted refuses the next boot
|
|
3363
|
+
|
|
3364
|
+
`restore` writes one row into `_voltro_replace_in_progress` **before** the first destructive statement and removes it **after** the last write — the blobs included. Its presence at boot is a refusal naming the artifact that was going in.
|
|
3365
|
+
|
|
3366
|
+
This is the counterpart to `--allow-live`, and it guards from the other side: `--allow-live` asks you not to restore over a running instance, and this says *this database is mid-restore, do not serve it*. A half-restored database looks exactly like a normal one from the inside — every query answers, nothing errors.
|
|
3367
|
+
|
|
3368
|
+
Whether the marker survives the restore depends on the dialect's restore shape, and that is stated rather than implied:
|
|
3369
|
+
|
|
3370
|
+
| dialect | shape | effect |
|
|
3371
|
+
|---|---|---|
|
|
3372
|
+
| postgres, mysql, mariadb | drops only the objects the dump names | the marker survives, so a killed restore is caught at the next boot |
|
|
3373
|
+
| sqlite, turso | whole-file replacement — made **atomic** (temp file + rename) | there is no half-restored state to catch; a killed restore leaves the live file untouched |
|
|
3374
|
+
| mssql | `sqlpackage /Action:Import` replaces the database | a *failed* import is the one case not covered here — verify with `--drill` |
|
|
3375
|
+
|
|
3376
|
+
Clear a marker deliberately with `voltro data clear-replace-marker --yes` once you have decided the current state is correct.
|
|
3377
|
+
|
|
3378
|
+
### Both directions are in the history
|
|
3379
|
+
|
|
3380
|
+
`backup` and `restore` write a row to the same `_voltro_data_transfers` record `import` and `export` use, so `voltro data transfers` answers "did last night's backup finish" from the instance that ran it:
|
|
3381
|
+
|
|
3382
|
+
```
|
|
3383
|
+
2026-08-23T02:00:00.000Z · backup native postgres + assets — finished (412 blob(s)) · via cli · from ./backups/2026-08-23/db.dump
|
|
3384
|
+
2026-08-22T09:14:02.000Z · FAILED restore native mariadb — mariadb-dump: exited with code 2 · via cli · from ./backups/2026-08-21/db.sql
|
|
3385
|
+
```
|
|
3386
|
+
|
|
3387
|
+
A native run reports **blobs**, not rows: the vendor tool reports no row count we can trust, and printing `0 row(s)` over a `pg_dump` that worked would be a measurement, and a wrong one. A target with no `_voltro_data_transfers` table still gets its backup — the closing line says it was not recorded, rather than implying it was.
|
|
3388
|
+
|
|
3339
3389
|
### The provenance stamp — a restore that refuses the wrong DB
|
|
3340
3390
|
|
|
3341
3391
|
A native dump is opaque: it doesn't say which dialect made it, which schema shape it carries, or when. `backup` writes a sidecar `voltro-backup-stamp.json` next to the artifact recording exactly that — `dialect`, the live schema `fingerprint`, the `@voltro/cli` version, and the timestamp.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.
|
|
1
|
+
# What's new in 0.50.0
|
|
2
2
|
|
|
3
3
|
Read this FIRST when a task touches an area you have not worked in recently.
|
|
4
4
|
It is the cheapest way to notice that the framework grew the thing you were
|
|
@@ -9,63 +9,54 @@ BREAKING entries name a codemod; run `voltro update` to apply it.
|
|
|
9
9
|
|
|
10
10
|
### ⚠ BREAKING
|
|
11
11
|
|
|
12
|
-
- **@voltro/cli
|
|
12
|
+
- **@voltro/cli** — The read-only run-history endpoint moved:
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
GET /_voltro/admin/imports → GET /_voltro/admin/transfers
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Same secret, same query parameters, same response shape. Only the path changed.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
It answers for four directions now — import, export, native backup, native restore — and it named one of them. The subcommand and the table were renamed for exactly that reason in 0.49.0 and this path was left behind, which is worse than renaming none of them: a reader who follows a rename tries the matching path, gets a 404, and concludes the instance is too old.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
`voltro data transfers --target api` uses the new path for you. What needs a hand is anything calling it directly — a monitoring check, an uptime probe, a curl in a runbook, a dashboard datasource. The codemod is `manual` and declares `reach: 'beyond-source'`, so it prints whether or not the path is found in your repository.
|
|
21
|
+
- **@voltro/database, @voltro/voltro** — `InterruptedReplace.tables` is `number | null`, and the interface gains `kind?: 'replace' | 'restore'`.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
`_voltro_replace_in_progress` records two destructive operations now — an import's `--mode replace` and a native `voltro data restore`. A restore replaces the whole database from an artefact, so "how many tables was this going to empty and refill" has no answer: not known up front, not meaningful after.
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
Writing `0` would have preserved the type and been worse. That number is rendered into the boot refusal, which is read under pressure, and it would have said `began emptying 0 table(s)` — a measurement that was never taken. The framework's own text says "this database" instead; `Number(null)` is `0`, so coercing it reintroduces exactly the sentence being avoided.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
- **@voltro/database, @voltro/voltro** — The run-history exports say `transfer`, not `import`.
|
|
27
|
+
`DataTransferRun.direction` also widens to name `'backup'` and `'restore'` explicitly. That one is documentary — the union already ended in `| string`, so no assignability changes.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| was | is | |---|---| | `ImportRun` | `DataTransferRun` | | `describeImportRun` | `describeTransferRun` | | `IMPORT_RUNS_TABLE` | `DATA_TRANSFERS_TABLE` | | `_voltroImportRunsTable` | `_voltroDataTransfersTable` |
|
|
32
|
-
|
|
33
|
-
An EXPORT writes to this record now — the row carries a `direction` — so every one of those names described half of what it holds.
|
|
34
|
-
|
|
35
|
-
A `transform` codemod rewrites all four, alias-aware, from either module spelling. It also rewrites a hand-spelled `_voltro_data_imports` in a string, template or raw-SQL fragment, and that is the half worth stating: the four identifiers announce themselves as compile errors, while a query that addresses the table by name has nothing to fail on. The table itself moves with its rows via the declarative differ on every dialect.
|
|
36
|
-
|
|
37
|
-
This is filed apart from the transfer-protocol entry beside it deliberately. That one's codemod is `manual` and is about a CLI invocation living in scripts and CI jobs; this one is application source and is rewritten for you. Reading the first as covering both is what would leave a build broken with a note saying nothing in your source was affected.
|
|
29
|
+
**`voltro update` carries you across this** — codemod `0.50.0/03_interrupted-replace-tables-nullable`.
|
|
38
30
|
|
|
39
31
|
### Added
|
|
40
32
|
|
|
41
|
-
- **@voltro/
|
|
33
|
+
- **@voltro/cli, @voltro/data-transfer, @voltro/database** — `voltro data backup --assets` and `voltro data restore --assets` now move the stored blobs alongside the vendor dump, through the same content-addressed phase the logical `export` / `import` path uses — streamed, deduped by sha256, verified on the way back, resumable per key.
|
|
42
34
|
|
|
43
|
-
|
|
35
|
+
`--assets` was accepted by `backup` and silently ignored, with the only signal a field in the closing JSON reading `NOT included`; `restore` did not accept it at all. A rows-only backup restores a database whose rows reference objects nothing puts back, and the reference and the object are checked at different times, so that state is discovered by a user rather than by the restore.
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
Three refusals, each for a belief that is otherwise acted on silently: `backup --assets` with no storage provider is refused rather than swallowed; `restore --assets` on a rows-only artefact is refused; a restore WITHOUT `--assets` over an artefact that has them warns and proceeds, because restoring rows without blobs is legitimate and refusing it would push people at `--force`.
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- **@voltro/data-transfer, @voltro/sql-sqlite, @voltro/database** — A successful `--mode replace --no-atomic` left a marker that refused the next boot.
|
|
39
|
+
The dump itself still has no resume — a vendor artefact is one opaque file with no offset to restart from, and the logical path is what exists for that.
|
|
40
|
+
- **@voltro/cli, @voltro/database, @voltro/data-transfer** — A native `backup` / `restore` now writes to the same `_voltro_data_transfers` record `import` and `export` use, so `voltro data transfers` answers "did last night's backup finish" from the instance that ran it. A native run reports blobs rather than rows — a vendor tool reports no row count we can trust, and printing `0 row(s)` over a dump that worked would be a wrong measurement.
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
`restore` also writes the `_voltro_replace_in_progress` marker before its first destructive statement and clears it after the last write, blobs included, so a killed restore refuses the next boot instead of serving a half-loaded database. `--allow-live` guards from the wrong side — it asks you not to — and this guards from the right one. The marker carries a `kind` so the refusal can say something different for a `replace` (re-import the capture) and a `restore` (finish the restore), and `tables` is nullable because a native restore has no table count to claim.
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
The sqlite / turso restore is atomic now (temp file + rename): its marker lives in the very file being replaced, so a plain in-place copy would leave a truncated database with nothing left to catch it.
|
|
54
45
|
|
|
55
|
-
|
|
46
|
+
A target with no `_voltro_data_transfers` table still gets its backup; the closing line says it was not recorded rather than implying it was.
|
|
47
|
+
- **@voltro/cli** — A re-issued migration note for the `voltro data imports` → `voltro data transfers` rename that shipped in 0.49.0.
|
|
56
48
|
|
|
57
|
-
|
|
49
|
+
Codemods are selected by `from < version <= to`, so the 0.49.0 note fires once, on the jump that crosses 0.49.0, and cannot be corrected for anyone already past it. Its gate searched `.ts` / `.tsx` while the command it is about lives in shell scripts, CI job definitions and runbooks — so a project whose only occurrence sat in `.gitlab-ci.yml` crossed 0.49.0 and was told there was nothing to apply.
|
|
58
50
|
|
|
59
|
-
The
|
|
60
|
-
- **@voltro/cli** — `voltro codegen` declared twenty framework tables fewer than a boot.
|
|
51
|
+
The re-issue is filed under 0.50.0, prints unconditionally, and says what to grep for. Redundant for anyone already fixed; the alternative is firing for nobody.
|
|
61
52
|
|
|
62
|
-
|
|
53
|
+
### Fixed
|
|
63
54
|
|
|
64
|
-
|
|
55
|
+
- **@voltro/cli** — A `manual` codemod's `appliesTo` can now search every text file the project owns — `.sh`, `.yml`, `.json`, `.md`, `Makefile`, the `.js` scripts — through a new `ctx.text` on the predicate context, and a codemod may declare `reach: 'beyond-source'` to print its note even when nothing matched.
|
|
65
56
|
|
|
66
|
-
|
|
67
|
-
- **@voltro/cli** — `voltro data --help` advertised four subcommands out of nine.
|
|
57
|
+
Both halves close the same gap, and it was in the codemod most in need of a gate. A manual codemod exists BECAUSE its subject could not be transformed, which usually means it is not source at all — and `appliesTo` was reading the ts-morph project, which holds `.ts` / `.tsx` and nothing else. Measured with one identical CLI invocation in four files: the `.ts` one printed the note, the `.sh`, `.yml` and `.md` ones printed nothing, and the run reported `codemods: nothing to apply for this jump`. That is an acquittal from a check that never looked at the file, and an acquittal gets acted on.
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
`reach: 'beyond-source'` covers what no scan of one repository can reach — an inline script in a CI runner's own UI, a CronJob spec in another repo, a wiki runbook. The note prints either way; only its framing changes, and an uncertain one says plainly that we could not look there.
|
|
60
|
+
- **@voltro/data-transfer** — When `mariadb-dump` is absent and the mysql-family fallback runs Oracle's `mysqldump` against a MariaDB server, the failure now names the way out.
|
|
70
61
|
|
|
71
|
-
|
|
62
|
+
The stderr it prints is the child's own words and is the right first thing to show — and on its own it is a dead end: `Unknown table 'COLUMN_STATISTICS' in information_schema (1109)` names a table nobody asked for, in a schema nobody wrote, about a feature nobody enabled. Everything needed to act on it was known where the fallback was DECIDED: which binary we wanted, which one we took, and why the difference matters. That travels with the step now and prints under the stderr, including the counter-move a reader reaches for on their own (`--column-statistics=0` does not exist on `mariadb-dump`, so it fixes the wrong client and breaks the right one).
|