@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,162 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { CreateBucketCommand, DeleteObjectCommand, GetObjectCommand, HeadBucketCommand, PutObjectCommand, S3Client, } from "@aws-sdk/client-s3";
3
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
4
+ // Defaults match the minio service in docker-compose.yml (same treatment as
5
+ // POSTGRES_TEST_URL), so local dev works with zero required config. Point
6
+ // these at real S3/R2 via .env — see .env.example.
7
+ export function mediaStorageConfigFromEnv() {
8
+ return {
9
+ endpoint: process.env.S3_ENDPOINT ?? "http://localhost:9000",
10
+ region: process.env.S3_REGION ?? "us-east-1",
11
+ accessKeyId: process.env.S3_ACCESS_KEY_ID ?? "velora",
12
+ secretAccessKey: process.env.S3_SECRET_ACCESS_KEY ?? "velora-secret",
13
+ bucket: process.env.S3_BUCKET ?? "velora-media",
14
+ };
15
+ }
16
+ export class MediaService {
17
+ prisma;
18
+ config;
19
+ dialect;
20
+ s3;
21
+ constructor(prisma, config,
22
+ // Which Prisma provider the injected client is actually querying against
23
+ // (postgresql | mysql | sqlite) — needed by list()'s search filter,
24
+ // see buildFilenameSearchFilter below. Passed in rather than
25
+ // rediscovered here so this class stays agnostic of how the caller
26
+ // resolved it (db/prisma.ts's VELORA_PRISMA_CLIENT_DIR-derived value in
27
+ // the real app, a literal in tests).
28
+ dialect) {
29
+ this.prisma = prisma;
30
+ this.config = config;
31
+ this.dialect = dialect;
32
+ this.s3 = new S3Client({
33
+ endpoint: config.endpoint,
34
+ region: config.region,
35
+ credentials: {
36
+ accessKeyId: config.accessKeyId,
37
+ secretAccessKey: config.secretAccessKey,
38
+ },
39
+ // MinIO and R2 route by path, not by bucket subdomain — and a
40
+ // localhost endpoint can't do virtual-hosted buckets at all.
41
+ forcePathStyle: true,
42
+ });
43
+ }
44
+ // Idempotent; safe to call on startup or from tests. Only creates the
45
+ // bucket when it doesn't exist yet.
46
+ async ensureBucket() {
47
+ try {
48
+ await this.s3.send(new HeadBucketCommand({ Bucket: this.config.bucket }));
49
+ }
50
+ catch {
51
+ await this.s3.send(new CreateBucketCommand({ Bucket: this.config.bucket }));
52
+ }
53
+ }
54
+ async upload(input) {
55
+ const id = randomUUID();
56
+ const storageKey = `${id}/${sanitizeForKey(input.filename)}`;
57
+ await this.s3.send(new PutObjectCommand({
58
+ Bucket: this.config.bucket,
59
+ Key: storageKey,
60
+ Body: input.data,
61
+ ContentType: input.mimeType,
62
+ ContentLength: input.data.length,
63
+ }));
64
+ try {
65
+ const row = await this.prisma.mediaFile.create({
66
+ data: {
67
+ id,
68
+ filename: input.filename,
69
+ mimeType: input.mimeType,
70
+ size: input.data.length,
71
+ storageKey,
72
+ url: this.canonicalUrl(storageKey),
73
+ uploadedBy: input.uploadedBy,
74
+ },
75
+ });
76
+ return toMediaFile(row);
77
+ }
78
+ catch (error) {
79
+ // Metadata is the source of truth — don't leave an object around that
80
+ // no metadata row points to.
81
+ await this.s3
82
+ .send(new DeleteObjectCommand({ Bucket: this.config.bucket, Key: storageKey }))
83
+ .catch(() => undefined);
84
+ throw error;
85
+ }
86
+ }
87
+ async getById(id) {
88
+ const row = await this.prisma.mediaFile.findUnique({ where: { id } });
89
+ return row ? toMediaFile(row) : null;
90
+ }
91
+ // Newest-first, cursor-paginated (cursor = previous page's last id,
92
+ // same semantics as the content list endpoints). Prisma positions the
93
+ // cursor row within the compound order and skips it.
94
+ async list(options) {
95
+ const rows = await this.prisma.mediaFile.findMany({
96
+ where: options.search
97
+ ? { filename: buildFilenameSearchFilter(options.search, this.dialect) }
98
+ : undefined,
99
+ orderBy: [{ uploadedAt: "desc" }, { id: "desc" }],
100
+ take: options.limit,
101
+ ...(options.cursor ? { cursor: { id: options.cursor }, skip: 1 } : {}),
102
+ });
103
+ return rows.map(toMediaFile);
104
+ }
105
+ // Time-limited presigned GET — works against private buckets, which is
106
+ // why downloads go through this rather than the stored canonical url.
107
+ async getDownloadUrl(id, expiresInSeconds = 900) {
108
+ const row = await this.prisma.mediaFile.findUnique({ where: { id } });
109
+ if (!row) {
110
+ throw new Error(`Media file not found: ${id}`);
111
+ }
112
+ return getSignedUrl(this.s3, new GetObjectCommand({ Bucket: this.config.bucket, Key: row.storageKey }), { expiresIn: expiresInSeconds });
113
+ }
114
+ async delete(id) {
115
+ const row = await this.prisma.mediaFile.findUnique({ where: { id } });
116
+ if (!row) {
117
+ throw new Error(`Media file not found: ${id}`);
118
+ }
119
+ await this.s3.send(new DeleteObjectCommand({ Bucket: this.config.bucket, Key: row.storageKey }));
120
+ await this.prisma.mediaFile.delete({ where: { id } });
121
+ }
122
+ canonicalUrl(storageKey) {
123
+ const encodedKey = storageKey.split("/").map(encodeURIComponent).join("/");
124
+ return `${this.config.endpoint.replace(/\/$/, "")}/${this.config.bucket}/${encodedKey}`;
125
+ }
126
+ }
127
+ // Case-insensitive filename search, built per the active Prisma provider's
128
+ // verified capabilities (Session 131 walkthrough, task-4-report.md step 13
129
+ // — SQLite 500'd here because `mode: "insensitive"` isn't a real argument
130
+ // outside the postgresql provider):
131
+ // - postgresql: bare `contains` compiles to a case-SENSITIVE LIKE, so
132
+ // Prisma's `mode: "insensitive"` is genuinely required there.
133
+ // - mysql: the generated client rejects `mode` (Prisma only accepts it
134
+ // for postgresql). Dropping `mode` assumes MySQL 8's default collation
135
+ // (utf8mb4_0900_ai_ci); case-sensitive collations silently degrade to
136
+ // case-sensitive search. Velora does not pin collation; the
137
+ // collation-independent fix (S104 LOWER()-both-sides) is backlogged.
138
+ // - sqlite: same rejection as mysql, and dropping `mode` is safe for the
139
+ // same reason — `contains` compiles to `LIKE`, which SQLite evaluates
140
+ // ASCII-case-insensitively by default.
141
+ // Verified empirically against real postgres/mysql/sqlite instances before
142
+ // writing this — don't "simplify" this back to one shape for every
143
+ // dialect; that's exactly what caused the SQLite 500.
144
+ export function buildFilenameSearchFilter(search, dialect) {
145
+ return dialect === "postgresql" ? { contains: search, mode: "insensitive" } : { contains: search };
146
+ }
147
+ // Original filename lives untouched in metadata; the object key only keeps
148
+ // characters that are safe in S3 keys and URLs.
149
+ function sanitizeForKey(filename) {
150
+ return filename.replace(/[^A-Za-z0-9._-]/g, "_");
151
+ }
152
+ function toMediaFile(row) {
153
+ return {
154
+ id: row.id,
155
+ filename: row.filename,
156
+ mimeType: row.mimeType,
157
+ size: row.size,
158
+ url: row.url,
159
+ uploadedBy: row.uploadedBy,
160
+ uploadedAt: row.uploadedAt.toISOString(),
161
+ };
162
+ }
@@ -0,0 +1,32 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ import type { PluginRegistryService } from "./plugin-registry-service.js";
3
+ export interface BootLog {
4
+ info(msg: string): void;
5
+ warn(msg: string): void;
6
+ }
7
+ export interface BootPluginsReport {
8
+ attached: string[];
9
+ skipped: {
10
+ pluginId: string;
11
+ reason: string;
12
+ }[];
13
+ failed: {
14
+ pluginId: string;
15
+ reason: string;
16
+ }[];
17
+ }
18
+ /**
19
+ * The registry-driven boot loader (Session 122) — the caller of the
20
+ * attachManifest() bridge Sessions 62-63 designed for exactly this.
21
+ * Runs once at boot, AFTER the registry exists and BEFORE the server
22
+ * answers requests: for every installed plugin row (enabled or not —
23
+ * attaching a disabled plugin's manifest is what lets activate() work
24
+ * after a restart without a reinstall), import the stored package's
25
+ * self-contained server/plugin.js (Session 121), re-validate, attach.
26
+ *
27
+ * Failure posture (the Session 91 precedent): one plugin failing NEVER
28
+ * blocks boot or any other plugin. A failed/missing package logs a
29
+ * warning and its routes keep the existing 503-with-clear-cause
30
+ * behavior until reinstall.
31
+ */
32
+ export declare function bootInstalledPlugins(prisma: PrismaClient, registry: PluginRegistryService, log: BootLog): Promise<BootPluginsReport>;
@@ -0,0 +1,57 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { validatePluginManifest } from "@velora-cms/plugin-sdk/manifest";
5
+ /**
6
+ * The registry-driven boot loader (Session 122) — the caller of the
7
+ * attachManifest() bridge Sessions 62-63 designed for exactly this.
8
+ * Runs once at boot, AFTER the registry exists and BEFORE the server
9
+ * answers requests: for every installed plugin row (enabled or not —
10
+ * attaching a disabled plugin's manifest is what lets activate() work
11
+ * after a restart without a reinstall), import the stored package's
12
+ * self-contained server/plugin.js (Session 121), re-validate, attach.
13
+ *
14
+ * Failure posture (the Session 91 precedent): one plugin failing NEVER
15
+ * blocks boot or any other plugin. A failed/missing package logs a
16
+ * warning and its routes keep the existing 503-with-clear-cause
17
+ * behavior until reinstall.
18
+ */
19
+ export async function bootInstalledPlugins(prisma, registry, log) {
20
+ const report = { attached: [], skipped: [], failed: [] };
21
+ const rows = await prisma.pluginRegistry.findMany();
22
+ for (const row of rows) {
23
+ if (!row.packagePath) {
24
+ report.skipped.push({
25
+ pluginId: row.pluginId,
26
+ reason: "no stored package recorded (live-source plugin, or an install that never recorded its package)",
27
+ });
28
+ continue;
29
+ }
30
+ try {
31
+ const entryPath = join(row.packagePath, "server", "plugin.js");
32
+ if (!existsSync(entryPath)) {
33
+ report.failed.push({ pluginId: row.pluginId, reason: `package missing at ${entryPath}` });
34
+ log.warn(`[plugin-boot] ${row.pluginId}: package missing at ${entryPath} — routes will 503 until reinstall`);
35
+ continue;
36
+ }
37
+ const mod = (await import(pathToFileURL(entryPath).href));
38
+ if (!mod.default) {
39
+ throw new Error("server/plugin.js has no default export");
40
+ }
41
+ const validated = validatePluginManifest(mod.default);
42
+ if (!validated.ok) {
43
+ throw new Error(`manifest failed validation: ${validated.errors.join("; ")}`);
44
+ }
45
+ await registry.attachManifest(validated.manifest);
46
+ report.attached.push(row.pluginId);
47
+ }
48
+ catch (error) {
49
+ const reason = error instanceof Error ? error.message : String(error);
50
+ report.failed.push({ pluginId: row.pluginId, reason });
51
+ log.warn(`[plugin-boot] ${row.pluginId}: failed to load — ${reason}`);
52
+ }
53
+ }
54
+ log.info(`[plugin-boot] attached ${report.attached.length}, skipped ${report.skipped.length}, failed ${report.failed.length}` +
55
+ (report.attached.length ? ` (attached: ${report.attached.join(", ")})` : ""));
56
+ return report;
57
+ }
@@ -0,0 +1,13 @@
1
+ import type { ContentLifecycleEvent, ContentService } from "@velora-cms/content-service";
2
+ import type { DatabaseAdapter } from "@velora-cms/db-adapter";
3
+ import type { PluginRegistryService } from "./plugin-registry-service.js";
4
+ import type { StructuredStorageAPI } from "./structured-storage-api.js";
5
+ export declare function createHookDispatcher(deps: {
6
+ registry: PluginRegistryService;
7
+ structuredStorageAPI: StructuredStorageAPI;
8
+ contentService: ContentService;
9
+ adapter: DatabaseAdapter;
10
+ log: {
11
+ error: (obj: unknown, msg: string) => void;
12
+ };
13
+ }): (event: ContentLifecycleEvent) => void;
@@ -0,0 +1,68 @@
1
+ import { buildContext } from "./plugin-context.js";
2
+ // S159: the hook engine's host half. Resolves every ACTIVE plugin's
3
+ // handler for the event and invokes each fire-and-forget with the same
4
+ // containment posture as plugin API routes: one plugin throwing is a log
5
+ // line, never a failed publish. The returned function is synchronous and
6
+ // void — ContentService's editorial path never awaits hook work.
7
+ export function createHookDispatcher(deps) {
8
+ return (event) => {
9
+ // listActiveHookContributions reads manifest.contributions off objects
10
+ // supplied by dynamically-imported plugin code, same as buildContext
11
+ // below — a throwing getter here is just as untrusted, and sits above
12
+ // the loop, so it needs its own boundary or it would silently abort
13
+ // dispatch for every plugin on every event.
14
+ let contributions;
15
+ try {
16
+ contributions = deps.registry.listActiveHookContributions(event.event);
17
+ }
18
+ catch (err) {
19
+ try {
20
+ deps.log.error({ err, event: event.event }, "plugin hook lookup failed");
21
+ }
22
+ catch {
23
+ // Same untrusted-boundary swallow as below.
24
+ }
25
+ return;
26
+ }
27
+ for (const { pluginId, handler } of contributions) {
28
+ // The loop body itself — not just the deferred handler call below —
29
+ // must be per-plugin contained. buildContext and the synchronous
30
+ // prelude around it run on THIS plugin's turn through the loop; a
31
+ // throwing getter or similar from dynamically-imported plugin code
32
+ // here would otherwise abort dispatch for every plugin after this
33
+ // one, silently (nothing would log it).
34
+ try {
35
+ const context = buildContext(pluginId, deps.structuredStorageAPI, deps.contentService, deps.adapter);
36
+ // Each handler gets its own shallow copy of the event payload —
37
+ // every invocation below is a deferred microtask sharing what
38
+ // would otherwise be one object, so one plugin mutating its
39
+ // payload could otherwise leak that mutation into another
40
+ // plugin's handler.
41
+ const payload = { ...event };
42
+ void Promise.resolve()
43
+ .then(() => handler(payload, context))
44
+ .catch((err) => {
45
+ try {
46
+ deps.log.error({ err, pluginId, event: event.event }, "plugin hook handler threw");
47
+ }
48
+ catch {
49
+ // A plugin can influence the logged `err` value at this
50
+ // untrusted boundary (its own thrown error) — if that value
51
+ // makes the logger itself throw (e.g. a hostile toJSON/
52
+ // getter), swallow it rather than leave an unhandled
53
+ // rejection from this .catch.
54
+ }
55
+ });
56
+ }
57
+ catch (err) {
58
+ try {
59
+ deps.log.error({ err, pluginId, event: event.event }, "plugin hook dispatch failed");
60
+ }
61
+ catch {
62
+ // Same untrusted-boundary swallow as above, for the synchronous
63
+ // path.
64
+ }
65
+ }
66
+ }
67
+ };
68
+ }
@@ -0,0 +1,36 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ import type { DatabaseAdapter } from "@velora-cms/db-adapter";
3
+ import { type ManifestRowFields, type RegisterLocalPluginResult } from "../sandbox/register-local-plugin.js";
4
+ import { PluginRegistryService } from "./plugin-registry-service.js";
5
+ import type { TrustTier } from "./verify-package.js";
6
+ /** Resolves the server-importable manifest entry a `velora-plugin
7
+ * build` package always produces at this fixed path. */
8
+ export declare function resolveBuiltManifestPath(packageDir: string): string;
9
+ export declare function installBuiltPackage(service: PluginRegistryService, packageDir: string, remoteUrl: string, setRemoteUrl: (pluginId: string, remoteUrl: string) => Promise<void>, syncManifestFields: (pluginId: string, fields: ManifestRowFields) => Promise<void>, setPackagePath?: (pluginId: string, packagePath: string) => Promise<void>, opts?: {
10
+ trustTier?: TrustTier;
11
+ seed?: {
12
+ prisma: PrismaClient;
13
+ adapter: DatabaseAdapter;
14
+ createdBy?: string;
15
+ };
16
+ }): Promise<RegisterLocalPluginResult>;
17
+ export interface InstallBuiltPackageCliArgs {
18
+ target: string;
19
+ remoteUrl: string;
20
+ sidecarPath?: string;
21
+ }
22
+ /** Validates `main()`'s argv shape only — NOT whether "" is the right
23
+ * value for this particular plugin. A view-less plugin type (theme/
24
+ * template/bundle) has no remoteEntry.js at all — install-from-
25
+ * marketplace.ts computes remoteUrl as `""` for exactly that case ("Empty
26
+ * string = the loader's existing 'nothing to load' contract"), so an
27
+ * explicitly-passed empty string here is a legitimate value, not a missing
28
+ * argument, and this parser accepts it unconditionally. Only an actually
29
+ * omitted argv slot (undefined — the caller never supplied a second
30
+ * positional at all) is a usage error; `target` has no such legitimate-
31
+ * empty case, so it keeps the plain falsy check. This parser runs before
32
+ * any manifest is read, so it CANNOT tell a view-less "" apart from a
33
+ * view-bearing type's "" typo'd in by mistake — that type-aware check
34
+ * happens later, inside installBuiltPackage, once the manifest's real
35
+ * type is known. */
36
+ export declare function parseInstallBuiltPackageCliArgs(argv: string[]): InstallBuiltPackageCliArgs;
@@ -0,0 +1,199 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { hasClientBundle } from "@velora-cms/plugin-sdk/manifest";
5
+ import { registerLocalPlugin } from "../sandbox/register-local-plugin.js";
6
+ import { storePackage } from "./plugin-package-store.js";
7
+ import { PluginRegistryService } from "./plugin-registry-service.js";
8
+ import { seedTemplateSampleContent } from "./seed-template-content.js";
9
+ // The counterpart to ../sandbox/register-local-plugin.ts: that one loads
10
+ // a manifest from LIVE SOURCE (src/plugin.ts(x)) for velora-dev's
11
+ // same-filesystem dev sandbox; this one loads from a BUILT, distributable
12
+ // package's server/plugin.js (produced by `velora-plugin build`,
13
+ // Session 81) — proving a plugin installs from a package with no source
14
+ // tree alongside it at all. Both funnel into the same, unmodified
15
+ // registerLocalPlugin() — the manifest's origin doesn't matter to it.
16
+ //
17
+ // Since Session 121, server/plugin.js is a self-contained Vite SSR bundle
18
+ // (react, react/jsx-runtime, and @velora-cms/plugin-sdk all inlined; zero bare
19
+ // import specifiers) rather than a tsc-emitted file with live import
20
+ // specifiers — which is why no node_modules needs to exist anywhere near
21
+ // the extraction point for this to resolve.
22
+ //
23
+ // Since Session 122, install COPIES the package into the managed plugin
24
+ // store (plugin-package-store.ts) before importing anything, and imports
25
+ // from that STORED copy rather than the caller's (often tmpdir) extraction
26
+ // directory — the same copy a later boot loader will import on restart.
27
+ /** Resolves the server-importable manifest entry a `velora-plugin
28
+ * build` package always produces at this fixed path. */
29
+ export function resolveBuiltManifestPath(packageDir) {
30
+ const entryPath = join(packageDir, "server", "plugin.js");
31
+ if (!existsSync(entryPath)) {
32
+ throw new Error(`No built manifest found at ${packageDir} — expected server/plugin.js`);
33
+ }
34
+ return entryPath;
35
+ }
36
+ export async function installBuiltPackage(service, packageDir, remoteUrl, setRemoteUrl, syncManifestFields, setPackagePath, opts) {
37
+ resolveBuiltManifestPath(packageDir); // fail fast on a non-package before any copying
38
+ // manifest.json (written by `velora-plugin build`) supplies id+version
39
+ // WITHOUT importing code — the store path must be known before the
40
+ // import so the import runs against the STORED copy (what the boot
41
+ // loader will import later is byte-identical to what installs now).
42
+ const manifestJsonPath = join(packageDir, "manifest.json");
43
+ if (!existsSync(manifestJsonPath)) {
44
+ throw new Error(`No manifest.json found in ${packageDir} — not a velora-plugin built package`);
45
+ }
46
+ const summary = JSON.parse(readFileSync(manifestJsonPath, "utf8"));
47
+ if (!summary.id || !summary.version) {
48
+ throw new Error(`${manifestJsonPath} is missing id/version`);
49
+ }
50
+ // Path-safety gate: these two values become directory names BEFORE the
51
+ // manifest's own validation runs (validatePluginManifest fires later,
52
+ // inside registerLocalPlugin). Mirror the SDK manifest schema's id rule
53
+ // and a path-safe version shape so a hostile manifest.json can't
54
+ // traverse out of the store root.
55
+ if (!/^[a-z0-9-]+(\.[a-z0-9-]+)+$/i.test(summary.id)) {
56
+ throw new Error(`manifest.json id "${summary.id}" is not a valid reverse-domain plugin id`);
57
+ }
58
+ // Must start and end with an alphanumeric — otherwise a version of "."
59
+ // or ".." (both match the bare character-class check on their own)
60
+ // resolves as a filesystem self-reference/parent-reference segment once
61
+ // joined into a path, not a literal directory name.
62
+ if (!/^[0-9a-z](?:[0-9a-z.+-]*[0-9a-z])?$/i.test(summary.version) ||
63
+ summary.version.includes("..")) {
64
+ throw new Error(`manifest.json version "${summary.version}" is not a path-safe version string`);
65
+ }
66
+ const storedDir = storePackage(packageDir, summary.id, summary.version);
67
+ const entryPath = resolveBuiltManifestPath(storedDir);
68
+ const mod = (await import(pathToFileURL(entryPath).href));
69
+ if (!mod.default) {
70
+ throw new Error(`${entryPath} has no default export`);
71
+ }
72
+ const manifestId = mod.default.id;
73
+ if (manifestId !== summary.id) {
74
+ throw new Error(`manifest.json id "${summary.id}" does not match server/plugin.js id "${manifestId}"`);
75
+ }
76
+ const manifestVersion = mod.default.version;
77
+ if (manifestVersion !== summary.version) {
78
+ throw new Error(`manifest.json version "${summary.version}" does not match server/plugin.js version "${manifestVersion}"`);
79
+ }
80
+ // SEC-2 (S172 audit): the declared type in manifest.json — the value the
81
+ // marketplace catalogs as `listing.type` and the human reviewer approves
82
+ // against — must equal the plugin's ACTUAL runtime type in server/plugin.js.
83
+ // The marketplace never inspects the (opaque, minified) server bundle, so a
84
+ // package could be listed/reviewed as a benign `datatype`/`theme` while its
85
+ // code runs as a `section` with public apiRoutes/hooks/scheduledTasks.
86
+ // Enforcing declared === runtime here makes any such spoof uninstallable
87
+ // everywhere, so the runtime type a plugin ships can never diverge from the
88
+ // type it was reviewed and listed as. (When manifest.json carries no type —
89
+ // an older sideload shape — there is nothing to contradict, so skip.)
90
+ const manifestType = mod.default.type;
91
+ if (summary.type && manifestType && summary.type !== manifestType) {
92
+ throw new Error(`manifest.json type "${summary.type}" does not match server/plugin.js type "${manifestType}" — the listed type must match the plugin's actual runtime type`);
93
+ }
94
+ // Type-aware remoteUrl gate. parseInstallBuiltPackageCliArgs (below)
95
+ // only enforces that the argv slot was supplied at all — it runs before
96
+ // any manifest is read, so it has no way to know the plugin's type and
97
+ // deliberately accepts an explicit "" unconditionally. install-from-
98
+ // marketplace.ts's own remoteUrl computation is the authority on when
99
+ // "" is actually correct: only for a view-less type (theme/template/
100
+ // bundle — see hasClientBundle), which ships no remoteEntry.js at all.
101
+ // A view-BEARING type (datatype/section/integration/utility) installed
102
+ // with an empty remoteUrl would register successfully but silently skip
103
+ // loading its views forever — boot-remote-plugins.ts's `if
104
+ // (!plugin.remoteUrl) continue` treats "" exactly like "nothing to
105
+ // load," with no error anywhere. Catch that here, now that the
106
+ // manifest's real type is known, rather than letting it install broken.
107
+ if (remoteUrl === "" && manifestType && hasClientBundle(manifestType)) {
108
+ throw new Error(`"${summary.id}" is type "${manifestType}", which ships a client bundle (remoteEntry.js) — an empty remoteUrl is only valid for view-less plugin types (theme/template/bundle). Pass the plugin's actual remoteUrl.`);
109
+ }
110
+ const outcome = await registerLocalPlugin(service, mod.default, remoteUrl, setRemoteUrl, syncManifestFields, opts);
111
+ await setPackagePath?.(summary.id, storedDir);
112
+ // D1: invoked AFTER registerLocalPlugin returns, never from inside
113
+ // PluginRegistryService.install() — the S88 documentTypes path stays
114
+ // untouched. Only a genuinely fresh install seeds — "activated"/
115
+ // "already-active" mean this call didn't create anything new, so
116
+ // there's nothing to seed against (and, for the already-active case,
117
+ // any real sample content would already exist anyway). storedDir is
118
+ // exactly the STORED package dir seedTemplateSampleContent reads
119
+ // sample-content.json from — the same copy the boot loader will import
120
+ // on restart. Wrapped in its own try/catch as a belt-and-braces guard
121
+ // on top of the seeder's own internal non-fatal handling — D2 requires
122
+ // this install to stand no matter what happens here.
123
+ if (outcome === "installed" && opts?.seed) {
124
+ try {
125
+ const seedResult = await seedTemplateSampleContent({ prisma: opts.seed.prisma, adapter: opts.seed.adapter }, summary.id, storedDir, opts.seed.createdBy);
126
+ if (typeof seedResult === "object") {
127
+ console.log(`[install-built-package] seeded ${seedResult.created} sample content node(s) for "${summary.id}"`);
128
+ }
129
+ else if (seedResult !== "none") {
130
+ console.log(`[install-built-package] sample content seeding for "${summary.id}": ${seedResult}`);
131
+ }
132
+ }
133
+ catch (error) {
134
+ console.error(`[install-built-package] sample content seeding for "${summary.id}" failed — the install stands`, error);
135
+ }
136
+ }
137
+ return outcome;
138
+ }
139
+ /** Validates `main()`'s argv shape only — NOT whether "" is the right
140
+ * value for this particular plugin. A view-less plugin type (theme/
141
+ * template/bundle) has no remoteEntry.js at all — install-from-
142
+ * marketplace.ts computes remoteUrl as `""` for exactly that case ("Empty
143
+ * string = the loader's existing 'nothing to load' contract"), so an
144
+ * explicitly-passed empty string here is a legitimate value, not a missing
145
+ * argument, and this parser accepts it unconditionally. Only an actually
146
+ * omitted argv slot (undefined — the caller never supplied a second
147
+ * positional at all) is a usage error; `target` has no such legitimate-
148
+ * empty case, so it keeps the plain falsy check. This parser runs before
149
+ * any manifest is read, so it CANNOT tell a view-less "" apart from a
150
+ * view-bearing type's "" typo'd in by mistake — that type-aware check
151
+ * happens later, inside installBuiltPackage, once the manifest's real
152
+ * type is known. */
153
+ export function parseInstallBuiltPackageCliArgs(argv) {
154
+ const [target, remoteUrl, sidecarPath] = argv;
155
+ if (!target || remoteUrl === undefined) {
156
+ throw new Error("Usage: tsx install-built-package.ts <packageDir|package.tar.gz> <remoteUrl> [sidecarPath]");
157
+ }
158
+ return { target, remoteUrl, sidecarPath };
159
+ }
160
+ async function main() {
161
+ const { target, remoteUrl, sidecarPath: sidecarFlag } = parseInstallBuiltPackageCliArgs(process.argv.slice(2));
162
+ // Since Session 122, the CLI connects through connectContentDb() rather
163
+ // than hardcoding a PostgreSQLAdapter — this makes the sqlite sandbox a
164
+ // first-class CLI target (Session 121's live proof needed a throwaway
165
+ // driver precisely because of the old hardcoded adapter).
166
+ const { prisma } = await import("../db/prisma.js");
167
+ const { connectContentDb } = await import("../db/content-db.js");
168
+ const contentDb = await connectContentDb();
169
+ const activeDialect = process.env.VELORA_PLUGIN_ACTIVE_DIALECT ?? contentDb.dialect;
170
+ const service = new PluginRegistryService(prisma, contentDb.adapter, { activeDialect });
171
+ const setRemoteUrl = async (pluginId, url) => {
172
+ await prisma.pluginRegistry.update({ where: { pluginId }, data: { remoteUrl: url } });
173
+ };
174
+ const syncManifestFields = async (pluginId, fields) => {
175
+ await prisma.pluginRegistry.update({ where: { pluginId }, data: fields });
176
+ };
177
+ const setPackagePath = async (pluginId, packagePath) => {
178
+ await prisma.pluginRegistry.update({ where: { pluginId }, data: { packagePath } });
179
+ };
180
+ // Session 127: a .tar.gz takes the verifying path; a directory takes the
181
+ // original one, unchanged — velora-dev and in-monorepo development have
182
+ // no tarball.
183
+ if (target.endsWith(".tar.gz")) {
184
+ const { installPackageTarball } = await import("./install-package-tarball.js");
185
+ const { outcome, verification } = await installPackageTarball(service, target, remoteUrl, setRemoteUrl, syncManifestFields, setPackagePath, sidecarFlag ? { sidecarPath: sidecarFlag } : {});
186
+ console.log(`[install-built-package] ${outcome} (${verification.status})`);
187
+ }
188
+ else {
189
+ const outcome = await installBuiltPackage(service, target, remoteUrl, setRemoteUrl, syncManifestFields, setPackagePath);
190
+ console.log(`[install-built-package] ${outcome}`);
191
+ }
192
+ await prisma.$disconnect();
193
+ }
194
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
195
+ main().catch((error) => {
196
+ console.error("[install-built-package] failed:", error);
197
+ process.exit(1);
198
+ });
199
+ }
@@ -0,0 +1,25 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ import type { TrustedKey, VerifyResult } from "@velora-cms/plugin-package";
3
+ import type { DatabaseAdapter } from "@velora-cms/db-adapter";
4
+ import type { ManifestRowFields, RegisterLocalPluginResult } from "../sandbox/register-local-plugin.js";
5
+ import type { PluginRegistryService } from "./plugin-registry-service.js";
6
+ export interface InstallPackageTarballOptions {
7
+ /** Defaults to `<tarballPath>.sig` when present; pass null to force the
8
+ * unsigned path. */
9
+ sidecarPath?: string | null;
10
+ /** Defaults to loadTrustedKeys(). */
11
+ trustedKeys?: TrustedKey[];
12
+ /** Forwarded verbatim to installBuiltPackage (Session 151): when
13
+ * supplied, a template plugin's sample-content.json is seeded after a
14
+ * fresh install — see installBuiltPackage's own opts.seed doc. Purely
15
+ * additive: every pre-existing caller omits it and behaves unchanged. */
16
+ seed?: {
17
+ prisma: PrismaClient;
18
+ adapter: DatabaseAdapter;
19
+ createdBy?: string;
20
+ };
21
+ }
22
+ export declare function installPackageTarball(service: PluginRegistryService, tarballPath: string, remoteUrl: string, setRemoteUrl: (pluginId: string, remoteUrl: string) => Promise<void>, syncManifestFields: (pluginId: string, fields: ManifestRowFields) => Promise<void>, setPackagePath?: (pluginId: string, packagePath: string) => Promise<void>, options?: InstallPackageTarballOptions): Promise<{
23
+ outcome: RegisterLocalPluginResult;
24
+ verification: VerifyResult;
25
+ }>;