@velora-cms/server 0.11.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/LICENSE +202 -0
- package/README.md +65 -0
- package/dist/admin-bundle/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js_commonjs-proxy-Ng0fOpdU.js +1 -0
- package/dist/admin-bundle/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom__loadShare__.js_commonjs-proxy-oc1i_iBU.js +9 -0
- package/dist/admin-bundle/assets/_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DOKdWYyj.js +1 -0
- package/dist/admin-bundle/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare___mf_0_velora_mf_2_cms_mf_1_plugin_mf_2_sdk__loadShare__.js-C1-ZAxwO.js +2 -0
- package/dist/admin-bundle/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js-BuUBskgj.js +9 -0
- package/dist/admin-bundle/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DMaku-HC.js +9 -0
- package/dist/admin-bundle/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom__loadShare__.js-DYfqn12F.js +1 -0
- package/dist/admin-bundle/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-BPoj3DC9.js +25 -0
- package/dist/admin-bundle/assets/content-trash.schema-DfXHkC-w.js +72 -0
- package/dist/admin-bundle/assets/hostInit--C4xK6nj.js +1 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-400-normal-CyU-ddYS.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-400-normal-EA1o-u_Q.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-500-normal-C4MQITzh.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-500-normal-DPXcppbm.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-600-normal-0pRdybE_.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-600-normal-MJZ0liF5.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-400-normal-Bo5KPYvw.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-400-normal-CFZh1unN.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-500-normal-BletK1Hp.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-500-normal-Cd6jVIg7.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-600-normal-Dk5eISD_.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-600-normal-KrqB56Mw.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-400-normal-BeVLg08x.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-400-normal-BpLfq-63.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-500-normal-Ck_W4G78.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-500-normal-eJxPnL1P.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-600-normal-DT29Q8HW.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-600-normal-DjDAeNQD.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-400-normal-BTotfTJu.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-400-normal-DZqxrq2p.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-500-normal-ByOcLdNv.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-500-normal-CocWQlwt.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-600-normal-71GNu3SW.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-600-normal-BGq0mW3O.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-400-normal-Dsrv2Tcn.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-400-normal-g30qAdWV.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-500-normal-Cs5J6C77.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-500-normal-DB5PtV2g.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-600-normal-Bz0x94Yp.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-600-normal-DUMzJB7m.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-greek-400-normal-D9ESIMu3.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-greek-400-normal-_efipK4i.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-greek-500-normal-CuWXN6rf.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-greek-500-normal-JMMifIXV.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-greek-600-normal-D-CqTdkO.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-greek-600-normal-DzTrcv_p.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-400-normal-C5H60-Va.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-400-normal-RBey6euL.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-500-normal-D0aIdm-b.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-500-normal-DakdToA3.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-600-normal-DIrixKbi.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-600-normal-DOrvGEcy.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-400-normal-DG4YqDda.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-400-normal-fK1oJ5dG.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-500-normal-BEb3_waV.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-500-normal-e4dixQRQ.woff2 +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-600-normal-DgdngZtN.woff +0 -0
- package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-600-normal-DpPYBSTl.woff2 +0 -0
- package/dist/admin-bundle/assets/index-BIAF0ShP.js +542 -0
- package/dist/admin-bundle/assets/index-DhMY-0sC.js +148 -0
- package/dist/admin-bundle/assets/index-DnZV_gsg.css +1 -0
- package/dist/admin-bundle/assets/index-Do71v6NZ.js +7 -0
- package/dist/admin-bundle/assets/literata-cyrillic-ext-opsz-italic-5yUt4G_9.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-cyrillic-ext-opsz-normal-C5tfwALZ.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-cyrillic-opsz-italic-Bj0ndbyp.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-cyrillic-opsz-normal-DgmypKXX.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-greek-ext-opsz-italic-DFpO5j-Z.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-greek-ext-opsz-normal-DGm64vGR.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-greek-opsz-italic-CHERNRFq.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-greek-opsz-normal-DFglUmAd.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-latin-ext-opsz-italic-4y8iAqqs.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-latin-ext-opsz-normal-STiTPs0F.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-latin-opsz-italic-CJ93D38p.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-latin-opsz-normal-BHZsWIlc.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-vietnamese-opsz-italic-BdcrZMcO.woff2 +0 -0
- package/dist/admin-bundle/assets/literata-vietnamese-opsz-normal-Gqw5JQlq.woff2 +0 -0
- package/dist/admin-bundle/assets/mf-entry-bootstrap-0-aef015cd.js +41 -0
- package/dist/admin-bundle/assets/remoteEntry-CNyN68bc.js +14 -0
- package/dist/admin-bundle/assets/virtualExposes-BDCSo5OS.js +1 -0
- package/dist/admin-bundle/assets/vite-preload-helper-Cgledu0r.js +1 -0
- package/dist/admin-bundle/index.html +16 -0
- package/dist/app.d.ts +8 -0
- package/dist/app.js +252 -0
- package/dist/auth/api-content-author.d.ts +2 -0
- package/dist/auth/api-content-author.js +27 -0
- package/dist/auth/api-keys.d.ts +7 -0
- package/dist/auth/api-keys.js +85 -0
- package/dist/auth/jwt-payload.d.ts +16 -0
- package/dist/auth/jwt-payload.js +1 -0
- package/dist/auth/preview-tokens.d.ts +7 -0
- package/dist/auth/preview-tokens.js +76 -0
- package/dist/auth/rate-limit.d.ts +16 -0
- package/dist/auth/rate-limit.js +283 -0
- package/dist/auth/require-auth.d.ts +4 -0
- package/dist/auth/require-auth.js +28 -0
- package/dist/auth/route-rate-limits.d.ts +31 -0
- package/dist/auth/route-rate-limits.js +155 -0
- package/dist/auth/tokens.d.ts +15 -0
- package/dist/auth/tokens.js +38 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +6 -0
- package/dist/boot/core-migration-gate.d.ts +12 -0
- package/dist/boot/core-migration-gate.js +52 -0
- package/dist/boot/resolve-boot-mode.d.ts +6 -0
- package/dist/boot/resolve-boot-mode.js +206 -0
- package/dist/bundled-templates/com.velora.blog/manifest.json +39 -0
- package/dist/bundled-templates/com.velora.blog/package.tar.gz +0 -0
- package/dist/bundled-templates/com.velora.blog/sample-content.json +14 -0
- package/dist/config/admin-ui.d.ts +1 -0
- package/dist/config/admin-ui.js +10 -0
- package/dist/config/cors.d.ts +7 -0
- package/dist/config/cors.js +53 -0
- package/dist/config/env-file-path.d.ts +2 -0
- package/dist/config/env-file-path.js +22 -0
- package/dist/config/graphql-limits.d.ts +2 -0
- package/dist/config/graphql-limits.js +26 -0
- package/dist/config/headless.d.ts +1 -0
- package/dist/config/headless.js +8 -0
- package/dist/config/license-revalidation.d.ts +2 -0
- package/dist/config/license-revalidation.js +16 -0
- package/dist/config/load-env.d.ts +1 -0
- package/dist/config/load-env.js +53 -0
- package/dist/config/marketplace.d.ts +11 -0
- package/dist/config/marketplace.js +19 -0
- package/dist/config/preview.d.ts +3 -0
- package/dist/config/preview.js +39 -0
- package/dist/config/public-docs.d.ts +1 -0
- package/dist/config/public-docs.js +9 -0
- package/dist/config/site.d.ts +7 -0
- package/dist/config/site.js +12 -0
- package/dist/config/trust-proxy.d.ts +2 -0
- package/dist/config/trust-proxy.js +42 -0
- package/dist/data-types/validate-data-type-settings.d.ts +1 -0
- package/dist/data-types/validate-data-type-settings.js +33 -0
- package/dist/db/content-db.d.ts +16 -0
- package/dist/db/content-db.js +109 -0
- package/dist/db/core-migrations/index.d.ts +14 -0
- package/dist/db/core-migrations/index.js +184 -0
- package/dist/db/core-migrations/steps.d.ts +4 -0
- package/dist/db/core-migrations/steps.js +66 -0
- package/dist/db/load-prisma-client.d.ts +2 -0
- package/dist/db/load-prisma-client.js +44 -0
- package/dist/db/prisma.d.ts +3 -0
- package/dist/db/prisma.js +67 -0
- package/dist/db/resolve-client-dir.d.ts +2 -0
- package/dist/db/resolve-client-dir.js +83 -0
- package/dist/docs/filter-public-api-spec.d.ts +2 -0
- package/dist/docs/filter-public-api-spec.js +52 -0
- package/dist/docs-bundle/404.html +41 -0
- package/dist/docs-bundle/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js +1 -0
- package/dist/docs-bundle/_astro/Search.astro_astro_type_script_index_0_lang.CavldbAs.js +1 -0
- package/dist/docs-bundle/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js +1 -0
- package/dist/docs-bundle/_astro/common.DTXA7sXM.css +3 -0
- package/dist/docs-bundle/_astro/ec.0vx5m.js +3 -0
- package/dist/docs-bundle/_astro/ec.w36nc.css +1 -0
- package/dist/docs-bundle/_astro/page.Dwipeu-R.js +1 -0
- package/dist/docs-bundle/_astro/print.ehPL0gv-.css +1 -0
- package/dist/docs-bundle/_astro/starlight-toc.CTCQXEge.js +1 -0
- package/dist/docs-bundle/_astro/ui-core.D-7Scnhs.js +2 -0
- package/dist/docs-bundle/favicon.svg +1 -0
- package/dist/docs-bundle/index.html +1 -0
- package/dist/docs-bundle/pagefind/fragment/en_18a36d7.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_1d9eb24.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_1ef320c.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_3099406.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_4a5b6fe.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_9aa652e.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_baccdf6.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_d81f3fe.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_d855550.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_e6d88d8.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_e9d3189.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/index/en_5feeed7.pf_index +0 -0
- package/dist/docs-bundle/pagefind/index/en_c6981f9.pf_index +0 -0
- package/dist/docs-bundle/pagefind/index/en_ce4f6bf.pf_index +0 -0
- package/dist/docs-bundle/pagefind/pagefind-component-ui.css +1509 -0
- package/dist/docs-bundle/pagefind/pagefind-component-ui.js +56 -0
- package/dist/docs-bundle/pagefind/pagefind-entry.json +1 -0
- package/dist/docs-bundle/pagefind/pagefind-highlight.js +1070 -0
- package/dist/docs-bundle/pagefind/pagefind-modular-ui.css +214 -0
- package/dist/docs-bundle/pagefind/pagefind-modular-ui.js +8 -0
- package/dist/docs-bundle/pagefind/pagefind-ui.css +1 -0
- package/dist/docs-bundle/pagefind/pagefind-ui.js +2 -0
- package/dist/docs-bundle/pagefind/pagefind-worker.js +6 -0
- package/dist/docs-bundle/pagefind/pagefind.en_1e94abd852.pf_meta +0 -0
- package/dist/docs-bundle/pagefind/pagefind.js +6 -0
- package/dist/docs-bundle/pagefind/wasm.en.pagefind +0 -0
- package/dist/docs-bundle/pagefind/wasm.unknown.pagefind +0 -0
- package/dist/docs-bundle/v1/index.html +86 -0
- package/dist/docs-bundle/v1/using-velora/build-a-headless-frontend/index.html +413 -0
- package/dist/docs-bundle/v1/using-velora/content-model/index.html +858 -0
- package/dist/docs-bundle/v1/using-velora/editing/index.html +748 -0
- package/dist/docs-bundle/v1/using-velora/getting-started/index.html +588 -0
- package/dist/docs-bundle/v1/using-velora/headless-api/index.html +1620 -0
- package/dist/docs-bundle/v1/using-velora/index.html +215 -0
- package/dist/docs-bundle/v1/using-velora/installation/index.html +886 -0
- package/dist/docs-bundle/v1/using-velora/installing-plugins/index.html +836 -0
- package/dist/docs-bundle/v1/using-velora/media/index.html +468 -0
- package/dist/docs-bundle/v1/using-velora/users-and-roles/index.html +561 -0
- package/dist/graphql/field-count-rule.d.ts +5 -0
- package/dist/graphql/field-count-rule.js +59 -0
- package/dist/graphql/schema.d.ts +12 -0
- package/dist/graphql/schema.js +330 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +180 -0
- package/dist/lib.d.ts +2 -0
- package/dist/lib.js +39 -0
- package/dist/marketplace/install-bundle-members.d.ts +33 -0
- package/dist/marketplace/install-bundle-members.js +137 -0
- package/dist/marketplace/install-from-marketplace.d.ts +60 -0
- package/dist/marketplace/install-from-marketplace.js +581 -0
- package/dist/marketplace/license-revalidation-job.d.ts +38 -0
- package/dist/marketplace/license-revalidation-job.js +139 -0
- package/dist/marketplace/marketplace-client.d.ts +43 -0
- package/dist/marketplace/marketplace-client.js +228 -0
- package/dist/marketplace/revalidate-license.d.ts +39 -0
- package/dist/marketplace/revalidate-license.js +103 -0
- package/dist/media/media-service.d.ts +36 -0
- package/dist/media/media-service.js +162 -0
- package/dist/plugins/boot-plugin-loader.d.ts +32 -0
- package/dist/plugins/boot-plugin-loader.js +57 -0
- package/dist/plugins/hook-dispatcher.d.ts +13 -0
- package/dist/plugins/hook-dispatcher.js +68 -0
- package/dist/plugins/install-built-package.d.ts +36 -0
- package/dist/plugins/install-built-package.js +199 -0
- package/dist/plugins/install-package-tarball.d.ts +25 -0
- package/dist/plugins/install-package-tarball.js +73 -0
- package/dist/plugins/plugin-context.d.ts +5 -0
- package/dist/plugins/plugin-context.js +26 -0
- package/dist/plugins/plugin-package-store.d.ts +31 -0
- package/dist/plugins/plugin-package-store.js +64 -0
- package/dist/plugins/plugin-registry-service.d.ts +227 -0
- package/dist/plugins/plugin-registry-service.js +636 -0
- package/dist/plugins/seed-template-content.d.ts +23 -0
- package/dist/plugins/seed-template-content.js +198 -0
- package/dist/plugins/server-serializers.d.ts +3 -0
- package/dist/plugins/server-serializers.js +16 -0
- package/dist/plugins/simple-storage-api.d.ts +9 -0
- package/dist/plugins/simple-storage-api.js +26 -0
- package/dist/plugins/snapshot-groups.d.ts +16 -0
- package/dist/plugins/snapshot-groups.js +81 -0
- package/dist/plugins/structured-query-builder.d.ts +21 -0
- package/dist/plugins/structured-query-builder.js +60 -0
- package/dist/plugins/structured-snapshot-service.d.ts +16 -0
- package/dist/plugins/structured-snapshot-service.js +286 -0
- package/dist/plugins/structured-storage-api.d.ts +22 -0
- package/dist/plugins/structured-storage-api.js +91 -0
- package/dist/plugins/structured-storage-transaction.d.ts +22 -0
- package/dist/plugins/structured-storage-transaction.js +63 -0
- package/dist/plugins/structured-table-naming.d.ts +1 -0
- package/dist/plugins/structured-table-naming.js +18 -0
- package/dist/plugins/trusted-keys.d.ts +11 -0
- package/dist/plugins/trusted-keys.js +67 -0
- package/dist/plugins/trusted-signing-keys.d.ts +27 -0
- package/dist/plugins/trusted-signing-keys.js +40 -0
- package/dist/plugins/uninstall-bundle.d.ts +29 -0
- package/dist/plugins/uninstall-bundle.js +150 -0
- package/dist/plugins/verify-package.d.ts +36 -0
- package/dist/plugins/verify-package.js +121 -0
- package/dist/routes/admin-static.d.ts +8 -0
- package/dist/routes/admin-static.js +196 -0
- package/dist/routes/api-keys.d.ts +2 -0
- package/dist/routes/api-keys.js +95 -0
- package/dist/routes/api-playground.d.ts +2 -0
- package/dist/routes/api-playground.js +21 -0
- package/dist/routes/auth.d.ts +2 -0
- package/dist/routes/auth.js +102 -0
- package/dist/routes/content.d.ts +3 -0
- package/dist/routes/content.js +471 -0
- package/dist/routes/data-types.d.ts +3 -0
- package/dist/routes/data-types.js +100 -0
- package/dist/routes/docs-static.d.ts +8 -0
- package/dist/routes/docs-static.js +137 -0
- package/dist/routes/document-types.d.ts +3 -0
- package/dist/routes/document-types.js +149 -0
- package/dist/routes/headless-bridge.d.ts +10 -0
- package/dist/routes/headless-bridge.js +207 -0
- package/dist/routes/health.d.ts +2 -0
- package/dist/routes/health.js +15 -0
- package/dist/routes/marketplace-proxy.d.ts +8 -0
- package/dist/routes/marketplace-proxy.js +135 -0
- package/dist/routes/media.d.ts +6 -0
- package/dist/routes/media.js +93 -0
- package/dist/routes/plugin-api-routes.d.ts +12 -0
- package/dist/routes/plugin-api-routes.js +224 -0
- package/dist/routes/plugin-assets.d.ts +8 -0
- package/dist/routes/plugin-assets.js +51 -0
- package/dist/routes/plugin-management.d.ts +7 -0
- package/dist/routes/plugin-management.js +525 -0
- package/dist/routes/plugin-storage.d.ts +8 -0
- package/dist/routes/plugin-storage.js +104 -0
- package/dist/routes/plugins.d.ts +2 -0
- package/dist/routes/plugins.js +36 -0
- package/dist/routes/public-api.d.ts +9 -0
- package/dist/routes/public-api.js +545 -0
- package/dist/routes/published-item.d.ts +57 -0
- package/dist/routes/published-item.js +236 -0
- package/dist/routes/setup.d.ts +9 -0
- package/dist/routes/setup.js +477 -0
- package/dist/routes/snapshots.d.ts +3 -0
- package/dist/routes/snapshots.js +65 -0
- package/dist/routes/templates.d.ts +3 -0
- package/dist/routes/templates.js +37 -0
- package/dist/routes/themes.d.ts +2 -0
- package/dist/routes/themes.js +30 -0
- package/dist/routes/users.d.ts +2 -0
- package/dist/routes/users.js +113 -0
- package/dist/sandbox/register-local-plugin.d.ts +36 -0
- package/dist/sandbox/register-local-plugin.js +108 -0
- package/dist/sandbox/seed-sandbox.d.ts +20 -0
- package/dist/sandbox/seed-sandbox.js +122 -0
- package/dist/scripts/copy-admin-bundle.d.ts +1 -0
- package/dist/scripts/copy-admin-bundle.js +24 -0
- package/dist/scripts/copy-docs-bundle.d.ts +1 -0
- package/dist/scripts/copy-docs-bundle.js +22 -0
- package/dist/scripts/create-api-key.d.ts +5 -0
- package/dist/scripts/create-api-key.js +56 -0
- package/dist/scripts/generate-prisma-clients.d.ts +6 -0
- package/dist/scripts/generate-prisma-clients.js +125 -0
- package/dist/scripts/pack-bundled-templates.d.ts +1 -0
- package/dist/scripts/pack-bundled-templates.js +87 -0
- package/dist/setup/build-connection-string.d.ts +19 -0
- package/dist/setup/build-connection-string.js +14 -0
- package/dist/setup/bundled-templates.d.ts +19 -0
- package/dist/setup/bundled-templates.js +121 -0
- package/dist/setup/ensure-prisma-client.d.ts +3 -0
- package/dist/setup/ensure-prisma-client.js +23 -0
- package/dist/setup/install-starter.d.ts +14 -0
- package/dist/setup/install-starter.js +76 -0
- package/dist/setup/normalize-database-url.d.ts +2 -0
- package/dist/setup/normalize-database-url.js +35 -0
- package/dist/setup/persist-env-config.d.ts +2 -0
- package/dist/setup/persist-env-config.js +63 -0
- package/dist/setup/provision-database.d.ts +2 -0
- package/dist/setup/provision-database.js +89 -0
- package/dist/setup-app.d.ts +4 -0
- package/dist/setup-app.js +43 -0
- package/package.json +96 -0
- package/prisma/schema.prisma +303 -0
|
@@ -0,0 +1,886 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en" dir="ltr" data-theme="dark" data-has-toc data-has-sidebar class="astro-ewhz5xxr"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>Installation | Velora</title><link rel="shortcut icon" href="/docs/favicon.svg" type="image/svg+xml"/><meta name="generator" content="Astro v7.2.10"/><meta name="generator" content="Starlight v0.41.5"/><meta property="og:title" content="Installation"/><meta property="og:type" content="article"/><meta property="og:locale" content="en"/><meta property="og:description" content="Set up a Velora instance with the setup wizard, and choose a database."/><meta property="og:site_name" content="Velora"/><meta name="twitter:card" content="summary_large_image"/><meta name="description" content="Set up a Velora instance with the setup wizard, and choose a database."/><script>
|
|
2
|
+
window.StarlightThemeProvider = (() => {
|
|
3
|
+
const storedTheme =
|
|
4
|
+
typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
|
|
5
|
+
const theme =
|
|
6
|
+
storedTheme ||
|
|
7
|
+
(window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
|
|
8
|
+
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
|
|
9
|
+
return {
|
|
10
|
+
updatePickers(theme = storedTheme || 'auto') {
|
|
11
|
+
document.querySelectorAll('starlight-theme-select').forEach((picker) => {
|
|
12
|
+
const select = picker.querySelector('select');
|
|
13
|
+
if (select) select.value = theme;
|
|
14
|
+
/** @type {HTMLTemplateElement | null} */
|
|
15
|
+
const tmpl = document.querySelector(`#theme-icons`);
|
|
16
|
+
const newIcon = tmpl && tmpl.content.querySelector('.' + theme);
|
|
17
|
+
if (newIcon) {
|
|
18
|
+
const oldIcon = picker.querySelector('svg.label-icon');
|
|
19
|
+
if (oldIcon) {
|
|
20
|
+
oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
})();
|
|
27
|
+
</script><template id="theme-icons"><svg aria-hidden="true" class="light astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm.64 5-.71.71a1 1 0 0 0 0 1.41 1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM12 5a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1Zm5.66 2.34a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.66.71a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.29Zm-12-.29a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.71-.71a1.004 1.004 0 1 0-1.43 1.41l.73.71ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-2.64 6A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.76-.66ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Zm0 3.5a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Z"/></svg><svg aria-hidden="true" class="dark astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.64 13a1 1 0 0 0-1.05-.14 8.049 8.049 0 0 1-3.37.73 8.15 8.15 0 0 1-8.14-8.1 8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69 1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14 9.784 9.784 0 0 0 2.1-.22 8.11 8.11 0 0 1-7.18 4.32v-.04Z"/></svg><svg aria-hidden="true" class="auto astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg></template><link rel="stylesheet" href="/docs/_astro/print.ehPL0gv-.css" media="print"><link rel="stylesheet" href="/docs/_astro/common.DTXA7sXM.css"><script type="module" src="/docs/_astro/page.Dwipeu-R.js"></script></head><body class="astro-ewhz5xxr"><a class="sl-skip-link astro-zufphfvp" href="#_top">Skip to content</a><div class="page sl-flex astro-5auw3bkx"><header class="header astro-5auw3bkx"><div class="header astro-6ytusalw"><div class="title-wrapper sl-flex astro-6ytusalw"><a href="/docs/" class="site-title sl-flex astro-nu4hftpf"><span class="astro-nu4hftpf" translate="no">Velora</span></a></div><div class="sl-flex print:hidden astro-6ytusalw"><site-search class="astro-6ytusalw astro-zwj6qr56" data-translations="{"placeholder":"Search"}"><button data-open-modal disabled aria-label="Search" aria-keyshortcuts="Control+K" class="astro-zwj6qr56"><svg aria-hidden="true" class="astro-zwj6qr56 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.71 20.29 18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.39ZM11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z"/></svg><span class="sl-hidden md:sl-block astro-zwj6qr56" aria-hidden="true">Search</span><kbd class="sl-hidden md:sl-flex astro-zwj6qr56" style="display: none;"><kbd class="astro-zwj6qr56">Ctrl</kbd><kbd class="astro-zwj6qr56">K</kbd></kbd></button><dialog style="padding:0" aria-label="Search" class="astro-zwj6qr56"><div class="dialog-frame sl-flex astro-zwj6qr56"><button data-close-modal class="sl-flex md:sl-hidden astro-zwj6qr56">Cancel</button><div class="search-container astro-zwj6qr56"><div id="starlight__search" class="astro-zwj6qr56"></div></div></div></dialog></site-search><script>
|
|
28
|
+
(() => {
|
|
29
|
+
const openBtn = document.querySelector('button[data-open-modal]');
|
|
30
|
+
const shortcut = openBtn?.querySelector('kbd');
|
|
31
|
+
if (!openBtn || !(shortcut instanceof HTMLElement)) return;
|
|
32
|
+
const platformKey = shortcut.querySelector('kbd');
|
|
33
|
+
if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
|
|
34
|
+
platformKey.textContent = '⌘';
|
|
35
|
+
openBtn.setAttribute('aria-keyshortcuts', 'Meta+K');
|
|
36
|
+
}
|
|
37
|
+
shortcut.style.display = '';
|
|
38
|
+
})();
|
|
39
|
+
</script><script type="module" src="/docs/_astro/Search.astro_astro_type_script_index_0_lang.CavldbAs.js"></script></div><div class="sl-hidden md:sl-flex print:hidden right-group astro-6ytusalw"><div class="sl-flex social-icons astro-6ytusalw"></div><starlight-theme-select><label style="--sl-select-width: 6.25em" class="astro-7uz3f5wr"><span class="sr-only astro-7uz3f5wr">Select theme</span><svg aria-hidden="true" class="icon label-icon astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg><select autocomplete="off" class="astro-7uz3f5wr"><option value="dark" class="astro-7uz3f5wr">Dark</option><option value="light" class="astro-7uz3f5wr">Light</option><option value="auto" selected class="astro-7uz3f5wr">Auto</option></select><svg aria-hidden="true" class="icon caret astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg></label></starlight-theme-select><script>
|
|
40
|
+
StarlightThemeProvider.updatePickers();
|
|
41
|
+
</script><script type="module">var e=`starlight-theme`,t=e=>e===`auto`||e===`dark`||e===`light`?e:`auto`,n=()=>t(typeof localStorage<`u`&&localStorage.getItem(e));function r(t){typeof localStorage<`u`&&localStorage.setItem(e,t===`light`||t===`dark`?t:``)}var i=()=>matchMedia(`(prefers-color-scheme: light)`).matches?`light`:`dark`;function a(e){StarlightThemeProvider.updatePickers(e),document.documentElement.dataset.theme=e===`auto`?i():e,r(e)}matchMedia(`(prefers-color-scheme: light)`).addEventListener(`change`,()=>{n()===`auto`&&a(`auto`)});var o=class extends HTMLElement{constructor(){super(),a(n()),this.querySelector(`select`)?.addEventListener(`change`,e=>{e.currentTarget instanceof HTMLSelectElement&&a(t(e.currentTarget.value))})}};customElements.define(`starlight-theme-select`,o);</script><script type="module">var e=class extends HTMLElement{constructor(){super();let e=this.querySelector(`select`);e&&(e.addEventListener(`change`,e=>{e.currentTarget instanceof HTMLSelectElement&&(window.location.pathname=e.currentTarget.value)}),window.addEventListener(`pageshow`,t=>{if(!t.persisted)return;let n=e.querySelector(`option[selected]`)?.index;n!==e.selectedIndex&&(e.selectedIndex=n??0)}))}};customElements.define(`starlight-lang-select`,e);</script></div></div></header><nav class="sidebar print:hidden astro-5auw3bkx" aria-label="Main"><starlight-menu-button class="print:hidden astro-gnkm6dw5"><button aria-expanded="false" aria-label="Menu" aria-controls="starlight__sidebar" class="sl-flex md:sl-hidden astro-gnkm6dw5"><svg aria-hidden="true" class="open-menu astro-gnkm6dw5 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M3 8h18a1 1 0 1 0 0-2H3a1 1 0 0 0 0 2Zm18 8H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Zm0-5H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Z"/></svg><svg aria-hidden="true" class="close-menu astro-gnkm6dw5 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="m13.41 12 6.3-6.29a1.004 1.004 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1.004 1.004 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 0 1.42.998.998 0 0 0 1.42 0l6.29-6.3 6.29 6.3a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.42L13.41 12Z"/></svg></button></starlight-menu-button><script type="module">var e=class extends HTMLElement{btn=this.querySelector(`button`);constructor(){super(),this.btn.addEventListener(`click`,()=>this.toggleExpanded());let e=this.closest(`nav`);e&&e.addEventListener(`keyup`,e=>this.closeOnEscape(e)),matchMedia(`(min-width: 50em)`).addEventListener(`change`,()=>this.setExpanded(!1))}setExpanded(e){this.setAttribute(`aria-expanded`,String(e)),document.body.toggleAttribute(`data-mobile-menu-expanded`,e),document.querySelectorAll(`.main-frame, .sl-skip-link`).forEach(t=>{t.toggleAttribute(`inert`,e)})}toggleExpanded(){this.setExpanded(this.getAttribute(`aria-expanded`)!==`true`)}closeOnEscape(e){e.code===`Escape`&&(this.setExpanded(!1),this.btn.focus())}};customElements.define(`starlight-menu-button`,e);</script><div id="starlight__sidebar" class="sidebar-pane astro-5auw3bkx"><div class="sidebar-content sl-flex astro-5auw3bkx"><sl-sidebar-state-persist data-hash="03jp7ll" class="astro-pcs3l5kp"><script aria-hidden="true">
|
|
42
|
+
(() => {
|
|
43
|
+
try {
|
|
44
|
+
if (!matchMedia('(min-width: 50em)').matches) return;
|
|
45
|
+
/** @type {HTMLElement | null} */
|
|
46
|
+
const target = document.querySelector('sl-sidebar-state-persist');
|
|
47
|
+
const state = JSON.parse(sessionStorage.getItem('sl-sidebar-state') || '0');
|
|
48
|
+
if (!target || !state || target.dataset.hash !== state.hash) return;
|
|
49
|
+
window._starlightScrollRestore = state.scroll;
|
|
50
|
+
customElements.define(
|
|
51
|
+
'sl-sidebar-restore',
|
|
52
|
+
class SidebarRestore extends HTMLElement {
|
|
53
|
+
connectedCallback() {
|
|
54
|
+
try {
|
|
55
|
+
const idx = parseInt(this.dataset.index || '');
|
|
56
|
+
const details = this.closest('details');
|
|
57
|
+
if (details && typeof state.open[idx] === 'boolean') details.open = state.open[idx];
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
} catch {}
|
|
63
|
+
})();
|
|
64
|
+
</script><ul class="top-level astro-ck7l566j"><li class="astro-ck7l566j"><details open class="astro-ck7l566j"><summary class="astro-ck7l566j"><span class="group-label astro-ck7l566j"><span class="large astro-ck7l566j">Using Velora</span></span><svg aria-hidden="true" class="caret astro-ck7l566j astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.25rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></summary><sl-sidebar-restore data-index="0"></sl-sidebar-restore><ul class="astro-ck7l566j"><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/" class="astro-ck7l566j"><span class="astro-ck7l566j">Using Velora</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/getting-started/" class="astro-ck7l566j"><span class="astro-ck7l566j">Getting started</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/installation/" aria-current="page" class="astro-ck7l566j"><span class="astro-ck7l566j">Installation</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/content-model/" class="astro-ck7l566j"><span class="astro-ck7l566j">Document types</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/editing/" class="astro-ck7l566j"><span class="astro-ck7l566j">Content editing</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/media/" class="astro-ck7l566j"><span class="astro-ck7l566j">Media</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/users-and-roles/" class="astro-ck7l566j"><span class="astro-ck7l566j">Users and roles</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/installing-plugins/" class="astro-ck7l566j"><span class="astro-ck7l566j">Installing plugins</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/headless-api/" class="astro-ck7l566j"><span class="astro-ck7l566j">Headless API</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/build-a-headless-frontend/" class="astro-ck7l566j"><span class="astro-ck7l566j">Build a headless frontend</span></a></li></ul></details></li></ul><script aria-hidden="true">
|
|
65
|
+
(() => {
|
|
66
|
+
const scroller = document.getElementById('starlight__sidebar');
|
|
67
|
+
if (!window._starlightScrollRestore || !scroller) return;
|
|
68
|
+
scroller.scrollTop = window._starlightScrollRestore;
|
|
69
|
+
delete window._starlightScrollRestore;
|
|
70
|
+
})();
|
|
71
|
+
</script></sl-sidebar-state-persist><div class="md:sl-hidden"><div class="mobile-preferences sl-flex astro-yfet6llj"><div class="social-icons astro-yfet6llj"></div><starlight-theme-select><label style="--sl-select-width: 6.25em" class="astro-7uz3f5wr"><span class="sr-only astro-7uz3f5wr">Select theme</span><svg aria-hidden="true" class="icon label-icon astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg><select autocomplete="off" class="astro-7uz3f5wr"><option value="dark" class="astro-7uz3f5wr">Dark</option><option value="light" class="astro-7uz3f5wr">Light</option><option value="auto" selected class="astro-7uz3f5wr">Auto</option></select><svg aria-hidden="true" class="icon caret astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg></label></starlight-theme-select><script>
|
|
72
|
+
StarlightThemeProvider.updatePickers();
|
|
73
|
+
</script></div></div></div></div></nav><div class="main-frame astro-5auw3bkx"><script type="module">var e=document.getElementById(`starlight__sidebar`),t=e?.querySelector(`sl-sidebar-state-persist`),n=`sl-sidebar-state`,r=()=>{let r=[],i=t?.dataset.hash||``;try{let e=sessionStorage.getItem(n),t=JSON.parse(e||`{}`);Array.isArray(t.open)&&t.hash===i&&(r=t.open)}catch{}return{hash:i,open:r,scroll:e?.scrollTop||0}},i=e=>{try{sessionStorage.setItem(n,JSON.stringify(e))}catch{}},a=()=>i(r()),o=(e,t)=>{let n=r();n.open[t]=e,i(n)};t?.addEventListener(`click`,e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`summary`)?.closest(`details`);if(!t)return;let n=t.querySelector(`sl-sidebar-restore`),r=parseInt(n?.dataset.index||``);isNaN(r)||o(!t.open,r)}),addEventListener(`visibilitychange`,()=>{document.visibilityState===`hidden`&&a()});</script><div class="lg:sl-flex astro-perbdhd2"><aside class="right-sidebar-container print:hidden astro-perbdhd2"><div class="right-sidebar astro-perbdhd2"><div class="lg:sl-hidden astro-epm5tkrc"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-bnvebtr4"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-bnvebtr4"><details id="starlight__mobile-toc" class="astro-bnvebtr4"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-bnvebtr4"><span class="toggle sl-flex astro-bnvebtr4">On this page<svg aria-hidden="true" class="caret astro-bnvebtr4 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></span><span class="display-current astro-bnvebtr4"></span></summary><div class="dropdown astro-bnvebtr4"><ul class="isMobile astro-lptfoybu" style="--depth: 0;"><li style="--depth: 0;" class="astro-lptfoybu"><a href="#_top" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Overview</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#what-the-wizard-does" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">What the wizard does</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#step-1--the-first-admin-account" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Step 1 — the first admin account</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#step-2--the-database" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Step 2 — the database</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#step-3--the-starter-template" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Step 3 — the starter template</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#the-wizards-api" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">The wizard’s API</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#choosing-a-database" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Choosing a database</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#configuring-the-server" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Configuring the server</span></a><ul class="isMobile astro-lptfoybu" style="--depth: 1;"><li style="--depth: 1;" class="astro-lptfoybu"><a href="#core" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Core</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#features" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Features</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#media-storage" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Media storage</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#limits" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Limits</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#licensing" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Licensing</span></a></li></ul></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#after-setup" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">After setup</span></a></li></ul></div></details></nav></mobile-starlight-toc><script type="module" src="/docs/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js"></script></div><div class="right-sidebar-panel sl-hidden lg:sl-block astro-epm5tkrc"><div class="sl-container astro-epm5tkrc"><starlight-toc data-min-h="2" data-max-h="3"><nav aria-labelledby="starlight__on-this-page"><h2 id="starlight__on-this-page">On this page</h2><ul class="astro-lptfoybu" style="--depth: 0;"><li style="--depth: 0;" class="astro-lptfoybu"><a href="#_top" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Overview</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#what-the-wizard-does" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">What the wizard does</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#step-1--the-first-admin-account" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Step 1 — the first admin account</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#step-2--the-database" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Step 2 — the database</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#step-3--the-starter-template" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Step 3 — the starter template</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#the-wizards-api" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">The wizard’s API</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#choosing-a-database" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Choosing a database</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#configuring-the-server" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Configuring the server</span></a><ul class="astro-lptfoybu" style="--depth: 1;"><li style="--depth: 1;" class="astro-lptfoybu"><a href="#core" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Core</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#features" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Features</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#media-storage" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Media storage</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#limits" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Limits</span></a></li><li style="--depth: 1;" class="astro-lptfoybu"><a href="#licensing" style="--depth: 1;" class="astro-lptfoybu"><span style="--depth: 1;" class="astro-lptfoybu">Licensing</span></a></li></ul></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#after-setup" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">After setup</span></a></li></ul></nav></starlight-toc><script type="module" src="/docs/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js"></script></div></div></div></aside><div class="main-pane astro-perbdhd2"><main data-pagefind-body class="astro-ewhz5xxr" lang="en" dir="ltr"><div class="content-panel astro-ahkzlqop"><div class="sl-container astro-ahkzlqop"><h1 id="_top" class="astro-oef2efwn">Installation</h1></div></div><div class="content-panel astro-ahkzlqop"><div class="sl-container astro-ahkzlqop"><div class="sl-markdown-content"><p>Velora ships as a self-hosted application: <code dir="auto">apps/server</code> (the API) and
|
|
74
|
+
<code dir="auto">apps/admin-ui</code> (the back office) run against a database you own. There
|
|
75
|
+
is no hosted signup step — the first time the server boots against an
|
|
76
|
+
unconfigured database, it serves the setup wizard instead of the normal
|
|
77
|
+
API.</p>
|
|
78
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="what-the-wizard-does">What the wizard does</h2><a class="sl-anchor-link" href="#what-the-wizard-does"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “What the wizard does”</span></a></div>
|
|
79
|
+
<p>The browser-based setup wizard walks through everything a fresh instance
|
|
80
|
+
needs before it’s usable:</p>
|
|
81
|
+
<ol>
|
|
82
|
+
<li><strong>The first admin account</strong> — email, name, and password.</li>
|
|
83
|
+
<li><strong>Database connection</strong> — pick a dialect and supply its connection
|
|
84
|
+
details (host/port/database/credentials for PostgreSQL and MySQL, or
|
|
85
|
+
a file path for SQLite).</li>
|
|
86
|
+
<li><strong>Starter template</strong> — optionally install one of the templates bundled
|
|
87
|
+
with the build, with or without its sample content.</li>
|
|
88
|
+
</ol>
|
|
89
|
+
<p>The wizard submits all three as one <code dir="auto">POST /api/setup/complete</code> request.
|
|
90
|
+
Until that request succeeds, the server only serves the setup routes — it
|
|
91
|
+
won’t accept normal API traffic against a database that isn’t configured
|
|
92
|
+
yet.</p>
|
|
93
|
+
<p>Which shape the wizard takes is decided at boot, by whether <code dir="auto">DATABASE_URL</code>
|
|
94
|
+
is set and whether an administrator already exists
|
|
95
|
+
(<code dir="auto">apps/server/src/boot/resolve-boot-mode.ts</code>):</p>
|
|
96
|
+
<ul>
|
|
97
|
+
<li><strong><code dir="auto">DATABASE_URL</code> unset</strong> — the full wizard, database step included. This
|
|
98
|
+
is the fresh-install path.</li>
|
|
99
|
+
<li><strong><code dir="auto">DATABASE_URL</code> set, no administrator rows</strong> — the wizard runs in
|
|
100
|
+
admin-only mode: no database step, because the environment already
|
|
101
|
+
decided it. This is the container/systemd path, where the database is
|
|
102
|
+
injected and only the first account is missing.</li>
|
|
103
|
+
<li><strong><code dir="auto">DATABASE_URL</code> set, at least one administrator</strong> — no wizard; the full
|
|
104
|
+
application boots and <code dir="auto">/api/setup/complete</code> answers <code dir="auto">409</code>.</li>
|
|
105
|
+
</ul>
|
|
106
|
+
<p>If the administrator probe fails (database down, wrong credentials), the
|
|
107
|
+
server <strong>refuses to boot</strong> and prints the cause rather than guessing. A
|
|
108
|
+
failed probe is never read as “no admin yet” — that would turn a live
|
|
109
|
+
instance into an unauthenticated create-admin endpoint.</p>
|
|
110
|
+
<p>Whichever boot mode applies, the same running server also serves the
|
|
111
|
+
wizard and, once setup is done, the rest of the admin — at <code dir="auto">/velora</code>. A
|
|
112
|
+
bare <code dir="auto">/</code> request redirects there, since v1 has no site renderer of its own
|
|
113
|
+
to answer it. A public-facing instance such as the hosted demo can turn
|
|
114
|
+
this off with <code dir="auto">VELORA_ADMIN=off</code> (see <code dir="auto">VELORA_ADMIN</code> below) without
|
|
115
|
+
affecting the API; and if the admin bundle is missing entirely, <code dir="auto">/velora/*</code>
|
|
116
|
+
degrades to a clear 404 naming the cause rather than breaking anything
|
|
117
|
+
else.</p>
|
|
118
|
+
<aside aria-label="Note" class="starlight-aside starlight-aside--note"><p class="starlight-aside__title" aria-hidden="true"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" class="starlight-aside__icon"><path d="M12 11a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-4a1 1 0 0 0-1-1Zm.38-3.92a1 1 0 0 0-.76 0 1 1 0 0 0-.33.21 1.15 1.15 0 0 0-.21.33 1 1 0 0 0 .21 1.09c.097.088.209.16.33.21A1 1 0 0 0 13 8a1.05 1.05 0 0 0-.29-.71 1 1 0 0 0-.33-.21ZM12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16.001A8 8 0 0 1 12 20Z"></path></svg>Note</p><div class="starlight-aside__content"><p>A packaged install — <code dir="auto">npm create velora</code>, scaffolding a full site from
|
|
119
|
+
npm — is coming. Today, running your own instance means working from
|
|
120
|
+
source (available to contributors on request); see
|
|
121
|
+
<a href="https://docs.velora-cms.com/v1/contributing/local-setup/">Local setup</a>. To try Velora right now,
|
|
122
|
+
start with the <a href="/docs/v1/using-velora/build-a-headless-frontend/">headless tutorial</a>
|
|
123
|
+
or <a href="https://docs.velora-cms.com/v1/building-plugins/build-a-plugin/">build a plugin</a>.</p></div></aside>
|
|
124
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="step-1--the-first-admin-account">Step 1 — the first admin account</h2><a class="sl-anchor-link" href="#step-1--the-first-admin-account"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Step 1 — the first admin account”</span></a></div>
|
|
125
|
+
<p>The wizard opens on “Set up Velora”. All four fields are validated in the
|
|
126
|
+
browser before it will advance, and the first three are re-validated on
|
|
127
|
+
the server by <code dir="auto">SetupCompleteRequestSchema</code>:</p>
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td>Email</td><td>string (email)</td><td>Sign-in address for the first administrator. Rejected with “Enter a valid email address.” if it has no <code dir="auto">@</code> and dotted domain.</td><td><code dir="auto">you@example.com</code></td></tr><tr><td>Name</td><td>string (non-empty)</td><td>Display name shown throughout the admin UI.</td><td><code dir="auto">Ada Lovelace</code></td></tr><tr><td>Password</td><td>string, minimum 8 characters</td><td>The account password. Shorter values are rejected with “Password must be at least 8 characters.”</td><td><code dir="auto">correct-horse-8</code></td></tr><tr><td>Confirm password</td><td>string</td><td>Must equal Password exactly, or the wizard shows “Passwords do not match.” Never sent to the server.</td><td><code dir="auto">correct-horse-8</code></td></tr></tbody></table>
|
|
164
|
+
<p>The account is created with role <code dir="auto">admin</code>, inside the same database
|
|
165
|
+
transaction that writes a single-row <code dir="auto">setup_lock</code> sentinel — which is what
|
|
166
|
+
makes “only one first administrator, ever” hold under concurrent requests
|
|
167
|
+
on all three dialects.</p>
|
|
168
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="step-2--the-database">Step 2 — the database</h2><a class="sl-anchor-link" href="#step-2--the-database"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Step 2 — the database”</span></a></div>
|
|
169
|
+
<p>This step is skipped entirely when <code dir="auto">DATABASE_URL</code> was already set at boot.
|
|
170
|
+
Otherwise, choose a <strong>Database type</strong> and fill in the fields it reveals:</p>
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td>Database type</td><td><code dir="auto">postgresql</code> | <code dir="auto">mysql</code> | <code dir="auto">sqlite</code></td><td>Which dialect this instance stores everything in. The wizard cannot change it afterwards.</td><td><code dir="auto">sqlite</code></td></tr><tr><td>File path</td><td>string, non-empty (SQLite only)</td><td>Where the database file lives. Relative paths are accepted and resolved to an absolute path once, when setup completes, so the connection string written to <code dir="auto">.env</code> is already absolute.</td><td><code dir="auto">./data/velora.db</code></td></tr><tr><td>Host</td><td>string, non-empty (PostgreSQL/MySQL)</td><td>Hostname or IP of the database server. Empty gives “Enter a host.”</td><td><code dir="auto">localhost</code></td></tr><tr><td>Port</td><td>integer > 0 (PostgreSQL/MySQL)</td><td>Port to connect on. Pre-filled <code dir="auto">5432</code> for PostgreSQL, <code dir="auto">3306</code> for MySQL.</td><td><code dir="auto">5432</code></td></tr><tr><td>Database name</td><td>string, non-empty (PostgreSQL/MySQL)</td><td>The database to use on that server.</td><td><code dir="auto">velora</code></td></tr><tr><td>Username</td><td>string, non-empty (PostgreSQL/MySQL)</td><td>Database user. URL-encoded into the connection string.</td><td><code dir="auto">velora</code></td></tr><tr><td>Password</td><td>string (PostgreSQL/MySQL)</td><td>That user’s password. May be empty. URL-encoded, so <code dir="auto">@</code>, <code dir="auto">:</code> and <code dir="auto">/</code> in a password are safe.</td><td><code dir="auto">s3cr#t@pass</code></td></tr></tbody></table>
|
|
225
|
+
<p>From those fields the server assembles the connection string itself
|
|
226
|
+
(<code dir="auto">apps/server/src/setup/build-connection-string.ts</code>) — for a server
|
|
227
|
+
dialect, <code dir="auto"><dialect>://<user>:<password>@<host>:<port>/<database></code>; for
|
|
228
|
+
SQLite, the absolute <code dir="auto">file:</code> URL for the path you gave.</p>
|
|
229
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="step-3--the-starter-template">Step 3 — the starter template</h2><a class="sl-anchor-link" href="#step-3--the-starter-template"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Step 3 — the starter template”</span></a></div>
|
|
230
|
+
<p>The last step offers <strong>Blank site</strong> (pre-selected) plus a card for every
|
|
231
|
+
template bundled with this build:</p>
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td>Template card</td><td>Blank site, or one bundled template</td><td>Which starter to install as part of setup. Blank site installs nothing and the button reads “Finish setup”.</td><td><code dir="auto">Blog</code> (badged <strong>Official</strong>)</td></tr><tr><td>Include sample content</td><td>boolean, default <code dir="auto">true</code></td><td>Whether to seed the template’s <code dir="auto">sample-content.json</code> tree alongside its document types.</td><td>checked</td></tr></tbody></table>
|
|
256
|
+
<p>A starter install can fail without failing setup: the account and database
|
|
257
|
+
configuration always stand, and the response reports the outcome so the
|
|
258
|
+
admin can install the template later from the marketplace instead.</p>
|
|
259
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="the-wizards-api">The wizard’s API</h2><a class="sl-anchor-link" href="#the-wizards-api"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “The wizard’s API”</span></a></div>
|
|
260
|
+
<p>The wizard is an ordinary client of two public routes; you can drive them
|
|
261
|
+
directly, which is what an automated provisioning script would do. Ask a
|
|
262
|
+
fresh instance what it still needs:</p>
|
|
263
|
+
<div class="expressive-code"><link rel="stylesheet" href="/docs/_astro/ec.w36nc.css"><script type="module" src="/docs/_astro/ec.0vx5m.js"></script><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">http://localhost:3000/api/setup/status</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s http://localhost:3000/api/setup/status"><div></div></button></div></figure></div>
|
|
264
|
+
<p>On an unconfigured instance it reports that setup is required, that no
|
|
265
|
+
database is configured, and which templates it can offer:</p>
|
|
266
|
+
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"setupRequired"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"bundledTemplates"</span><span style="--0:#D6DEEB;--1:#403F53">: [</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"pluginId"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">com.velora.blog</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"version"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">0.1.0</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"name"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Blog</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"description"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">The official Velora blog template — posts, authors and tags, ready to publish.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"sampleContent"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">],</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"databaseConfigured"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">false</span></div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{ "setupRequired": true, "bundledTemplates": [ { "pluginId": "com.velora.blog", "version": "0.1.0", "name": "Blog", "description": "The official Velora blog template — posts, authors and tags, ready to publish.", "sampleContent": true } ], "databaseConfigured": false}"><div></div></button></div></figure></div>
|
|
267
|
+
<p>Every property of that response comes from <code dir="auto">SetupStatusResponseSchema</code> and
|
|
268
|
+
<code dir="auto">BundledTemplateSchema</code> (<code dir="auto">packages/api-schemas/src/setup-api.schema.ts</code>):</p>
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">setupRequired</code></td><td>boolean</td><td>Whether the wizard still has work to do. <code dir="auto">false</code> on a configured instance.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">bundledTemplates</code></td><td>array</td><td>Templates this build can install offline. Always present — <code dir="auto">[]</code> outside setup mode or when nothing is resolvable, never <code dir="auto">null</code>.</td><td><code dir="auto">[{ "pluginId": "com.velora.blog", … }]</code></td></tr><tr><td><code dir="auto">bundledTemplates[].pluginId</code></td><td>string, non-empty</td><td>The template plugin’s manifest id — the same id the marketplace install flow uses.</td><td><code dir="auto">com.velora.blog</code></td></tr><tr><td><code dir="auto">bundledTemplates[].version</code></td><td>string, non-empty</td><td>The bundled version of that template.</td><td><code dir="auto">0.1.0</code></td></tr><tr><td><code dir="auto">bundledTemplates[].name</code></td><td>string, non-empty</td><td>Display name on the wizard card.</td><td><code dir="auto">Blog</code></td></tr><tr><td><code dir="auto">bundledTemplates[].description</code></td><td>string, optional</td><td>Card subtitle. Absent when the manifest has none.</td><td><code dir="auto">The official Velora blog template…</code></td></tr><tr><td><code dir="auto">bundledTemplates[].sampleContent</code></td><td>boolean</td><td>Whether the packed artifact carries a <code dir="auto">sample-content.json</code> seed tree.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">databaseConfigured</code></td><td>boolean</td><td><code dir="auto">true</code> when <code dir="auto">DATABASE_URL</code> was set at boot, so the wizard hides its database step.</td><td><code dir="auto">false</code></td></tr></tbody></table>
|
|
329
|
+
<p>Completing setup is a single unauthenticated <code dir="auto">POST</code>, accepted only while
|
|
330
|
+
<code dir="auto">setupRequired</code> is <code dir="auto">true</code>:</p>
|
|
331
|
+
<div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-X</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">POST</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">http://localhost:3000/api/setup/complete</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-H</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Content-Type: application/json</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-d</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#ECC48D;--1:#984E4D">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#ECC48D;--1:#984E4D"> </span></span><span style="--0:#ECC48D;--1:#984E4D">"admin": { "email": "you@example.com", "name": "Ada Lovelace", "password": "correct-horse-8" },</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#ECC48D;--1:#984E4D"> </span></span><span style="--0:#ECC48D;--1:#984E4D">"database": { "dialect": "sqlite", "filePath": "./data/velora.db" },</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#ECC48D;--1:#984E4D"> </span></span><span style="--0:#ECC48D;--1:#984E4D">"starter": { "pluginId": "com.velora.blog", "includeSampleContent": true }</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#ECC48D;--1:#984E4D"> </span></span><span style="--0:#ECC48D;--1:#984E4D">}</span><span style="--0:#D9F5DD;--1:#111111">'</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s -X POST http://localhost:3000/api/setup/complete \ -H "Content-Type: application/json" \ -d '{ "admin": { "email": "you@example.com", "name": "Ada Lovelace", "password": "correct-horse-8" }, "database": { "dialect": "sqlite", "filePath": "./data/velora.db" }, "starter": { "pluginId": "com.velora.blog", "includeSampleContent": true } }'"><div></div></button></div></figure></div>
|
|
332
|
+
<p>It provisions the schema, creates the administrator, installs the starter,
|
|
333
|
+
writes <code dir="auto">DATABASE_URL</code> to the env file, and answers:</p>
|
|
334
|
+
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span><span style="--0:#7FDBCA;--1:#096E72">"success"</span><span style="--0:#D6DEEB;--1:#403F53">:</span><span style="--0:#FF6A83;--1:#A24848">true</span><span style="--0:#D6DEEB;--1:#403F53">,</span><span style="--0:#7FDBCA;--1:#096E72">"starter"</span><span style="--0:#D6DEEB;--1:#403F53">:{</span><span style="--0:#7FDBCA;--1:#096E72">"pluginId"</span><span style="--0:#D6DEEB;--1:#403F53">:</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">com.velora.blog</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span><span style="--0:#7FDBCA;--1:#096E72">"outcome"</span><span style="--0:#D6DEEB;--1:#403F53">:</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">installed</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">}}</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{"success":true,"starter":{"pluginId":"com.velora.blog","outcome":"installed"}}"><div></div></button></div></figure></div>
|
|
335
|
+
<p>The request body is <code dir="auto">SetupCompleteRequestSchema</code>:</p>
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">admin.email</code></td><td>string (email), required</td><td>The first administrator’s sign-in address.</td><td><code dir="auto">you@example.com</code></td></tr><tr><td><code dir="auto">admin.name</code></td><td>string, non-empty, required</td><td>Display name for that account.</td><td><code dir="auto">Ada Lovelace</code></td></tr><tr><td><code dir="auto">admin.password</code></td><td>string, minimum 8 characters, required</td><td>Password, hashed before storage.</td><td><code dir="auto">correct-horse-8</code></td></tr><tr><td><code dir="auto">database</code></td><td>object, optional</td><td>The dialect selection. <strong>Required</strong> when <code dir="auto">databaseConfigured</code> is <code dir="auto">false</code>, and <strong>rejected with 400</strong> when it is <code dir="auto">true</code> — the route enforces the pairing both ways so a selection is never silently ignored.</td><td><code dir="auto">{ "dialect": "sqlite", "filePath": "./data/velora.db" }</code></td></tr><tr><td><code dir="auto">database.dialect</code></td><td><code dir="auto">sqlite</code> | <code dir="auto">postgresql</code> | <code dir="auto">mysql</code></td><td>Which branch of the union the rest of the object follows.</td><td><code dir="auto">postgresql</code></td></tr><tr><td><code dir="auto">database.filePath</code></td><td>string, non-empty (sqlite)</td><td>SQLite database file path.</td><td><code dir="auto">./data/velora.db</code></td></tr><tr><td><code dir="auto">database.host</code></td><td>string, non-empty (postgresql/mysql)</td><td>Database server hostname.</td><td><code dir="auto">localhost</code></td></tr><tr><td><code dir="auto">database.port</code></td><td>integer > 0 (postgresql/mysql)</td><td>Database server port; coerced from a string.</td><td><code dir="auto">5432</code></td></tr><tr><td><code dir="auto">database.database</code></td><td>string, non-empty (postgresql/mysql)</td><td>Database name on that server.</td><td><code dir="auto">velora</code></td></tr><tr><td><code dir="auto">database.username</code></td><td>string, non-empty (postgresql/mysql)</td><td>Database user.</td><td><code dir="auto">velora</code></td></tr><tr><td><code dir="auto">database.password</code></td><td>string (postgresql/mysql)</td><td>That user’s password; may be empty.</td><td><code dir="auto">velora</code></td></tr><tr><td><code dir="auto">starter</code></td><td>object, optional</td><td>Which bundled template to install. Omit entirely to skip — never send <code dir="auto">null</code>.</td><td><code dir="auto">{ "pluginId": "com.velora.blog", "includeSampleContent": true }</code></td></tr><tr><td><code dir="auto">starter.pluginId</code></td><td>string, non-empty</td><td>Must match a <code dir="auto">bundledTemplates[].pluginId</code> from the status route.</td><td><code dir="auto">com.velora.blog</code></td></tr><tr><td><code dir="auto">starter.includeSampleContent</code></td><td>boolean</td><td>Whether to seed the template’s sample content.</td><td><code dir="auto">true</code></td></tr></tbody></table>
|
|
432
|
+
<p>The response is <code dir="auto">SetupCompleteResponseSchema</code>:</p>
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">success</code></td><td>literal <code dir="auto">true</code></td><td>Setup completed: the administrator exists and the database is provisioned.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">starter</code></td><td>object, optional</td><td>Absent when no starter was requested, so the skip path stays byte-identical to a starter-free response.</td><td><code dir="auto">{ "pluginId": "com.velora.blog", "outcome": "installed" }</code></td></tr><tr><td><code dir="auto">starter.pluginId</code></td><td>string, non-empty</td><td>The template that was attempted.</td><td><code dir="auto">com.velora.blog</code></td></tr><tr><td><code dir="auto">starter.outcome</code></td><td><code dir="auto">installed</code> | <code dir="auto">failed</code></td><td>A failure here never fails setup — it rides alongside <code dir="auto">success: true</code>.</td><td><code dir="auto">installed</code></td></tr><tr><td><code dir="auto">starter.reason</code></td><td>string, non-empty, optional</td><td>Present only on <code dir="auto">failed</code>, explaining why.</td><td><code dir="auto">artifact not found</code></td></tr><tr><td><code dir="auto">configWarning</code></td><td>string, non-empty, optional</td><td>Present only when setup succeeded but could not write its configuration to the env file. Set <code dir="auto">DATABASE_URL</code> yourself before restarting, or the instance will run setup again.</td><td><code dir="auto">Setup finished, but the configuration could not be saved to /srv/velora/.env: EACCES…</code></td></tr></tbody></table>
|
|
481
|
+
<p>Failure answers use the uniform <code dir="auto">{ "message": "…" }</code> error body. A <code dir="auto">400</code>
|
|
482
|
+
means the request and the boot mode disagree about the database, or the
|
|
483
|
+
configured <code dir="auto">DATABASE_URL</code> names an unsupported dialect, or provisioning
|
|
484
|
+
failed. A <code dir="auto">409</code> means setup already completed — including the distinctive
|
|
485
|
+
case where a <code dir="auto">setup_lock</code> row exists with no administrator (an admin was
|
|
486
|
+
deleted afterwards), whose message names the recovery: delete row <code dir="auto">id = 1</code>
|
|
487
|
+
from <code dir="auto">setup_lock</code> and re-run setup. A <code dir="auto">503</code> means the server could not
|
|
488
|
+
confirm whether setup is still open and you should retry. The route is
|
|
489
|
+
also rate-limited — 5 attempts per hour by default (see
|
|
490
|
+
<code dir="auto">VELORA_RATE_LIMIT_SETUP</code> below).</p>
|
|
491
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="choosing-a-database">Choosing a database</h2><a class="sl-anchor-link" href="#choosing-a-database"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Choosing a database”</span></a></div>
|
|
492
|
+
<p>Velora treats PostgreSQL, MySQL 8+, and SQLite as equal, first-class
|
|
493
|
+
options — not a primary database with fallbacks bolted on. All three run
|
|
494
|
+
through the same <code dir="auto">DatabaseAdapter</code> interface and the same conformance
|
|
495
|
+
suite, so a method that works on one is required to work identically on
|
|
496
|
+
all three before it ships. Pick whichever fits your deployment:</p>
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td>PostgreSQL</td><td><code dir="auto">dialect: "postgresql"</code></td><td>The default choice for a networked production deployment: strongest concurrency story of the three, and the dialect most operators already run.</td><td><code dir="auto">postgresql://velora:velora@localhost:5432/velora</code></td></tr><tr><td>MySQL</td><td><code dir="auto">dialect: "mysql"</code></td><td>Equally supported; choose it when your hosting already provides MySQL 8+ and you would rather not add another engine.</td><td><code dir="auto">mysql://velora:velora@localhost:3306/velora</code></td></tr><tr><td>SQLite</td><td><code dir="auto">dialect: "sqlite"</code></td><td>A single file, no server process — simplest for local trials, single-node sites, and evaluation. The wizard turns your path into an absolute <code dir="auto">file:</code> URL.</td><td><code dir="auto">file:/srv/velora/data/velora.db</code></td></tr></tbody></table>
|
|
527
|
+
<p>Moving an existing instance to a different dialect later (SQLite to
|
|
528
|
+
PostgreSQL, say) isn’t a wizard feature yet — v1.0 ships compatibility
|
|
529
|
+
checks, but the automated migration wizard is planned for a later
|
|
530
|
+
release. Manual export/import is the fallback until then, so it’s worth
|
|
531
|
+
choosing deliberately at setup rather than assuming an easy switch
|
|
532
|
+
later.</p>
|
|
533
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="configuring-the-server">Configuring the server</h2><a class="sl-anchor-link" href="#configuring-the-server"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Configuring the server”</span></a></div>
|
|
534
|
+
<p>Everything else is environment configuration, read from the process
|
|
535
|
+
environment and from an env file loaded at boot
|
|
536
|
+
(<code dir="auto">apps/server/src/config/load-env.ts</code>). Two rules govern that file: a real
|
|
537
|
+
environment variable always beats a value in the file, and a missing file
|
|
538
|
+
is normal rather than an error — a deployment configured entirely by
|
|
539
|
+
injected variables has no file at all. A file with non-comment content
|
|
540
|
+
that yields no <code dir="auto">KEY=value</code> pairs is refused at boot rather than
|
|
541
|
+
half-applied; a file that is empty or contains only comments boots
|
|
542
|
+
normally.</p>
|
|
543
|
+
<p>Values are parsed defensively throughout: where a variable expects a
|
|
544
|
+
positive integer or a duration, a blank, negative, or unparseable value
|
|
545
|
+
falls back to the documented default instead of being trusted verbatim.</p>
|
|
546
|
+
<p>The tables below cover every operator-facing variable the server reads.
|
|
547
|
+
A handful of internal/dev-only variables (for example
|
|
548
|
+
<code dir="auto">VELORA_CONTENT_DATABASE_URL</code>, <code dir="auto">VELORA_PRISMA_CLIENT_DIR</code>) exist for the
|
|
549
|
+
sandbox and test setup and aren’t listed here.</p>
|
|
550
|
+
<div class="sl-heading-wrapper level-h3"><h3 id="core">Core</h3><a class="sl-anchor-link" href="#core"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Core”</span></a></div>
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">DATABASE_URL</code></td><td>string (URL)</td><td>Connection string for the configured database. No default: unset means the server boots into the full setup wizard, and the wizard writes this variable itself when it finishes. A relative SQLite path is made absolute once, at boot.</td><td><code dir="auto">postgresql://velora:velora@localhost:5432/velora</code></td></tr><tr><td><code dir="auto">JWT_SECRET</code></td><td>string</td><td>Signs and verifies the session tokens issued by <code dir="auto">/api/auth/*</code>. No default and no fallback — the server refuses to start with the error <code dir="auto">JWT_SECRET must be set — see .env.example</code>. Generate one with <code dir="auto">openssl rand -hex 32</code>.</td><td><code dir="auto">9f2c…</code> (64 hex chars)</td></tr><tr><td><code dir="auto">PORT</code></td><td>integer</td><td>TCP port the server listens on. Default <code dir="auto">3000</code>.</td><td><code dir="auto">8080</code></td></tr><tr><td><code dir="auto">HOST</code></td><td>string</td><td>Interface to bind. Default <code dir="auto">127.0.0.1</code> — loopback only. Set <code dir="auto">0.0.0.0</code> to accept connections from outside the host (behind a reverse proxy).</td><td><code dir="auto">0.0.0.0</code></td></tr><tr><td><code dir="auto">VELORA_ENV_FILE</code></td><td>string (path)</td><td>Which env file the server reads at boot and the setup wizard writes to. Default: <code dir="auto">.env</code> resolved against the working directory. A relative override is also resolved against the working directory.</td><td><code dir="auto">/srv/velora/config/velora.env</code></td></tr></tbody></table>
|
|
593
|
+
<div class="sl-heading-wrapper level-h3"><h3 id="features">Features</h3><a class="sl-anchor-link" href="#features"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Features”</span></a></div>
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">VELORA_HEADLESS</code></td><td><code dir="auto">"true"</code> | <code dir="auto">"1"</code></td><td>Registers the key-gated public <code dir="auto">/api/v1/*</code> namespace at boot. Default unset = off, and anything other than those two values is off. Deploy-time only; there is deliberately no runtime toggle, so changing it needs a restart.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">VELORA_MARKETPLACE_URL</code></td><td>string (origin) | <code dir="auto">off</code></td><td>Which marketplace the admin browses. Default <code dir="auto">https://marketplace.velora-cms.com</code>. <code dir="auto">off</code> (any case) or a blank value removes the in-CMS marketplace routes entirely, for air-gapped installs. Any other value is treated as a custom marketplace origin; trailing slashes are stripped.</td><td><code dir="auto">https://marketplace.velora-cms.com</code></td></tr><tr><td><code dir="auto">VELORA_PUBLIC_DOCS</code></td><td><code dir="auto">"false"</code> | <code dir="auto">"0"</code></td><td>Serves the public OpenAPI UI at <code dir="auto">/api/v1/docs</code>. <strong>On by default</strong> — only an explicit <code dir="auto">false</code>/<code dir="auto">0</code> disables it, which 404s that URL without touching the <code dir="auto">/api/v1</code> API itself.</td><td><code dir="auto">false</code></td></tr><tr><td><code dir="auto">VELORA_ADMIN</code></td><td><code dir="auto">"off"</code></td><td>Serves the admin SPA at <code dir="auto">/velora</code>. <strong>On by default</strong> — only the literal <code dir="auto">off</code> (trimmed, case-insensitive) disables it; every other value, including unset, leaves it on. Turning it off never touches the API, only <code dir="auto">/velora/*</code> and the <code dir="auto">/</code> redirect below.</td><td><code dir="auto">off</code></td></tr><tr><td><code dir="auto">VELORA_ADMIN_DIR</code></td><td>string (path)</td><td>Override for the bundled admin UI served at <code dir="auto">/velora/</code>. No default; without it the server tries <code dir="auto"><server dist>/admin-bundle</code>, then <code dir="auto"><repo>/apps/admin-ui/dist-bundle</code>. The directory must exist and contain an <code dir="auto">index.html</code>, or <code dir="auto">/velora/*</code> answers a 404 naming the override as the cause — a missing bundle never fails boot.</td><td><code dir="auto">/srv/velora/admin-bundle</code></td></tr><tr><td><code dir="auto">VELORA_DOCS_DIR</code></td><td>string (path)</td><td>Override for the bundled documentation served at <code dir="auto">/docs/</code>. No default; without it the server tries <code dir="auto"><server dist>/docs-bundle</code>, then <code dir="auto"><repo>/apps/docs/dist-bundle</code>. The directory must exist and contain a <code dir="auto">v1</code> subdirectory, or <code dir="auto">/docs/*</code> answers a 404 that names the cause — a missing bundle never fails boot.</td><td><code dir="auto">/srv/velora/docs-bundle</code></td></tr><tr><td><code dir="auto">VELORA_PLUGINS_DIR</code></td><td>string (path)</td><td>Where installed plugin packages are stored on disk. Default <code dir="auto">.velora/plugins</code> under the working directory.</td><td><code dir="auto">/var/lib/velora/plugins</code></td></tr><tr><td><code dir="auto">VELORA_TRUSTED_SIGNING_KEYS</code></td><td>JSON string</td><td>Extra plugin signing keys this instance trusts, merged over the set shipped with the server so a key can be added or a shipped one overridden without waiting for a release. A marketplace install blocks unless the package is signed by one of these keys; a sideload never blocks either way. Invalid JSON is warned about and ignored rather than stopping the server. Tabled in full, with the key format, under <a href="/docs/v1/using-velora/installing-plugins/">Installing plugins</a>.</td><td><code dir="auto">{"keys":[{"keyId":"a1b2…","publicKey":"MCowBQ…"}]}</code></td></tr><tr><td><code dir="auto">VELORA_BUNDLED_TEMPLATES_DIR</code></td><td>string (path)</td><td>Override for the starter templates the wizard offers. No default; without it the server tries <code dir="auto"><server dist>/bundled-templates</code>, then <code dir="auto">apps/server/bundled-templates</code>. A missing or malformed tree degrades to an empty list rather than failing.</td><td><code dir="auto">/srv/velora/bundled-templates</code></td></tr><tr><td><code dir="auto">VELORA_SITE_DOMAIN</code></td><td>string (host)</td><td>This instance’s own domain, as the operator declares it — never taken from a request’s <code dir="auto">Host</code> header. A paid plugin’s license binds to this value once, so it must be stable. A scheme and trailing slash are tolerated and stripped; the value is lowercased. No default.</td><td><code dir="auto">example.com</code></td></tr><tr><td><code dir="auto">VELORA_PREVIEW_BASE_URL</code></td><td>string (origin)</td><td>Base URL preview links are built against, as <code dir="auto"><base>/api/preview?token=…&id=…</code>. No default: unset (or blank) means no preview URL can be built. Trailing slashes are stripped.</td><td><code dir="auto">https://www.example.com</code></td></tr><tr><td><code dir="auto">VELORA_PREVIEW_TOKEN_TTL</code></td><td>integer (seconds)</td><td>How long a minted preview token stays valid. Default <code dir="auto">1800</code> (30 minutes).</td><td><code dir="auto">600</code></td></tr><tr><td><code dir="auto">VELORA_CORS_ORIGINS</code></td><td>comma-separated origins</td><td>Which browser origins may call public plugin routes cross-origin (<code dir="auto">GET</code>, <code dir="auto">POST</code>, <code dir="auto">OPTIONS</code> only). Default empty = no CORS headers at all, same-origin only. Entries that are not absolute origins — a trailing slash, a bare host, a path — are dropped with a warning.</td><td><code dir="auto">https://example.com,https://www.example.com</code></td></tr><tr><td><code dir="auto">VELORA_TRUST_PROXY</code></td><td><code dir="auto">true</code> | <code dir="auto">false</code> | integer | string</td><td>Whether, and how far, to trust <code dir="auto">X-Forwarded-*</code> when resolving the caller’s IP. Default unset = trust nothing, so every visitor behind a proxy collapses onto the proxy’s address — which flattens the per-IP rate lane. Set it only when genuinely behind a proxy you control; setting it otherwise lets a caller forge any IP.</td><td><code dir="auto">1</code></td></tr></tbody></table>
|
|
690
|
+
<div class="sl-heading-wrapper level-h3"><h3 id="media-storage">Media storage</h3><a class="sl-anchor-link" href="#media-storage"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Media storage”</span></a></div>
|
|
691
|
+
<p>Media uploads go to an S3-compatible bucket. All five variables have
|
|
692
|
+
in-code defaults matching the repository’s local MinIO service, so they
|
|
693
|
+
only need setting when pointing at real S3 or R2. Individual uploads are
|
|
694
|
+
capped at 50 MiB.</p>
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">S3_ENDPOINT</code></td><td>string (URL)</td><td>Storage endpoint. Default <code dir="auto">http://localhost:9000</code>.</td><td><code dir="auto">https://s3.eu-central-1.amazonaws.com</code></td></tr><tr><td><code dir="auto">S3_REGION</code></td><td>string</td><td>Bucket region. Default <code dir="auto">us-east-1</code>.</td><td><code dir="auto">eu-central-1</code></td></tr><tr><td><code dir="auto">S3_ACCESS_KEY_ID</code></td><td>string</td><td>Access key id. Default <code dir="auto">velora</code>.</td><td><code dir="auto">AKIA…</code></td></tr><tr><td><code dir="auto">S3_SECRET_ACCESS_KEY</code></td><td>string</td><td>Secret access key. Default <code dir="auto">velora-secret</code>.</td><td><code dir="auto">wJalr…</code></td></tr><tr><td><code dir="auto">S3_BUCKET</code></td><td>string</td><td>Bucket name. Default <code dir="auto">velora-media</code>.</td><td><code dir="auto">velora-media</code></td></tr></tbody></table>
|
|
737
|
+
<div class="sl-heading-wrapper level-h3"><h3 id="limits">Limits</h3><a class="sl-anchor-link" href="#limits"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Limits”</span></a></div>
|
|
738
|
+
<p>Rate limiting runs in three lanes, keyed by what the request actually
|
|
739
|
+
presents: a <code dir="auto">vk_</code> token that resolves to a live API key (<code dir="auto">key:</code>), a
|
|
740
|
+
signature-verified admin session (<code dir="auto">jwt:</code>, effectively unlimited), and
|
|
741
|
+
everything else — no credentials, an unknown or revoked key, an
|
|
742
|
+
unverifiable token — which falls to the capped anonymous <code dir="auto">ip:</code> lane.
|
|
743
|
+
Windows accept any duration string the limiter can parse (“1 minute”,
|
|
744
|
+
“15 minutes”, “1 hour”).</p>
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">VELORA_RATE_LIMIT_MAX</code></td><td>integer > 0</td><td>Requests per window for a caller presenting a valid API key (<code dir="auto">key:</code> lane). Default <code dir="auto">100</code>.</td><td><code dir="auto">500</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_IP_MAX</code></td><td>integer > 0</td><td>Requests per window for anonymous callers (<code dir="auto">ip:</code> lane), including public plugin routes. Also the ceiling for the setup scope. Default <code dir="auto">60</code>.</td><td><code dir="auto">120</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_WINDOW</code></td><td>duration string</td><td>The window for the shared three-lane limiter — the default for auth, docs, plugin routes, and the public API. Default <code dir="auto">1 minute</code>.</td><td><code dir="auto">1 minute</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_LOGIN</code></td><td>integer > 0</td><td><code dir="auto">POST /api/auth/login</code> attempts per window, keyed on IP alone. The tightest ceiling in the system. Default <code dir="auto">10</code>.</td><td><code dir="auto">10</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_LOGIN_WINDOW</code></td><td>duration string</td><td>Window for the login ceiling. Default <code dir="auto">15 minutes</code>.</td><td><code dir="auto">15 minutes</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_SETUP</code></td><td>integer > 0</td><td><code dir="auto">POST /api/setup/complete</code> attempts per window. Default <code dir="auto">5</code>.</td><td><code dir="auto">5</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_SETUP_WINDOW</code></td><td>duration string</td><td>Window for the setup ceiling. Default <code dir="auto">1 hour</code>.</td><td><code dir="auto">1 hour</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_DOCS</code></td><td>integer > 0</td><td>Requests per window for the bundled documentation served at <code dir="auto">/docs/</code>. Default <code dir="auto">120</code>.</td><td><code dir="auto">120</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_DOCS_WINDOW</code></td><td>duration string</td><td>Window for the bundled-documentation rate limit above. Default <code dir="auto">1 minute</code>.</td><td><code dir="auto">1 minute</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_ADMIN</code></td><td>integer > 0</td><td>Requests per window for the admin SPA served at <code dir="auto">/velora/</code>, keyed on IP. Covers the page shell, the SPA fallback, and every hashed asset file the bundle serves — they share this one plugin-level ceiling because the asset routes carry no per-route rate config of their own. Default <code dir="auto">120</code>.</td><td><code dir="auto">120</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_ADMIN_WINDOW</code></td><td>duration string</td><td>Window for the admin rate limit above. Default <code dir="auto">1 minute</code>.</td><td><code dir="auto">1 minute</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_KEY_CACHE_TTL_MS</code></td><td>integer > 0 (milliseconds)</td><td>How long the limiter caches whether a presented API key is live, so repeat calls with the same key avoid a database lookup. Default <code dir="auto">30000</code>.</td><td><code dir="auto">30000</code></td></tr><tr><td><code dir="auto">VELORA_RATE_LIMIT_KEY_CACHE_MAX_ENTRIES</code></td><td>integer > 0</td><td>Hard ceiling on that cache, so a flood of never-repeating fake tokens cannot grow it without bound. Default <code dir="auto">5000</code>.</td><td><code dir="auto">5000</code></td></tr><tr><td><code dir="auto">VELORA_GRAPHQL_MAX_DEPTH</code></td><td>integer > 0</td><td>Maximum nesting depth accepted on the public GraphQL endpoint. Default <code dir="auto">8</code>.</td><td><code dir="auto">8</code></td></tr><tr><td><code dir="auto">VELORA_GRAPHQL_MAX_COMPLEXITY</code></td><td>integer > 0</td><td>Maximum field-count complexity accepted on the same endpoint. Default <code dir="auto">500</code>.</td><td><code dir="auto">500</code></td></tr></tbody></table>
|
|
847
|
+
<div class="sl-heading-wrapper level-h3"><h3 id="licensing">Licensing</h3><a class="sl-anchor-link" href="#licensing"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Licensing”</span></a></div>
|
|
848
|
+
<p>Paid plugins re-validate against the marketplace’s license server on a
|
|
849
|
+
schedule; both knobs are read fresh, so a change takes effect without a
|
|
850
|
+
restart of the module graph.</p>
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
<table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">VELORA_LICENSE_CHECK_INTERVAL_HOURS</code></td><td>integer > 0</td><td>How often installed paid plugins are re-validated. Default <code dir="auto">24</code>.</td><td><code dir="auto">24</code></td></tr><tr><td><code dir="auto">VELORA_LICENSE_STALE_WARN_DAYS</code></td><td>integer > 0</td><td>How long an unreachable license server may go unheard from before the admin sees a warning. Default <code dir="auto">7</code>.</td><td><code dir="auto">7</code></td></tr></tbody></table>
|
|
875
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="after-setup">After setup</h2><a class="sl-anchor-link" href="#after-setup"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “After setup”</span></a></div>
|
|
876
|
+
<p>With the instance running, the next steps are:</p>
|
|
877
|
+
<ul>
|
|
878
|
+
<li><a href="/docs/v1/using-velora/content-model/">Document types</a> — model the content
|
|
879
|
+
you’re about to create.</li>
|
|
880
|
+
<li><a href="/docs/v1/using-velora/editing/">Content editing</a> — how saving, publishing,
|
|
881
|
+
and rollback work.</li>
|
|
882
|
+
<li><a href="/docs/v1/using-velora/users-and-roles/">Users and roles</a> — add more accounts,
|
|
883
|
+
and create the API keys the headless API needs.</li>
|
|
884
|
+
<li><a href="/docs/v1/using-velora/headless-api/">Headless API</a> — what turning on
|
|
885
|
+
<code dir="auto">VELORA_HEADLESS</code> exposes, endpoint by endpoint.</li>
|
|
886
|
+
</ul></div><footer class="sl-flex astro-gjkl2a5w"><div class="meta sl-flex astro-gjkl2a5w"></div><div class="pagination-links print:hidden astro-3tj6ibx2" dir="ltr"><a href="/docs/v1/using-velora/getting-started/" rel="prev" class="astro-3tj6ibx2"><svg aria-hidden="true" class="astro-3tj6ibx2 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17 11H9.41l3.3-3.29a1.004 1.004 0 1 0-1.42-1.42l-5 5a1 1 0 0 0-.21.33 1 1 0 0 0 0 .76 1 1 0 0 0 .21.33l5 5a1.002 1.002 0 0 0 1.639-.325 1 1 0 0 0-.219-1.095L9.41 13H17a1 1 0 0 0 0-2Z"/></svg><span class="astro-3tj6ibx2">Previous<br class="astro-3tj6ibx2"><span class="link-title astro-3tj6ibx2">Getting started</span></span></a><a href="/docs/v1/using-velora/content-model/" rel="next" class="astro-3tj6ibx2"><svg aria-hidden="true" class="astro-3tj6ibx2 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg><span class="astro-3tj6ibx2">Next<br class="astro-3tj6ibx2"><span class="link-title astro-3tj6ibx2">Document types</span></span></a></div></footer><div class="velora-bundle-stamp astro-llmj63sw">Velora 0.9.0 · bundled documentation</div></div></div></main></div></div></div></div></body></html>
|