@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
package/dist/serveEntry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as e } from "./
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
export {
|
|
1
|
+
import { t as e } from "./serveCommand-N3udT49p.js";
|
|
2
|
+
import { t } from "./loadEnv-D9nEOClM.js";
|
|
3
|
+
import { r as n } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
|
+
import { i as r } from "./dialectDriver-czCHYpeH.js";
|
|
5
|
+
export { t as loadDotEnv, n as registerAppModules, r as registerDriver, e as runServe };
|
|
@@ -19,9 +19,19 @@ var e = [
|
|
|
19
19
|
"scan-credentials",
|
|
20
20
|
"encrypt-column"
|
|
21
21
|
], t = [
|
|
22
|
+
"export",
|
|
23
|
+
"import",
|
|
24
|
+
"transfers",
|
|
25
|
+
"inspect",
|
|
26
|
+
"unpack",
|
|
27
|
+
"backup",
|
|
28
|
+
"restore",
|
|
29
|
+
"clear-replace-marker",
|
|
30
|
+
"clear-staging"
|
|
31
|
+
], n = [
|
|
22
32
|
"scope",
|
|
23
33
|
"export",
|
|
24
34
|
"erase"
|
|
25
|
-
],
|
|
35
|
+
], r = (e) => `<${e.join("|")}>`;
|
|
26
36
|
//#endregion
|
|
27
|
-
export {
|
|
37
|
+
export { r as i, e as n, n as r, t };
|
|
@@ -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-De1_316I.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";
|
|
@@ -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-DFVuzOj7.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.49.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",
|
|
@@ -652,6 +652,18 @@
|
|
|
652
652
|
"title": "an aggregate’s `incremental.source` is typechecked against the app’s tables",
|
|
653
653
|
"kind": "manual"
|
|
654
654
|
},
|
|
655
|
+
{
|
|
656
|
+
"version": "0.49.0",
|
|
657
|
+
"id": "0.49.0/01_data-imports-to-transfers",
|
|
658
|
+
"title": "`voltro data imports` → `voltro data transfers`",
|
|
659
|
+
"kind": "manual"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"version": "0.49.0",
|
|
663
|
+
"id": "0.49.0/02_import-run-symbols",
|
|
664
|
+
"title": "`ImportRun` / `describeImportRun` / `IMPORT_RUNS_TABLE` → their `…TransferRun` names",
|
|
665
|
+
"kind": "transform"
|
|
666
|
+
},
|
|
655
667
|
{
|
|
656
668
|
"version": "0.5.0",
|
|
657
669
|
"id": "0.5.0/01_one-terminal-exactly-one",
|
|
@@ -739,22 +751,22 @@
|
|
|
739
751
|
"@effect/platform-node": "^0.108.0",
|
|
740
752
|
"@effect/sql": "^0.52.0",
|
|
741
753
|
"@effect/workflow": "^0.19.0",
|
|
742
|
-
"@voltro/ai": "0.
|
|
743
|
-
"@voltro/cache": "0.
|
|
744
|
-
"@voltro/data-transfer": "0.
|
|
745
|
-
"@voltro/database": "0.
|
|
746
|
-
"@voltro/env": "0.
|
|
747
|
-
"@voltro/kv": "0.
|
|
748
|
-
"@voltro/logger": "0.
|
|
749
|
-
"@voltro/plugin-auth": "0.
|
|
750
|
-
"@voltro/plugin-broadcast": "0.
|
|
751
|
-
"@voltro/plugin-mail": "0.
|
|
752
|
-
"@voltro/plugin-storage": "0.
|
|
753
|
-
"@voltro/plugin-webhooks": "0.
|
|
754
|
-
"@voltro/protocol": "0.
|
|
755
|
-
"@voltro/runtime": "0.
|
|
756
|
-
"@voltro/serverless": "0.
|
|
757
|
-
"@voltro/workflow": "0.
|
|
754
|
+
"@voltro/ai": "0.49.0",
|
|
755
|
+
"@voltro/cache": "0.49.0",
|
|
756
|
+
"@voltro/data-transfer": "0.49.0",
|
|
757
|
+
"@voltro/database": "0.49.0",
|
|
758
|
+
"@voltro/env": "0.49.0",
|
|
759
|
+
"@voltro/kv": "0.49.0",
|
|
760
|
+
"@voltro/logger": "0.49.0",
|
|
761
|
+
"@voltro/plugin-auth": "0.49.0",
|
|
762
|
+
"@voltro/plugin-broadcast": "0.49.0",
|
|
763
|
+
"@voltro/plugin-mail": "0.49.0",
|
|
764
|
+
"@voltro/plugin-storage": "0.49.0",
|
|
765
|
+
"@voltro/plugin-webhooks": "0.49.0",
|
|
766
|
+
"@voltro/protocol": "0.49.0",
|
|
767
|
+
"@voltro/runtime": "0.49.0",
|
|
768
|
+
"@voltro/serverless": "0.49.0",
|
|
769
|
+
"@voltro/workflow": "0.49.0",
|
|
758
770
|
"chokidar": "^5.0.0",
|
|
759
771
|
"ioredis": "^5.11.1",
|
|
760
772
|
"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.49.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.49.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. |
|
|
@@ -2885,7 +2885,7 @@ recorder is for. Every suspended run says so, and the suspension is scoped to th
|
|
|
2885
2885
|
run rather than the process, so requests served alongside it keep recording.
|
|
2886
2886
|
|
|
2887
2887
|
Instead of per-row history, the operation records **itself**. One row in
|
|
2888
|
-
`
|
|
2888
|
+
`_voltro_data_transfers` per run — in either direction: the mode, the transport, the bundle, the source
|
|
2889
2889
|
deployment's schema fingerprint, the counts — and the failure, for the run you
|
|
2890
2890
|
are usually looking for. A trail that only records successes goes quiet exactly
|
|
2891
2891
|
when it is needed.
|
|
@@ -2895,9 +2895,57 @@ interlock and a run which cannot write it must not proceed, while this is
|
|
|
2895
2895
|
history. A target whose schema is not migrated yet still imports, and says the
|
|
2896
2896
|
trace could not be written.
|
|
2897
2897
|
|
|
2898
|
-
###
|
|
2898
|
+
### Every request fits a budget
|
|
2899
2899
|
|
|
2900
|
-
|
|
2900
|
+
Some environments cap a single request: a job runner that kills a client after
|
|
2901
|
+
ten minutes, an ingress with a 30-second ceiling, a CI step with a deadline. A
|
|
2902
|
+
whole transfer may still take an hour — it just has to do so as a series of short
|
|
2903
|
+
requests, each individually abandonable and individually retryable.
|
|
2904
|
+
|
|
2905
|
+
The rule the endpoints follow:
|
|
2906
|
+
|
|
2907
|
+
> **A request that carries bytes never runs a transfer. A request that starts a
|
|
2908
|
+
> transfer never carries bytes.**
|
|
2909
|
+
|
|
2910
|
+
```bash
|
|
2911
|
+
# Nothing here may take longer than 30 seconds per request.
|
|
2912
|
+
voltro data import ./bundle --target api --api-url https://app.example \
|
|
2913
|
+
--mode replace --max-request-seconds 30
|
|
2914
|
+
|
|
2915
|
+
# Or: start it and walk away. The outcome is NOT known when this returns.
|
|
2916
|
+
voltro data import ./bundle --target api --api-url https://app.example --detach
|
|
2917
|
+
```
|
|
2918
|
+
|
|
2919
|
+
Both staging areas — the uploaded bundle on its way in, the produced one on its
|
|
2920
|
+
way out — sit in the system temp directory by default and move with
|
|
2921
|
+
`VOLTRO_IMPORT_UPLOAD_DIR` / `VOLTRO_EXPORT_ARTIFACT_DIR`. Worth setting on a
|
|
2922
|
+
container: a bundle is the size your database is, and a default `/tmp` is
|
|
2923
|
+
frequently a small tmpfs.
|
|
2924
|
+
|
|
2925
|
+
`--max-request-seconds` is DECLARED rather than probed. The thing that kills a
|
|
2926
|
+
request is a policy on your side, and only you know it — in the one environment
|
|
2927
|
+
this was measured against, the ingress would happily hold a connection for an
|
|
2928
|
+
hour and the caller's own toolchain killed the client at ten minutes.
|
|
2929
|
+
|
|
2930
|
+
**An import is three steps.** The bundle goes up (in 16 MiB chunks when it is
|
|
2931
|
+
big, resumable, one plain request when it is small); `import/start` begins the
|
|
2932
|
+
run and answers as soon as the run is recorded; then the client watches the
|
|
2933
|
+
record. `start` is idempotent — retrying it under a budget returns the run that
|
|
2934
|
+
is already going rather than beginning a second destructive one.
|
|
2935
|
+
|
|
2936
|
+
**An export is three steps too.** Ask, wait for the record, then fetch the bytes
|
|
2937
|
+
in ranges from `GET /_voltro/admin/export/download`. The archive used to arrive
|
|
2938
|
+
in the response body, which made the request last as long as reading your whole
|
|
2939
|
+
database.
|
|
2940
|
+
|
|
2941
|
+
**`--detach` returns once the run has started** and says so plainly: exit `0`
|
|
2942
|
+
there means "it started", not "it worked". Attached, the exit code comes from the
|
|
2943
|
+
run's record — `0` finished, `1` failed, `2` still going when you stopped
|
|
2944
|
+
watching. Ctrl-C loses the watching and never the run.
|
|
2945
|
+
|
|
2946
|
+
### Watching a transfer you cannot see
|
|
2947
|
+
|
|
2948
|
+
Over `--target api` the run happens INSIDE the instance. Everything it decides
|
|
2901
2949
|
— whether it stages, whether recorders are suspended, how far it has got — is
|
|
2902
2950
|
printed in the pod's log, and someone reaching for `--target api` is by
|
|
2903
2951
|
construction someone who cannot reach the database directly and usually cannot
|
|
@@ -2906,9 +2954,12 @@ killing the client does not stop it, which is what keeps a dead client from
|
|
|
2906
2954
|
leaving a half-emptied target. Both properties are right, and together they used
|
|
2907
2955
|
to mean an operator could neither see the run nor learn how it ended.
|
|
2908
2956
|
|
|
2909
|
-
Two things close that, and neither is a streamed response
|
|
2910
|
-
|
|
2911
|
-
|
|
2957
|
+
Two things close that, and neither is a streamed response on the upload
|
|
2958
|
+
connection. That connection is the thing an operator is most likely to lose: a
|
|
2959
|
+
client killed by a job timeout while the import runs on inside the instance is
|
|
2960
|
+
the ordinary case, and a stream would go quiet at exactly the moment somebody
|
|
2961
|
+
needs to know what happened. A poll can be run from a different machine than
|
|
2962
|
+
the one that started the import.
|
|
2912
2963
|
|
|
2913
2964
|
**Ask before you upload.** A `replace` over the api asks the instance what it is
|
|
2914
2965
|
going to do, before a byte of the bundle goes up. The instance answers from the
|
|
@@ -2918,7 +2969,8 @@ same function the run itself calls, so the answer cannot drift from the run:
|
|
|
2918
2969
|
$ voltro data import ./bundle --target api --api-url https://app.example --mode replace
|
|
2919
2970
|
api replace: the instance WILL stage — 104 table(s) load into copies and the
|
|
2920
2971
|
target keeps its rows until one short swap at the end. Interrupting the load leaves the target intact.
|
|
2921
|
-
|
|
2972
|
+
importing — 41200 row(s) across 18 table(s) (staged; the target still holds its own rows)
|
|
2973
|
+
done — 228866 row(s) across 104 table(s)
|
|
2922
2974
|
```
|
|
2923
2975
|
|
|
2924
2976
|
With `--bundle-key` the client never holds the bundle, so it sends the key and
|
|
@@ -2932,15 +2984,16 @@ That is the difference between "interrupting this is safe" and "interrupting
|
|
|
2932
2984
|
this empties the target", which is exactly the decision an operator is making
|
|
2933
2985
|
while they watch.
|
|
2934
2986
|
|
|
2935
|
-
**Read the run from anywhere.** `
|
|
2936
|
-
first table, advanced every couple of
|
|
2937
|
-
outcome — so polling it IS the progress
|
|
2987
|
+
**Read the run from anywhere.** `_voltro_data_transfers` carries one row per run
|
|
2988
|
+
in EITHER direction: opened before the first table, advanced every couple of
|
|
2989
|
+
seconds as tables land, closed with the outcome — so polling it IS the progress
|
|
2990
|
+
feed:
|
|
2938
2991
|
|
|
2939
2992
|
```
|
|
2940
|
-
$ voltro data
|
|
2993
|
+
$ voltro data transfers --target api --api-url https://app.example
|
|
2941
2994
|
1 import(s) IN FLIGHT — re-run this to watch the counters move
|
|
2942
|
-
2026-08-
|
|
2943
|
-
2026-08-
|
|
2995
|
+
2026-08-23T09:04:01.000Z · replace — started and never reported finishing · via api · staged (target untouched until the swap) · from /tmp/b
|
|
2996
|
+
2026-08-23T08:00:00.000Z · export all — 228866 row(s) across 104 table(s) · via api · from backups/nightly.vbundle
|
|
2944
2997
|
```
|
|
2945
2998
|
|
|
2946
2999
|
Same data over `GET /_voltro/admin/imports?limit=20`, behind the same
|
|
@@ -2948,6 +3001,11 @@ data-transfer secret (the row names bundles and schema fingerprints). It works
|
|
|
2948
3001
|
from a different machine than the one that started the import, and through
|
|
2949
3002
|
anything that forwards a GET.
|
|
2950
3003
|
|
|
3004
|
+
The `staged` part is a separate claim from the preflight's, and both are needed.
|
|
3005
|
+
The preflight says what the instance WILL do; this says what it did. Without it
|
|
3006
|
+
the two could only be closed by reading the pod's log, which is the one place a
|
|
3007
|
+
`--target api` caller cannot reach.
|
|
3008
|
+
|
|
2951
3009
|
### An interrupted `replace` cannot be silent
|
|
2952
3010
|
|
|
2953
3011
|
The capture only helps if somebody knows to reach for it. A half-replaced database is indistinguishable from an empty one **from the inside** — every table exists, every constraint holds, every query returns nothing without erroring — so a run that emptied a target and disappeared can be served over for hours before anyone asks the right question.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.
|
|
1
|
+
# What's new in 0.49.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
|
|
@@ -7,78 +7,65 @@ workaround for something that shipped two versions ago.
|
|
|
7
7
|
|
|
8
8
|
BREAKING entries name a codemod; run `voltro update` to apply it.
|
|
9
9
|
|
|
10
|
-
###
|
|
11
|
-
|
|
12
|
-
- **@voltro/cli, @voltro/data-transfer** — An import over `--target api` can be asked what it will do, and watched while it does it.
|
|
13
|
-
|
|
14
|
-
The transport's two correct properties combined into one blind spot: the run happens INSIDE the instance, so every line it produces goes to a pod log; and it is deliberately decoupled from the caller, so killing the client does not stop it (which is what keeps a dead client from leaving a half-emptied target). Someone reaching for `--target api` cannot reach the database directly and usually cannot read that log either, so "watch for the staging line" was advice they could not follow.
|
|
10
|
+
### ⚠ BREAKING
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
- **@voltro/cli, @voltro/data-transfer, @voltro/database, @voltro/sql-sqlite, @voltro/voltro** — A data transfer is a series of short requests now — no single one may outlive a caller's budget.
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
**The rule:** *a request that carries bytes never runs a transfer; a request that starts a transfer never carries bytes.* It was broken in the worst available place. The upload was already chunked and resumable — many short requests, each abandonable — and then the FINAL chunk fell through and ran the whole import. So the longest request of the flow arrived AFTER the entire upload had succeeded, and a caller under a policy that caps a single request (a job runner that kills a client at ten minutes; a 30 s ingress ceiling) lost the most expensive thing they had already paid for. A single-request upload had the same shape without the excuse, and the export had no protocol at all: one request that read the whole database and streamed it back.
|
|
19
15
|
|
|
20
|
-
**
|
|
16
|
+
**Import.** `POST /_voltro/admin/import` accumulates and answers `202`. `POST /_voltro/admin/import/start` begins the run and answers `202 { runId }` as soon as the run's first row exists. `start` is idempotent per upload — it is a short request and therefore a retryable one, and without a claim a retry would begin a second destructive run from the same bytes. A claim whose run has ENDED is taken over rather than honoured forever, so a process that dies holding one cannot poison a bundle.
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
**Export.** `POST /_voltro/admin/export` answers `202 { runId }` and produces in the background; the bytes come back from `GET /_voltro/admin/export/download?runId=&offset=&length=` in ranges, resumable, with the total in a header. Object storage (`--bundle-key`) remains for a bundle you want to KEEP — it is no longer the only way to get one out, because requiring it would leave an instance without storage unable to export at all.
|
|
23
19
|
|
|
24
|
-
-
|
|
20
|
+
**The client.** `--max-request-seconds` (or `VOLTRO_MAX_REQUEST_SECONDS`) declares the budget — declared rather than probed, because the thing that kills a request is a policy on the caller's side and only they know it. `--detach` returns once the run has started and says the outcome is NOT known. Attached, the CLI polls the record and prints per-table progress; Ctrl-C then loses the watching and never the run.
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
**The trap, stated because it is the one way to get this wrong:** a failure used to arrive in the response (409 on drift, 409 on a refused mode, 500 otherwise). After the split the response is a `202`, so **a client deriving its exit code from the status line reports a failed import as a success.** The exit code comes from the polled record, in one shared function, and the drift check moved into `start` where it can still be a refusal that leaves no history.
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
**Two knobs that were constants.** `VOLTRO_IMPORT_UPLOAD_DIR` and `VOLTRO_EXPORT_ARTIFACT_DIR` move the staging areas off the default temp filesystem — which on a container is frequently a small tmpfs, so an instance simply could not accept a bundle the size a grown database produces, and the failure arrived as a write error halfway through an upload somebody had been waiting on.
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
**Renamed:** `voltro data imports` → `voltro data transfers`, and `_voltro_data_imports` → `_voltro_data_transfers` with a `direction` column. The command showed one direction and now shows both; the table rename carries its rows via the declarative differ on every dialect and needs nothing from you. The CLI rename ships a `manual` codemod — the command lives in scripts, CI jobs and runbooks, which `voltro update` cannot see or rewrite. The four PUBLIC exports that named the same record were renamed with it (`ImportRun`, `describeImportRun`, `IMPORT_RUNS_TABLE`, `_voltroImportRunsTable`); those are application source, they ship their own `transform` codemod, and they have their own entry.
|
|
27
|
+
- **@voltro/database, @voltro/voltro** — The run-history exports say `transfer`, not `import`.
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
`voltro doctor` now prints the three decided tables and what decided each, on a HEALTHY run. That text existed and was reachable only from the `prod-mismatch` refusal — a message that appears exclusively after a fleet is down is an explanation, not a warning.
|
|
35
|
-
|
|
36
|
-
### Fixed
|
|
29
|
+
`@voltro/database` (and `voltro/database`) renamed four public exports along with the table behind them:
|
|
37
30
|
|
|
38
|
-
|
|
31
|
+
| was | is | |---|---| | `ImportRun` | `DataTransferRun` | | `describeImportRun` | `describeTransferRun` | | `IMPORT_RUNS_TABLE` | `DATA_TRANSFERS_TABLE` | | `_voltroImportRunsTable` | `_voltroDataTransfersTable` |
|
|
39
32
|
|
|
40
|
-
|
|
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.
|
|
41
34
|
|
|
42
|
-
|
|
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.
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
- **@voltro/sql-turso** — Opening a second pooled turso connection could fail instantly with `database is locked` — from inside the constructor, before a single query ran.
|
|
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.
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
SqlError: Failed to enable Turso MVCC (journal_mode=experimental_mvcc): database is locked
|
|
50
|
-
|
|
51
|
-
`busy_timeout` is set FIRST now. Nothing else changed — same value, same pragmas, same connection.
|
|
52
|
-
|
|
53
|
-
**Why it hid for so long.** The file already carried a long, correct note about `busy_timeout` being mandatory with a pool, and a separate fix had closed the DDL half (`retryFilter` + bounded retries in `applySchema`). Both are about the same lock class, so the constructor read as covered — but a setting cannot protect the two pragmas that run before it.
|
|
39
|
+
### Added
|
|
54
40
|
|
|
55
|
-
|
|
41
|
+
- **@voltro/database, @voltro/data-transfer, @voltro/cli** — An import records WHETHER it staged, and a soft-dropped column says so in a drift refusal.
|
|
56
42
|
|
|
57
|
-
|
|
58
|
-
- **@voltro/runtime, @voltro/data-transfer, @voltro/cli** — The `source:` recorder broke every WRITE on the in-memory store, and actions are recorded now.
|
|
43
|
+
**`_voltro_data_imports.staged`.** The pre-upload preflight says what the instance WILL do; the run's own line says what it did — and that line is printed inside the instance, which is exactly where an operator using `--target api` cannot read it. So "we were told it would stage" and "it staged" were two claims with no way to close the gap between them from outside. The column is `null` for a mode where the question does not arise; `voltro data imports` and `GET /_voltro/admin/imports` both carry it.
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
**A soft-dropped column is named as one.** `<original>__dropped_<stamp>` is what the differ leaves behind when an app stops declaring a column — only the database that did the drop has it, so it drifts against every target. The refusal reported it as an ordinary missing column ("the value has nowhere to go"), which points at the TARGET's schema: the one place the fix does not lie. It now says where the column lives and how to reclaim it.
|
|
61
46
|
|
|
62
|
-
|
|
47
|
+
### Fixed
|
|
63
48
|
|
|
64
|
-
|
|
49
|
+
- **@voltro/data-transfer, @voltro/sql-sqlite, @voltro/database** — A successful `--mode replace --no-atomic` left a marker that refused the next boot.
|
|
65
50
|
|
|
66
|
-
|
|
51
|
+
Two defects, one visible symptom, and both were silent by construction.
|
|
67
52
|
|
|
68
|
-
**
|
|
53
|
+
**The clear was gated on the WRITE's condition.** `!(useLedger && ledger.truncated)` means "an earlier attempt already recorded this destructive run, do not write a second row" — correct on the write. Copied down to the clear its meaning inverts: `ledger.truncated` is set by the emptying step of THIS run, so on `--no-atomic` (the only mode where `useLedger` is true) the clear was skipped by the very run that wrote the marker.
|
|
69
54
|
|
|
70
|
-
**And
|
|
55
|
+
**And a `Date` in a predicate is not bindable on sqlite.** `better-sqlite3` binds numbers, strings, bigints, buffers and null; the row path has coerced Dates since that store was written, and the eager-join compiler carried its own private copy of the fix, but `query` / `updateMany` / `deleteMany` bound the raw value. So every comparison of a timestamp column against a `Date` failed with `Failed to execute statement` — including the marker's clear, which swallows its errors ON PURPOSE (a store with no marker table must not fail an import over a bookkeeping row) and therefore said nothing. The retention sweep compares `lt(column, cutoff)` the same way.
|
|
71
56
|
|
|
72
|
-
|
|
57
|
+
Together: a fully successful replace left the marker standing, and the next boot REFUSED with "a destructive import did not finish" over a database that was completely fine. The one recovery is a command the operator has no reason to think they need. It stayed invisible because `atomic` defaults to true for `replace`, and because a staged replace writes no marker at all — two defaults hiding the one mode that exists for large, interruptible loads.
|
|
73
58
|
|
|
74
|
-
|
|
59
|
+
The coercion is shared now and applied at all three predicate sites, with a guard that fails on a fourth that forgets. A dry run also closes its trace row: a preview that finished instantly used to leave the record open, so a polling caller waited out its whole budget over a run that was long done.
|
|
60
|
+
- **@voltro/cli** — `voltro codegen` declared twenty framework tables fewer than a boot.
|
|
75
61
|
|
|
76
|
-
|
|
62
|
+
The app half of this was fixed last release and looked like the whole thing. It was not: `codegen` derived the FEATURE MIX from the file list it had just walked, and that list is the entity/relations set — which contains no `*.workflow.tsx`, no `*.agent.ts`, no `*.cron.tsx`. So every feature flag came back false, and the dialect was never passed at all, taking `_voltro_cdc_offsets` with it. Measured on an app with two workflow files: 18 framework tables where the shared assembly produces 33.
|
|
77
63
|
|
|
78
|
-
|
|
64
|
+
It calls `assembleFrameworkTables({ root })` now — the same entry `voltro db plan/apply` uses, which detects the mix from the root rather than being handed one.
|
|
79
65
|
|
|
80
|
-
|
|
66
|
+
The parity guard moved with it. Comparing the two WALKS could not see this: both walks were right about files, and the divergence was introduced one layer past them. It compares the assembled SETS now, and runs codegen's own table function on a tree whose only feature signals are a workflow file and an agent file — a source assertion that the right function is CALLED cannot see a wrong argument handed to it, and a wrong argument is what this was.
|
|
67
|
+
- **@voltro/cli** — `voltro data --help` advertised four subcommands out of nine.
|
|
81
68
|
|
|
82
|
-
|
|
69
|
+
It printed `<export|import|backup|restore>` while the command dispatched those four plus `imports`, `inspect`, `unpack`, `clear-replace-marker` and `clear-staging`. A quoted enumeration is read as exhaustive — the same failure `subcommandNames.ts` was written for after a `db` list cost two wrong conclusions — and the missing entry here is the one that answers "what is my import doing right now" for somebody who cannot reach the pod.
|
|
83
70
|
|
|
84
|
-
|
|
71
|
+
`subcommandHelpParity.test.ts` had listed `data` among the commands it could not check, loudly and correctly: there was no name list to check against. There is one now (`DATA_SUBCOMMANDS`), the dispatch is a keyed `Record`, so a subcommand with no name and a name with no handler are both compile errors, and the usage line is generated from the same array. `data` is out of the unchecked list.
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@effect/platform": "^0.97.0",
|
|
14
14
|
"@effect/rpc": "^0.76.0",
|
|
15
|
-
"@voltro/ai": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/protocol": "0.
|
|
20
|
-
"@voltro/runtime": "0.
|
|
15
|
+
"@voltro/ai": "0.49.0",
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/protocol": "0.49.0",
|
|
20
|
+
"@voltro/runtime": "0.49.0",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@voltro/testing": "0.
|
|
24
|
+
"@voltro/testing": "0.49.0",
|
|
25
25
|
"typescript": "^6.0.3",
|
|
26
26
|
"@vitest/coverage-v8": "^4.1.10",
|
|
27
27
|
"vitest": "^4.1.10"
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-auth": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
22
|
-
"@voltro/sql-postgres": "0.
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/plugin-auth": "0.49.0",
|
|
20
|
+
"@voltro/protocol": "0.49.0",
|
|
21
|
+
"@voltro/runtime": "0.49.0",
|
|
22
|
+
"@voltro/sql-postgres": "0.49.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.49.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
28
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
29
|
"vitest": "^4.1.10"
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@effect/platform": "^0.97.0",
|
|
18
18
|
"@effect/rpc": "^0.76.0",
|
|
19
|
-
"@voltro/cli": "0.
|
|
20
|
-
"@voltro/database": "0.
|
|
21
|
-
"@voltro/env": "0.
|
|
22
|
-
"@voltro/plugin-multitenancy": "0.
|
|
23
|
-
"@voltro/protocol": "0.
|
|
24
|
-
"@voltro/runtime": "0.
|
|
19
|
+
"@voltro/cli": "0.49.0",
|
|
20
|
+
"@voltro/database": "0.49.0",
|
|
21
|
+
"@voltro/env": "0.49.0",
|
|
22
|
+
"@voltro/plugin-multitenancy": "0.49.0",
|
|
23
|
+
"@voltro/protocol": "0.49.0",
|
|
24
|
+
"@voltro/runtime": "0.49.0",
|
|
25
25
|
"effect": "^3.22.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@voltro/testing": "0.
|
|
28
|
+
"@voltro/testing": "0.49.0",
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"@vitest/coverage-v8": "^4.1.10",
|
|
31
31
|
"vitest": "^4.1.10"
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-deactivation": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/plugin-deactivation": "0.49.0",
|
|
20
|
+
"@voltro/protocol": "0.49.0",
|
|
21
|
+
"@voltro/runtime": "0.49.0",
|
|
22
22
|
"effect": "^3.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/testing": "0.
|
|
25
|
+
"@voltro/testing": "0.49.0",
|
|
26
26
|
"typescript": "^6.0.3",
|
|
27
27
|
"@vitest/coverage-v8": "^4.1.10",
|
|
28
28
|
"vitest": "^4.1.10"
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@react-email/components": "^1.0.12",
|
|
15
15
|
"@react-email/render": "^1.4.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-mail": "0.
|
|
20
|
-
"@voltro/plugin-multitenancy": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.49.0",
|
|
17
|
+
"@voltro/database": "0.49.0",
|
|
18
|
+
"@voltro/env": "0.49.0",
|
|
19
|
+
"@voltro/plugin-mail": "0.49.0",
|
|
20
|
+
"@voltro/plugin-multitenancy": "0.49.0",
|
|
21
|
+
"@voltro/protocol": "0.49.0",
|
|
22
|
+
"@voltro/runtime": "0.49.0",
|
|
23
23
|
"effect": "^3.22.0",
|
|
24
24
|
"react": "^19.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/testing": "0.49.0",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|