@velora-cms/server 0.12.0 → 0.12.1
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/README.md +6 -0
- package/dist/admin/sync-admin-bundle.js +1 -1
- package/dist/admin-bundle/.velora-version +1 -1
- package/dist/bin-sync-admin.js +2 -2
- package/dist/bundled-templates/com.velora.blog/package.tar.gz +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_6c5ee82.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_f053753.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/index/en_33ea61e.pf_index +0 -0
- package/dist/docs-bundle/pagefind/index/en_bb7c383.pf_index +0 -0
- package/dist/docs-bundle/pagefind/index/en_ff6eddf.pf_index +0 -0
- package/dist/docs-bundle/pagefind/pagefind-entry.json +1 -1
- package/dist/docs-bundle/pagefind/pagefind.en_6bbff64ea9.pf_meta +0 -0
- package/dist/docs-bundle/v1/index.html +4 -4
- package/dist/docs-bundle/v1/using-velora/installation/index.html +3 -3
- package/dist/routes/admin-static.js +1 -1
- package/package.json +7 -7
- package/dist/docs-bundle/pagefind/fragment/en_1ef320c.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/fragment/en_67dccf8.pf_fragment +0 -0
- package/dist/docs-bundle/pagefind/index/en_8450ec7.pf_index +0 -0
- package/dist/docs-bundle/pagefind/index/en_c285f7b.pf_index +0 -0
- package/dist/docs-bundle/pagefind/index/en_e8cada7.pf_index +0 -0
- package/dist/docs-bundle/pagefind/pagefind.en_57d2f8922f.pf_meta +0 -0
package/README.md
CHANGED
|
@@ -63,3 +63,9 @@ endpoint — `S3_ENDPOINT` (defaults to `http://localhost:9000`),
|
|
|
63
63
|
|
|
64
64
|
Full documentation, guides, and the API reference live at
|
|
65
65
|
[docs.velora-cms.com](https://docs.velora-cms.com).
|
|
66
|
+
|
|
67
|
+
## Source & support
|
|
68
|
+
|
|
69
|
+
Velora's source is not public. Questions and bug reports:
|
|
70
|
+
[velora-starter](https://github.com/velora-cms/velora-starter).
|
|
71
|
+
Docs at https://docs.velora-cms.com. Licensed Apache-2.0.
|
|
@@ -2,7 +2,7 @@ import { cpSync, existsSync, readFileSync, readdirSync, renameSync, rmSync, writ
|
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
// S186b (visible scaffold): a scaffolded site copies the installed admin
|
|
5
|
-
// bundle out to its own public/velora
|
|
5
|
+
// bundle out to its own public/velora/admin instead of serving it straight
|
|
6
6
|
// out of node_modules, so it needs a way to re-copy after
|
|
7
7
|
// `npm update @velora-cms/server`. This is that machinery — wrapped by the
|
|
8
8
|
// velora-sync-admin bin (../bin-sync-admin.ts) and consulted (read-only, via
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.12.
|
|
1
|
+
0.12.1
|
package/dist/bin-sync-admin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// The `velora-sync-admin` command (S186b): re-copies the installed admin
|
|
3
|
-
// bundle into the scaffold's public/velora
|
|
3
|
+
// bundle into the scaffold's public/velora/admin (or VELORA_ADMIN_DIR),
|
|
4
4
|
// rewriting its version stamp — the drift-control half of the visible
|
|
5
5
|
// scaffold, run after `npm update @velora-cms/server`. Runs with cwd set to
|
|
6
6
|
// the USER's project, never this package, which is exactly what
|
|
@@ -19,7 +19,7 @@ loadEnvFile();
|
|
|
19
19
|
// guard, for the rare case where a caller genuinely wants to replace a
|
|
20
20
|
// directory that doesn't look like a prior admin bundle.
|
|
21
21
|
const force = process.argv.slice(2).includes("--force");
|
|
22
|
-
const targetDir = process.env.VELORA_ADMIN_DIR || "public/velora
|
|
22
|
+
const targetDir = process.env.VELORA_ADMIN_DIR || "public/velora/admin";
|
|
23
23
|
// Resolved up front so every line this bin prints — success or failure —
|
|
24
24
|
// names the actual absolute path being acted on, not the raw (possibly
|
|
25
25
|
// relative) override string.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.5.2","languages":{"en":{"hash":"
|
|
1
|
+
{"version":"1.5.2","languages":{"en":{"hash":"en_6bbff64ea9","wasm":"en","page_count":11}},"include_characters":["_","‿","⁀","⁔","︳","︴","﹍","﹎","﹏","_"]}
|
|
Binary file
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
})();
|
|
72
72
|
</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>
|
|
73
73
|
StarlightThemeProvider.updatePickers();
|
|
74
|
-
</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="#about-this-documentation" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">About this documentation</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="#about-this-documentation" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">About this documentation</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">Velora</h1></div></div><div class="content-panel astro-ahkzlqop"><div class="sl-container astro-ahkzlqop"><div class="sl-markdown-content"><p>Velora is
|
|
74
|
+
</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="#about-this-documentation" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">About this documentation</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="#about-this-documentation" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">About this documentation</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">Velora</h1></div></div><div class="content-panel astro-ahkzlqop"><div class="sl-container astro-ahkzlqop"><div class="sl-markdown-content"><p>Velora is a CMS framework built on Node.js and React. Content is
|
|
75
75
|
immutable — every save writes a new version and rollback only changes which
|
|
76
76
|
version is current — updates never break a running site, the content tree
|
|
77
77
|
scales from a handful of pages to very large ones, and the same instance can
|
|
@@ -81,6 +81,6 @@ be used headless through its API or traditionally through its own rendering.</p>
|
|
|
81
81
|
<p>These docs describe <strong>v1</strong>, the first public release line. Everything lives
|
|
82
82
|
under <code dir="auto">/v1/</code> so that future versions can be published alongside it without
|
|
83
83
|
breaking links to this one.</p>
|
|
84
|
-
<p>
|
|
85
|
-
<
|
|
86
|
-
|
|
84
|
+
<p>Get a Velora instance running with <a href="/docs/v1/using-velora/installation/">Installation</a>:
|
|
85
|
+
<code dir="auto">npm create velora@latest my-site</code> scaffolds a runnable project in one
|
|
86
|
+
command, and the setup wizard takes it from there.</p></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"></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>
|
|
@@ -125,11 +125,11 @@ want to run from source instead: see
|
|
|
125
125
|
<p><code dir="auto">npm create velora@latest</code> writes a normal Node project you can read and
|
|
126
126
|
extend — the Velora engine itself lives in <code dir="auto">node_modules</code> and updates with
|
|
127
127
|
<code dir="auto">npm update</code>; everything else is a visible file that’s yours:</p>
|
|
128
|
-
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="plaintext"><code><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">my-site/</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">server.js your entry point — imports the Velora engine from</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">node_modules and starts it; add your own routes,</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">middleware, or redirects here</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">public/</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">velora-admin/
|
|
128
|
+
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="plaintext"><code><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">my-site/</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">server.js your entry point — imports the Velora engine from</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">node_modules and starts it; add your own routes,</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">middleware, or redirects here</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">public/</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">velora/</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">admin/ the admin UI, copied from the installed server</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">package (re-copy with `npm run sync-admin`)</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">media/ uploaded files (in .gitignore, like velora.db)</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">templates/ reserved for a future release — templates created</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">in the admin will land here as editable files</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">velora.db content + settings — SQLite only, appears after</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">setup. With PostgreSQL/MySQL the data lives in the</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">database server instead, and only DATABASE_URL in</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">.env points at it.</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">.env JWT_SECRET, VELORA_ADMIN_DIR, and (PostgreSQL/MySQL)</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">DATABASE_URL</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">.gitignore</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">package.json</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">README.md</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">docker-compose.yml Custom mode with PostgreSQL or MySQL only</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="my-site/ server.js your entry point — imports the Velora engine from node_modules and starts it; add your own routes, middleware, or redirects here public/ velora/ admin/ the admin UI, copied from the installed server package (re-copy with `npm run sync-admin`) media/ uploaded files (in .gitignore, like velora.db) templates/ reserved for a future release — templates created in the admin will land here as editable files velora.db content + settings — SQLite only, appears after setup. With PostgreSQL/MySQL the data lives in the database server instead, and only DATABASE_URL in .env points at it. .env JWT_SECRET, VELORA_ADMIN_DIR, and (PostgreSQL/MySQL) DATABASE_URL .gitignore package.json README.md docker-compose.yml Custom mode with PostgreSQL or MySQL only"><div></div></button></div></figure></div>
|
|
129
129
|
<p><code dir="auto">server.js</code> is yours to extend — nothing between <code dir="auto">createApp()</code> and
|
|
130
130
|
<code dir="auto">listen()</code> is ever overwritten by an update. Add a route, for example:</p>
|
|
131
131
|
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="js"><code><div class="ec-line"><div class="code"><span style="--0:#7FDBCA;--1:#096E72">app</span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">get</span><span style="--0:#D6DEEB;--1:#403F53">(</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">/hello</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#C792EA;--1:#8844AE">async</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">()</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> ({ hello: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">world</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="app.get("/hello", async () => ({ hello: "world" }));"><div></div></button></div></figure></div>
|
|
132
|
-
<p><code dir="auto">public/velora
|
|
132
|
+
<p><code dir="auto">public/velora/admin/</code> is a copy of the admin UI, not a live link into
|
|
133
133
|
<code dir="auto">node_modules</code>, so keep it in sync after an update:</p>
|
|
134
134
|
<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">npm</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">update</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">@velora-cms/server</span><span style="--0:#D6DEEB;--1:#403F53"> && </span><span style="--0:#82AAFF;--1:#3B61B0">npm</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">run</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">sync-admin</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="npm update @velora-cms/server && npm run sync-admin"><div></div></button></div></figure></div>
|
|
135
135
|
<p>Skip that and the server still boots and serves the (stale) copy — it
|
|
@@ -712,7 +712,7 @@ with no separate build step:</p>
|
|
|
712
712
|
|
|
713
713
|
|
|
714
714
|
|
|
715
|
-
<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>. A scaffolded project’s <code dir="auto">.env</code> sets this to <code dir="auto">public/velora
|
|
715
|
+
<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>. A scaffolded project’s <code dir="auto">.env</code> sets this to <code dir="auto">public/velora/admin</code> by default, pointing at the copy <code dir="auto">npm create velora</code> writes there (see “What’s in the scaffolded folder” above); without it — or outside a scaffold — 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_PUBLIC_URL</code></td><td>string (origin)</td><td>Base URL used to make the <strong>public</strong> <code dir="auto">/api/v1/media</code> and GraphQL <code dir="auto">downloadUrl</code> fields absolute, e.g. <code dir="auto">https://cms.example.com/media/<id>/<filename></code> — a headless frontend fetches that URL from its own origin, so a path-relative value would resolve against the wrong host. Set this behind a reverse proxy/CDN where the request’s own <code dir="auto">Host</code>/protocol isn’t the public-facing one. Unset (or blank) means the base is derived per-request from the incoming <code dir="auto">Host</code> header and protocol instead (honors <code dir="auto">VELORA_TRUST_PROXY</code>) — fine for direct access. Doesn’t affect the backoffice <code dir="auto">/api/media</code> surface, which stays path-relative, same-origin with the admin SPA either way. Trailing slashes are stripped.</td><td><code dir="auto">https://cms.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>
|
|
716
716
|
<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>
|
|
717
717
|
<p>Media uploads go through one of two storage drivers — see
|
|
718
718
|
<a href="/docs/v1/using-velora/media/#where-the-bytes-live">Media</a> for the full
|
|
@@ -183,7 +183,7 @@ export async function adminStaticRoutes(app) {
|
|
|
183
183
|
decorateReply: false,
|
|
184
184
|
});
|
|
185
185
|
// S186b drift check: a scaffolded site copies the admin bundle out to
|
|
186
|
-
// VELORA_ADMIN_DIR (public/velora
|
|
186
|
+
// VELORA_ADMIN_DIR (public/velora/admin) instead of serving it straight
|
|
187
187
|
// from node_modules, so it can go stale after `npm update` bumps the
|
|
188
188
|
// installed server without a matching `npm run sync-admin`. One clear
|
|
189
189
|
// warning on mismatch, never a hard failure — a stale admin is better
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velora-cms/server",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=22.12"
|
|
6
6
|
},
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
],
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
29
|
-
"url": "git+https://github.com/velora-cms/velora.git"
|
|
30
|
-
"directory": "apps/server"
|
|
29
|
+
"url": "git+https://github.com/velora-cms/velora-starter.git"
|
|
31
30
|
},
|
|
32
31
|
"bugs": {
|
|
33
|
-
"url": "https://github.com/velora-cms/velora/issues"
|
|
32
|
+
"url": "https://github.com/velora-cms/velora-starter/issues"
|
|
34
33
|
},
|
|
34
|
+
"homepage": "https://velora-cms.com",
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"zod": "4.4.3",
|
|
62
62
|
"@velora-cms/api-schemas": "0.12.0",
|
|
63
63
|
"@velora-cms/db-adapter": "0.11.2",
|
|
64
|
-
"@velora-cms/content-service": "0.11.0",
|
|
65
64
|
"@velora-cms/design-tokens": "0.11.0",
|
|
66
65
|
"@velora-cms/plugin-package": "0.11.0",
|
|
66
|
+
"@velora-cms/content-service": "0.11.0",
|
|
67
67
|
"@velora-cms/plugin-sdk": "0.11.0",
|
|
68
68
|
"@velora-cms/prisma-variants": "0.11.0"
|
|
69
69
|
},
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
"tsx": "4.22.4",
|
|
79
79
|
"@velora-cms/admin-ui": "0.1.0",
|
|
80
80
|
"@velora-cms/docs": "0.1.0",
|
|
81
|
-
"@velora-cms/google-maps": "0.1.0",
|
|
82
81
|
"create-velora-plugin": "0.11.0",
|
|
83
82
|
"velora-plugin": "0.11.0",
|
|
84
|
-
"@velora-cms/reading-time": "0.1.0"
|
|
83
|
+
"@velora-cms/reading-time": "0.1.0",
|
|
84
|
+
"@velora-cms/google-maps": "0.1.0"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "prisma generate && tsc -p . && node dist/scripts/generate-prisma-clients.js && node dist/scripts/copy-docs-bundle.js && node dist/scripts/copy-admin-bundle.js && node dist/scripts/pack-bundled-templates.js",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|