@voltro/cli 0.33.0 → 0.34.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 +1801 -0
- package/bin/nodeEnvironment.d.mts +30 -0
- package/bin/nodeEnvironment.mjs +158 -0
- package/bin/voltro.mjs +69 -5
- package/dist/addCommand-BNeoeSxe.js +124 -0
- package/dist/addCommand-aXSQveak.js +2 -0
- package/dist/agentsMd-BTchIZku.js +2 -0
- package/dist/agentsMd-mhQMF1bx.js +254 -0
- package/dist/apiBuild-BICVGnEC.js +2 -0
- package/dist/{apiBuild-h9VHtnlw.js → apiBuild-DZF_f0_I.js} +46 -46
- package/dist/appPort-B_HpJ_ck.js +48 -0
- package/dist/baselineCommand-C2ClWZN3.js +2 -0
- package/dist/baselineCommand-DIttzO8A.js +227 -0
- package/dist/bin.js +71 -28
- package/dist/build-CE7Ca9gm.js +711 -0
- package/dist/cacheCommand-DA4OH9xt.js +42 -0
- package/dist/capabilitiesCommand-nq_pz5xd.js +123 -0
- package/dist/checkCommand-Dv8r9tGO.js +231 -0
- package/dist/checkCommand-YZDmkAGd.js +2 -0
- package/dist/{cliArgs-qdZSElM3.js → cliArgs-D4p8n7EE.js} +12 -1
- package/dist/cliError-BmdYnghb.js +10 -0
- package/dist/cliOutput-D1tSBoRM.js +15 -0
- package/dist/{cliRuntime-Oh517vCV.js → cliRuntime-Dh7UDinH.js} +20 -20
- package/dist/cloudClient-DWL-Hw_T.js +67 -0
- package/dist/cloudCmd-Cvv5HGaZ.js +364 -0
- package/dist/clusterCmd-CNXKlcvD.js +54 -0
- package/dist/codegen-CYM3Zqrf.js +605 -0
- package/dist/codegen-ChBi_hVa.js +2 -0
- package/dist/codegenCommand-DC6w2tNZ.js +30 -0
- package/dist/codemodRunner-DRRqXR74.js +5243 -0
- package/dist/commandRunner-BLAEFLjp.js +47 -0
- package/dist/commands-gutsz-Ac.js +808 -0
- package/dist/connectionConfig-UFlIEiys.js +66 -0
- package/dist/dashboardCommand-3YG8p-UA.js +25 -0
- package/dist/dataCommand-qL0r7fPO.js +535 -0
- package/dist/dataProfile-dW-PsfLB.js +15 -0
- package/dist/{dbCommand-DTLKAfbA.js → dbCommand-B6X0FZbq.js} +551 -401
- package/dist/dbCommand-CpdKLeQq.js +2 -0
- package/dist/{dev-C_P8FLSx.js → dev-CerMd0mW.js} +3122 -3129
- package/dist/dev-CoG-ZPx8.js +3 -0
- package/dist/devActivity-Dx_3nnGv.js +100 -0
- package/dist/devActivity.js +1 -1
- package/dist/dialectDriver-CgXnDfec.js +39 -0
- package/dist/discover-C9XKJDco.js +25 -0
- package/dist/doctorCommand-BvqGBwNG.js +2 -0
- package/dist/{checkCommand-xGhRFFg2.js → doctorCommand-CnDXQxfa.js} +520 -1278
- package/dist/dormancyCommand-Dszo57d6.js +69 -0
- package/dist/e2eCmd-BRabZww-.js +147 -0
- package/dist/embeddingsCommand-C0sKVRo1.js +73 -0
- package/dist/envCommand-DPgdV1Bq.js +60 -0
- package/dist/evalCommand-6RUfPen4.js +118 -0
- package/dist/evolveCommand-DHpkgjgH.js +281 -0
- package/dist/fileTaxonomy-CJfgOllU.js +457 -0
- package/dist/frameworkTableAssembly-BGHmck-x.js +2 -0
- package/dist/{frameworkTableAssembly-BwIrO5nv.js → frameworkTableAssembly-DkkP6BgC.js} +184 -148
- package/dist/generateCommand-oibemh97.js +147 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +4 -3
- package/dist/infoCommand-BJw9nLUR.js +60 -0
- package/dist/{inspect-BUUjt773.js → inspect-CBqFtAKA.js} +82 -40
- package/dist/inspect-C_T_WGvl.js +2 -0
- package/dist/inspectCmd-Bppy-GGw.js +224 -0
- package/dist/inspectFetch-Cm8_wVvp.js +151 -0
- package/dist/inspectMetrics-CfdKLh6t.js +72 -0
- package/dist/loadEnv-D9nEOClM.js +44 -0
- package/dist/logFileSink-C_D2wRN1.js +105 -0
- package/dist/logsCmd-CCca3KRZ.js +260 -0
- package/dist/manifestBuild-ChsKAhmn.js +2 -0
- package/dist/{manifestBuild-BLrVuSlM.js → manifestBuild-sxpwdKY1.js} +1 -1
- package/dist/metaCommands-7MJfZ5cf.js +196 -0
- package/dist/migrate-CBwOt_iV.js +83 -0
- package/dist/mssqlClusterPatch-_4cE_nun.js +44 -0
- package/dist/newCommand-COWOJ1_E.js +156 -0
- package/dist/nodeEnvironment-cGFAj1J8.js +28 -0
- package/dist/packageCommand-Cug_3Ogl.js +271 -0
- package/dist/pageConvention-cEiRxdab.js +5 -0
- package/dist/privacyCommand-C-Df56U_.js +146 -0
- package/dist/projectScaffold-DmzEKHib.js +2 -0
- package/dist/projectScaffold-LMMtaavR.js +814 -0
- package/dist/renderModeScan-D7J1B7Kw.js +105 -0
- package/dist/renderProfile-1OWWAAtx.js +81 -0
- package/dist/runtimeRegistry-DMeKfTHP.js +81 -0
- package/dist/runtimeTrace-CRxalXTs.js +91 -0
- package/dist/scheduleCmd--jksTrf6.js +69 -0
- package/dist/scheduleManifestCmd-D2x0CTTY.js +249 -0
- package/dist/schemaIr-UJybUUZW.js +103 -0
- package/dist/{sdkgen-C81QIkiL.js → sdkgen-CYJscZC7.js} +111 -209
- package/dist/seedRunner-TFHHiToI.js +329 -0
- package/dist/serveCommand-B_isw7q4.js +1647 -0
- package/dist/serveCommand-DOvbgRnQ.js +2 -0
- package/dist/serveEntry.js +5 -5
- package/dist/serverlessCommand-CfJZy6dS.js +482 -0
- package/dist/start-9LiUOfES.js +1087 -0
- package/dist/start-B-9Nsp-S.js +3 -0
- package/dist/startEntry.js +2 -2
- package/dist/staticCommand-Dr2M6tpU.js +304 -0
- package/dist/storageCommand-Co6NfLqN.js +42 -0
- package/dist/templates-De8IR5-c.js +102 -0
- package/dist/test-CI6iDsYc.js +115 -0
- package/dist/tracesCmd-CkEZQrtt.js +232 -0
- package/dist/tsconfigPaths-BWXBWgcl.js +107 -0
- package/dist/tsxLoader-EuXmSJ1K.js +51 -0
- package/dist/typecheckCommand-BlsWiCNq.js +61 -0
- package/dist/updateCommand-Bkptutss.js +585 -0
- package/dist/updateCommand-us1_hdIC.js +2 -0
- package/dist/{inspectMetrics-1xzTKAFx.js → webDev-CBYvPqQr.js} +975 -1559
- package/dist/webDev-Cg-fFiyd2.js +2 -0
- package/dist/webhookDiscovery-CrGAfhIG.js +2 -0
- package/dist/webhookDiscovery-D7VaeMlz.js +51 -0
- package/dist/webhooksCommand-CID96Rga.js +267 -0
- package/dist/workflowsCmd-D1VTmLMY.js +608 -0
- package/package.json +179 -17
- package/templates/AGENTS.core.md +58 -3
- package/templates/AGENTS.md +64 -7
- package/templates/agent-docs/_index.md +6 -4
- package/templates/agent-docs/_manifest.json +22 -5
- package/templates/agent-docs/ai.md +370 -0
- package/templates/agent-docs/authentication.md +265 -31
- package/templates/agent-docs/caching.md +6 -0
- package/templates/agent-docs/cli.md +794 -50
- package/templates/agent-docs/data.md +550 -11
- package/templates/agent-docs/database/migrations.md +174 -25
- package/templates/agent-docs/database/misc.md +156 -40
- package/templates/agent-docs/database/querying.md +19 -1
- package/templates/agent-docs/database/scaling.md +60 -0
- package/templates/agent-docs/database/schema.md +1 -0
- package/templates/agent-docs/database/seedsdialects.md +208 -19
- package/templates/agent-docs/database/transactions.md +68 -0
- package/templates/agent-docs/deployment.md +69 -3
- package/templates/agent-docs/introduction.md +87 -16
- package/templates/agent-docs/local-first-mobile.md +79 -4
- package/templates/agent-docs/multi-tenancy.md +95 -20
- package/templates/agent-docs/observability.md +58 -3
- package/templates/agent-docs/plugins/ai-flows.md +161 -2
- package/templates/agent-docs/plugins/analytics-postgres.md +1 -1
- package/templates/agent-docs/plugins/audit.md +37 -1
- package/templates/agent-docs/plugins/auth-social.md +143 -0
- package/templates/agent-docs/plugins/auth-workos.md +4 -2
- package/templates/agent-docs/plugins/auth.md +131 -6
- package/templates/agent-docs/plugins/billing.md +132 -15
- package/templates/agent-docs/plugins/cdc-out.md +46 -7
- package/templates/agent-docs/plugins/clickhouse.md +1 -1
- package/templates/agent-docs/plugins/duckdb.md +1 -1
- package/templates/agent-docs/plugins/flags.md +132 -0
- package/templates/agent-docs/plugins/governance.md +105 -7
- package/templates/agent-docs/plugins/multitenancy.md +9 -4
- package/templates/agent-docs/plugins/presence.md +13 -2
- package/templates/agent-docs/plugins/ratelimit.md +9 -0
- package/templates/agent-docs/plugins/search.md +157 -6
- package/templates/agent-docs/plugins/sso-saml.md +47 -8
- package/templates/agent-docs/plugins/webhooks.md +105 -0
- package/templates/agent-docs/plugins.md +150 -18
- package/templates/agent-docs/reference.md +60 -3
- package/templates/agent-docs/releases.md +1117 -0
- package/templates/agent-docs/routing.md +43 -25
- package/templates/agent-docs/scheduling.md +10 -0
- package/templates/agent-docs/schema-driven-ui.md +92 -12
- package/templates/agent-docs/security.md +426 -0
- package/templates/agent-docs/templates/apibackends.md +87 -18
- package/templates/agent-docs/templates/appshells.md +32 -14
- package/templates/agent-docs/templates/overview.md +13 -8
- package/templates/agent-docs/testing.md +211 -14
- package/templates/agent-docs/whats-new.md +1700 -104
- package/templates/agent-docs/workflows.md +130 -14
- package/templates/apps/api-ai/actions/summarize.action.ts +11 -0
- package/templates/apps/api-ai/package.json +8 -7
- package/templates/apps/api-auth/actions/me.action.ts +13 -0
- package/templates/apps/api-auth/package.json +9 -8
- package/templates/apps/api-backend/mutations/notes.create.mutation.ts +9 -0
- package/templates/apps/api-backend/package.json +12 -8
- package/templates/apps/api-backend/queries/notes.query.ts +30 -8
- package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +14 -0
- package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +8 -0
- package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +10 -0
- package/templates/apps/api-backend-deactivation/package.json +8 -7
- package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +17 -0
- package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +9 -0
- package/templates/apps/api-backend-mail/package.json +9 -8
- package/templates/apps/api-backend-mail/queries/notes.query.ts +30 -8
- package/templates/apps/api-backend-mariadb/.env.example +14 -0
- package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +9 -0
- package/templates/apps/api-backend-mariadb/package.json +10 -9
- package/templates/apps/api-backend-mariadb/queries/notes.query.ts +30 -8
- package/templates/apps/api-backend-sqlite/.env.example +14 -0
- package/templates/apps/api-backend-sqlite/mutations/notes.create.mutation.ts +9 -0
- package/templates/apps/api-backend-sqlite/package.json +9 -8
- package/templates/apps/api-backend-sqlite/queries/notes.query.ts +30 -8
- package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +13 -0
- package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +12 -0
- package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +9 -0
- package/templates/apps/api-backend-storage/package.json +9 -8
- package/templates/apps/api-backend-storage/queries/notes.query.ts +30 -8
- package/templates/apps/api-cms/actions/content.get.action.ts +7 -0
- package/templates/apps/api-cms/actions/content.types.action.ts +6 -0
- package/templates/apps/api-cms/actions/me.action.ts +13 -0
- package/templates/apps/api-cms/app.config.ts +19 -0
- package/templates/apps/api-cms/authz.ts +63 -0
- package/templates/apps/api-cms/mutations/content.publish.mutation.ts +10 -0
- package/templates/apps/api-cms/mutations/content.saveDraft.mutation.ts +10 -0
- package/templates/apps/api-cms/mutations/content.unpublish.mutation.ts +5 -0
- package/templates/apps/api-cms/package.json +11 -10
- package/templates/apps/api-cms/queries/content.list.query.ts +23 -7
- package/templates/apps/api-cms/tests/accessDecisions.test.ts +121 -0
- package/templates/apps/api-cms/tests/content.descriptors.test.ts +8 -4
- package/templates/apps/api-collab/mutations/documents.create.mutation.ts +8 -0
- package/templates/apps/api-collab/mutations/documents.setBody.mutation.ts +13 -0
- package/templates/apps/api-collab/package.json +9 -8
- package/templates/apps/api-collab/queries/documents.query.ts +19 -7
- package/templates/apps/api-data-advanced/package.json +9 -8
- package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +12 -0
- package/templates/apps/api-data-advanced/queries/books.search.query.ts +9 -0
- package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +17 -0
- package/templates/apps/api-durable/mutations/orders.place.mutation.ts +9 -0
- package/templates/apps/api-durable/package.json +9 -8
- package/templates/apps/api-feature-flags/actions/notes.export.action.ts +16 -0
- package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +12 -0
- package/templates/apps/api-feature-flags/package.json +10 -9
- package/templates/apps/api-governance/README.md +30 -8
- package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -1
- package/templates/apps/api-governance/actions/profiles.get.action.ts +29 -4
- package/templates/apps/api-governance/database/schema.ts +16 -4
- package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +12 -0
- package/templates/apps/api-governance/package.json +9 -8
- package/templates/apps/api-kv/actions/sync.pull.action.ts +15 -0
- package/templates/apps/api-kv/actions/sync.reset.action.ts +13 -0
- package/templates/apps/api-kv/actions/sync.status.action.ts +7 -0
- package/templates/apps/api-kv/package.json +9 -8
- package/templates/apps/api-kv/queries/events.list.query.ts +19 -8
- package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +11 -0
- package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +13 -0
- package/templates/apps/api-moderation/package.json +9 -8
- package/templates/apps/api-observability/mutations/notes.create.mutation.ts +8 -0
- package/templates/apps/api-observability/package.json +9 -8
- package/templates/apps/api-observability/queries/notes.list.query.ts +13 -0
- package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +14 -0
- package/templates/apps/api-ratelimit/package.json +9 -8
- package/templates/apps/api-rbac/package.json +9 -8
- package/templates/apps/api-rest/package.json +8 -7
- package/templates/apps/api-saas/mutations/projects.create.mutation.ts +13 -0
- package/templates/apps/api-saas/package.json +12 -11
- package/templates/apps/api-saas/queries/projects.list.query.ts +11 -0
- package/templates/apps/api-saas-starter/actions/me.action.ts +13 -0
- package/templates/apps/api-saas-starter/app.config.ts +19 -0
- package/templates/apps/api-saas-starter/authz.ts +75 -0
- package/templates/apps/api-saas-starter/mutations/invites.create.mutation.ts +10 -0
- package/templates/apps/api-saas-starter/mutations/projects.create.mutation.ts +9 -0
- package/templates/apps/api-saas-starter/package.json +15 -11
- package/templates/apps/api-saas-starter/queries/invites.list.query.ts +19 -8
- package/templates/apps/api-saas-starter/queries/projects.list.query.ts +18 -7
- package/templates/apps/api-saas-starter/tests/accessDecisions.test.ts +135 -0
- package/templates/apps/api-search/mutations/articles.create.mutation.ts +14 -0
- package/templates/apps/api-search/package.json +9 -8
- package/templates/apps/api-search/queries/articles.list.query.ts +21 -8
- package/templates/apps/api-status/README.md +10 -3
- package/templates/apps/api-status/app.config.ts +8 -3
- package/templates/apps/api-status/authz.ts +5 -3
- package/templates/apps/api-status/package.json +9 -8
- package/templates/apps/api-status/queries/components.list.query.ts +14 -6
- package/templates/apps/api-status/queries/incidents.live.query.ts +23 -10
- package/templates/apps/api-status/queries/updates.list.query.ts +16 -9
- package/templates/apps/api-status/tests/status.test.ts +9 -1
- package/templates/apps/api-versioning/actions/documents.asOf.action.ts +12 -0
- package/templates/apps/api-versioning/actions/documents.history.action.ts +13 -0
- package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +9 -0
- package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +12 -0
- package/templates/apps/api-versioning/package.json +9 -8
- package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +16 -0
- package/templates/apps/api-webhooks/package.json +10 -9
- package/templates/apps/api-webhooks/queries/orders.list.query.ts +10 -0
- package/templates/apps/changelog/package.json +8 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +10 -8
- package/templates/apps/frontend-admin/src/lib/admin.ts +20 -9
- package/templates/apps/frontend-admin/src/locales/de.ts +11 -1
- package/templates/apps/frontend-admin/src/locales/en.ts +13 -1
- package/templates/apps/frontend-admin/src/pages/admin/[entity]/page.tsx +65 -22
- package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +130 -23
- package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +3 -2
- package/templates/apps/frontend-admin/src/pages/admin/page.test.tsx +19 -2
- package/templates/apps/frontend-admin/src/pages/admin/page.tsx +9 -4
- package/templates/apps/frontend-app/app.config.ts +4 -3
- package/templates/apps/frontend-app/package.json +11 -8
- package/templates/apps/frontend-app/src/lib/api.ts +25 -0
- package/templates/apps/frontend-app/src/pages/page.test.tsx +130 -82
- package/templates/apps/frontend-app/src/pages/page.tsx +14 -18
- package/templates/apps/frontend-auth/package.json +10 -8
- package/templates/apps/frontend-blank/package.json +9 -7
- package/templates/apps/frontend-cms/package.json +11 -9
- package/templates/apps/frontend-collab/package.json +12 -9
- package/templates/apps/frontend-collab/src/pages/page.test.tsx +122 -78
- package/templates/apps/frontend-contact/package.json +9 -7
- package/templates/apps/frontend-dashboard/package.json +9 -7
- package/templates/apps/frontend-docs/package.json +9 -7
- package/templates/apps/frontend-i18n/package.json +8 -6
- package/templates/apps/frontend-landing/package.json +9 -7
- package/templates/apps/frontend-portal/package.json +10 -8
- package/templates/apps/frontend-saas/app.config.ts +10 -6
- package/templates/apps/frontend-saas/package.json +10 -8
- package/templates/apps/frontend-saas/src/lib/api.ts +27 -32
- package/templates/apps/frontend-saas/src/pages/dashboard/billing/page.tsx +7 -8
- package/templates/apps/frontend-saas/src/pages/dashboard/page.test.tsx +27 -3
- package/templates/apps/frontend-saas/src/pages/dashboard/page.tsx +4 -4
- package/templates/apps/frontend-saas/src/pages/dashboard/team/page.tsx +3 -4
- package/templates/apps/frontend-spa/package.json +9 -7
- package/templates/apps/frontend-ssr/package.json +9 -7
- package/templates/apps/frontend-ssr-api/package.json +10 -8
- package/templates/apps/frontend-static-blog/package.json +8 -6
- package/templates/apps/frontend-status/package.json +10 -8
- package/templates/apps/mobile-app/README.md +1 -0
- package/templates/apps/mobile-app/package.json +4 -2
- package/templates/apps/mobile-app/src/app/index.tsx +22 -12
- package/templates/apps/mobile-app/src/app/orders/[id].tsx +1 -1
- package/templates/apps/mobile-app/src/lib/api.ts +34 -0
- package/templates/apps/mobile-app/voltro.mobile.ts +4 -2
- package/templates/baselines/bare/.env.example +14 -0
- package/templates/baselines/bare/baseline.json +4 -4
- package/templates/baselines/compose/.env.example +14 -0
- package/templates/baselines/compose/README.md +1 -1
- package/templates/baselines/compose/baseline.json +5 -5
- package/templates/baselines/compose-mariadb/.env.example +14 -0
- package/templates/baselines/compose-mariadb/README.md +1 -1
- package/templates/baselines/compose-mariadb/baseline.json +5 -5
- package/templates/baselines/helm/.env.example +14 -0
- package/templates/baselines/helm/baseline.json +4 -4
- package/dist/apiBuild-C-x9YacA.js +0 -2
- package/dist/checkCommand-DRovTKza.js +0 -2
- package/dist/commands-CJfepbm4.js +0 -11541
- package/dist/dbCommand-b1gum4td.js +0 -2
- package/dist/dev-iiMtlkfs.js +0 -3
- package/dist/devActivity-BhIu6ncs.js +0 -159
- package/dist/frameworkTableAssembly-D-EebUQX.js +0 -2
- package/dist/inspect-mmBuRXmy.js +0 -2
- package/dist/manifestBuild-Dj8Jjoto.js +0 -2
- package/dist/seedRunner-Bqxgp7HZ.js +0 -230
- package/dist/serveCommand-DdaM4Hup.js +0 -1608
- package/dist/start-C0koT0UO.js +0 -1084
- /package/templates/apps/api-ai/actions/{summarize.action.server.tsx → summarize.action.server.ts} +0 -0
|
@@ -707,11 +707,13 @@ What still cannot defer on this path:
|
|
|
707
707
|
|
|
708
708
|
`interactive` is **orthogonal** to `renderMode` — it controls how much JS runs in the browser. See [Islands](/docs/routing/islands).
|
|
709
709
|
|
|
710
|
-
| `interactive` | What's hydrated |
|
|
711
|
-
|
|
712
|
-
| `'none'` | Nothing — pure HTML. |
|
|
713
|
-
| `'islands'` | Only `*.island.tsx` files. |
|
|
714
|
-
| `'full'` *(default)* | Whole page. |
|
|
710
|
+
| `interactive` | What's hydrated | JS shipped |
|
|
711
|
+
|---|---|---|
|
|
712
|
+
| `'none'` | Nothing — pure HTML. | None — the script tags are stripped. |
|
|
713
|
+
| `'islands'` | Only `*.island.tsx` files. | The full app bundle, same as `'full'`. |
|
|
714
|
+
| `'full'` *(default)* | Whole page. | The full app bundle. |
|
|
715
|
+
|
|
716
|
+
The third column is the one people get wrong: `'islands'` buys back hydration CPU, not download. Only `'none'` removes bytes. See [Islands](/docs/routing/islands) for the measured numbers.
|
|
715
717
|
|
|
716
718
|
Combinations:
|
|
717
719
|
|
|
@@ -745,7 +747,7 @@ That last case is how dynamic `static` routes work in dev / when `getStaticPaths
|
|
|
745
747
|
## Where to read next
|
|
746
748
|
|
|
747
749
|
- [Loaders & meta](/docs/routing/loaders-and-meta) — fetch data before render, inject `<head>` tags
|
|
748
|
-
- [Islands](/docs/routing/islands) —
|
|
750
|
+
- [Islands](/docs/routing/islands) — scope hydration to explicit islands (note: this reduces hydration work, not the JS payload — `'none'` is the mode that removes bytes)
|
|
749
751
|
|
|
750
752
|
|
|
751
753
|
|
|
@@ -1659,7 +1661,7 @@ Useful when the prefetch trigger isn't a `<Link>` (e.g. an entire card area, whe
|
|
|
1659
1661
|
|
|
1660
1662
|
_interactive: 'islands' — ship pure HTML with selectively-hydrated interactive components._
|
|
1661
1663
|
|
|
1662
|
-
The **islands** model: serve the page as pure HTML, then hydrate only the bits that need interactivity. The rest of the page
|
|
1664
|
+
The **islands** model: serve the page as pure HTML, then hydrate only the bits that need interactivity. The rest of the page stays inert — no React lifecycle runs through it.
|
|
1663
1665
|
|
|
1664
1666
|
Voltro implements islands per-page via the `interactive` export:
|
|
1665
1667
|
|
|
@@ -1668,7 +1670,15 @@ export const renderMode = 'static' as const
|
|
|
1668
1670
|
export const interactive = 'islands' as const
|
|
1669
1671
|
```
|
|
1670
1672
|
|
|
1671
|
-
|
|
1673
|
+
> **Islands cut hydration WORK, not DOWNLOAD — read this before you pick the mode.**
|
|
1674
|
+
>
|
|
1675
|
+
> `interactive: 'islands'` ships **exactly the same JavaScript** as `interactive: 'full'`. Measured on the framework's reference fixture, the same page: `full` = 195,229 bytes gzipped of first-load JS, `islands` = 195,231 bytes. That is the whole difference — two bytes of noise.
|
|
1676
|
+
>
|
|
1677
|
+
> The reason is structural, not a missing optimisation pass: the generated browser entry imports `mount` and your `App` at value level, so the browser has already downloaded, parsed and evaluated the entire app bundle before the islands branch is even reached. Only `interactive: 'none'` removes bytes today — it strips every `<script type="module">` and `<link rel="modulepreload">` from the page's HTML.
|
|
1678
|
+
>
|
|
1679
|
+
> So islands are the right choice when the cost you want back is **CPU on the main thread** (hydration walking a large tree, effects firing across a page of prose). They are the wrong choice if you adopted them to make the download smaller — for that, use `interactive: 'none'` and put the interactive bits behind a separate page, or accept the full payload.
|
|
1680
|
+
|
|
1681
|
+
With `interactive: 'islands'`, the page's HTML keeps its script tags and the app bundle still loads; what changes is that `mount()` skips hydrating the page tree and instead scans for island markers, hydrating each one on its own schedule.
|
|
1672
1682
|
|
|
1673
1683
|
## When to use islands
|
|
1674
1684
|
|
|
@@ -1676,7 +1686,7 @@ With `interactive: 'islands'`, the framework strips the page's React runtime fro
|
|
|
1676
1686
|
- **Docs** that are mostly text but have a search modal + theme toggle.
|
|
1677
1687
|
- **Blog posts** with an embedded poll or comment widget.
|
|
1678
1688
|
|
|
1679
|
-
|
|
1689
|
+
In each case what you get back is hydration time, not bytes: React's *runtime* overhead applies only to the interactive parts, while the *download* is unchanged. If the page has no interactive part at all, `interactive: 'none'` is strictly better — it ships no JavaScript.
|
|
1680
1690
|
|
|
1681
1691
|
## Writing an island
|
|
1682
1692
|
|
|
@@ -1750,17 +1760,29 @@ Each island declares WHEN it hydrates via the `hydrate` option (default `'visibl
|
|
|
1750
1760
|
|
|
1751
1761
|
Mix freely inside one page: a `load` search box, a `visible` comment widget, and a `never` build banner can all coexist.
|
|
1752
1762
|
|
|
1753
|
-
##
|
|
1763
|
+
## What each mode actually costs
|
|
1754
1764
|
|
|
1755
|
-
|
|
1765
|
+
Measured on the framework's reference web fixture — the same page, three values of `interactive`, first-load JavaScript read out of the page's own built HTML (entry script + every `modulepreload`) and gzipped:
|
|
1756
1766
|
|
|
1757
|
-
| Mode | JS shipped |
|
|
1758
|
-
|
|
1759
|
-
| `interactive: 'full'` |
|
|
1760
|
-
| `interactive: 'islands'` |
|
|
1761
|
-
| `interactive: 'none'` |
|
|
1767
|
+
| Mode | JS shipped | Hydration |
|
|
1768
|
+
|---|---|---|
|
|
1769
|
+
| `interactive: 'full'` | 195,229 B gz | The whole page tree |
|
|
1770
|
+
| `interactive: 'islands'` | 195,231 B gz | Only the marked islands, each on its own strategy |
|
|
1771
|
+
| `interactive: 'none'` | 0 B — every module script and modulepreload is stripped from the HTML | None |
|
|
1772
|
+
|
|
1773
|
+
Two things to take from that table. **`islands` is not a download optimisation** — it is level with `full` to within two bytes, and the numbers above are the whole story, not a "before we finish the work" snapshot. And **`none` is the one that removes bytes**, because it is the only mode that removes the script tags.
|
|
1774
|
+
|
|
1775
|
+
The floor those first two numbers sit on is the framework's browser runtime — React plus the Effect-based RPC client — and it is pinned in CI so it cannot drift silently. Reproduce it yourself:
|
|
1776
|
+
|
|
1777
|
+
```sh
|
|
1778
|
+
node packages/web/scripts/bundle-budget.mjs
|
|
1779
|
+
```
|
|
1780
|
+
|
|
1781
|
+
## Making islands reduce bytes too
|
|
1762
1782
|
|
|
1763
|
-
|
|
1783
|
+
It is a real gap, and it is a build-pipeline change rather than a runtime one: the browser entry would have to be emitted *per page*, so an islands page's entry imports the island runtime and its own islands instead of the whole app. Nothing in the page's own code can shortcut it — the bytes are pulled in above `mount()`, by the entry that imports it.
|
|
1784
|
+
|
|
1785
|
+
Until then, if download size is what you are optimising, reach for `interactive: 'none'`.
|
|
1764
1786
|
|
|
1765
1787
|
## Island boundaries
|
|
1766
1788
|
|
|
@@ -1816,17 +1838,13 @@ If you need to pass a function reference, define it INSIDE the island.
|
|
|
1816
1838
|
|
|
1817
1839
|
## Inspecting
|
|
1818
1840
|
|
|
1819
|
-
|
|
1841
|
+
Each `*.island.tsx` becomes its own chunk, so `.framework/dist/assets/` carries an `island-<Name>-<hash>.js` per island alongside the app chunks. Listing that directory is the whole report:
|
|
1820
1842
|
|
|
1821
|
-
```
|
|
1822
|
-
|
|
1823
|
-
chunks emitted:
|
|
1824
|
-
main.abc.js 145 KB ← page runtime (full pages only)
|
|
1825
|
-
island-LikeButton.def.js 3.4 KB ← per-island bundle
|
|
1826
|
-
island-Search.ghi.js 8.1 KB
|
|
1843
|
+
```sh
|
|
1844
|
+
ls -l .framework/dist/assets
|
|
1827
1845
|
```
|
|
1828
1846
|
|
|
1829
|
-
|
|
1847
|
+
Per-island chunks are cached independently across deploys and fetched in parallel — but note they are *additional* files reachable from the app bundle, not a replacement for it. See the mode table above for what actually reaches the browser.
|
|
1830
1848
|
|
|
1831
1849
|
## Anti-patterns
|
|
1832
1850
|
|
|
@@ -355,6 +355,16 @@ replica C ─┘ └─ PK conflict → stands down (no
|
|
|
355
355
|
|
|
356
356
|
Losers don't write a run row — at scale that would be N−1 noise rows per firing. Only the winner's run appears in the dashboard, tagged `wonLock`.
|
|
357
357
|
|
|
358
|
+
**If your app registers its own bound for a framework table, yours wins.** `registerRetention({ table, timeColumn, ttlMs })` from a startup outranks the framework's default for the same table — app > plugin > framework, and `source` defaults to `'app'` so you do not have to pass anything. A real disagreement is reported at boot, on the line beside the policy that survived:
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
! _voltro_schedule_claims: two registrations — kept the app's 1h,
|
|
362
|
+
dropped the framework's 24h. An app registration wins over a plugin's,
|
|
363
|
+
and a plugin's over a framework default.
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Through 0.32.0 this was a silent last-write-wins: a consumer's 1-hour bound was replaced one second later by the framework's default, their startup went on logging `bounded to 1h` at every boot, and they found it by counting rows. Note the direction — the loser is chosen by WHO registered, not by which TTL is narrower. "Narrower wins" would let a framework default we tighten in a later release silently start deleting your data faster than you asked for.
|
|
367
|
+
|
|
358
368
|
## `cluster`
|
|
359
369
|
|
|
360
370
|
If you already run `@effect/cluster` (for [workflows](/docs/workflows/cluster)), schedules can ride the same sharding fabric. Each schedule becomes a `ClusterCron` singleton; the cluster assigns it to exactly one shard owner, and only that runner fires. The in-app `self` timer is **not** armed in this mode — the cluster owns the clock, so arming it too would double-fire.
|
|
@@ -583,8 +583,23 @@ stack lives on the server, it survives a page reload.
|
|
|
583
583
|
Capture has a per-mutation cost (a read-before-write on update/delete + a
|
|
584
584
|
log-row insert), so it's **on outside production, off in production** by default;
|
|
585
585
|
set `VOLTRO_UNDO=on|off` to override (the same environment-aware default the
|
|
586
|
-
durable trace persistence uses). When off,
|
|
587
|
-
|
|
586
|
+
durable trace persistence uses). When capture is off, `_voltro_undo_log` isn't
|
|
587
|
+
created and nothing is recorded.
|
|
588
|
+
|
|
589
|
+
**The WIRE SURFACE is a separate question, and it reads only the explicit
|
|
590
|
+
declaration.** The three `__voltro.undo.*` procedures are generated into the
|
|
591
|
+
client's rpc group and bound on the server unless `VOLTRO_UNDO=off` — regardless
|
|
592
|
+
of `NODE_ENV`. The reason is that `rpcGroup.generated.ts` is written by `voltro
|
|
593
|
+
dev` and `voltro build` never regenerates it: an environment-derived answer baked
|
|
594
|
+
there is the developer machine's answer shipped to a production process that
|
|
595
|
+
binds none of it, and the failure appears only when someone presses undo after a
|
|
596
|
+
deploy.
|
|
597
|
+
|
|
598
|
+
So with capture off, the procedures exist and answer honestly rather than 404:
|
|
599
|
+
`useUndoLog` returns an empty list (nothing was captured) and apply/redo answer
|
|
600
|
+
`UndoNotFound`. Both boot paths log a line at startup saying so, so a
|
|
601
|
+
permanently empty undo list is not a mystery. `VOLTRO_UNDO=off` removes the
|
|
602
|
+
procedures from the server AND from the client bundle.
|
|
588
603
|
|
|
589
604
|
## Boundaries
|
|
590
605
|
|
|
@@ -887,17 +902,18 @@ The manifest carries:
|
|
|
887
902
|
|
|
888
903
|
| Field | Contents |
|
|
889
904
|
|---|---|
|
|
890
|
-
| `procedures` | Every procedure's `tag`, `kind`, `input`/`output` Schema,
|
|
891
|
-
| `tables` | The user tables — `name`, `columns` (`type`, `nullable`, `refersTo`, `enum
|
|
905
|
+
| `procedures` | Every procedure's `tag`, `kind`, `input`/`output` Schema, the `source` table a query reads, the `targets` (`{ table, op }`) a mutation writes, and the `guards` it declares. |
|
|
906
|
+
| `tables` | The user tables — `name`, `columns` (`type`, `nullable`, `refersTo`, `enum`, and the three exposure axes), `pkColumn`, `editable`, and whether the table is `reactive`. Framework `_voltro_*` tables are flagged `framework`. |
|
|
892
907
|
| `workflows` | The discovered workflow names. |
|
|
893
908
|
| `widgets` | The registered widget ids. |
|
|
909
|
+
| `scopes` | Every scope the installed plugins declare. Empty means "not declared" — never "no scopes exist". |
|
|
894
910
|
| `version` | The manifest format version. |
|
|
895
911
|
|
|
896
912
|
## Deriving an admin surface
|
|
897
913
|
|
|
898
914
|
`deriveEntityAdmins(manifest)` is the pure projection the [admin
|
|
899
915
|
template](/docs/templates/admin) is built on. It joins each user table to the
|
|
900
|
-
procedures that read and write it, so a
|
|
916
|
+
procedures that read and write it, so a back-office binds to tags that
|
|
901
917
|
**actually exist** instead of guessing them from a naming convention:
|
|
902
918
|
|
|
903
919
|
```tsx
|
|
@@ -905,15 +921,71 @@ import { useCapabilityManifest, deriveEntityAdmins } from '@voltro/client'
|
|
|
905
921
|
|
|
906
922
|
const { manifest } = useCapabilityManifest('app')
|
|
907
923
|
const entities = manifest ? deriveEntityAdmins(manifest) : []
|
|
908
|
-
// each: { table, columns,
|
|
909
|
-
//
|
|
924
|
+
// each: { table, columns, serverOnlyColumns, sensitiveColumns, reactive,
|
|
925
|
+
// pkColumn?, editable,
|
|
926
|
+
// list, create, update, delete } // each an { tag?, guards? }
|
|
910
927
|
```
|
|
911
928
|
|
|
912
|
-
|
|
913
|
-
that affordance read-only rather than binding to a tag that
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
929
|
+
An action's `tag` is `undefined` when the app exposes no procedure for that
|
|
930
|
+
operation — render that affordance read-only rather than binding to a tag that
|
|
931
|
+
does not resolve.
|
|
932
|
+
|
|
933
|
+
### Why derive at runtime instead of generating an admin
|
|
934
|
+
|
|
935
|
+
A generated back-office snapshots the answer at codegen time. The moment you edit
|
|
936
|
+
`guards:` on a mutation the generated gate is stale — and stale in the silent
|
|
937
|
+
direction: it renders a control the server now refuses, or hides one that would
|
|
938
|
+
work. The manifest is served by the **running** app, so a derived surface cannot
|
|
939
|
+
drift from it. Customisation is not the tradeoff it looks like: the derived spec
|
|
940
|
+
is plain data, and the component that maps over it is your own template code.
|
|
941
|
+
|
|
942
|
+
## Gating on the access the api declares
|
|
943
|
+
|
|
944
|
+
Each action carries `guards` — the procedure's own `guards:` / `openAccess:`
|
|
945
|
+
declaration, the same data the server enforces. `useAccessDecision` turns it into
|
|
946
|
+
a decision against the scopes you fed
|
|
947
|
+
[`<PermissionProvider>`](/docs/ui/client-utilities/use-can):
|
|
948
|
+
|
|
949
|
+
```tsx
|
|
950
|
+
import { useAccessDecision, requiredScopes } from '@voltro/client'
|
|
951
|
+
|
|
952
|
+
const decision = useAccessDecision(entity.create.guards) // 'allowed' | 'denied' | 'unknown'
|
|
953
|
+
{entity.create.tag && decision !== 'denied' ? <AutoForm … /> : null}
|
|
954
|
+
{decision === 'denied' ? <p>Requires {requiredScopes(entity.create.guards).join(', ')}</p> : null}
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
**The decision is three-valued, and `unknown` is the important one.** A guard that
|
|
958
|
+
carries a `resource` extractor is answered per **row** by the server, and a browser
|
|
959
|
+
holding only the subject's global scopes cannot pre-compute it. Both ways of
|
|
960
|
+
collapsing that gap are bugs:
|
|
961
|
+
|
|
962
|
+
| Collapse | What ships |
|
|
963
|
+
|---|---|
|
|
964
|
+
| `unknown` → `denied` | Every affordance disappears for callers whose authority is per-resource — the multi-tenant case, where subjects are minted with no global scopes. A total outage wearing a permission check's clothes. |
|
|
965
|
+
| `unknown` → `allowed` | A control that always errors. |
|
|
966
|
+
|
|
967
|
+
So show it and let the server answer: it is the authorization boundary, and it
|
|
968
|
+
replies with a typed `ScopeError`. `decideAccess(guards, scopes)` is the pure form
|
|
969
|
+
if you need it outside React.
|
|
970
|
+
|
|
971
|
+
`guards: undefined` means the procedure declared **neither** `guards:` nor
|
|
972
|
+
`openAccess:` — undecided, not open. That is refused outright under
|
|
973
|
+
`security.defaultDeny`, so it is reported as `unknown` rather than guessed.
|
|
974
|
+
|
|
975
|
+
## The three exposure axes in a derived UI
|
|
976
|
+
|
|
977
|
+
The manifest's columns carry all three schema markers, and they are **orthogonal** —
|
|
978
|
+
`deriveEntityAdmins` treats each one differently, and so must you:
|
|
979
|
+
|
|
980
|
+
| Marker | What it says | What the admin does |
|
|
981
|
+
|---|---|---|
|
|
982
|
+
| `.serverOnly()` | Never crosses **any** wire; the runtime refuses a mutation input that sets it | **Excluded** from `columns`; listed in `serverOnlyColumns` so the UI can say why it is absent |
|
|
983
|
+
| `.encrypted()` | Ciphertext **at rest** | **Kept.** Your procedures read it decrypted — hiding it is a category error |
|
|
984
|
+
| `.sensitive(class)` | Personal data; the **export**-masking axis | **Kept**, and listed in `sensitiveColumns` so a bulk export masks it |
|
|
985
|
+
|
|
986
|
+
`pkColumn` is the column row-keyed actions must target — do not hard-code `id`. When
|
|
987
|
+
a table has no single primary key, `editable` is `false` and no row can be addressed
|
|
988
|
+
for update or delete.
|
|
917
989
|
|
|
918
990
|
The manifest GET is bearer-gated wherever it runs — `/_voltro/inspect/*` is
|
|
919
991
|
fail-closed, so no configured `VOLTRO_INSPECT_TOKEN` means `401`, not "everyone".
|
|
@@ -1088,6 +1160,14 @@ middleware again and resolves the new subject.
|
|
|
1088
1160
|
Optimistic patches survive the refresh: they are tied to mutation lifecycles, not
|
|
1089
1161
|
subscription lifecycles, and the new snapshots land underneath them.
|
|
1090
1162
|
|
|
1163
|
+
The **data does not** — each entry's rows are cleared and the components go back
|
|
1164
|
+
to `loading` until their new snapshot arrives. That is deliberate: the whole
|
|
1165
|
+
reason to call this is that the identity changed, and the new subject may be
|
|
1166
|
+
entitled to strictly less than the old one. It is the same boundary that stops a
|
|
1167
|
+
[reconnect](/docs/data/subscriptions#reconnect) from seeding across a
|
|
1168
|
+
`useReconnect()` — a dropped connection keeps your screen, a change of identity
|
|
1169
|
+
clears it.
|
|
1170
|
+
|
|
1091
1171
|
This is not a cache-invalidation tool. Subscriptions are already live, so a
|
|
1092
1172
|
normal write needs no refresh — reach for this only when the *connection's
|
|
1093
1173
|
identity* changed underneath them.
|