@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.
Files changed (367) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +65 -0
  3. package/dist/admin-bundle/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js_commonjs-proxy-Ng0fOpdU.js +1 -0
  4. 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
  5. package/dist/admin-bundle/assets/_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DOKdWYyj.js +1 -0
  6. 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
  7. package/dist/admin-bundle/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js-BuUBskgj.js +9 -0
  8. 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
  9. 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
  10. 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
  11. package/dist/admin-bundle/assets/content-trash.schema-DfXHkC-w.js +72 -0
  12. package/dist/admin-bundle/assets/hostInit--C4xK6nj.js +1 -0
  13. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  14. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  15. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
  16. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
  17. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  18. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  19. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
  20. package/dist/admin-bundle/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
  21. package/dist/admin-bundle/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  22. package/dist/admin-bundle/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  23. package/dist/admin-bundle/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  24. package/dist/admin-bundle/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  25. package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  26. package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  27. package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
  28. package/dist/admin-bundle/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
  29. package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  30. package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  31. package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
  32. package/dist/admin-bundle/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
  33. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-400-normal-CyU-ddYS.woff2 +0 -0
  34. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-400-normal-EA1o-u_Q.woff +0 -0
  35. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-500-normal-C4MQITzh.woff2 +0 -0
  36. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-500-normal-DPXcppbm.woff +0 -0
  37. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-600-normal-0pRdybE_.woff2 +0 -0
  38. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-arabic-600-normal-MJZ0liF5.woff +0 -0
  39. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-400-normal-Bo5KPYvw.woff2 +0 -0
  40. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-400-normal-CFZh1unN.woff +0 -0
  41. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-500-normal-BletK1Hp.woff +0 -0
  42. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-500-normal-Cd6jVIg7.woff2 +0 -0
  43. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-600-normal-Dk5eISD_.woff +0 -0
  44. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-600-normal-KrqB56Mw.woff2 +0 -0
  45. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-400-normal-BeVLg08x.woff +0 -0
  46. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-400-normal-BpLfq-63.woff2 +0 -0
  47. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-500-normal-Ck_W4G78.woff2 +0 -0
  48. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-500-normal-eJxPnL1P.woff +0 -0
  49. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-600-normal-DT29Q8HW.woff +0 -0
  50. package/dist/admin-bundle/assets/ibm-plex-sans-arabic-latin-ext-600-normal-DjDAeNQD.woff2 +0 -0
  51. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-400-normal-BTotfTJu.woff +0 -0
  52. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-400-normal-DZqxrq2p.woff2 +0 -0
  53. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-500-normal-ByOcLdNv.woff +0 -0
  54. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-500-normal-CocWQlwt.woff2 +0 -0
  55. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-600-normal-71GNu3SW.woff2 +0 -0
  56. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-600-normal-BGq0mW3O.woff +0 -0
  57. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-400-normal-Dsrv2Tcn.woff +0 -0
  58. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-400-normal-g30qAdWV.woff2 +0 -0
  59. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-500-normal-Cs5J6C77.woff2 +0 -0
  60. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-500-normal-DB5PtV2g.woff +0 -0
  61. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-600-normal-Bz0x94Yp.woff +0 -0
  62. package/dist/admin-bundle/assets/ibm-plex-sans-cyrillic-ext-600-normal-DUMzJB7m.woff2 +0 -0
  63. package/dist/admin-bundle/assets/ibm-plex-sans-greek-400-normal-D9ESIMu3.woff +0 -0
  64. package/dist/admin-bundle/assets/ibm-plex-sans-greek-400-normal-_efipK4i.woff2 +0 -0
  65. package/dist/admin-bundle/assets/ibm-plex-sans-greek-500-normal-CuWXN6rf.woff +0 -0
  66. package/dist/admin-bundle/assets/ibm-plex-sans-greek-500-normal-JMMifIXV.woff2 +0 -0
  67. package/dist/admin-bundle/assets/ibm-plex-sans-greek-600-normal-D-CqTdkO.woff +0 -0
  68. package/dist/admin-bundle/assets/ibm-plex-sans-greek-600-normal-DzTrcv_p.woff2 +0 -0
  69. package/dist/admin-bundle/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  70. package/dist/admin-bundle/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  71. package/dist/admin-bundle/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  72. package/dist/admin-bundle/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  73. package/dist/admin-bundle/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  74. package/dist/admin-bundle/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  75. package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-400-normal-C5H60-Va.woff2 +0 -0
  76. package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-400-normal-RBey6euL.woff +0 -0
  77. package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-500-normal-D0aIdm-b.woff +0 -0
  78. package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-500-normal-DakdToA3.woff2 +0 -0
  79. package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-600-normal-DIrixKbi.woff +0 -0
  80. package/dist/admin-bundle/assets/ibm-plex-sans-latin-ext-600-normal-DOrvGEcy.woff2 +0 -0
  81. package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-400-normal-DG4YqDda.woff2 +0 -0
  82. package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-400-normal-fK1oJ5dG.woff +0 -0
  83. package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-500-normal-BEb3_waV.woff +0 -0
  84. package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-500-normal-e4dixQRQ.woff2 +0 -0
  85. package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-600-normal-DgdngZtN.woff +0 -0
  86. package/dist/admin-bundle/assets/ibm-plex-sans-vietnamese-600-normal-DpPYBSTl.woff2 +0 -0
  87. package/dist/admin-bundle/assets/index-BIAF0ShP.js +542 -0
  88. package/dist/admin-bundle/assets/index-DhMY-0sC.js +148 -0
  89. package/dist/admin-bundle/assets/index-DnZV_gsg.css +1 -0
  90. package/dist/admin-bundle/assets/index-Do71v6NZ.js +7 -0
  91. package/dist/admin-bundle/assets/literata-cyrillic-ext-opsz-italic-5yUt4G_9.woff2 +0 -0
  92. package/dist/admin-bundle/assets/literata-cyrillic-ext-opsz-normal-C5tfwALZ.woff2 +0 -0
  93. package/dist/admin-bundle/assets/literata-cyrillic-opsz-italic-Bj0ndbyp.woff2 +0 -0
  94. package/dist/admin-bundle/assets/literata-cyrillic-opsz-normal-DgmypKXX.woff2 +0 -0
  95. package/dist/admin-bundle/assets/literata-greek-ext-opsz-italic-DFpO5j-Z.woff2 +0 -0
  96. package/dist/admin-bundle/assets/literata-greek-ext-opsz-normal-DGm64vGR.woff2 +0 -0
  97. package/dist/admin-bundle/assets/literata-greek-opsz-italic-CHERNRFq.woff2 +0 -0
  98. package/dist/admin-bundle/assets/literata-greek-opsz-normal-DFglUmAd.woff2 +0 -0
  99. package/dist/admin-bundle/assets/literata-latin-ext-opsz-italic-4y8iAqqs.woff2 +0 -0
  100. package/dist/admin-bundle/assets/literata-latin-ext-opsz-normal-STiTPs0F.woff2 +0 -0
  101. package/dist/admin-bundle/assets/literata-latin-opsz-italic-CJ93D38p.woff2 +0 -0
  102. package/dist/admin-bundle/assets/literata-latin-opsz-normal-BHZsWIlc.woff2 +0 -0
  103. package/dist/admin-bundle/assets/literata-vietnamese-opsz-italic-BdcrZMcO.woff2 +0 -0
  104. package/dist/admin-bundle/assets/literata-vietnamese-opsz-normal-Gqw5JQlq.woff2 +0 -0
  105. package/dist/admin-bundle/assets/mf-entry-bootstrap-0-aef015cd.js +41 -0
  106. package/dist/admin-bundle/assets/remoteEntry-CNyN68bc.js +14 -0
  107. package/dist/admin-bundle/assets/virtualExposes-BDCSo5OS.js +1 -0
  108. package/dist/admin-bundle/assets/vite-preload-helper-Cgledu0r.js +1 -0
  109. package/dist/admin-bundle/index.html +16 -0
  110. package/dist/app.d.ts +8 -0
  111. package/dist/app.js +252 -0
  112. package/dist/auth/api-content-author.d.ts +2 -0
  113. package/dist/auth/api-content-author.js +27 -0
  114. package/dist/auth/api-keys.d.ts +7 -0
  115. package/dist/auth/api-keys.js +85 -0
  116. package/dist/auth/jwt-payload.d.ts +16 -0
  117. package/dist/auth/jwt-payload.js +1 -0
  118. package/dist/auth/preview-tokens.d.ts +7 -0
  119. package/dist/auth/preview-tokens.js +76 -0
  120. package/dist/auth/rate-limit.d.ts +16 -0
  121. package/dist/auth/rate-limit.js +283 -0
  122. package/dist/auth/require-auth.d.ts +4 -0
  123. package/dist/auth/require-auth.js +28 -0
  124. package/dist/auth/route-rate-limits.d.ts +31 -0
  125. package/dist/auth/route-rate-limits.js +155 -0
  126. package/dist/auth/tokens.d.ts +15 -0
  127. package/dist/auth/tokens.js +38 -0
  128. package/dist/bin.d.ts +2 -0
  129. package/dist/bin.js +6 -0
  130. package/dist/boot/core-migration-gate.d.ts +12 -0
  131. package/dist/boot/core-migration-gate.js +52 -0
  132. package/dist/boot/resolve-boot-mode.d.ts +6 -0
  133. package/dist/boot/resolve-boot-mode.js +206 -0
  134. package/dist/bundled-templates/com.velora.blog/manifest.json +39 -0
  135. package/dist/bundled-templates/com.velora.blog/package.tar.gz +0 -0
  136. package/dist/bundled-templates/com.velora.blog/sample-content.json +14 -0
  137. package/dist/config/admin-ui.d.ts +1 -0
  138. package/dist/config/admin-ui.js +10 -0
  139. package/dist/config/cors.d.ts +7 -0
  140. package/dist/config/cors.js +53 -0
  141. package/dist/config/env-file-path.d.ts +2 -0
  142. package/dist/config/env-file-path.js +22 -0
  143. package/dist/config/graphql-limits.d.ts +2 -0
  144. package/dist/config/graphql-limits.js +26 -0
  145. package/dist/config/headless.d.ts +1 -0
  146. package/dist/config/headless.js +8 -0
  147. package/dist/config/license-revalidation.d.ts +2 -0
  148. package/dist/config/license-revalidation.js +16 -0
  149. package/dist/config/load-env.d.ts +1 -0
  150. package/dist/config/load-env.js +53 -0
  151. package/dist/config/marketplace.d.ts +11 -0
  152. package/dist/config/marketplace.js +19 -0
  153. package/dist/config/preview.d.ts +3 -0
  154. package/dist/config/preview.js +39 -0
  155. package/dist/config/public-docs.d.ts +1 -0
  156. package/dist/config/public-docs.js +9 -0
  157. package/dist/config/site.d.ts +7 -0
  158. package/dist/config/site.js +12 -0
  159. package/dist/config/trust-proxy.d.ts +2 -0
  160. package/dist/config/trust-proxy.js +42 -0
  161. package/dist/data-types/validate-data-type-settings.d.ts +1 -0
  162. package/dist/data-types/validate-data-type-settings.js +33 -0
  163. package/dist/db/content-db.d.ts +16 -0
  164. package/dist/db/content-db.js +109 -0
  165. package/dist/db/core-migrations/index.d.ts +14 -0
  166. package/dist/db/core-migrations/index.js +184 -0
  167. package/dist/db/core-migrations/steps.d.ts +4 -0
  168. package/dist/db/core-migrations/steps.js +66 -0
  169. package/dist/db/load-prisma-client.d.ts +2 -0
  170. package/dist/db/load-prisma-client.js +44 -0
  171. package/dist/db/prisma.d.ts +3 -0
  172. package/dist/db/prisma.js +67 -0
  173. package/dist/db/resolve-client-dir.d.ts +2 -0
  174. package/dist/db/resolve-client-dir.js +83 -0
  175. package/dist/docs/filter-public-api-spec.d.ts +2 -0
  176. package/dist/docs/filter-public-api-spec.js +52 -0
  177. package/dist/docs-bundle/404.html +41 -0
  178. package/dist/docs-bundle/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js +1 -0
  179. package/dist/docs-bundle/_astro/Search.astro_astro_type_script_index_0_lang.CavldbAs.js +1 -0
  180. package/dist/docs-bundle/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js +1 -0
  181. package/dist/docs-bundle/_astro/common.DTXA7sXM.css +3 -0
  182. package/dist/docs-bundle/_astro/ec.0vx5m.js +3 -0
  183. package/dist/docs-bundle/_astro/ec.w36nc.css +1 -0
  184. package/dist/docs-bundle/_astro/page.Dwipeu-R.js +1 -0
  185. package/dist/docs-bundle/_astro/print.ehPL0gv-.css +1 -0
  186. package/dist/docs-bundle/_astro/starlight-toc.CTCQXEge.js +1 -0
  187. package/dist/docs-bundle/_astro/ui-core.D-7Scnhs.js +2 -0
  188. package/dist/docs-bundle/favicon.svg +1 -0
  189. package/dist/docs-bundle/index.html +1 -0
  190. package/dist/docs-bundle/pagefind/fragment/en_18a36d7.pf_fragment +0 -0
  191. package/dist/docs-bundle/pagefind/fragment/en_1d9eb24.pf_fragment +0 -0
  192. package/dist/docs-bundle/pagefind/fragment/en_1ef320c.pf_fragment +0 -0
  193. package/dist/docs-bundle/pagefind/fragment/en_3099406.pf_fragment +0 -0
  194. package/dist/docs-bundle/pagefind/fragment/en_4a5b6fe.pf_fragment +0 -0
  195. package/dist/docs-bundle/pagefind/fragment/en_9aa652e.pf_fragment +0 -0
  196. package/dist/docs-bundle/pagefind/fragment/en_baccdf6.pf_fragment +0 -0
  197. package/dist/docs-bundle/pagefind/fragment/en_d81f3fe.pf_fragment +0 -0
  198. package/dist/docs-bundle/pagefind/fragment/en_d855550.pf_fragment +0 -0
  199. package/dist/docs-bundle/pagefind/fragment/en_e6d88d8.pf_fragment +0 -0
  200. package/dist/docs-bundle/pagefind/fragment/en_e9d3189.pf_fragment +0 -0
  201. package/dist/docs-bundle/pagefind/index/en_5feeed7.pf_index +0 -0
  202. package/dist/docs-bundle/pagefind/index/en_c6981f9.pf_index +0 -0
  203. package/dist/docs-bundle/pagefind/index/en_ce4f6bf.pf_index +0 -0
  204. package/dist/docs-bundle/pagefind/pagefind-component-ui.css +1509 -0
  205. package/dist/docs-bundle/pagefind/pagefind-component-ui.js +56 -0
  206. package/dist/docs-bundle/pagefind/pagefind-entry.json +1 -0
  207. package/dist/docs-bundle/pagefind/pagefind-highlight.js +1070 -0
  208. package/dist/docs-bundle/pagefind/pagefind-modular-ui.css +214 -0
  209. package/dist/docs-bundle/pagefind/pagefind-modular-ui.js +8 -0
  210. package/dist/docs-bundle/pagefind/pagefind-ui.css +1 -0
  211. package/dist/docs-bundle/pagefind/pagefind-ui.js +2 -0
  212. package/dist/docs-bundle/pagefind/pagefind-worker.js +6 -0
  213. package/dist/docs-bundle/pagefind/pagefind.en_1e94abd852.pf_meta +0 -0
  214. package/dist/docs-bundle/pagefind/pagefind.js +6 -0
  215. package/dist/docs-bundle/pagefind/wasm.en.pagefind +0 -0
  216. package/dist/docs-bundle/pagefind/wasm.unknown.pagefind +0 -0
  217. package/dist/docs-bundle/v1/index.html +86 -0
  218. package/dist/docs-bundle/v1/using-velora/build-a-headless-frontend/index.html +413 -0
  219. package/dist/docs-bundle/v1/using-velora/content-model/index.html +858 -0
  220. package/dist/docs-bundle/v1/using-velora/editing/index.html +748 -0
  221. package/dist/docs-bundle/v1/using-velora/getting-started/index.html +588 -0
  222. package/dist/docs-bundle/v1/using-velora/headless-api/index.html +1620 -0
  223. package/dist/docs-bundle/v1/using-velora/index.html +215 -0
  224. package/dist/docs-bundle/v1/using-velora/installation/index.html +886 -0
  225. package/dist/docs-bundle/v1/using-velora/installing-plugins/index.html +836 -0
  226. package/dist/docs-bundle/v1/using-velora/media/index.html +468 -0
  227. package/dist/docs-bundle/v1/using-velora/users-and-roles/index.html +561 -0
  228. package/dist/graphql/field-count-rule.d.ts +5 -0
  229. package/dist/graphql/field-count-rule.js +59 -0
  230. package/dist/graphql/schema.d.ts +12 -0
  231. package/dist/graphql/schema.js +330 -0
  232. package/dist/index.d.ts +1 -0
  233. package/dist/index.js +180 -0
  234. package/dist/lib.d.ts +2 -0
  235. package/dist/lib.js +39 -0
  236. package/dist/marketplace/install-bundle-members.d.ts +33 -0
  237. package/dist/marketplace/install-bundle-members.js +137 -0
  238. package/dist/marketplace/install-from-marketplace.d.ts +60 -0
  239. package/dist/marketplace/install-from-marketplace.js +581 -0
  240. package/dist/marketplace/license-revalidation-job.d.ts +38 -0
  241. package/dist/marketplace/license-revalidation-job.js +139 -0
  242. package/dist/marketplace/marketplace-client.d.ts +43 -0
  243. package/dist/marketplace/marketplace-client.js +228 -0
  244. package/dist/marketplace/revalidate-license.d.ts +39 -0
  245. package/dist/marketplace/revalidate-license.js +103 -0
  246. package/dist/media/media-service.d.ts +36 -0
  247. package/dist/media/media-service.js +162 -0
  248. package/dist/plugins/boot-plugin-loader.d.ts +32 -0
  249. package/dist/plugins/boot-plugin-loader.js +57 -0
  250. package/dist/plugins/hook-dispatcher.d.ts +13 -0
  251. package/dist/plugins/hook-dispatcher.js +68 -0
  252. package/dist/plugins/install-built-package.d.ts +36 -0
  253. package/dist/plugins/install-built-package.js +199 -0
  254. package/dist/plugins/install-package-tarball.d.ts +25 -0
  255. package/dist/plugins/install-package-tarball.js +73 -0
  256. package/dist/plugins/plugin-context.d.ts +5 -0
  257. package/dist/plugins/plugin-context.js +26 -0
  258. package/dist/plugins/plugin-package-store.d.ts +31 -0
  259. package/dist/plugins/plugin-package-store.js +64 -0
  260. package/dist/plugins/plugin-registry-service.d.ts +227 -0
  261. package/dist/plugins/plugin-registry-service.js +636 -0
  262. package/dist/plugins/seed-template-content.d.ts +23 -0
  263. package/dist/plugins/seed-template-content.js +198 -0
  264. package/dist/plugins/server-serializers.d.ts +3 -0
  265. package/dist/plugins/server-serializers.js +16 -0
  266. package/dist/plugins/simple-storage-api.d.ts +9 -0
  267. package/dist/plugins/simple-storage-api.js +26 -0
  268. package/dist/plugins/snapshot-groups.d.ts +16 -0
  269. package/dist/plugins/snapshot-groups.js +81 -0
  270. package/dist/plugins/structured-query-builder.d.ts +21 -0
  271. package/dist/plugins/structured-query-builder.js +60 -0
  272. package/dist/plugins/structured-snapshot-service.d.ts +16 -0
  273. package/dist/plugins/structured-snapshot-service.js +286 -0
  274. package/dist/plugins/structured-storage-api.d.ts +22 -0
  275. package/dist/plugins/structured-storage-api.js +91 -0
  276. package/dist/plugins/structured-storage-transaction.d.ts +22 -0
  277. package/dist/plugins/structured-storage-transaction.js +63 -0
  278. package/dist/plugins/structured-table-naming.d.ts +1 -0
  279. package/dist/plugins/structured-table-naming.js +18 -0
  280. package/dist/plugins/trusted-keys.d.ts +11 -0
  281. package/dist/plugins/trusted-keys.js +67 -0
  282. package/dist/plugins/trusted-signing-keys.d.ts +27 -0
  283. package/dist/plugins/trusted-signing-keys.js +40 -0
  284. package/dist/plugins/uninstall-bundle.d.ts +29 -0
  285. package/dist/plugins/uninstall-bundle.js +150 -0
  286. package/dist/plugins/verify-package.d.ts +36 -0
  287. package/dist/plugins/verify-package.js +121 -0
  288. package/dist/routes/admin-static.d.ts +8 -0
  289. package/dist/routes/admin-static.js +196 -0
  290. package/dist/routes/api-keys.d.ts +2 -0
  291. package/dist/routes/api-keys.js +95 -0
  292. package/dist/routes/api-playground.d.ts +2 -0
  293. package/dist/routes/api-playground.js +21 -0
  294. package/dist/routes/auth.d.ts +2 -0
  295. package/dist/routes/auth.js +102 -0
  296. package/dist/routes/content.d.ts +3 -0
  297. package/dist/routes/content.js +471 -0
  298. package/dist/routes/data-types.d.ts +3 -0
  299. package/dist/routes/data-types.js +100 -0
  300. package/dist/routes/docs-static.d.ts +8 -0
  301. package/dist/routes/docs-static.js +137 -0
  302. package/dist/routes/document-types.d.ts +3 -0
  303. package/dist/routes/document-types.js +149 -0
  304. package/dist/routes/headless-bridge.d.ts +10 -0
  305. package/dist/routes/headless-bridge.js +207 -0
  306. package/dist/routes/health.d.ts +2 -0
  307. package/dist/routes/health.js +15 -0
  308. package/dist/routes/marketplace-proxy.d.ts +8 -0
  309. package/dist/routes/marketplace-proxy.js +135 -0
  310. package/dist/routes/media.d.ts +6 -0
  311. package/dist/routes/media.js +93 -0
  312. package/dist/routes/plugin-api-routes.d.ts +12 -0
  313. package/dist/routes/plugin-api-routes.js +224 -0
  314. package/dist/routes/plugin-assets.d.ts +8 -0
  315. package/dist/routes/plugin-assets.js +51 -0
  316. package/dist/routes/plugin-management.d.ts +7 -0
  317. package/dist/routes/plugin-management.js +525 -0
  318. package/dist/routes/plugin-storage.d.ts +8 -0
  319. package/dist/routes/plugin-storage.js +104 -0
  320. package/dist/routes/plugins.d.ts +2 -0
  321. package/dist/routes/plugins.js +36 -0
  322. package/dist/routes/public-api.d.ts +9 -0
  323. package/dist/routes/public-api.js +545 -0
  324. package/dist/routes/published-item.d.ts +57 -0
  325. package/dist/routes/published-item.js +236 -0
  326. package/dist/routes/setup.d.ts +9 -0
  327. package/dist/routes/setup.js +477 -0
  328. package/dist/routes/snapshots.d.ts +3 -0
  329. package/dist/routes/snapshots.js +65 -0
  330. package/dist/routes/templates.d.ts +3 -0
  331. package/dist/routes/templates.js +37 -0
  332. package/dist/routes/themes.d.ts +2 -0
  333. package/dist/routes/themes.js +30 -0
  334. package/dist/routes/users.d.ts +2 -0
  335. package/dist/routes/users.js +113 -0
  336. package/dist/sandbox/register-local-plugin.d.ts +36 -0
  337. package/dist/sandbox/register-local-plugin.js +108 -0
  338. package/dist/sandbox/seed-sandbox.d.ts +20 -0
  339. package/dist/sandbox/seed-sandbox.js +122 -0
  340. package/dist/scripts/copy-admin-bundle.d.ts +1 -0
  341. package/dist/scripts/copy-admin-bundle.js +24 -0
  342. package/dist/scripts/copy-docs-bundle.d.ts +1 -0
  343. package/dist/scripts/copy-docs-bundle.js +22 -0
  344. package/dist/scripts/create-api-key.d.ts +5 -0
  345. package/dist/scripts/create-api-key.js +56 -0
  346. package/dist/scripts/generate-prisma-clients.d.ts +6 -0
  347. package/dist/scripts/generate-prisma-clients.js +125 -0
  348. package/dist/scripts/pack-bundled-templates.d.ts +1 -0
  349. package/dist/scripts/pack-bundled-templates.js +87 -0
  350. package/dist/setup/build-connection-string.d.ts +19 -0
  351. package/dist/setup/build-connection-string.js +14 -0
  352. package/dist/setup/bundled-templates.d.ts +19 -0
  353. package/dist/setup/bundled-templates.js +121 -0
  354. package/dist/setup/ensure-prisma-client.d.ts +3 -0
  355. package/dist/setup/ensure-prisma-client.js +23 -0
  356. package/dist/setup/install-starter.d.ts +14 -0
  357. package/dist/setup/install-starter.js +76 -0
  358. package/dist/setup/normalize-database-url.d.ts +2 -0
  359. package/dist/setup/normalize-database-url.js +35 -0
  360. package/dist/setup/persist-env-config.d.ts +2 -0
  361. package/dist/setup/persist-env-config.js +63 -0
  362. package/dist/setup/provision-database.d.ts +2 -0
  363. package/dist/setup/provision-database.js +89 -0
  364. package/dist/setup-app.d.ts +4 -0
  365. package/dist/setup-app.js +43 -0
  366. package/package.json +96 -0
  367. package/prisma/schema.prisma +303 -0
@@ -0,0 +1,206 @@
1
+ import { loadPrismaClient } from "../db/load-prisma-client.js";
2
+ import { resolveClientDir } from "../db/resolve-client-dir.js";
3
+ // How long resolveBootMode waits for countAdmins() before giving up.
4
+ //
5
+ // FAIL CLOSED cuts both ways: a hung probe must not be allowed to hang the
6
+ // whole boot forever, because that trades a wrong-mode security bug for a
7
+ // silent-hang operability bug — no log line, just a process that never
8
+ // reaches app.listen and an orchestrator that restart-loops it with no
9
+ // explanation. This bounds the wait and routes a timeout into the exact
10
+ // same refusal as any other probe failure, so the operator gets the named
11
+ // cause instead of a silent hang.
12
+ export const ADMIN_PROBE_TIMEOUT_MS = 10_000;
13
+ // Exported so routes/setup.ts's request-time re-probe (POST /api/setup/
14
+ // complete, admin-only mode) can bound ITS await on countAdminUsers() the
15
+ // same way this module bounds its own boot-time probe (F4, S164 final
16
+ // review of Session 164's admin-only wizard task) — one bound, one
17
+ // constant, both call sites, instead of a second timeout implementation
18
+ // that could drift from this one.
19
+ export function withTimeout(promise, ms) {
20
+ return new Promise((resolve, reject) => {
21
+ const timer = setTimeout(() => {
22
+ reject(new Error(`admin probe did not resolve within ${ms}ms`));
23
+ }, ms);
24
+ promise.then((value) => {
25
+ clearTimeout(timer);
26
+ resolve(value);
27
+ }, (err) => {
28
+ clearTimeout(timer);
29
+ reject(err);
30
+ });
31
+ });
32
+ }
33
+ // Which of three states this process starts in.
34
+ //
35
+ // It used to be two — index.ts asked only whether DATABASE_URL was set —
36
+ // and that left a hole big enough to brick an instance. routes/setup.ts's
37
+ // admin creation is the ONLY production path that makes a user with
38
+ // role:"admin", and it is registered solely by buildSetupOnlyApp(), which
39
+ // only ran when DATABASE_URL was unset. Inject a DATABASE_URL pointing at
40
+ // an empty database, as every container and systemd deployment does, and
41
+ // you got the full app with no users, no login and no way to create one.
42
+ //
43
+ // DATABASE_URL unset -> setup-full (unchanged)
44
+ // set, no admin rows -> setup-admin-only (new)
45
+ // set, at least one admin -> full (unchanged)
46
+ //
47
+ // FAIL CLOSED, deliberately. The probe is a real query and can fail for
48
+ // reasons that have nothing to do with setup. If an error were treated as
49
+ // "no admin yet", a transient database outage would turn a live public
50
+ // instance into an unauthenticated create-admin endpoint. Only a
51
+ // SUCCESSFUL count of zero selects setup-admin-only; anything else
52
+ // refuses the boot and says why.
53
+ export async function resolveBootMode(env, countAdmins) {
54
+ if (!env.DATABASE_URL)
55
+ return "setup-full";
56
+ // Both a rejected probe and a bad-but-resolved one refuse through this
57
+ // same shape, so the operator always gets the named cause rather than a
58
+ // silently wrong mode.
59
+ const refuse = (cause) => {
60
+ throw new Error("Refusing to start: DATABASE_URL is set but Velora could not determine whether an administrator " +
61
+ `exists. Continuing would either lock you out or expose first-run setup on a live instance. Cause: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
62
+ };
63
+ let admins;
64
+ try {
65
+ admins = await withTimeout(countAdmins(), ADMIN_PROBE_TIMEOUT_MS);
66
+ }
67
+ catch (err) {
68
+ return refuse(err);
69
+ }
70
+ // A resolution is not a rejection. countAdmins is an injected function
71
+ // with no compile-time guarantee about what it resolves with — NaN, a
72
+ // negative number, undefined from a caller that forgot to return — and
73
+ // every one of those makes `admins > 0` false, which is exactly what
74
+ // used to select "setup-admin-only", the branch that exposes an
75
+ // unauthenticated create-admin endpoint. Only a SUCCESSFUL count of zero
76
+ // may select it, so anything else routes through the same refusal a
77
+ // rejection gets.
78
+ if (!Number.isInteger(admins) || admins < 0) {
79
+ return refuse(new Error(`countAdmins() resolved with ${String(admins)}, which is not a non-negative integer`));
80
+ }
81
+ // Safe polarity: written so that even if the guard above were ever
82
+ // removed, the fallthrough is the locked-out branch ("full", requiring a
83
+ // real admin to already exist) rather than the exposed one.
84
+ return admins === 0 ? "setup-admin-only" : "full";
85
+ }
86
+ // F1: which Prisma error codes are POSITIVE EVIDENCE that the database has
87
+ // nothing in it yet, as opposed to an unknown/ambiguous failure. Every
88
+ // container and systemd deployment (see resolveBootMode's own header above)
89
+ // commonly injects a DATABASE_URL pointing at a database that exists but
90
+ // has no tables yet, or — less commonly — that doesn't exist as a catalog
91
+ // entry on the server at all. Both are a real, provable "zero admins,"
92
+ // not a probe that merely came back inconclusive.
93
+ //
94
+ // Confirmed against the ACTUAL installed @prisma/client@6.19.3 runtime,
95
+ // two ways:
96
+ // 1. Read node_modules/.pnpm/@prisma+client@6.19.3.../runtime/client.js:
97
+ // its engine-error-kind switch maps "TableDoesNotExist" -> "P2021"
98
+ // and "DatabaseDoesNotExist" -> "P1003" verbatim.
99
+ // 2. Reproduced both live against this repo's own generated per-dialect
100
+ // clients (apps/server/dist/prisma-clients/*), not just the mapping
101
+ // table: querying a genuinely empty (freshly created, zero-table)
102
+ // SQLite file throws PrismaClientKnownRequestError with
103
+ // `.code === "P2021"`; connecting to a Postgres database name that
104
+ // does not exist on the server at all throws
105
+ // PrismaClientInitializationError with `.errorCode === "P1003"`.
106
+ // Deliberately checked BOTH `.code` (PrismaClientKnownRequestError,
107
+ // the class query-execution failures like P2021 use) and `.errorCode`
108
+ // (PrismaClientInitializationError, the class connection-time
109
+ // failures like P1003 use) — they are different classes with the
110
+ // code on a different property, and matching only one would silently
111
+ // miss the other. Also confirmed, so this stays fail-closed: an
112
+ // unrelated failure (wrong password -> P1000, unreachable host ->
113
+ // P1001) still comes back with neither property matching either code,
114
+ // so it keeps refusing exactly as before.
115
+ const UNPROVISIONED_DATABASE_ERROR_CODES = new Set(["P2021", "P1003"]);
116
+ function isUnprovisionedDatabaseError(err) {
117
+ if (typeof err !== "object" || err === null)
118
+ return false;
119
+ const candidate = err;
120
+ return ((typeof candidate.code === "string" && UNPROVISIONED_DATABASE_ERROR_CODES.has(candidate.code)) ||
121
+ (typeof candidate.errorCode === "string" && UNPROVISIONED_DATABASE_ERROR_CODES.has(candidate.errorCode)));
122
+ }
123
+ // F1 (fix wave 2): the non-secret SHAPE of a DATABASE_URL — host, database
124
+ // name/path, and ?schema= if present — for the warning below. Never the
125
+ // password: this is logged, potentially to a place less trusted than the
126
+ // process's own env. Duck-typed parsing (not a Prisma helper) because the
127
+ // three Tier 1 dialects don't share one URL grammar: postgres/mysql are
128
+ // real `scheme://user:pass@host:port/db?query` URLs `new URL()` parses
129
+ // natively; `file:` (SQLite) has no host/credentials at all, just a path,
130
+ // which isn't secret.
131
+ export function describeDatabaseUrlShape(url) {
132
+ if (!url)
133
+ return "(no DATABASE_URL set)";
134
+ if (url.startsWith("file:")) {
135
+ return `sqlite file "${url.slice("file:".length)}"`;
136
+ }
137
+ try {
138
+ const parsed = new URL(url);
139
+ const schema = parsed.searchParams.get("schema");
140
+ const database = parsed.pathname.replace(/^\//, "");
141
+ return (`host "${parsed.hostname}${parsed.port ? `:${parsed.port}` : ""}", database "${database}"` +
142
+ (schema ? `, schema "${schema}"` : ""));
143
+ }
144
+ catch {
145
+ return "(DATABASE_URL could not be parsed)";
146
+ }
147
+ }
148
+ // The real probe. Uses its own short-lived client rather than db/prisma.ts's
149
+ // module-level `prisma` singleton: importing that module connects as a
150
+ // side effect of the import, and the decision this informs is whether to
151
+ // build an app that connects at all.
152
+ export async function countAdminUsers() {
153
+ const client = await loadPrismaClient(resolveClientDir());
154
+ let result;
155
+ try {
156
+ // Explicit $connect() BEFORE the query, not Prisma's default lazy
157
+ // connect-on-first-query: confirmed empirically (see above) that a
158
+ // "database does not exist" failure reached via a bare `user.count()`
159
+ // call comes back as a PrismaClientInitializationError with
160
+ // `errorCode: undefined` — Prisma's lazy-connect path drops it — while
161
+ // the IDENTICAL failure reached via an explicit `$connect()` carries
162
+ // `errorCode: "P1003"` correctly. Table-not-found (P2021) is a
163
+ // query-execution error either way, unaffected by this ordering, since
164
+ // it can only happen after a connection already succeeded.
165
+ await client.$connect();
166
+ result = await client.user.count({ where: { role: "admin" } });
167
+ }
168
+ catch (err) {
169
+ // The query's own error (e.g. ECONNREFUSED) is the diagnostic the
170
+ // operator needs. Without this catch, a $disconnect() failure in a
171
+ // `finally` below would REPLACE it — JS lets a throw in `finally`
172
+ // override a pending exception — so the operator would see a
173
+ // disconnect error instead of the real cause. Swallow the disconnect
174
+ // failure and let the original win.
175
+ try {
176
+ await client.$disconnect();
177
+ }
178
+ catch {
179
+ // Swallowed deliberately: see above.
180
+ }
181
+ // A missing table or missing database IS a successful count of zero,
182
+ // not a failure — see UNPROVISIONED_DATABASE_ERROR_CODES above. Every
183
+ // other error still refuses by rethrowing, unchanged.
184
+ if (isUnprovisionedDatabaseError(err)) {
185
+ // F1 (fix wave 2, S164 review): this conversion is defensible — a
186
+ // connection that cannot see a `users` table holds no admin
187
+ // credentials to protect — but it must not be SILENT. Verified
188
+ // live: a real, populated Postgres reached through a `?schema=`
189
+ // that lacks the tables throws this same P2021 and, before this
190
+ // warning, opened the unauthenticated wizard with zero diagnostics.
191
+ // A mistyped sqlite path and a mistyped database name (P1003) do the
192
+ // same. Named channel + remedy, same tone as
193
+ // db/resolve-client-dir.ts's own console.warn.
194
+ const code = err.code ?? err.errorCode;
195
+ console.warn(`countAdminUsers: treating ${String(code)} as zero admins (no users table reachable) at ` +
196
+ `${describeDatabaseUrlShape(process.env.DATABASE_URL)}. This is expected on a genuinely fresh, ` +
197
+ "unprovisioned database. If this DATABASE_URL is meant to reach an EXISTING, populated database, " +
198
+ "check for a typo in the host, database name, or ?schema= — getting this wrong opens the " +
199
+ "unauthenticated setup wizard on an instance whose real admins are just one connection detail away.");
200
+ return 0;
201
+ }
202
+ throw err;
203
+ }
204
+ await client.$disconnect();
205
+ return result;
206
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "id": "com.velora.blog",
3
+ "name": "Blog",
4
+ "version": "0.1.0",
5
+ "type": "template",
6
+ "description": "The official Velora blog template — posts, authors and tags, ready to publish.",
7
+ "author": "Velora",
8
+ "license": "MIT",
9
+ "cmsVersion": "^0.1.0",
10
+ "databaseCompatibility": {
11
+ "storageType": "simple",
12
+ "supported": [
13
+ "postgresql",
14
+ "mysql",
15
+ "sqlite"
16
+ ]
17
+ },
18
+ "permissions": {
19
+ "needsStructuredData": false,
20
+ "needsExternalNetwork": false,
21
+ "needsFileSystemAccess": false
22
+ },
23
+ "contributions": {
24
+ "documentTypes": [
25
+ {
26
+ "name": "Author",
27
+ "icon": "user"
28
+ },
29
+ {
30
+ "name": "Post",
31
+ "icon": "file-text"
32
+ },
33
+ {
34
+ "name": "Tag",
35
+ "icon": "tag"
36
+ }
37
+ ]
38
+ }
39
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "nodes": [
3
+ { "documentType": "Author", "slug": "jane-doe", "parent": null,
4
+ "data": { "name": "Jane Doe", "bio": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Founding editor of this blog." } ] } ] } } },
5
+ { "documentType": "Tag", "slug": "announcements", "parent": null,
6
+ "data": { "label": "Announcements", "description": "Site news." } },
7
+ { "documentType": "Tag", "slug": "guides", "parent": null,
8
+ "data": { "label": "Guides", "description": "How-to articles." } },
9
+ { "documentType": "Post", "slug": "hello-velora", "parent": "jane-doe",
10
+ "data": { "title": "Hello, Velora", "body": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "This sample post was created by the Blog template. Edit or delete it freely." } ] } ] }, "publishedDate": "2026-08-13", "tags": "announcements" } },
11
+ { "documentType": "Post", "slug": "writing-your-first-post", "parent": "jane-doe",
12
+ "data": { "title": "Writing your first post", "body": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Open the content tree, pick an author, and add a Post under them." } ] } ] }, "publishedDate": "2026-08-13", "tags": "guides" } }
13
+ ]
14
+ }
@@ -0,0 +1 @@
1
+ export declare function isAdminUiEnabled(env?: NodeJS.ProcessEnv): boolean;
@@ -0,0 +1,10 @@
1
+ // The /velora admin SPA (S184). ON by default — `VELORA_ADMIN=off`
2
+ // disables serving it (the hosted demo's setting) without touching the
3
+ // API. Same trim/lowercase parsing idiom as public-docs.ts, with one
4
+ // deliberate difference: the docs flag accepts the general "false"/"0"
5
+ // disable spellings, while this one is specified (design doc §2) as the
6
+ // single literal `off` — the value the demo box's env file carries.
7
+ export function isAdminUiEnabled(env = process.env) {
8
+ // Default ON: only an explicit `off` turns it off.
9
+ return env.VELORA_ADMIN?.trim().toLowerCase() !== "off";
10
+ }
@@ -0,0 +1,7 @@
1
+ export declare function parseCorsOrigins(raw: string | undefined, warn?: (msg: string) => void): string[];
2
+ export declare function corsOptionsFromEnv(warn?: (msg: string) => void): {
3
+ origin: string[] | false;
4
+ methods: string[];
5
+ allowedHeaders: string[];
6
+ credentials: false;
7
+ };
@@ -0,0 +1,53 @@
1
+ // S160: cross-origin access for plugin routes. A form submission comes
2
+ // from a visitor's browser on the FRONTEND's origin, so the public
3
+ // access tier is only reachable cross-origin when the operator names
4
+ // that origin here. Empty/unset means no CORS headers at all —
5
+ // same-origin only, secure by default; enabling it is a conscious
6
+ // per-deployment act. Deploy-time env, not per-form: the plugin-route
7
+ // dispatcher has no path params, so a preflight can never know which
8
+ // form it is for.
9
+ //
10
+ // `warn`, when given, is called once per dropped entry (non-empty but
11
+ // not an absolute origin — e.g. a trailing slash, a bare host, a path)
12
+ // so a misconfigured `VELORA_CORS_ORIGINS` doesn't fail in total
13
+ // silence; optional (and defaulted to a no-op by corsOptionsFromEnv
14
+ // below) so the existing single-argument call shape keeps working.
15
+ export function parseCorsOrigins(raw, warn) {
16
+ if (!raw)
17
+ return [];
18
+ const valid = [];
19
+ for (const entry of raw.split(",").map((e) => e.trim())) {
20
+ if (!entry)
21
+ continue;
22
+ try {
23
+ const url = new URL(entry);
24
+ if (url.origin === entry) {
25
+ valid.push(entry);
26
+ continue;
27
+ }
28
+ }
29
+ catch {
30
+ // falls through to the dropped-entry warning below
31
+ }
32
+ warn?.(`VELORA_CORS_ORIGINS: dropping "${entry}" — not an absolute origin (scheme://host[:port], no path)`);
33
+ }
34
+ return valid;
35
+ }
36
+ export function corsOptionsFromEnv(warn = () => { }) {
37
+ const origins = parseCorsOrigins(process.env.VELORA_CORS_ORIGINS, warn);
38
+ return {
39
+ // `false` disables CORS headers entirely rather than echoing "*".
40
+ origin: origins.length > 0 ? origins : false,
41
+ // GET/POST/OPTIONS only — a manifest can declare a "public" apiRoute
42
+ // on PUT/PATCH/DELETE too, but it's deliberately not reachable
43
+ // cross-origin: those verbs aren't part of this allowlist's browser
44
+ // contract, only same-origin (or apiKey/admin, credentialed) callers
45
+ // can reach them. Widen this list only as a deliberate, reviewed
46
+ // decision, not to unblock one plugin.
47
+ methods: ["GET", "POST", "OPTIONS"],
48
+ allowedHeaders: ["content-type", "authorization"],
49
+ // Plugin routes authenticate via the Authorization header, never
50
+ // cookies — so no credentialed cross-origin surface is opened.
51
+ credentials: false,
52
+ };
53
+ }
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_ENV_FILENAME = ".env";
2
+ export declare function resolveEnvFilePath(env?: NodeJS.ProcessEnv, cwd?: string): string;
@@ -0,0 +1,22 @@
1
+ import { isAbsolute, resolve } from "node:path";
2
+ // The filename used when VELORA_ENV_FILE isn't set. Named so it's a
3
+ // config-visible constant, never a magic literal repeated between this
4
+ // module and its tests.
5
+ export const DEFAULT_ENV_FILENAME = ".env";
6
+ // The ONE env-file rule, shared by the loader (load-env.ts) and the
7
+ // wizard's writer (setup/persist-env-config.ts). Because both use this,
8
+ // the file the wizard writes is by construction the file the next boot
9
+ // reads.
10
+ //
11
+ // Deliberately NOT a directory walk. persist-env-config.ts used to build
12
+ // its path by walking four levels up from its own compiled location,
13
+ // which assumes the monorepo's depth and overshoots — potentially to the
14
+ // drive root — on a flattened `pnpm deploy` output. Nothing here reads
15
+ // import.meta.url: where the code lives must not decide where config
16
+ // lives.
17
+ export function resolveEnvFilePath(env = process.env, cwd = process.cwd()) {
18
+ const override = env.VELORA_ENV_FILE?.trim();
19
+ if (override)
20
+ return isAbsolute(override) ? override : resolve(cwd, override);
21
+ return resolve(cwd, DEFAULT_ENV_FILENAME);
22
+ }
@@ -0,0 +1,2 @@
1
+ export declare function maxQueryDepth(): number;
2
+ export declare function maxQueryComplexity(): number;
@@ -0,0 +1,26 @@
1
+ // Depth + complexity guards for the public GraphQL surface (Session 115,
2
+ // Task 2) — wired into mercurius' registration in public-api.ts. Same idiom
3
+ // as rate-limit.ts's configuredMax(): read fresh at call time, not frozen
4
+ // at module-import time, since this module is statically imported (via
5
+ // app.ts) well before a test's env override gets a chance to take effect.
6
+ //
7
+ // GraphiQL's own introspection query is depth 7 and measures at complexity
8
+ // 220 against this schema (see src/graphql/field-count-rule.ts for the
9
+ // fragment-aware field-count calculation). 500 clears it with a >2x margin.
10
+ // Decided during the Session 115 GraphQL search protection design work.
11
+ const DEFAULT_MAX_DEPTH = 8;
12
+ const DEFAULT_MAX_COMPLEXITY = 500;
13
+ // Number(raw ?? fallback) is rate-limit.ts's exact expression shape; the
14
+ // only addition here is validation that the value is a positive integer.
15
+ // Reject NaN, 0 (which silently disables mercurius' depth check), and
16
+ // negative values — all fall back to the default.
17
+ function readPositiveInt(raw, fallback) {
18
+ const value = Number(raw ?? fallback);
19
+ return !Number.isInteger(value) || value <= 0 ? fallback : value;
20
+ }
21
+ export function maxQueryDepth() {
22
+ return readPositiveInt(process.env.VELORA_GRAPHQL_MAX_DEPTH, DEFAULT_MAX_DEPTH);
23
+ }
24
+ export function maxQueryComplexity() {
25
+ return readPositiveInt(process.env.VELORA_GRAPHQL_MAX_COMPLEXITY, DEFAULT_MAX_COMPLEXITY);
26
+ }
@@ -0,0 +1 @@
1
+ export declare function isHeadlessEnabled(env?: NodeJS.ProcessEnv): boolean;
@@ -0,0 +1,8 @@
1
+ // The deploy-time headless switch (Month 9): config-file-only by design,
2
+ // like the DB dialect — no runtime admin toggle exists or should. Only
3
+ // "true"/"1" opt in; anything else (including unset) keeps the public
4
+ // /api/v1 namespace unregistered entirely.
5
+ export function isHeadlessEnabled(env = process.env) {
6
+ const value = env.VELORA_HEADLESS?.trim().toLowerCase();
7
+ return value === "true" || value === "1";
8
+ }
@@ -0,0 +1,2 @@
1
+ export declare function licenseCheckIntervalHours(env?: NodeJS.ProcessEnv): number;
2
+ export declare function licenseStaleWarnDays(env?: NodeJS.ProcessEnv): number;
@@ -0,0 +1,16 @@
1
+ /** How often installed paid plugins are re-validated against the license
2
+ * server, and how long an unreachable license server may go unheard from
3
+ * before the admin sees a warning. Both read fresh at call time so a test
4
+ * (or an operator) can change them without a restart of the module graph. */
5
+ function readPositiveInt(raw, fallback) {
6
+ const parsed = Number(raw);
7
+ if (!raw || !Number.isInteger(parsed) || parsed <= 0)
8
+ return fallback;
9
+ return parsed;
10
+ }
11
+ export function licenseCheckIntervalHours(env = process.env) {
12
+ return readPositiveInt(env.VELORA_LICENSE_CHECK_INTERVAL_HOURS, 24);
13
+ }
14
+ export function licenseStaleWarnDays(env = process.env) {
15
+ return readPositiveInt(env.VELORA_LICENSE_STALE_WARN_DAYS, 7);
16
+ }
@@ -0,0 +1 @@
1
+ export declare function loadEnvFile(env?: NodeJS.ProcessEnv, cwd?: string): void;
@@ -0,0 +1,53 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { parse } from "dotenv";
3
+ import { resolveEnvFilePath } from "./env-file-path.js";
4
+ // Loads the env file in-process, so the production `start` script is a
5
+ // plain `node dist/index.js` with no devDependency on its path.
6
+ //
7
+ // This replaces `dotenv -e ../../.env --` in package.json's start script.
8
+ // dotenv-cli is a devDependency, so `pnpm deploy --prod` produced a
9
+ // target where `start` failed before Node ran — the same defect class as
10
+ // Session 155's @velora-cms/prisma-variants misclassification.
11
+ //
12
+ // Two behaviours are preserved deliberately, both measured against the
13
+ // installed dotenv-cli@11.0.0 before this was written:
14
+ // 1. A real environment variable BEATS a file value. Everything in
15
+ // apps/server/src/config/*.ts reads process.env directly, so this is
16
+ // the only place precedence is decided.
17
+ // 2. A missing file is normal, not an error — a deploy target
18
+ // configured entirely by injected env vars has no file at all.
19
+ //
20
+ // Parsing is dotenv's own, the same parser dotenv-cli used. Note honestly
21
+ // what that does NOT give us: dotenv.parse silently skips individual
22
+ // malformed lines and reports no per-line error. We detect a file that
23
+ // cannot be read, and a file with content that yields zero keys; we do
24
+ // NOT detect one bad line among good ones. A hand-rolled line scanner
25
+ // would false-positive on legitimate multi-line quoted values.
26
+ export function loadEnvFile(env = process.env, cwd = process.cwd()) {
27
+ const path = resolveEnvFilePath(env, cwd);
28
+ if (!existsSync(path))
29
+ return;
30
+ let raw;
31
+ try {
32
+ raw = readFileSync(path, "utf8");
33
+ }
34
+ catch (err) {
35
+ throw new Error(`Could not read the environment file at ${path}: ${err instanceof Error ? err.message : String(err)}`);
36
+ }
37
+ const parsed = parse(raw);
38
+ if (Object.keys(parsed).length === 0 && raw.trim().length > 0 && hasNonCommentContent(raw)) {
39
+ throw new Error(`The environment file at ${path} has content but no readable KEY=value pairs. ` +
40
+ "Refusing to boot half-configured — fix the file or delete it.");
41
+ }
42
+ for (const [key, value] of Object.entries(parsed)) {
43
+ if (key in env)
44
+ continue;
45
+ env[key] = value;
46
+ }
47
+ }
48
+ function hasNonCommentContent(raw) {
49
+ return raw.split(/\r?\n/).some((line) => {
50
+ const trimmed = line.trim();
51
+ return trimmed.length > 0 && !trimmed.startsWith("#");
52
+ });
53
+ }
@@ -0,0 +1,11 @@
1
+ /** The hosted marketplace a fresh install browses out of the box (Session
2
+ * 180) — no setup step required for the common case. Deploy-time knob,
3
+ * like the headless flag: an operator who wants a different (or no)
4
+ * marketplace overrides it via VELORA_MARKETPLACE_URL. `off`
5
+ * (case-insensitive) or a blank value opts all the way out — the in-CMS
6
+ * marketplace browse/detail proxy routes go structurally absent (app.ts),
7
+ * same as the old unset-means-disabled behavior — for air-gapped or
8
+ * no-marketplace installs. Any other value is treated as a custom
9
+ * marketplace origin (e.g. a private/self-hosted marketplace). */
10
+ export declare const DEFAULT_MARKETPLACE_URL = "https://marketplace.velora-cms.com";
11
+ export declare function getMarketplaceBaseUrl(env?: NodeJS.ProcessEnv): string | undefined;
@@ -0,0 +1,19 @@
1
+ /** The hosted marketplace a fresh install browses out of the box (Session
2
+ * 180) — no setup step required for the common case. Deploy-time knob,
3
+ * like the headless flag: an operator who wants a different (or no)
4
+ * marketplace overrides it via VELORA_MARKETPLACE_URL. `off`
5
+ * (case-insensitive) or a blank value opts all the way out — the in-CMS
6
+ * marketplace browse/detail proxy routes go structurally absent (app.ts),
7
+ * same as the old unset-means-disabled behavior — for air-gapped or
8
+ * no-marketplace installs. Any other value is treated as a custom
9
+ * marketplace origin (e.g. a private/self-hosted marketplace). */
10
+ export const DEFAULT_MARKETPLACE_URL = "https://marketplace.velora-cms.com";
11
+ export function getMarketplaceBaseUrl(env = process.env) {
12
+ const raw = env.VELORA_MARKETPLACE_URL;
13
+ if (raw === undefined)
14
+ return DEFAULT_MARKETPLACE_URL;
15
+ const trimmed = raw.trim();
16
+ if (!trimmed || trimmed.toLowerCase() === "off")
17
+ return undefined;
18
+ return trimmed.replace(/\/+$/, "");
19
+ }
@@ -0,0 +1,3 @@
1
+ export declare function previewTokenTtlSeconds(): number;
2
+ export declare function previewBaseUrl(): string | null;
3
+ export declare function buildPreviewUrl(token: string, contentId: string): string | null;
@@ -0,0 +1,39 @@
1
+ // Preview-token TTL (Session 116, Task 1) — separate file from
2
+ // graphql-limits.ts since this is a different feature, but mirrors its
3
+ // exact idiom: read fresh at call time (not frozen at module-import time)
4
+ // so a test's env override always takes effect, and reject non-positive/
5
+ // NaN/garbage input by falling back to the default rather than throwing.
6
+ const DEFAULT_TTL_SECONDS = 1800;
7
+ function readPositiveInt(raw, fallback) {
8
+ const value = Number(raw ?? fallback);
9
+ return !Number.isInteger(value) || value <= 0 ? fallback : value;
10
+ }
11
+ export function previewTokenTtlSeconds() {
12
+ return readPositiveInt(process.env.VELORA_PREVIEW_TOKEN_TTL, DEFAULT_TTL_SECONDS);
13
+ }
14
+ // Preview base URL (Session 117, Task 1) — returns the configured base URL
15
+ // for preview links, or null if not configured. Empty/whitespace-only values
16
+ // are treated as unset. Trailing slashes are stripped.
17
+ export function previewBaseUrl() {
18
+ const raw = process.env.VELORA_PREVIEW_BASE_URL;
19
+ if (!raw) {
20
+ return null;
21
+ }
22
+ const trimmed = raw.trim();
23
+ if (!trimmed) {
24
+ return null;
25
+ }
26
+ // Strip trailing slashes
27
+ return trimmed.replace(/\/+$/, "");
28
+ }
29
+ // Builds a preview URL from the base and a token, or null if base is not
30
+ // configured. Both token and contentId are URL-encoded.
31
+ export function buildPreviewUrl(token, contentId) {
32
+ const base = previewBaseUrl();
33
+ if (!base) {
34
+ return null;
35
+ }
36
+ const encodedToken = encodeURIComponent(token);
37
+ const encodedId = encodeURIComponent(contentId);
38
+ return `${base}/api/preview?token=${encodedToken}&id=${encodedId}`;
39
+ }
@@ -0,0 +1 @@
1
+ export declare function isPublicDocsEnabled(env?: NodeJS.ProcessEnv): boolean;
@@ -0,0 +1,9 @@
1
+ // The public OpenAPI docs surface (Month 9, Session 109). ON by default —
2
+ // an owner turns it OFF for post-launch hardening ("false"/"0"), which
3
+ // 404s the docs URL without touching the /api/v1 API itself. Config-file
4
+ // only, same shape as VELORA_HEADLESS.
5
+ export function isPublicDocsEnabled(env = process.env) {
6
+ const value = env.VELORA_PUBLIC_DOCS?.trim().toLowerCase();
7
+ // Default ON: only an explicit disable turns it off.
8
+ return value !== "false" && value !== "0";
9
+ }
@@ -0,0 +1,7 @@
1
+ /** This instance's own domain, as the OPERATOR declares it — never the
2
+ * request's Host header. A license binds to this value once, on first
3
+ * validation, so it must be stable and unspoofable; an admin browsing
4
+ * via localhost, an IP, or a proxy must not be able to burn a buyer's
5
+ * one-shot binding on the wrong domain. Scheme and trailing slash are
6
+ * tolerated so a URL-shaped value still yields a bare host. */
7
+ export declare function getSiteDomain(env?: NodeJS.ProcessEnv): string | undefined;
@@ -0,0 +1,12 @@
1
+ /** This instance's own domain, as the OPERATOR declares it — never the
2
+ * request's Host header. A license binds to this value once, on first
3
+ * validation, so it must be stable and unspoofable; an admin browsing
4
+ * via localhost, an IP, or a proxy must not be able to burn a buyer's
5
+ * one-shot binding on the wrong domain. Scheme and trailing slash are
6
+ * tolerated so a URL-shaped value still yields a bare host. */
7
+ export function getSiteDomain(env = process.env) {
8
+ const raw = env.VELORA_SITE_DOMAIN?.trim().toLowerCase();
9
+ if (!raw)
10
+ return undefined;
11
+ return raw.replace(/^https?:\/\//, "").replace(/\/+$/, "");
12
+ }
@@ -0,0 +1,2 @@
1
+ export declare function parseTrustProxy(raw: string | undefined): boolean | number | string | undefined;
2
+ export declare function trustProxyFromEnv(env?: NodeJS.ProcessEnv): boolean | number | string | undefined;