@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,87 @@
|
|
|
1
|
+
// Build-time only. Packs the first-party starter templates the setup
|
|
2
|
+
// wizard's optional "starter template" step offers (currently just the
|
|
3
|
+
// blog template — plugins/blog) with the REAL velora-plugin build
|
|
4
|
+
// pipeline, and lays the result out for setup/bundled-templates.ts to
|
|
5
|
+
// find: apps/server/bundled-templates/<pluginId>/{package.tar.gz,
|
|
6
|
+
// manifest.json, sample-content.json} (repo path — what a `tsx`-run dev
|
|
7
|
+
// server resolves), then copied wholesale into
|
|
8
|
+
// apps/server/dist/bundled-templates (the production-shaped location —
|
|
9
|
+
// copy-docs-bundle.ts's precedent: ship the artifact inside the server's
|
|
10
|
+
// own dist/, not just the repo path).
|
|
11
|
+
//
|
|
12
|
+
// ONE plugin only, packed IN-PROCESS via packPlugin(). velora-plugin's
|
|
13
|
+
// build runs a real Vite Module Federation build — running a SECOND one
|
|
14
|
+
// inside the same process deadlocks reproducibly (S143, discovered while
|
|
15
|
+
// building apps/marketplace/scripts/seed-artifacts.ts: five straight
|
|
16
|
+
// hangs at the second plugin, hours of spun CPU, while every
|
|
17
|
+
// single-plugin run completed in seconds — leaked in-process Vite build
|
|
18
|
+
// state, not a property of any one plugin). See seed-artifact-one.ts for
|
|
19
|
+
// the child-process-per-plugin pattern this script MUST switch to before
|
|
20
|
+
// a second bundled template is ever added here.
|
|
21
|
+
import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
import { loadManifest } from "velora-plugin";
|
|
25
|
+
import { packPlugin } from "velora-plugin/pack";
|
|
26
|
+
// This script runs from TWO locations: <server>/dist/scripts (compiled,
|
|
27
|
+
// via `pnpm build`) and <server>/src/scripts (standalone `tsx` run via the
|
|
28
|
+
// pack-templates script). Both sit exactly two directories under the
|
|
29
|
+
// package root, so anchor everything off that root — never off `here`'s
|
|
30
|
+
// parent, which would land the dist copy inside src/ on a tsx run and
|
|
31
|
+
// shadow the repo-dir candidate resolveBundledTemplatesDir() checks.
|
|
32
|
+
const here = dirname(fileURLToPath(import.meta.url)); // <server>/{dist|src}/scripts
|
|
33
|
+
const serverDir = join(here, "..", ".."); // <server> (package root)
|
|
34
|
+
const serverDist = join(serverDir, "dist"); // <server>/dist
|
|
35
|
+
const repoRoot = join(serverDir, "..", ".."); // repo root
|
|
36
|
+
const PLUGIN_DIRS = [join(repoRoot, "plugins", "blog")];
|
|
37
|
+
const repoOutRoot = join(serverDir, "bundled-templates");
|
|
38
|
+
const distOutRoot = join(serverDist, "bundled-templates");
|
|
39
|
+
async function packOne(pluginDir) {
|
|
40
|
+
const manifestResult = await loadManifest(pluginDir);
|
|
41
|
+
if (!manifestResult.ok) {
|
|
42
|
+
throw new Error(`pack-bundled-templates: manifest failed to load from ${pluginDir}:\n${manifestResult.errors.join("\n")}`);
|
|
43
|
+
}
|
|
44
|
+
const { id } = manifestResult.manifest;
|
|
45
|
+
console.log(`[pack-bundled-templates] packing ${id} (real build — this takes a while)…`);
|
|
46
|
+
const packed = await packPlugin(pluginDir);
|
|
47
|
+
try {
|
|
48
|
+
const templateOutDir = join(repoOutRoot, id);
|
|
49
|
+
rmSync(templateOutDir, { recursive: true, force: true });
|
|
50
|
+
mkdirSync(templateOutDir, { recursive: true });
|
|
51
|
+
cpSync(packed.archivePath, join(templateOutDir, "package.tar.gz"));
|
|
52
|
+
// manifest.json and sample-content.json (when present) come from the
|
|
53
|
+
// build's own outDir — velora-plugin's writeManifestJson/
|
|
54
|
+
// copySampleContentIfPresent already put them there; this only ever
|
|
55
|
+
// COPIES what the build produced, never regenerates it.
|
|
56
|
+
const manifestJsonPath = join(packed.buildResult.outDir, "manifest.json");
|
|
57
|
+
if (!existsSync(manifestJsonPath)) {
|
|
58
|
+
throw new Error(`pack-bundled-templates: ${manifestJsonPath} missing after build — did velora-plugin's writeManifestJson change?`);
|
|
59
|
+
}
|
|
60
|
+
cpSync(manifestJsonPath, join(templateOutDir, "manifest.json"));
|
|
61
|
+
const sampleContentPath = join(packed.buildResult.outDir, "sample-content.json");
|
|
62
|
+
if (existsSync(sampleContentPath)) {
|
|
63
|
+
cpSync(sampleContentPath, join(templateOutDir, "sample-content.json"));
|
|
64
|
+
}
|
|
65
|
+
console.log(`[pack-bundled-templates] ${id} -> ${templateOutDir}`);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
// packPlugin leaves <pluginDir>/<id>-<version>.tar.gz behind (its
|
|
69
|
+
// default outFile) — apps/marketplace/scripts/seed-artifact-one.ts's
|
|
70
|
+
// precedent for cleaning it up unconditionally, success or failure.
|
|
71
|
+
rmSync(packed.archivePath, { force: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function main() {
|
|
75
|
+
for (const pluginDir of PLUGIN_DIRS) {
|
|
76
|
+
await packOne(pluginDir);
|
|
77
|
+
}
|
|
78
|
+
rmSync(distOutRoot, { recursive: true, force: true });
|
|
79
|
+
cpSync(repoOutRoot, distOutRoot, { recursive: true });
|
|
80
|
+
console.log(`[pack-bundled-templates] copied bundled templates -> ${distOutRoot}`);
|
|
81
|
+
}
|
|
82
|
+
main().catch((error) => {
|
|
83
|
+
// Loud failure, same convention as copy-docs-bundle.ts: a broken bundled
|
|
84
|
+
// template is a build regression, never a skippable case.
|
|
85
|
+
console.error(`[pack-bundled-templates] failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type DatabaseSelection = {
|
|
2
|
+
dialect: "sqlite";
|
|
3
|
+
filePath: string;
|
|
4
|
+
} | {
|
|
5
|
+
dialect: "postgresql";
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
database: string;
|
|
9
|
+
username: string;
|
|
10
|
+
password: string;
|
|
11
|
+
} | {
|
|
12
|
+
dialect: "mysql";
|
|
13
|
+
host: string;
|
|
14
|
+
port: number;
|
|
15
|
+
database: string;
|
|
16
|
+
username: string;
|
|
17
|
+
password: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function buildConnectionString(selection: DatabaseSelection): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { normalizeDatabaseUrl } from "./normalize-database-url.js";
|
|
2
|
+
// Credentials must be encoded — a password containing @, :, or / would
|
|
3
|
+
// otherwise silently corrupt the assembled URL (e.g. a literal "@" in
|
|
4
|
+
// the password would be parsed as the user/host separator).
|
|
5
|
+
export function buildConnectionString(selection) {
|
|
6
|
+
if (selection.dialect === "sqlite") {
|
|
7
|
+
// Absolute, always — see normalize-database-url.ts for why a relative
|
|
8
|
+
// file: URL becomes two physical databases.
|
|
9
|
+
return normalizeDatabaseUrl(selection.filePath);
|
|
10
|
+
}
|
|
11
|
+
const user = encodeURIComponent(selection.username);
|
|
12
|
+
const password = encodeURIComponent(selection.password);
|
|
13
|
+
return `${selection.dialect}://${user}:${password}@${selection.host}:${selection.port}/${selection.database}`;
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BundledTemplate } from "@velora-cms/api-schemas";
|
|
2
|
+
export declare function resolveBundledTemplatesDir(): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Never throws. Returns [] when the bundled-templates directory can't be
|
|
5
|
+
* resolved, is empty, or every entry in it is malformed — the "outside
|
|
6
|
+
* setup mode" and "nothing bundled" cases both answer this way from
|
|
7
|
+
* routes/setup.ts.
|
|
8
|
+
*/
|
|
9
|
+
export declare function listBundledTemplates(): BundledTemplate[];
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the packed archive for one bundled template by EXACT match
|
|
12
|
+
* against listBundledTemplates() — pluginId is only ever compared with
|
|
13
|
+
* `===`, never joined into a filesystem path itself. The path actually
|
|
14
|
+
* joined and returned is built from the matched listing's own pluginId
|
|
15
|
+
* (which came from enumerating real directory entries, not from the
|
|
16
|
+
* request), so an unrelated or path-traversal-shaped input can only ever
|
|
17
|
+
* fail to match and return null.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveBundledTemplateTarball(pluginId: string): string | null;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
// Lists the first-party starter templates pack-bundled-templates.ts (a
|
|
5
|
+
// build-time script) packs into the server build, for the setup wizard's
|
|
6
|
+
// optional "starter template" step. Resolution order mirrors
|
|
7
|
+
// routes/docs-static.ts's resolveDocsDir() exactly:
|
|
8
|
+
// 1. VELORA_BUNDLED_TEMPLATES_DIR (ops override)
|
|
9
|
+
// 2. <server dist>/bundled-templates (what pack-bundled-templates.ts
|
|
10
|
+
// copies there — the production-shaped location)
|
|
11
|
+
// 3. <repo>/apps/server/bundled-templates (the pre-copy location the
|
|
12
|
+
// script writes FIRST, and the only one that exists when running the
|
|
13
|
+
// server straight off `tsx` in the monorepo — same "dev candidate"
|
|
14
|
+
// role docs-static.ts's apps/docs/dist-bundle candidate plays there)
|
|
15
|
+
// This module is imported by routes/setup.ts, which is registered by BOTH
|
|
16
|
+
// buildApp() (full app, db access available) and buildSetupOnlyApp() (a
|
|
17
|
+
// bare Fastify app during first-run setup, NO db access) — so everything
|
|
18
|
+
// here must be pure filesystem, never prisma/adapter.
|
|
19
|
+
//
|
|
20
|
+
// A missing or malformed bundled-templates tree NEVER throws: it degrades
|
|
21
|
+
// to an empty list, same "never break boot over an optional extra"
|
|
22
|
+
// philosophy as docs-static.ts's 404-with-cause.
|
|
23
|
+
function isUsableBundledTemplatesDir(candidate) {
|
|
24
|
+
try {
|
|
25
|
+
return statSync(candidate).isDirectory();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function resolveBundledTemplatesDir() {
|
|
32
|
+
const override = process.env.VELORA_BUNDLED_TEMPLATES_DIR;
|
|
33
|
+
if (override) {
|
|
34
|
+
const resolved = resolve(override);
|
|
35
|
+
return isUsableBundledTemplatesDir(resolved) ? resolved : null;
|
|
36
|
+
}
|
|
37
|
+
const here = dirname(fileURLToPath(import.meta.url)); // dist/setup or src/setup
|
|
38
|
+
const candidates = [
|
|
39
|
+
join(here, "..", "bundled-templates"), // dist sibling: dist/setup/../bundled-templates
|
|
40
|
+
join(here, "..", "..", "bundled-templates"), // repo path: apps/server/bundled-templates
|
|
41
|
+
// (same two levels-up from both dist/setup and src/setup, since both
|
|
42
|
+
// sit two directories under the apps/server package root)
|
|
43
|
+
];
|
|
44
|
+
return candidates.find(isUsableBundledTemplatesDir) ?? null;
|
|
45
|
+
}
|
|
46
|
+
function isNonEmptyString(value) {
|
|
47
|
+
return typeof value === "string" && value.length > 0;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Reads and validates one <bundledTemplatesDir>/<entryName>/manifest.json.
|
|
51
|
+
* Returns null (never throws) for anything unreadable, unparsable, or
|
|
52
|
+
* missing the fields the setup wizard needs — a malformed entry is
|
|
53
|
+
* skipped, not fatal to the rest of the listing.
|
|
54
|
+
*/
|
|
55
|
+
function readTemplateListing(templateDir) {
|
|
56
|
+
const manifestPath = join(templateDir, "manifest.json");
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (!isNonEmptyString(parsed.id) || !isNonEmptyString(parsed.name) || !isNonEmptyString(parsed.version)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const sampleContent = existsSync(join(templateDir, "sample-content.json"));
|
|
68
|
+
return {
|
|
69
|
+
pluginId: parsed.id,
|
|
70
|
+
version: parsed.version,
|
|
71
|
+
name: parsed.name,
|
|
72
|
+
...(isNonEmptyString(parsed.description) ? { description: parsed.description } : {}),
|
|
73
|
+
sampleContent,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Never throws. Returns [] when the bundled-templates directory can't be
|
|
78
|
+
* resolved, is empty, or every entry in it is malformed — the "outside
|
|
79
|
+
* setup mode" and "nothing bundled" cases both answer this way from
|
|
80
|
+
* routes/setup.ts.
|
|
81
|
+
*/
|
|
82
|
+
export function listBundledTemplates() {
|
|
83
|
+
const dir = resolveBundledTemplatesDir();
|
|
84
|
+
if (!dir)
|
|
85
|
+
return [];
|
|
86
|
+
let entries;
|
|
87
|
+
try {
|
|
88
|
+
entries = readdirSync(dir, { withFileTypes: true })
|
|
89
|
+
.filter((entry) => entry.isDirectory())
|
|
90
|
+
.map((entry) => entry.name);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const templates = [];
|
|
96
|
+
for (const entryName of entries) {
|
|
97
|
+
const listing = readTemplateListing(join(dir, entryName));
|
|
98
|
+
if (listing)
|
|
99
|
+
templates.push(listing);
|
|
100
|
+
}
|
|
101
|
+
return templates;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolves the packed archive for one bundled template by EXACT match
|
|
105
|
+
* against listBundledTemplates() — pluginId is only ever compared with
|
|
106
|
+
* `===`, never joined into a filesystem path itself. The path actually
|
|
107
|
+
* joined and returned is built from the matched listing's own pluginId
|
|
108
|
+
* (which came from enumerating real directory entries, not from the
|
|
109
|
+
* request), so an unrelated or path-traversal-shaped input can only ever
|
|
110
|
+
* fail to match and return null.
|
|
111
|
+
*/
|
|
112
|
+
export function resolveBundledTemplateTarball(pluginId) {
|
|
113
|
+
const match = listBundledTemplates().find((template) => template.pluginId === pluginId);
|
|
114
|
+
if (!match)
|
|
115
|
+
return null;
|
|
116
|
+
const dir = resolveBundledTemplatesDir();
|
|
117
|
+
if (!dir)
|
|
118
|
+
return null;
|
|
119
|
+
const tarballPath = join(dir, match.pluginId, "package.tar.gz");
|
|
120
|
+
return existsSync(tarballPath) ? tarballPath : null;
|
|
121
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { clientDirFor, generatePrismaClients } from "../scripts/generate-prisma-clients.js";
|
|
2
|
+
import { hasGeneratedClientOnDisk } from "../db/resolve-client-dir.js";
|
|
3
|
+
// An npm-installed server ships no generated Prisma clients (they are
|
|
4
|
+
// platform-specific and huge) — the dialect's client is generated on this
|
|
5
|
+
// machine the first time it is needed: at wizard provisioning, and here at
|
|
6
|
+
// boot as self-heal after a node_modules wipe.
|
|
7
|
+
export async function ensurePrismaClientGenerated(dialect, opts = {}) {
|
|
8
|
+
// resolve-client-dir.ts:64-66 gives VELORA_PRISMA_CLIENT_DIR strict
|
|
9
|
+
// precedence over the dialect-derived dist/prisma-clients/<dialect> path
|
|
10
|
+
// — velora-dev's sandbox sets it to point at its own state directory for
|
|
11
|
+
// every --db choice. Honor that same precedence here: when it's set,
|
|
12
|
+
// that directory's owner (not this self-heal) manages what lives there.
|
|
13
|
+
// Generating into clientDirFor(dialect) instead would spend up to a
|
|
14
|
+
// minute producing a client at a path boot never actually loads.
|
|
15
|
+
if (process.env.VELORA_PRISMA_CLIENT_DIR?.trim())
|
|
16
|
+
return "present";
|
|
17
|
+
const dir = opts.clientDir ?? clientDirFor(dialect);
|
|
18
|
+
if (hasGeneratedClientOnDisk(dir))
|
|
19
|
+
return "present";
|
|
20
|
+
console.log(`generating Prisma clients for ${dialect} (first run after install — this can take a minute)…`);
|
|
21
|
+
await generatePrismaClients([dialect]);
|
|
22
|
+
return "generated";
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PrismaClient } from "@prisma/client";
|
|
2
|
+
import type { SetupStarterResult, SetupStarterSelection } from "@velora-cms/api-schemas";
|
|
3
|
+
export interface InstallStarterTemplateOptions {
|
|
4
|
+
/** The setup handler's dialect-specific client, still connected — the
|
|
5
|
+
* same instance that just created the admin user. */
|
|
6
|
+
prisma: PrismaClient;
|
|
7
|
+
/** The just-built connection string for the chosen database — not in
|
|
8
|
+
* process.env yet at this point in the request. */
|
|
9
|
+
databaseUrl: string;
|
|
10
|
+
/** The freshly-created admin row's id: sample content's createdBy. */
|
|
11
|
+
adminUserId: string;
|
|
12
|
+
starter: SetupStarterSelection;
|
|
13
|
+
}
|
|
14
|
+
export declare function installStarterTemplate(options: InstallStarterTemplateOptions): Promise<SetupStarterResult>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { connectContentDbAt } from "../db/content-db.js";
|
|
2
|
+
import { installPackageTarball } from "../plugins/install-package-tarball.js";
|
|
3
|
+
import { PluginRegistryService } from "../plugins/plugin-registry-service.js";
|
|
4
|
+
import { resolveBundledTemplateTarball } from "./bundled-templates.js";
|
|
5
|
+
export async function installStarterTemplate(options) {
|
|
6
|
+
const { prisma, databaseUrl, adminUserId, starter } = options;
|
|
7
|
+
const failed = (reason) => ({
|
|
8
|
+
pluginId: starter.pluginId,
|
|
9
|
+
outcome: "failed",
|
|
10
|
+
reason,
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
const tarballPath = resolveBundledTemplateTarball(starter.pluginId);
|
|
14
|
+
if (!tarballPath) {
|
|
15
|
+
return failed(`No bundled starter template found for "${starter.pluginId}"`);
|
|
16
|
+
}
|
|
17
|
+
// The content-db connection for the CHOSEN database — brings the
|
|
18
|
+
// content tables up to date (the setup-only app never connected a
|
|
19
|
+
// content db; the later real boot re-runs the same migrations
|
|
20
|
+
// idempotently via velora_migrations).
|
|
21
|
+
const contentDb = await connectContentDbAt(databaseUrl);
|
|
22
|
+
try {
|
|
23
|
+
// Same service construction as install-built-package.ts's CLI entry:
|
|
24
|
+
// the registry service plus the three prisma-backed row callbacks.
|
|
25
|
+
const service = new PluginRegistryService(prisma, contentDb.adapter, {
|
|
26
|
+
activeDialect: contentDb.dialect,
|
|
27
|
+
});
|
|
28
|
+
const setRemoteUrl = async (pluginId, remoteUrl) => {
|
|
29
|
+
await prisma.pluginRegistry.update({ where: { pluginId }, data: { remoteUrl } });
|
|
30
|
+
};
|
|
31
|
+
const syncManifestFields = async (pluginId, fields) => {
|
|
32
|
+
await prisma.pluginRegistry.update({ where: { pluginId }, data: fields });
|
|
33
|
+
};
|
|
34
|
+
const setPackagePath = async (pluginId, packagePath) => {
|
|
35
|
+
await prisma.pluginRegistry.update({ where: { pluginId }, data: { packagePath } });
|
|
36
|
+
};
|
|
37
|
+
// remoteUrl "" — a template plugin has no client bundle, so there is
|
|
38
|
+
// no remoteEntry.js to point the admin loader at (the same rule
|
|
39
|
+
// install-from-marketplace.ts applies to view-less plugin types).
|
|
40
|
+
await installPackageTarball(service, tarballPath, "", setRemoteUrl, syncManifestFields, setPackagePath, {
|
|
41
|
+
seed: starter.includeSampleContent
|
|
42
|
+
? { prisma, adapter: contentDb.adapter, createdBy: adminUserId }
|
|
43
|
+
: undefined,
|
|
44
|
+
});
|
|
45
|
+
return { pluginId: starter.pluginId, outcome: "installed" };
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
// Best-effort: a disconnect hiccup must not convert a completed
|
|
49
|
+
// install into a reported failure via the outer catch.
|
|
50
|
+
try {
|
|
51
|
+
await contentDb.adapter.disconnect();
|
|
52
|
+
}
|
|
53
|
+
catch (disconnectError) {
|
|
54
|
+
console.warn("[install-starter] content-db disconnect failed after starter install", disconnectError);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.error(`[install-starter] starter "${starter.pluginId}" failed — setup itself stands`, error);
|
|
60
|
+
return failed(failureReason(error));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Compresses an arbitrary thrown error into a schema-safe, single-line
|
|
65
|
+
* `reason` for the setup response: first line only, trimmed, capped at
|
|
66
|
+
* 200 chars, never empty ("" would fail SetupStarterResultSchema's
|
|
67
|
+
* `min(1)` and turn an already-succeeded setup into a 500). This response
|
|
68
|
+
* is unauthenticated, so the full error (stack, paths, connection
|
|
69
|
+
* strings) stays in the server-side log above — never in the reason.
|
|
70
|
+
*/
|
|
71
|
+
function failureReason(error) {
|
|
72
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
+
const firstLine = (message.split("\n", 1)[0] ?? "").trim();
|
|
74
|
+
const capped = firstLine.length > 200 ? firstLine.slice(0, 200) : firstLine;
|
|
75
|
+
return capped.length > 0 ? capped : "unknown error";
|
|
76
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2
|
+
// Config-visible constant, not a magic literal repeated between this
|
|
3
|
+
// module and its own tests (env-file-path.ts's DEFAULT_ENV_FILENAME sets
|
|
4
|
+
// the same precedent) — normalize-database-url.test.ts and
|
|
5
|
+
// build-connection-string.test.ts import this instead of spelling "file:"
|
|
6
|
+
// out themselves.
|
|
7
|
+
export const FILE_PREFIX = "file:";
|
|
8
|
+
// One choke point for the Session 155 "one sqlite database is two files"
|
|
9
|
+
// trap. A relative `file:` URL is resolved differently by Prisma's CLI
|
|
10
|
+
// (schema-directory-relative, see setup/provision-database.ts's
|
|
11
|
+
// `--schema` invocation) and by the content-db adapter (cwd-relative), so
|
|
12
|
+
// `file:./velora.db` produced two physical files that were each
|
|
13
|
+
// internally consistent and collectively wrong — the operator backs up
|
|
14
|
+
// the one they were told about, which may not be the one being written.
|
|
15
|
+
//
|
|
16
|
+
// Making the path absolute removes the divergence rather than documenting
|
|
17
|
+
// it: there is nothing relative left for the two resolvers to disagree
|
|
18
|
+
// about.
|
|
19
|
+
//
|
|
20
|
+
// Applied in TWO places, which together cover every source of a database
|
|
21
|
+
// URL: buildConnectionString (what the wizard collects) and index.ts (an
|
|
22
|
+
// externally injected DATABASE_URL, normalised in place at boot before
|
|
23
|
+
// anything reads it).
|
|
24
|
+
//
|
|
25
|
+
// Non-sqlite URLs are returned byte-identical — the credential encoding
|
|
26
|
+
// buildConnectionString performs must not be disturbed.
|
|
27
|
+
export function normalizeDatabaseUrl(url, cwd = process.cwd()) {
|
|
28
|
+
const isFileUrl = url.startsWith(FILE_PREFIX);
|
|
29
|
+
if (!isFileUrl && url.includes("://"))
|
|
30
|
+
return url;
|
|
31
|
+
const path = isFileUrl ? url.slice(FILE_PREFIX.length) : url;
|
|
32
|
+
if (path.length === 0)
|
|
33
|
+
return url;
|
|
34
|
+
return `${FILE_PREFIX}${isAbsolute(path) ? path : resolve(cwd, path)}`;
|
|
35
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolveEnvFilePath } from "../config/env-file-path.js";
|
|
3
|
+
export function upsertEnvVars(content, vars) {
|
|
4
|
+
let out = content;
|
|
5
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
6
|
+
const line = `${key}=${value}`;
|
|
7
|
+
const pattern = new RegExp(`^${key}=.*$`, "m");
|
|
8
|
+
if (pattern.test(out)) {
|
|
9
|
+
out = out.replace(pattern, () => line);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
out = out.length > 0 && !out.endsWith("\n") ? `${out}\n${line}\n` : `${out}${line}\n`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
// Writes ONLY DATABASE_URL, and only to the path config/env-file-path.ts
|
|
18
|
+
// resolves — the same path load-env.ts reads at the next boot, so the two
|
|
19
|
+
// cannot drift.
|
|
20
|
+
//
|
|
21
|
+
// Two things this deliberately no longer does:
|
|
22
|
+
//
|
|
23
|
+
// - It no longer walks four levels up from its own compiled location to
|
|
24
|
+
// find the repo root. That assumed the monorepo's directory depth and
|
|
25
|
+
// overshot on a flattened `pnpm deploy` output.
|
|
26
|
+
//
|
|
27
|
+
// - It no longer writes VELORA_PRISMA_CLIENT_DIR. That was an absolute
|
|
28
|
+
// path captured from the machine that ran setup, wrong as soon as the
|
|
29
|
+
// install moved. db/resolve-client-dir.ts derives it from
|
|
30
|
+
// DATABASE_URL's scheme instead. The variable is still READ, and
|
|
31
|
+
// still wins when set explicitly — velora-dev's sandbox depends on
|
|
32
|
+
// that (packages/velora-dev/src/config.ts).
|
|
33
|
+
//
|
|
34
|
+
// One thing that was true before this file's packaging rework and still
|
|
35
|
+
// is: this only ever writes a physical .env FILE. A deployment target
|
|
36
|
+
// configured entirely by externally injected environment variables (a
|
|
37
|
+
// container's env block, a platform's secret manager) has no file for
|
|
38
|
+
// this to find or create, and persisting to one there would be actively
|
|
39
|
+
// wrong — nothing downstream would read it back, and it would leave a
|
|
40
|
+
// stray file with no one owning its lifecycle. That per-deployment-shape
|
|
41
|
+
// decision now DOES exist upstream, in routes/setup.ts's POST
|
|
42
|
+
// /api/setup/complete handler: it calls persistDatabaseConfig() only when
|
|
43
|
+
// `!opts.databaseConfigured` (the setup-full path, where DATABASE_URL was
|
|
44
|
+
// unset at boot). In admin-only mode (opts.databaseConfigured: true —
|
|
45
|
+
// DATABASE_URL was already injected by the environment) it skips this
|
|
46
|
+
// call entirely, precisely because that shape has nothing of its own to
|
|
47
|
+
// persist. This module still just writes to whatever path it's given (or
|
|
48
|
+
// resolveEnvFilePath() derives) — it has no opinion of its own about
|
|
49
|
+
// when it should run; that decision belongs to, and now lives in, the
|
|
50
|
+
// caller.
|
|
51
|
+
//
|
|
52
|
+
// Only ever called on the setup-full path (routes/setup.ts's
|
|
53
|
+
// `if (!opts.databaseConfigured)` guard around this call), where
|
|
54
|
+
// DATABASE_URL was unset at boot. Two other cases never reach it: an
|
|
55
|
+
// already-fully-configured instance (setupRequired: false) is rejected by
|
|
56
|
+
// this route's earlier 409 guard before any of this runs at all, and
|
|
57
|
+
// admin-only mode (opts.databaseConfigured: true, DATABASE_URL already
|
|
58
|
+
// injected by the environment) reaches admin creation but is excluded by
|
|
59
|
+
// that same `if` — see the comment above for why.
|
|
60
|
+
export function persistDatabaseConfig(databaseUrl, envPath = resolveEnvFilePath()) {
|
|
61
|
+
const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
|
|
62
|
+
writeFileSync(envPath, upsertEnvVars(existing, { DATABASE_URL: databaseUrl }));
|
|
63
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { writeVariantSchema } from "../scripts/generate-prisma-clients.js";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
// Anchored the same way generate-prisma-clients.ts anchors its own
|
|
8
|
+
// SERVER_DIR (see that file's comment): npx should always resolve
|
|
9
|
+
// `prisma` as apps/server's own devDependency, not walk up from whatever
|
|
10
|
+
// cwd happened to invoke this function and potentially trigger an
|
|
11
|
+
// unwanted auto-install. Compiled location is dist/setup/provision-database.js,
|
|
12
|
+
// two levels under the package root (dist/setup -> dist -> apps/server) —
|
|
13
|
+
// same depth as dist/scripts.
|
|
14
|
+
const SERVER_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
15
|
+
// Deliberately `db push`, never `migrate deploy`/`migrate dev`: the real
|
|
16
|
+
// migration history under apps/server/prisma/migrations/ is hard-locked
|
|
17
|
+
// to provider = "postgresql" (migration_lock.toml) and its SQL is
|
|
18
|
+
// Postgres-specific — pointing a mysql/sqlite schema variant at it fails
|
|
19
|
+
// outright. `db push` is provider-agnostic and has no migration-history
|
|
20
|
+
// dependency, matching velora-dev's sandbox (Session 78) and Session 94's
|
|
21
|
+
// own verification test. Trade-off, deliberately unsolved this session: a
|
|
22
|
+
// database provisioned this way has no _prisma_migrations table, so it
|
|
23
|
+
// can't later be incrementally upgraded via a normal `migrate deploy` —
|
|
24
|
+
// that's a separate problem (existing self-hosted instance schema
|
|
25
|
+
// updates), not first-run setup.
|
|
26
|
+
// Twin of generate-prisma-clients.ts's runPrismaGenerate — same spawnSync +
|
|
27
|
+
// stdio: "inherit" + shell: true pattern, same fix for the same reason (see
|
|
28
|
+
// that file's comment on the vitest-worker "onTaskUpdate" RPC timeout).
|
|
29
|
+
// This call site's own single spawnSync is shorter in isolation (~10-12s
|
|
30
|
+
// against real infra), but it is a live setup-request code path — provision
|
|
31
|
+
// on any given call can run slower under load (the full-suite run's
|
|
32
|
+
// mysql-dialect setup-complete case measured 37s wall for the whole
|
|
33
|
+
// request) — so it carries the same class of risk and gets the same fix.
|
|
34
|
+
async function provisionDatabaseNow(dialect, databaseUrl) {
|
|
35
|
+
const variantPath = writeVariantSchema(dialect);
|
|
36
|
+
try {
|
|
37
|
+
const { stdout, stderr } = await execFileAsync("npx", ["prisma", "db", "push", "--schema", `"${variantPath}"`, "--skip-generate"], {
|
|
38
|
+
cwd: SERVER_DIR,
|
|
39
|
+
shell: true,
|
|
40
|
+
// Same rationale as generate-prisma-clients.ts: the 1 MiB default
|
|
41
|
+
// maxBuffer kills the child on overflow — setup must never fail
|
|
42
|
+
// that way over verbose prisma output.
|
|
43
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
44
|
+
env: { ...process.env, DATABASE_URL: databaseUrl },
|
|
45
|
+
});
|
|
46
|
+
if (stdout)
|
|
47
|
+
process.stdout.write(stdout);
|
|
48
|
+
if (stderr)
|
|
49
|
+
process.stderr.write(stderr);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const failed = error;
|
|
53
|
+
if (failed.stdout)
|
|
54
|
+
process.stdout.write(failed.stdout);
|
|
55
|
+
if (failed.stderr)
|
|
56
|
+
process.stderr.write(failed.stderr);
|
|
57
|
+
throw new Error(`provisionDatabase: prisma db push failed for ${dialect} (exit ${failed.code})`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// `prisma db push` is not safe to run truly concurrently against the same
|
|
61
|
+
// target: two overlapping schema-engine invocations racing on the same
|
|
62
|
+
// fresh schema were observed to fail outright — postgresql refuses with a
|
|
63
|
+
// data-loss warning it can't auto-accept, mysql fails a bare `CREATE TABLE`
|
|
64
|
+
// with "already exists" — instead of both landing cleanly. Before this
|
|
65
|
+
// file's spawnSync -> execFile conversion this was invisible: spawnSync
|
|
66
|
+
// blocks the entire process, so two "concurrent" provisionDatabase() calls
|
|
67
|
+
// in the same Node process could never actually overlap — the second
|
|
68
|
+
// caller's code couldn't even start running until the first's synchronous
|
|
69
|
+
// call returned, which serialized them as a side effect. Fixing the real
|
|
70
|
+
// bug (spawnSync blocking the event loop past vitest's RPC timeout) removed
|
|
71
|
+
// that accidental serialization and exposed the race directly:
|
|
72
|
+
// setup-complete.integration.test.ts's M-3 concurrent-completion test
|
|
73
|
+
// started seeing [200, 400] instead of [200, 409] on both postgresql and
|
|
74
|
+
// mysql. Restoring in-process serialization explicitly — a bare promise
|
|
75
|
+
// chain, not a new dependency — keeps calls in the SAME process (e.g. two
|
|
76
|
+
// inbound setup requests racing the same live server, exactly what that
|
|
77
|
+
// test reproduces) queued one at a time, while still letting the event
|
|
78
|
+
// loop answer other work between them. Calls from separate processes
|
|
79
|
+
// (separate vitest workers, a real deploy) are unaffected either way, same
|
|
80
|
+
// as before.
|
|
81
|
+
let queue = Promise.resolve();
|
|
82
|
+
export function provisionDatabase(dialect, databaseUrl) {
|
|
83
|
+
const run = queue.then(() => provisionDatabaseNow(dialect, databaseUrl));
|
|
84
|
+
// Chain the queue off a version that never rejects, so one failed
|
|
85
|
+
// provision doesn't wedge every call queued after it — each caller still
|
|
86
|
+
// observes its own real outcome (including a real rejection) via `run`.
|
|
87
|
+
queue = run.then(() => undefined, () => undefined);
|
|
88
|
+
return run;
|
|
89
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
import { serializerCompiler, validatorCompiler } from "fastify-type-provider-zod";
|
|
3
|
+
import { adminStaticRoutes } from "./routes/admin-static.js";
|
|
4
|
+
import { setupRoutes } from "./routes/setup.js";
|
|
5
|
+
// The reduced "not configured yet" boot mode (Session 96), later widened
|
|
6
|
+
// (Task 4, boot/resolve-boot-mode.ts's resolveBootMode) to a second case:
|
|
7
|
+
// a genuinely minimal app, built whenever resolveBootMode() picks anything
|
|
8
|
+
// other than "full" — that's no longer only DATABASE_URL being unset
|
|
9
|
+
// (setup-full); it's also "setup-admin-only", where DATABASE_URL IS set
|
|
10
|
+
// but no admin row exists yet. Never calls connectContentDb(), never
|
|
11
|
+
// touches prisma, never constructs PluginRegistryService/MediaService/
|
|
12
|
+
// StructuredStorageAPI — in the setup-full case there is nothing
|
|
13
|
+
// configured for those to connect to yet, and in setup-admin-only the
|
|
14
|
+
// whole point of this app is the single admin-creation route, not the
|
|
15
|
+
// rest of the stack. This is a SEPARATE boot path, not a gate inside
|
|
16
|
+
// buildApp() itself: buildApp() calls connectContentDb() before any hook
|
|
17
|
+
// could be registered, and connectContentDb() throws immediately when no
|
|
18
|
+
// database URL is set — a hook registered later in the same app could
|
|
19
|
+
// never run in that case.
|
|
20
|
+
//
|
|
21
|
+
// Session 164: also built when DATABASE_URL IS set but the database holds
|
|
22
|
+
// no admin user — the admin-only mode. In that case Prisma HAS already
|
|
23
|
+
// been reached, by boot/resolve-boot-mode.ts's probe, before this app was
|
|
24
|
+
// chosen; the "never touches prisma" invariant above is about the
|
|
25
|
+
// unconfigured path and still holds there.
|
|
26
|
+
export async function buildSetupOnlyApp(opts = { databaseConfigured: false }) {
|
|
27
|
+
const app = Fastify({ logger: true }).withTypeProvider();
|
|
28
|
+
app.setValidatorCompiler(validatorCompiler);
|
|
29
|
+
app.setSerializerCompiler(serializerCompiler);
|
|
30
|
+
await app.register(setupRoutes, { setupRequired: true, databaseConfigured: opts.databaseConfigured });
|
|
31
|
+
// S184: the wizard IS the admin SPA, so this reduced boot mode has to
|
|
32
|
+
// serve /velora too — a fresh install has no other browser surface.
|
|
33
|
+
// Registered BEFORE setNotFoundHandler below, and route matching beats a
|
|
34
|
+
// not-found handler regardless, so the 503 "not configured yet" reply
|
|
35
|
+
// still covers every path this module does not own. admin-static.ts is
|
|
36
|
+
// deliberately Prisma-free (see its rate-limit comment) so importing it
|
|
37
|
+
// here cannot violate this path's no-Prisma invariant.
|
|
38
|
+
await app.register(adminStaticRoutes);
|
|
39
|
+
app.setNotFoundHandler((_request, reply) => {
|
|
40
|
+
reply.code(503).send({ message: "Velora is not configured yet — complete setup first." });
|
|
41
|
+
});
|
|
42
|
+
return app;
|
|
43
|
+
}
|