@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,836 @@
1
+ <!DOCTYPE html><html lang="en" dir="ltr" data-theme="dark" data-has-toc data-has-sidebar class="astro-ewhz5xxr"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>Installing plugins | Velora</title><link rel="shortcut icon" href="/docs/favicon.svg" type="image/svg+xml"/><meta name="generator" content="Astro v7.2.10"/><meta name="generator" content="Starlight v0.41.5"/><meta property="og:title" content="Installing plugins"/><meta property="og:type" content="article"/><meta property="og:locale" content="en"/><meta property="og:description" content="Connecting to the marketplace, what the signature gate actually blocks, sideloading a built package, and managing installed plugins."/><meta property="og:site_name" content="Velora"/><meta name="twitter:card" content="summary_large_image"/><meta name="description" content="Connecting to the marketplace, what the signature gate actually blocks, sideloading a built package, and managing installed plugins."/><script>
2
+ window.StarlightThemeProvider = (() => {
3
+ const storedTheme =
4
+ typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
5
+ const theme =
6
+ storedTheme ||
7
+ (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
8
+ document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
9
+ return {
10
+ updatePickers(theme = storedTheme || 'auto') {
11
+ document.querySelectorAll('starlight-theme-select').forEach((picker) => {
12
+ const select = picker.querySelector('select');
13
+ if (select) select.value = theme;
14
+ /** @type {HTMLTemplateElement | null} */
15
+ const tmpl = document.querySelector(`#theme-icons`);
16
+ const newIcon = tmpl && tmpl.content.querySelector('.' + theme);
17
+ if (newIcon) {
18
+ const oldIcon = picker.querySelector('svg.label-icon');
19
+ if (oldIcon) {
20
+ oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes);
21
+ }
22
+ }
23
+ });
24
+ },
25
+ };
26
+ })();
27
+ </script><template id="theme-icons"><svg aria-hidden="true" class="light astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm.64 5-.71.71a1 1 0 0 0 0 1.41 1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM12 5a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1Zm5.66 2.34a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.66.71a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.29Zm-12-.29a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.71-.71a1.004 1.004 0 1 0-1.43 1.41l.73.71ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-2.64 6A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.76-.66ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Zm0 3.5a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Z"/></svg><svg aria-hidden="true" class="dark astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.64 13a1 1 0 0 0-1.05-.14 8.049 8.049 0 0 1-3.37.73 8.15 8.15 0 0 1-8.14-8.1 8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69 1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14 9.784 9.784 0 0 0 2.1-.22 8.11 8.11 0 0 1-7.18 4.32v-.04Z"/></svg><svg aria-hidden="true" class="auto astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg></template><link rel="stylesheet" href="/docs/_astro/print.ehPL0gv-.css" media="print"><link rel="stylesheet" href="/docs/_astro/common.DTXA7sXM.css"><script type="module" src="/docs/_astro/page.Dwipeu-R.js"></script></head><body class="astro-ewhz5xxr"><a class="sl-skip-link astro-zufphfvp" href="#_top">Skip to content</a><div class="page sl-flex astro-5auw3bkx"><header class="header astro-5auw3bkx"><div class="header astro-6ytusalw"><div class="title-wrapper sl-flex astro-6ytusalw"><a href="/docs/" class="site-title sl-flex astro-nu4hftpf"><span class="astro-nu4hftpf" translate="no">Velora</span></a></div><div class="sl-flex print:hidden astro-6ytusalw"><site-search class="astro-6ytusalw astro-zwj6qr56" data-translations="{&quot;placeholder&quot;:&quot;Search&quot;}"><button data-open-modal disabled aria-label="Search" aria-keyshortcuts="Control+K" class="astro-zwj6qr56"><svg aria-hidden="true" class="astro-zwj6qr56 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.71 20.29 18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.39ZM11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z"/></svg><span class="sl-hidden md:sl-block astro-zwj6qr56" aria-hidden="true">Search</span><kbd class="sl-hidden md:sl-flex astro-zwj6qr56" style="display: none;"><kbd class="astro-zwj6qr56">Ctrl</kbd><kbd class="astro-zwj6qr56">K</kbd></kbd></button><dialog style="padding:0" aria-label="Search" class="astro-zwj6qr56"><div class="dialog-frame sl-flex astro-zwj6qr56"><button data-close-modal class="sl-flex md:sl-hidden astro-zwj6qr56">Cancel</button><div class="search-container astro-zwj6qr56"><div id="starlight__search" class="astro-zwj6qr56"></div></div></div></dialog></site-search><script>
28
+ (() => {
29
+ const openBtn = document.querySelector('button[data-open-modal]');
30
+ const shortcut = openBtn?.querySelector('kbd');
31
+ if (!openBtn || !(shortcut instanceof HTMLElement)) return;
32
+ const platformKey = shortcut.querySelector('kbd');
33
+ if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
34
+ platformKey.textContent = '⌘';
35
+ openBtn.setAttribute('aria-keyshortcuts', 'Meta+K');
36
+ }
37
+ shortcut.style.display = '';
38
+ })();
39
+ </script><script type="module" src="/docs/_astro/Search.astro_astro_type_script_index_0_lang.CavldbAs.js"></script></div><div class="sl-hidden md:sl-flex print:hidden right-group astro-6ytusalw"><div class="sl-flex social-icons astro-6ytusalw"></div><starlight-theme-select><label style="--sl-select-width: 6.25em" class="astro-7uz3f5wr"><span class="sr-only astro-7uz3f5wr">Select theme</span><svg aria-hidden="true" class="icon label-icon astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg><select autocomplete="off" class="astro-7uz3f5wr"><option value="dark" class="astro-7uz3f5wr">Dark</option><option value="light" class="astro-7uz3f5wr">Light</option><option value="auto" selected class="astro-7uz3f5wr">Auto</option></select><svg aria-hidden="true" class="icon caret astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg></label></starlight-theme-select><script>
40
+ StarlightThemeProvider.updatePickers();
41
+ </script><script type="module">var e=`starlight-theme`,t=e=>e===`auto`||e===`dark`||e===`light`?e:`auto`,n=()=>t(typeof localStorage<`u`&&localStorage.getItem(e));function r(t){typeof localStorage<`u`&&localStorage.setItem(e,t===`light`||t===`dark`?t:``)}var i=()=>matchMedia(`(prefers-color-scheme: light)`).matches?`light`:`dark`;function a(e){StarlightThemeProvider.updatePickers(e),document.documentElement.dataset.theme=e===`auto`?i():e,r(e)}matchMedia(`(prefers-color-scheme: light)`).addEventListener(`change`,()=>{n()===`auto`&&a(`auto`)});var o=class extends HTMLElement{constructor(){super(),a(n()),this.querySelector(`select`)?.addEventListener(`change`,e=>{e.currentTarget instanceof HTMLSelectElement&&a(t(e.currentTarget.value))})}};customElements.define(`starlight-theme-select`,o);</script><script type="module">var e=class extends HTMLElement{constructor(){super();let e=this.querySelector(`select`);e&&(e.addEventListener(`change`,e=>{e.currentTarget instanceof HTMLSelectElement&&(window.location.pathname=e.currentTarget.value)}),window.addEventListener(`pageshow`,t=>{if(!t.persisted)return;let n=e.querySelector(`option[selected]`)?.index;n!==e.selectedIndex&&(e.selectedIndex=n??0)}))}};customElements.define(`starlight-lang-select`,e);</script></div></div></header><nav class="sidebar print:hidden astro-5auw3bkx" aria-label="Main"><starlight-menu-button class="print:hidden astro-gnkm6dw5"><button aria-expanded="false" aria-label="Menu" aria-controls="starlight__sidebar" class="sl-flex md:sl-hidden astro-gnkm6dw5"><svg aria-hidden="true" class="open-menu astro-gnkm6dw5 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M3 8h18a1 1 0 1 0 0-2H3a1 1 0 0 0 0 2Zm18 8H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Zm0-5H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Z"/></svg><svg aria-hidden="true" class="close-menu astro-gnkm6dw5 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="m13.41 12 6.3-6.29a1.004 1.004 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1.004 1.004 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 0 1.42.998.998 0 0 0 1.42 0l6.29-6.3 6.29 6.3a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.42L13.41 12Z"/></svg></button></starlight-menu-button><script type="module">var e=class extends HTMLElement{btn=this.querySelector(`button`);constructor(){super(),this.btn.addEventListener(`click`,()=>this.toggleExpanded());let e=this.closest(`nav`);e&&e.addEventListener(`keyup`,e=>this.closeOnEscape(e)),matchMedia(`(min-width: 50em)`).addEventListener(`change`,()=>this.setExpanded(!1))}setExpanded(e){this.setAttribute(`aria-expanded`,String(e)),document.body.toggleAttribute(`data-mobile-menu-expanded`,e),document.querySelectorAll(`.main-frame, .sl-skip-link`).forEach(t=>{t.toggleAttribute(`inert`,e)})}toggleExpanded(){this.setExpanded(this.getAttribute(`aria-expanded`)!==`true`)}closeOnEscape(e){e.code===`Escape`&&(this.setExpanded(!1),this.btn.focus())}};customElements.define(`starlight-menu-button`,e);</script><div id="starlight__sidebar" class="sidebar-pane astro-5auw3bkx"><div class="sidebar-content sl-flex astro-5auw3bkx"><sl-sidebar-state-persist data-hash="03jp7ll" class="astro-pcs3l5kp"><script aria-hidden="true">
42
+ (() => {
43
+ try {
44
+ if (!matchMedia('(min-width: 50em)').matches) return;
45
+ /** @type {HTMLElement | null} */
46
+ const target = document.querySelector('sl-sidebar-state-persist');
47
+ const state = JSON.parse(sessionStorage.getItem('sl-sidebar-state') || '0');
48
+ if (!target || !state || target.dataset.hash !== state.hash) return;
49
+ window._starlightScrollRestore = state.scroll;
50
+ customElements.define(
51
+ 'sl-sidebar-restore',
52
+ class SidebarRestore extends HTMLElement {
53
+ connectedCallback() {
54
+ try {
55
+ const idx = parseInt(this.dataset.index || '');
56
+ const details = this.closest('details');
57
+ if (details && typeof state.open[idx] === 'boolean') details.open = state.open[idx];
58
+ } catch {}
59
+ }
60
+ }
61
+ );
62
+ } catch {}
63
+ })();
64
+ </script><ul class="top-level astro-ck7l566j"><li class="astro-ck7l566j"><details open class="astro-ck7l566j"><summary class="astro-ck7l566j"><span class="group-label astro-ck7l566j"><span class="large astro-ck7l566j">Using Velora</span></span><svg aria-hidden="true" class="caret astro-ck7l566j astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.25rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></summary><sl-sidebar-restore data-index="0"></sl-sidebar-restore><ul class="astro-ck7l566j"><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/" class="astro-ck7l566j"><span class="astro-ck7l566j">Using Velora</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/getting-started/" class="astro-ck7l566j"><span class="astro-ck7l566j">Getting started</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/installation/" class="astro-ck7l566j"><span class="astro-ck7l566j">Installation</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/content-model/" class="astro-ck7l566j"><span class="astro-ck7l566j">Document types</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/editing/" class="astro-ck7l566j"><span class="astro-ck7l566j">Content editing</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/media/" class="astro-ck7l566j"><span class="astro-ck7l566j">Media</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/users-and-roles/" class="astro-ck7l566j"><span class="astro-ck7l566j">Users and roles</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/installing-plugins/" aria-current="page" class="astro-ck7l566j"><span class="astro-ck7l566j">Installing plugins</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/headless-api/" class="astro-ck7l566j"><span class="astro-ck7l566j">Headless API</span></a></li><li class="astro-ck7l566j"><a href="/docs/v1/using-velora/build-a-headless-frontend/" class="astro-ck7l566j"><span class="astro-ck7l566j">Build a headless frontend</span></a></li></ul></details></li></ul><script aria-hidden="true">
65
+ (() => {
66
+ const scroller = document.getElementById('starlight__sidebar');
67
+ if (!window._starlightScrollRestore || !scroller) return;
68
+ scroller.scrollTop = window._starlightScrollRestore;
69
+ delete window._starlightScrollRestore;
70
+ })();
71
+ </script></sl-sidebar-state-persist><div class="md:sl-hidden"><div class="mobile-preferences sl-flex astro-yfet6llj"><div class="social-icons astro-yfet6llj"></div><starlight-theme-select><label style="--sl-select-width: 6.25em" class="astro-7uz3f5wr"><span class="sr-only astro-7uz3f5wr">Select theme</span><svg aria-hidden="true" class="icon label-icon astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg><select autocomplete="off" class="astro-7uz3f5wr"><option value="dark" class="astro-7uz3f5wr">Dark</option><option value="light" class="astro-7uz3f5wr">Light</option><option value="auto" selected class="astro-7uz3f5wr">Auto</option></select><svg aria-hidden="true" class="icon caret astro-7uz3f5wr astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg></label></starlight-theme-select><script>
72
+ StarlightThemeProvider.updatePickers();
73
+ </script></div></div></div></div></nav><div class="main-frame astro-5auw3bkx"><script type="module">var e=document.getElementById(`starlight__sidebar`),t=e?.querySelector(`sl-sidebar-state-persist`),n=`sl-sidebar-state`,r=()=>{let r=[],i=t?.dataset.hash||``;try{let e=sessionStorage.getItem(n),t=JSON.parse(e||`{}`);Array.isArray(t.open)&&t.hash===i&&(r=t.open)}catch{}return{hash:i,open:r,scroll:e?.scrollTop||0}},i=e=>{try{sessionStorage.setItem(n,JSON.stringify(e))}catch{}},a=()=>i(r()),o=(e,t)=>{let n=r();n.open[t]=e,i(n)};t?.addEventListener(`click`,e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`summary`)?.closest(`details`);if(!t)return;let n=t.querySelector(`sl-sidebar-restore`),r=parseInt(n?.dataset.index||``);isNaN(r)||o(!t.open,r)}),addEventListener(`visibilitychange`,()=>{document.visibilityState===`hidden`&&a()});</script><div class="lg:sl-flex astro-perbdhd2"><aside class="right-sidebar-container print:hidden astro-perbdhd2"><div class="right-sidebar astro-perbdhd2"><div class="lg:sl-hidden astro-epm5tkrc"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-bnvebtr4"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-bnvebtr4"><details id="starlight__mobile-toc" class="astro-bnvebtr4"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-bnvebtr4"><span class="toggle sl-flex astro-bnvebtr4">On this page<svg aria-hidden="true" class="caret astro-bnvebtr4 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></span><span class="display-current astro-bnvebtr4"></span></summary><div class="dropdown astro-bnvebtr4"><ul class="isMobile astro-lptfoybu" style="--depth: 0;"><li style="--depth: 0;" class="astro-lptfoybu"><a href="#_top" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Overview</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#the-marketplace-connection" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">The marketplace connection</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#browsing" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Browsing</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#installing" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Installing</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#the-trust-gate-exactly" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">The trust gate, exactly</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#sideloading-a-built-package" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Sideloading a built package</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#managing-what-is-installed" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Managing what is installed</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#marketplace-terms-briefly" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Marketplace terms, briefly</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#writing-your-own" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Writing your own</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#next" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Next</span></a></li></ul></div></details></nav></mobile-starlight-toc><script type="module" src="/docs/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js"></script></div><div class="right-sidebar-panel sl-hidden lg:sl-block astro-epm5tkrc"><div class="sl-container astro-epm5tkrc"><starlight-toc data-min-h="2" data-max-h="3"><nav aria-labelledby="starlight__on-this-page"><h2 id="starlight__on-this-page">On this page</h2><ul class="astro-lptfoybu" style="--depth: 0;"><li style="--depth: 0;" class="astro-lptfoybu"><a href="#_top" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Overview</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#the-marketplace-connection" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">The marketplace connection</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#browsing" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Browsing</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#installing" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Installing</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#the-trust-gate-exactly" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">The trust gate, exactly</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#sideloading-a-built-package" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Sideloading a built package</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#managing-what-is-installed" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Managing what is installed</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#marketplace-terms-briefly" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Marketplace terms, briefly</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#writing-your-own" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Writing your own</span></a></li><li style="--depth: 0;" class="astro-lptfoybu"><a href="#next" style="--depth: 0;" class="astro-lptfoybu"><span style="--depth: 0;" class="astro-lptfoybu">Next</span></a></li></ul></nav></starlight-toc><script type="module" src="/docs/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js"></script></div></div></div></aside><div class="main-pane astro-perbdhd2"><main data-pagefind-body class="astro-ewhz5xxr" lang="en" dir="ltr"><div class="content-panel astro-ahkzlqop"><div class="sl-container astro-ahkzlqop"><h1 id="_top" class="astro-oef2efwn">Installing plugins</h1></div></div><div class="content-panel astro-ahkzlqop"><div class="sl-container astro-ahkzlqop"><div class="sl-markdown-content"><p>A Velora instance browses and installs plugins from a marketplace, and a
74
+ fresh install already points at the hosted one. Two rules shape everything
75
+ below, and they are not the same rule:</p>
76
+ <ul>
77
+ <li><strong>A marketplace install must verify.</strong> If the downloaded package does not
78
+ carry a signature from a key this instance trusts, the install is refused
79
+ before any of the package’s code runs.</li>
80
+ <li><strong>A sideload never blocks on signatures.</strong> A package you install by hand
81
+ installs as <code dir="auto">unverified</code> — silently if it is unsigned, loudly if it
82
+ claims a signature that fails.</li>
83
+ </ul>
84
+ <p>Everything in the <strong>Plugins</strong> section is admin-only: every
85
+ <code dir="auto">/api/plugin-management/*</code> route is behind <code dir="auto">requireAdmin</code>, so an editor gets
86
+ a <code dir="auto">403</code> regardless of what the app bar shows.</p>
87
+ <div class="sl-heading-wrapper level-h2"><h2 id="the-marketplace-connection">The marketplace connection</h2><a class="sl-anchor-link" href="#the-marketplace-connection"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “The marketplace connection”</span></a></div>
88
+ <p>The marketplace an instance talks to is a deploy-time setting, resolved
89
+ once from the environment:</p>
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">VELORA_MARKETPLACE_URL</code></td><td>string (origin) or <code dir="auto">off</code></td><td>The marketplace origin. <strong>Unset uses the hosted default</strong>, <code dir="auto">https://marketplace.velora-cms.com</code>. <code dir="auto">off</code> (case-insensitive) or a blank value opts out entirely — the browse, detail and install proxy routes are then structurally absent, not merely denied. Any other value is treated as a custom origin, for a private or self-hosted marketplace. Trailing slashes are trimmed.</td><td><code dir="auto">https://marketplace.velora-cms.com</code></td></tr></tbody></table>
108
+ <p>Because “no marketplace” and “marketplace down” are different problems, the
109
+ admin asks the server which one it is, once, at the section level:</p>
110
+ <div class="expressive-code"><link rel="stylesheet" href="/docs/_astro/ec.w36nc.css"><script type="module" src="/docs/_astro/ec.0vx5m.js"></script><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">http://localhost:3000/api/plugin-management/marketplace-status</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-H</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Authorization: Bearer </span><span style="--0:#C5E478;--1:#3B61B0">$TOKEN</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s http://localhost:3000/api/plugin-management/marketplace-status \ -H &#x22;Authorization: Bearer $TOKEN&#x22;"><div></div></button></div></figure></div>
111
+ <p>The answer is a single boolean — <code dir="auto">true</code> on a stock install, <code dir="auto">false</code> only
112
+ when an operator opted out:</p>
113
+ <div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{ </span><span style="--0:#7FDBCA;--1:#096E72">"configured"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span><span style="--0:#D6DEEB;--1:#403F53"> }</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{ &#x22;configured&#x22;: true }"><div></div></button></div></figure></div>
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">configured</code></td><td>boolean</td><td><code dir="auto">false</code> means <code dir="auto">VELORA_MARKETPLACE_URL</code> is <code dir="auto">off</code> or blank, so there is nothing to browse. It never means the marketplace is unreachable — a configured-but-down marketplace still reports <code dir="auto">true</code> and surfaces a load error instead.</td><td><code dir="auto">true</code></td></tr></tbody></table>
132
+ <p>With <code dir="auto">configured: false</code> the Marketplace screens render one honest empty
133
+ state: “No plugins found.” is <em>not</em> what you see — you get “No marketplace
134
+ connected”, with the instruction to set <code dir="auto">VELORA_MARKETPLACE_URL</code> in the
135
+ server’s environment and restart. The <strong>Installed</strong> view keeps working
136
+ either way; so does sideloading.</p>
137
+ <div class="sl-heading-wrapper level-h2"><h2 id="browsing">Browsing</h2><a class="sl-anchor-link" href="#browsing"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Browsing”</span></a></div>
138
+ <p>The <strong>Plugins</strong> section has two views, <strong>Installed</strong> and <strong>Marketplace</strong>.
139
+ Browsing proxies the upstream catalogue through your own server — your
140
+ browser never talks to the marketplace directly — and the server annotates
141
+ every listing with one thing the marketplace cannot know: whether it runs on
142
+ <em>your</em> database.</p>
143
+ <div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">http://localhost:3000/api/plugin-management/marketplace/listings?q=forms&#x26;limit=2</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-H</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Authorization: Bearer </span><span style="--0:#C5E478;--1:#3B61B0">$TOKEN</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s &#x22;http://localhost:3000/api/plugin-management/marketplace/listings?q=forms&#x26;limit=2&#x22; \ -H &#x22;Authorization: Bearer $TOKEN&#x22;"><div></div></button></div></figure></div>
144
+ <p>The response wraps the upstream page with the active dialect and the
145
+ compatibility verdict per listing (the listing values below are real ones
146
+ from the hosted marketplace; the envelope around them is derived from
147
+ <code dir="auto">MarketplaceListResponseSchema</code>):</p>
148
+ <div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"items"</span><span style="--0:#D6DEEB;--1:#403F53">: [</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"pluginId"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">com.velora.forms</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"name"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Forms</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"type"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">section</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"description"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Form builder with a public submission endpoint and a submissions inbox</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"author"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Velora</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"priceCents"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#F78C6C;--1:#AA0982">0</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"coverImagePath"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"latestVersion"</span><span style="--0:#D6DEEB;--1:#403F53">: {</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"version"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">0.1.0</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"supportedDialects"</span><span style="--0:#D6DEEB;--1:#403F53">: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">postgresql</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">mysql</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">sqlite</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">],</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"permissions"</span><span style="--0:#D6DEEB;--1:#403F53">: { </span><span style="--0:#7FDBCA;--1:#096E72">"needsStructuredData"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#7FDBCA;--1:#096E72">"needsExternalNetwork"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">false</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#7FDBCA;--1:#096E72">"needsFileSystemAccess"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">false</span><span style="--0:#D6DEEB;--1:#403F53"> },</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"license"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">MIT</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"cmsVersion"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">^0.1.0</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"verified"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"createdAt"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">2026-08-25T14:24:31.900Z</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"hasArtifact"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">},</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"compatible"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">],</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"nextCursor"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">b1d001bc-653c-4d46-84a5-10ba6939010d</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"activeDialect"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">postgresql</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"marketplaceBaseUrl"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">https://marketplace.velora-cms.com</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{ &#x22;items&#x22;: [ { &#x22;pluginId&#x22;: &#x22;com.velora.forms&#x22;, &#x22;name&#x22;: &#x22;Forms&#x22;, &#x22;type&#x22;: &#x22;section&#x22;, &#x22;description&#x22;: &#x22;Form builder with a public submission endpoint and a submissions inbox&#x22;, &#x22;author&#x22;: &#x22;Velora&#x22;, &#x22;priceCents&#x22;: 0, &#x22;coverImagePath&#x22;: null, &#x22;latestVersion&#x22;: { &#x22;version&#x22;: &#x22;0.1.0&#x22;, &#x22;supportedDialects&#x22;: [&#x22;postgresql&#x22;, &#x22;mysql&#x22;, &#x22;sqlite&#x22;], &#x22;permissions&#x22;: { &#x22;needsStructuredData&#x22;: true, &#x22;needsExternalNetwork&#x22;: false, &#x22;needsFileSystemAccess&#x22;: false }, &#x22;license&#x22;: &#x22;MIT&#x22;, &#x22;cmsVersion&#x22;: &#x22;^0.1.0&#x22;, &#x22;verified&#x22;: true, &#x22;createdAt&#x22;: &#x22;2026-08-25T14:24:31.900Z&#x22;, &#x22;hasArtifact&#x22;: true }, &#x22;compatible&#x22;: true } ], &#x22;nextCursor&#x22;: &#x22;b1d001bc-653c-4d46-84a5-10ba6939010d&#x22;, &#x22;activeDialect&#x22;: &#x22;postgresql&#x22;, &#x22;marketplaceBaseUrl&#x22;: &#x22;https://marketplace.velora-cms.com&#x22;}"><div></div></button></div></figure></div>
149
+ <p>The query parameters:</p>
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">q</code></td><td>string, optional</td><td>Free-text search, passed upstream. The admin’s search box.</td><td><code dir="auto">forms</code></td></tr><tr><td><code dir="auto">type</code></td><td>string, optional</td><td>Filter by plugin type.</td><td><code dir="auto">section</code></td></tr><tr><td><code dir="auto">db</code></td><td>string, optional</td><td>Filter by supported dialect.</td><td><code dir="auto">sqlite</code></td></tr><tr><td><code dir="auto">limit</code></td><td>integer 1–50, default <code dir="auto">24</code></td><td>Page size.</td><td><code dir="auto">2</code></td></tr><tr><td><code dir="auto">cursor</code></td><td>string (uuid), optional</td><td>The previous page’s cursor.</td><td><code dir="auto">b1d001bc-653c-4d46-84a5-10ba6939010d</code></td></tr></tbody></table>
192
+ <p>And each listing:</p>
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+
264
+
265
+
266
+
267
+
268
+
269
+
270
+
271
+
272
+
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
284
+
285
+
286
+
287
+
288
+
289
+
290
+
291
+
292
+
293
+
294
+
295
+
296
+
297
+
298
+
299
+
300
+
301
+
302
+
303
+
304
+
305
+
306
+
307
+
308
+
309
+
310
+
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">pluginId</code></td><td>string</td><td>Reverse-domain id. Unique per marketplace, and the id the registry stores.</td><td><code dir="auto">com.velora.forms</code></td></tr><tr><td><code dir="auto">name</code></td><td>string</td><td>Display name.</td><td><code dir="auto">Forms</code></td></tr><tr><td><code dir="auto">type</code></td><td>string</td><td>One of <code dir="auto">datatype</code>, <code dir="auto">section</code>, <code dir="auto">template</code>, <code dir="auto">theme</code>, <code dir="auto">integration</code>, <code dir="auto">utility</code>, <code dir="auto">bundle</code>. The type decides what the plugin may contribute.</td><td><code dir="auto">section</code></td></tr><tr><td><code dir="auto">description</code></td><td>string</td><td>One-line summary shown on the card.</td><td><code dir="auto">Form builder with a public submission endpoint…</code></td></tr><tr><td><code dir="auto">author</code></td><td>string</td><td>Publisher name.</td><td><code dir="auto">Velora</code></td></tr><tr><td><code dir="auto">priceCents</code></td><td>integer</td><td><code dir="auto">0</code> for a free plugin. Anything above zero requires a license key at install.</td><td><code dir="auto">0</code></td></tr><tr><td><code dir="auto">coverImagePath</code></td><td>string or <code dir="auto">null</code></td><td>Cover art path on the marketplace, <code dir="auto">null</code> when the listing has none.</td><td><code dir="auto">null</code></td></tr><tr><td><code dir="auto">latestVersion</code></td><td>object or <code dir="auto">null</code></td><td>The newest published version, or <code dir="auto">null</code> for a listing with no published version at all.</td><td>—</td></tr><tr><td><code dir="auto">latestVersion.version</code></td><td>string</td><td>Version string to install.</td><td><code dir="auto">0.1.0</code></td></tr><tr><td><code dir="auto">latestVersion.supportedDialects</code></td><td>array of strings</td><td>Databases the version supports. Compared against your <code dir="auto">activeDialect</code>.</td><td><code dir="auto">["postgresql","mysql","sqlite"]</code></td></tr><tr><td><code dir="auto">latestVersion.permissions</code></td><td>object of booleans</td><td>What the plugin declared it needs — shown in the detail view’s Permissions tab.</td><td><code dir="auto">{ "needsStructuredData": true, … }</code></td></tr><tr><td><code dir="auto">latestVersion.license</code></td><td>string</td><td>The plugin’s own software license.</td><td><code dir="auto">MIT</code></td></tr><tr><td><code dir="auto">latestVersion.cmsVersion</code></td><td>string (semver range)</td><td>The Velora range the version targets.</td><td><code dir="auto">^0.1.0</code></td></tr><tr><td><code dir="auto">latestVersion.verified</code></td><td>boolean</td><td>The marketplace’s own review/signing state for that version.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">latestVersion.createdAt</code></td><td>ISO datetime string</td><td>When the version was published.</td><td><code dir="auto">2026-08-25T14:24:31.900Z</code></td></tr><tr><td><code dir="auto">latestVersion.hasArtifact</code></td><td>boolean</td><td>Whether a downloadable package exists. <code dir="auto">false</code> disables the Install button with “Not yet available for download” rather than letting the install fail on a 404.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">compatible</code></td><td>boolean</td><td><strong>Computed by your server</strong>, not the marketplace: whether <code dir="auto">supportedDialects</code> contains your active dialect. <code dir="auto">false</code> renders “Not compatible with this site’s database (…)”.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">activeDialect</code></td><td>string</td><td>The dialect this instance actually runs.</td><td><code dir="auto">postgresql</code></td></tr><tr><td><code dir="auto">marketplaceBaseUrl</code></td><td>string</td><td>Which marketplace answered. Useful when an instance points at a private one.</td><td><code dir="auto">https://marketplace.velora-cms.com</code></td></tr></tbody></table>
319
+ <p>The same catalogue is public, so you can look at it without a Velora
320
+ instance at all:</p>
321
+ <div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">https://marketplace.velora-cms.com/api/v1/listings?limit=2</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s &#x22;https://marketplace.velora-cms.com/api/v1/listings?limit=2&#x22;"><div></div></button></div></figure></div>
322
+ <p>That returns the raw upstream page — the same <code dir="auto">items</code> and <code dir="auto">nextCursor</code>, but
323
+ without <code dir="auto">compatible</code>, <code dir="auto">activeDialect</code> or <code dir="auto">marketplaceBaseUrl</code>, which only
324
+ your own server can add.</p>
325
+ <p>Opening a listing loads the detail view (<code dir="auto">GET /api/plugin-management/marketplace/listings/:pluginId</code>), which adds the full
326
+ <code dir="auto">versions</code> array and three detail-only extras. Those three are typed on
327
+ every version object the detail view returns — <code dir="auto">latestVersion</code> and each
328
+ entry of <code dir="auto">versions</code> alike — not only on the newest one:</p>
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+
337
+
338
+
339
+
340
+
341
+
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">versions</code></td><td>array of version objects</td><td>Every published version of the listing, each shaped like <code dir="auto">latestVersion</code> (browse fields plus the three extras below).</td><td><code dir="auto">[{ "version": "0.1.0", … }]</code></td></tr><tr><td><code dir="auto">starter</code></td><td>object or <code dir="auto">null</code>, optional</td><td>A starter frontend for that version. <code dir="auto">name</code> (string), <code dir="auto">description</code> (string or <code dir="auto">null</code>), <code dir="auto">repository</code> (string or <code dir="auto">null</code>), <code dir="auto">hasArchive</code> (boolean — whether a downloadable archive exists).</td><td><code dir="auto">{ "name": "Blog starter", "description": null, "repository": null, "hasArchive": true }</code></td></tr><tr><td><code dir="auto">documentTypesSummary</code></td><td>array or <code dir="auto">null</code>, optional</td><td>Document types installing that version will provision, each with <code dir="auto">name</code> (string) and <code dir="auto">fields</code> (array of strings).</td><td><code dir="auto">[{ "name": "Article", "fields": ["title", "body"] }]</code></td></tr><tr><td><code dir="auto">bundledMembers</code></td><td>array or <code dir="auto">null</code>, optional</td><td>For a bundle version only: one entry per member, with <code dir="auto">pluginId</code>, <code dir="auto">name</code>, <code dir="auto">description</code> (string or <code dir="auto">null</code>), <code dir="auto">type</code>, and <code dir="auto">priceCents</code> (integer).</td><td><code dir="auto">[{ "pluginId": "com.velora.forms", "name": "Forms", "description": null, "type": "section", "priceCents": 0 }]</code></td></tr></tbody></table>
365
+ <div class="sl-heading-wrapper level-h2"><h2 id="installing">Installing</h2><a class="sl-anchor-link" href="#installing"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Installing”</span></a></div>
366
+ <p>Install is one request. The route runs a fixed order — already installed →
367
+ listing and version exist → paid plugins validate a license → download →
368
+ identity check → <strong>signature verification</strong> → register — and every step
369
+ returns before the next one has a side effect:</p>
370
+ <div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-X</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">POST</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">http://localhost:3000/api/plugin-management/marketplace/install</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-H</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Content-Type: application/json</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-H</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Authorization: Bearer </span><span style="--0:#C5E478;--1:#3B61B0">$TOKEN</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-d</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#ECC48D;--1:#984E4D">{"pluginId": "com.velora.forms", "version": "0.1.0"}</span><span style="--0:#D9F5DD;--1:#111111">'</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s -X POST http://localhost:3000/api/plugin-management/marketplace/install \ -H &#x22;Content-Type: application/json&#x22; \ -H &#x22;Authorization: Bearer $TOKEN&#x22; \ -d &#x27;{&#x22;pluginId&#x22;: &#x22;com.velora.forms&#x22;, &#x22;version&#x22;: &#x22;0.1.0&#x22;}&#x27;"><div></div></button></div></figure></div>
371
+ <p>A success is <code dir="auto">201</code>. <code dir="auto">trustTier</code> is a literal here, not a variable: this door
372
+ only ever answers <code dir="auto">201</code> for a verified package:</p>
373
+ <div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"pluginId"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">com.velora.forms</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"version"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">0.1.0</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"trustTier"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">verified</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"licensed"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">false</span></div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{ &#x22;pluginId&#x22;: &#x22;com.velora.forms&#x22;, &#x22;version&#x22;: &#x22;0.1.0&#x22;, &#x22;trustTier&#x22;: &#x22;verified&#x22;, &#x22;licensed&#x22;: false}"><div></div></button></div></figure></div>
374
+
375
+
376
+
377
+
378
+
379
+
380
+
381
+
382
+
383
+
384
+
385
+
386
+
387
+
388
+
389
+
390
+
391
+
392
+
393
+
394
+
395
+
396
+
397
+
398
+
399
+
400
+
401
+
402
+
403
+
404
+
405
+
406
+
407
+
408
+
409
+
410
+
411
+
412
+
413
+
414
+
415
+
416
+
417
+
418
+
419
+
420
+
421
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">pluginId</code></td><td>string, required</td><td>Request body. Must be a reverse-domain id — the pattern is enforced because this value becomes a directory name in the managed package store.</td><td><code dir="auto">com.velora.forms</code></td></tr><tr><td><code dir="auto">version</code></td><td>string, required</td><td>Request body. Must match a published version of that listing, or <code dir="auto">404</code>.</td><td><code dir="auto">0.1.0</code></td></tr><tr><td><code dir="auto">licenseKey</code></td><td>string, optional</td><td>Request body. Required when <code dir="auto">priceCents > 0</code>; validated upstream against the key, the plugin and this site’s domain <strong>before</strong> anything is downloaded.</td><td><code dir="auto">vlic_…</code></td></tr><tr><td><code dir="auto">trustTier</code></td><td>literal <code dir="auto">"verified"</code></td><td>Response. The only tier this route can return.</td><td><code dir="auto">verified</code></td></tr><tr><td><code dir="auto">licensed</code></td><td>boolean</td><td>Response. Whether a license row was persisted — <code dir="auto">true</code> only for a paid plugin.</td><td><code dir="auto">false</code></td></tr><tr><td><code dir="auto">members</code></td><td>array, optional</td><td>Response, bundles only. One entry per declared member: <code dir="auto">pluginId</code>, <code dir="auto">version</code>, and <code dir="auto">outcome</code> (<code dir="auto">installed</code> or <code dir="auto">already-installed</code>).</td><td><code dir="auto">[{"pluginId":"com.velora.forms","version":"0.1.0","outcome":"installed"}]</code></td></tr></tbody></table>
422
+ <p>Every refusal is a status code with a plain message, and nothing is left
423
+ half-installed behind any of them:</p>
424
+
425
+
426
+
427
+
428
+
429
+
430
+
431
+
432
+
433
+
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+
442
+
443
+
444
+
445
+
446
+
447
+
448
+
449
+
450
+
451
+
452
+
453
+
454
+
455
+
456
+
457
+
458
+
459
+
460
+
461
+
462
+
463
+
464
+
465
+
466
+
467
+
468
+
469
+
470
+
471
+
472
+
473
+
474
+
475
+
476
+
477
+
478
+
479
+
480
+
481
+
482
+
483
+
484
+
485
+
486
+
487
+
488
+
489
+
490
+
491
+
492
+
493
+
494
+
495
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">already-installed</code></td><td>409</td><td>This <code dir="auto">pluginId</code> already has a registry row. There is no in-place upgrade route — uninstall first.</td><td><code dir="auto">Plugin "…" is already installed</code></td></tr><tr><td><code dir="auto">not-found</code></td><td>404</td><td>No such listing, no such published version, or the artifact route is missing upstream.</td><td><code dir="auto">No published version "0.2.0" for plugin "…"</code></td></tr><tr><td><code dir="auto">license-required</code></td><td>400</td><td>A paid plugin was requested with no <code dir="auto">licenseKey</code>.</td><td>—</td></tr><tr><td><code dir="auto">site-domain-missing</code></td><td>409</td><td>A paid install with no <code dir="auto">VELORA_SITE_DOMAIN</code> set. The license binds to that domain once, so installing without it would burn the binding.</td><td>—</td></tr><tr><td><code dir="auto">license-rejected</code></td><td>403</td><td>The marketplace rejected the key for this plugin and domain.</td><td>—</td></tr><tr><td><code dir="auto">verification-failed</code></td><td>422</td><td>The package is not signed by a trusted key, the signature does not check out, or the downloaded package identifies itself as a different plugin or version than the one requested. Nothing was installed.</td><td><code dir="auto">Signature verification failed for "…"@0.1.0 (untrusted-key) — nothing was installed</code></td></tr><tr><td><code dir="auto">incompatible</code></td><td>422</td><td>The version does not support this instance’s dialect.</td><td>—</td></tr><tr><td><code dir="auto">dependency-missing</code></td><td>409</td><td>The manifest requires another plugin that is not installed and active.</td><td>—</td></tr><tr><td><code dir="auto">install-refused</code></td><td>422</td><td>Manifest validation, a migration, or another install-time refusal.</td><td>—</td></tr><tr><td><code dir="auto">bundle-member-failed</code></td><td>422</td><td>A declared member failed; every member this operation had already installed was rolled back.</td><td>—</td></tr></tbody></table>
496
+ <p>A paid install also stores a license row, which is re-checked in the
497
+ background and on demand:</p>
498
+
499
+
500
+
501
+
502
+
503
+
504
+
505
+
506
+
507
+
508
+
509
+
510
+
511
+
512
+
513
+
514
+
515
+
516
+
517
+
518
+
519
+
520
+
521
+
522
+
523
+
524
+
525
+
526
+
527
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">VELORA_SITE_DOMAIN</code></td><td>string (host)</td><td>The domain this instance declares as its own — never the request’s <code dir="auto">Host</code> header. A license binds to it on first validation. Scheme and trailing slash are trimmed.</td><td><code dir="auto">www.example.com</code></td></tr><tr><td><code dir="auto">VELORA_LICENSE_CHECK_INTERVAL_HOURS</code></td><td>integer > 0</td><td>How often licenses are re-validated in the background. Default <code dir="auto">24</code>.</td><td><code dir="auto">24</code></td></tr><tr><td><code dir="auto">VELORA_LICENSE_STALE_WARN_DAYS</code></td><td>integer > 0</td><td>After how many days without a successful check the admin shows a staleness warning. Default <code dir="auto">7</code>.</td><td><code dir="auto">7</code></td></tr></tbody></table>
528
+ <p>License checks fail <strong>open</strong>: an unreachable license server or a domain
529
+ mismatch warns but never disables a plugin. Only an upstream <code dir="auto">revoked</code>
530
+ verdict blocks — including when you try to re-enable a revoked plugin,
531
+ which answers <code dir="auto">403</code>.</p>
532
+ <div class="sl-heading-wrapper level-h2"><h2 id="the-trust-gate-exactly">The trust gate, exactly</h2><a class="sl-anchor-link" href="#the-trust-gate-exactly"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “The trust gate, exactly”</span></a></div>
533
+ <p>Verification produces one of three verdicts, and only the first earns the
534
+ <code dir="auto">verified</code> tier:</p>
535
+
536
+
537
+
538
+
539
+
540
+
541
+
542
+
543
+
544
+
545
+
546
+
547
+
548
+
549
+
550
+
551
+
552
+
553
+
554
+
555
+
556
+
557
+
558
+
559
+
560
+
561
+
562
+
563
+
564
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">verified</code></td><td>verdict</td><td>A detached <code dir="auto">&#x3C;artifact>.tar.gz.sig</code> signature over the package’s hash, made by a key in the trusted set, whose envelope names the same plugin id and version as the package’s own <code dir="auto">manifest.json</code>.</td><td>Any package from the hosted marketplace</td></tr><tr><td><code dir="auto">unsigned</code></td><td>verdict</td><td>No sidecar at all. Deliberately silent — locally built and private agency plugins are unsigned by design and must not nag.</td><td>A package you just built yourself</td></tr><tr><td><code dir="auto">failed</code></td><td>verdict</td><td>A sidecar exists but does not check out: unreadable or oversized (the ceiling is 8192 bytes), an untrusted key, a bad signature, or an identity mismatch. Logged loudly, with the reason.</td><td>A tampered or mis-signed artifact</td></tr></tbody></table>
565
+ <p>Where those verdicts land differs by install path, and this is the part
566
+ worth internalising:</p>
567
+
568
+
569
+
570
+
571
+
572
+
573
+
574
+
575
+
576
+
577
+
578
+
579
+
580
+
581
+
582
+
583
+
584
+
585
+
586
+
587
+
588
+
589
+
590
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td>Marketplace install</td><td>path</td><td><strong>Blocks</strong> on anything but <code dir="auto">verified</code>, before the package’s code is imported. <code dir="auto">unsigned</code> is refused here too — a marketplace artifact is expected to be signed.</td><td><code dir="auto">POST /api/plugin-management/marketplace/install</code></td></tr><tr><td>Sideload</td><td>path</td><td><strong>Never blocks</strong> on a verdict. <code dir="auto">unsigned</code> installs quietly as <code dir="auto">unverified</code>; <code dir="auto">failed</code> installs as <code dir="auto">unverified</code> with a loud log naming the reason. The only thing that fails a sideload outright is a package that cannot be extracted or has no <code dir="auto">manifest.json</code> — at that point it is not a plugin package at all.</td><td><code dir="auto">install-built-package</code></td></tr></tbody></table>
591
+ <p>A stock instance ships trusting the production marketplace’s signing key
592
+ and nothing else — the set holds exactly one entry, <code dir="auto">73e409f633dbbea3</code>. The
593
+ pre-rotation key it used to sit beside was retired once every listed
594
+ marketplace version had been re-signed with the active one, so nothing that
595
+ the marketplace lists needs it any more. That means a real marketplace
596
+ plugin verifies with zero configuration, and everything else installs, if at
597
+ all, as <code dir="auto">unverified</code>.</p>
598
+ <p>Operators can extend or override that set:</p>
599
+
600
+
601
+
602
+
603
+
604
+
605
+
606
+
607
+
608
+
609
+
610
+
611
+
612
+
613
+
614
+
615
+
616
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">VELORA_TRUSTED_SIGNING_KEYS</code></td><td>JSON string</td><td><code dir="auto">{"keys":[{"keyId":"…","publicKey":"…"}]}</code> — merged over the shipped set, later entries winning on a <code dir="auto">keyId</code> collision, so a shipped key can be overridden. Every entry’s <code dir="auto">keyId</code> is re-derived from its <code dir="auto">publicKey</code> and dropped with a warning if they disagree; invalid JSON is warned about and ignored rather than stopping the server.</td><td><code dir="auto">{"keys":[{"keyId":"a1b2…","publicKey":"MCowBQ…"}]}</code></td></tr></tbody></table>
617
+ <p>One thing signing does <em>not</em> mean: it is not a sandbox. A signature attests
618
+ to <strong>who built the package</strong>, not to what its code does once installed. The
619
+ permission model, the no-raw-SQL rule, the storage APIs and the error
620
+ boundary every plugin view renders inside are identical for verified and
621
+ unverified plugins. Read the badge as provenance.</p>
622
+ <p>One honest limit while you weigh that: a plugin may declare API routes that
623
+ opt into API-key authentication, and in this release such a route accepts
624
+ any valid, unrevoked key regardless of its scope — the <code dir="auto">read</code>/<code dir="auto">write</code> scope
625
+ described in <a href="/docs/v1/using-velora/users-and-roles/#create-a-key">Users and
626
+ roles</a> governs Velora’s own
627
+ content writes, not a plugin’s routes. Judge a plugin that declares
628
+ key-authenticated routes on what those routes do, not on the scope of the
629
+ key you hand out.</p>
630
+ <div class="sl-heading-wrapper level-h2"><h2 id="sideloading-a-built-package">Sideloading a built package</h2><a class="sl-anchor-link" href="#sideloading-a-built-package"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Sideloading a built package”</span></a></div>
631
+ <p>Sideloading is a supported path, not a loophole — it is how local
632
+ development, private client work, and any plugin you never intend to list
633
+ get installed. From a source checkout, the server exposes it as a script
634
+ that takes a package directory or a built <code dir="auto">.tar.gz</code>:</p>
635
+ <div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">pnpm</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">--filter</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">@velora-cms/server</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">exec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">tsx</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src/plugins/install-built-package.ts</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#ECC48D;--1:#3B61B0">./my-plugin/velora-package</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#ECC48D;--1:#3B61B0">http://localhost:5173/my-plugin/remoteEntry.js</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="pnpm --filter @velora-cms/server exec tsx src/plugins/install-built-package.ts \ ./my-plugin/velora-package \ http://localhost:5173/my-plugin/remoteEntry.js"><div></div></button></div></figure></div>
636
+ <p>It prints the outcome — <code dir="auto">installed</code> for a new plugin, <code dir="auto">activated</code> or
637
+ <code dir="auto">already-active</code> when a registry row already existed:</p>
638
+ <div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="plaintext"><code><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">[install-built-package] installed</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="[install-built-package] installed"><div></div></button></div></figure></div>
639
+
640
+
641
+
642
+
643
+
644
+
645
+
646
+
647
+
648
+
649
+
650
+
651
+
652
+
653
+
654
+
655
+
656
+
657
+
658
+
659
+
660
+
661
+
662
+
663
+
664
+
665
+
666
+
667
+
668
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">packageDir | package.tar.gz</code></td><td>path, required</td><td>First argument. A <code dir="auto">velora-plugin build</code> output directory, or a packed archive. A <code dir="auto">.tar.gz</code> takes the verifying path and reports its verdict; a directory does not.</td><td><code dir="auto">./my-plugin/velora-package</code></td></tr><tr><td><code dir="auto">remoteUrl</code></td><td>string (URL), required</td><td>Second argument. Where the admin loads the plugin’s <code dir="auto">remoteEntry.js</code> from. Pass <code dir="auto">""</code> <strong>only</strong> for a view-less type (<code dir="auto">theme</code>, <code dir="auto">template</code>, <code dir="auto">bundle</code>); a view-bearing plugin installed with an empty value would register but silently never load its views, so the install refuses it.</td><td><code dir="auto">http://localhost:5173/my-plugin/remoteEntry.js</code></td></tr><tr><td><code dir="auto">sidecarPath</code></td><td>path, optional</td><td>Third argument. An explicit signature file. Omitted, a <code dir="auto">.tar.gz</code> install looks for <code dir="auto">&#x3C;artifact>.tar.gz.sig</code> beside the archive.</td><td><code dir="auto">./my-plugin.tar.gz.sig</code></td></tr></tbody></table>
669
+ <p>Installing a <code dir="auto">.tar.gz</code> prints the verification verdict alongside the
670
+ outcome — <code dir="auto">installed (unsigned)</code> for an unsigned archive, <code dir="auto">installed (verified)</code> when a trusted signature checks out. Either way it installs;
671
+ the tier is what changes.</p>
672
+ <div class="sl-heading-wrapper level-h2"><h2 id="managing-what-is-installed">Managing what is installed</h2><a class="sl-anchor-link" href="#managing-what-is-installed"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Managing what is installed”</span></a></div>
673
+ <p>The <strong>Installed</strong> view lists every plugin, disabled ones included, with
674
+ columns for name, version, trust, storage, license and actions:</p>
675
+ <div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="sh"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">curl</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">-s</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">http://localhost:3000/api/plugin-management/plugins?limit=2</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">-H</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Authorization: Bearer </span><span style="--0:#C5E478;--1:#3B61B0">$TOKEN</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="curl -s &#x22;http://localhost:3000/api/plugin-management/plugins?limit=2&#x22; \ -H &#x22;Authorization: Bearer $TOKEN&#x22;"><div></div></button></div></figure></div>
676
+ <p>Each row carries everything the list renders, so no cell needs a second
677
+ request:</p>
678
+ <div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"items"</span><span style="--0:#D6DEEB;--1:#403F53">: [</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"pluginId"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">com.velora.forms</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"name"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Forms</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"type"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">section</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"version"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">0.1.0</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"trustTier"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">verified</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"storageType"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">structured</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"enabled"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">true</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"licenseStatus"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"licenseReason"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"licenseLastValidatedAt"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"licenseLastAttemptError"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"boundDomain"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">],</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"nextCursor"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span></div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{ &#x22;items&#x22;: [ { &#x22;pluginId&#x22;: &#x22;com.velora.forms&#x22;, &#x22;name&#x22;: &#x22;Forms&#x22;, &#x22;type&#x22;: &#x22;section&#x22;, &#x22;version&#x22;: &#x22;0.1.0&#x22;, &#x22;trustTier&#x22;: &#x22;verified&#x22;, &#x22;storageType&#x22;: &#x22;structured&#x22;, &#x22;enabled&#x22;: true, &#x22;licenseStatus&#x22;: null, &#x22;licenseReason&#x22;: null, &#x22;licenseLastValidatedAt&#x22;: null, &#x22;licenseLastAttemptError&#x22;: null, &#x22;boundDomain&#x22;: null } ], &#x22;nextCursor&#x22;: null}"><div></div></button></div></figure></div>
679
+
680
+
681
+
682
+
683
+
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+
692
+
693
+
694
+
695
+
696
+
697
+
698
+
699
+
700
+
701
+
702
+
703
+
704
+
705
+
706
+
707
+
708
+
709
+
710
+
711
+
712
+
713
+
714
+
715
+
716
+
717
+
718
+
719
+
720
+
721
+
722
+
723
+
724
+
725
+
726
+
727
+
728
+
729
+
730
+
731
+
732
+
733
+
734
+
735
+
736
+
737
+
738
+
739
+
740
+
741
+
742
+
743
+
744
+
745
+
746
+
747
+
748
+
749
+
750
+
751
+
752
+
753
+
754
+
755
+
756
+
757
+
758
+
759
+
760
+
761
+
762
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">pluginId</code></td><td>string</td><td>Reverse-domain id, as installed.</td><td><code dir="auto">com.velora.forms</code></td></tr><tr><td><code dir="auto">name</code></td><td>string</td><td>Display name from the manifest.</td><td><code dir="auto">Forms</code></td></tr><tr><td><code dir="auto">type</code></td><td>string</td><td>The plugin type, which decides what it may contribute.</td><td><code dir="auto">section</code></td></tr><tr><td><code dir="auto">version</code></td><td>string</td><td>The installed version.</td><td><code dir="auto">0.1.0</code></td></tr><tr><td><code dir="auto">trustTier</code></td><td><code dir="auto">"verified"</code> or <code dir="auto">"unverified"</code></td><td>Rendered as the <strong>Verified</strong> / <strong>Unverified</strong> badge. Fixed at install time.</td><td><code dir="auto">verified</code></td></tr><tr><td><code dir="auto">storageType</code></td><td><code dir="auto">"simple"</code> or <code dir="auto">"structured"</code></td><td>Whether the plugin stores JSON through the simple API or owns real tables. Structured plugins get data snapshots.</td><td><code dir="auto">structured</code></td></tr><tr><td><code dir="auto">enabled</code></td><td>boolean</td><td>The row’s toggle. A disabled plugin stays installed and keeps its data.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">licenseStatus</code></td><td>string or <code dir="auto">null</code></td><td><code dir="auto">valid</code>, <code dir="auto">revoked</code>, <code dir="auto">domain_mismatch</code>, <code dir="auto">unknown</code> — or <code dir="auto">null</code> for a free plugin with no license row at all.</td><td><code dir="auto">null</code></td></tr><tr><td><code dir="auto">licenseReason</code></td><td>string or <code dir="auto">null</code></td><td>The server’s explanation for a non-valid verdict.</td><td><code dir="auto">null</code></td></tr><tr><td><code dir="auto">licenseLastValidatedAt</code></td><td>ISO datetime string or <code dir="auto">null</code></td><td>The last <strong>successful</strong> check, used to compute staleness.</td><td><code dir="auto">null</code></td></tr><tr><td><code dir="auto">licenseLastAttemptError</code></td><td>string or <code dir="auto">null</code></td><td>Why the most recent attempt failed to reach a verdict; <code dir="auto">null</code> when it did not.</td><td><code dir="auto">null</code></td></tr><tr><td><code dir="auto">boundDomain</code></td><td>string or <code dir="auto">null</code></td><td>The domain the license bound to at install, so a mismatch warning can name it.</td><td><code dir="auto">null</code></td></tr></tbody></table>
763
+ <p>The license key itself is never in this response, or in any other.</p>
764
+ <p><strong>Turning a plugin off</strong> is <code dir="auto">POST /api/plugin-management/plugins/:pluginId/deactivate</code>,
765
+ and on again is <code dir="auto">.../activate</code>; a normal toggle answers <code dir="auto">204</code> either way.
766
+ Activation re-checks a license first and refuses with <code dir="auto">403</code> only on a
767
+ <code dir="auto">revoked</code> verdict, and — separately — answers <code dir="auto">409</code> if the plugin’s code
768
+ was never loaded (installed but not attached to a running server, so there
769
+ is nothing to activate). Deactivating a bundle cascades to its members in
770
+ reverse install order.</p>
771
+ <p><strong>Uninstalling</strong> is <code dir="auto">DELETE /api/plugin-management/plugins/:pluginId</code>, and it
772
+ is deliberately obstructive:</p>
773
+
774
+
775
+
776
+
777
+
778
+
779
+
780
+
781
+
782
+
783
+
784
+
785
+
786
+
787
+
788
+
789
+
790
+
791
+
792
+
793
+
794
+
795
+
796
+
797
+
798
+
799
+
800
+
801
+
802
+ <table><thead><tr><th>Name</th><th>Type</th><th>Meaning</th><th>Example</th></tr></thead><tbody><tr><td><code dir="auto">confirmStructuredDataCleanup</code></td><td>boolean, optional</td><td>Request body. A structured-storage plugin’s first <code dir="auto">DELETE</code> answers <code dir="auto">409</code> with <code dir="auto">requiresConfirmation: true</code> and a <code dir="auto">snapshotGroupId</code> — the snapshot has <strong>already been taken</strong>, so retrying with this flag is always safe.</td><td><code dir="auto">true</code></td></tr><tr><td><code dir="auto">snapshotGroupId</code></td><td>string or <code dir="auto">null</code></td><td>Response. The snapshot group created by the confirmed pass, or <code dir="auto">null</code> for a simple-storage plugin that never needed one.</td><td><code dir="auto">4f81b6c2-…</code></td></tr><tr><td><code dir="auto">blockedBy</code></td><td>array</td><td>Response, <code dir="auto">409</code>. Document types the plugin provisioned that still hold content or are referenced by templates, each with a <code dir="auto">contentCount</code> where one is known. This is a terminal refusal, not a confirmation — delete the content first.</td><td><code dir="auto">[{"documentType":"Form","contentCount":3}]</code></td></tr></tbody></table>
803
+ <p>A structured plugin’s snapshots outlive it: uninstalling deletes the
804
+ registry row but never the snapshot rows, so <strong>Data snapshots</strong> can still
805
+ restore the plugin’s tables after a reinstall.</p>
806
+ <p><strong>Updating</strong> a plugin today means uninstalling the old version and
807
+ installing the new one — install refuses a <code dir="auto">pluginId</code> that already has a
808
+ registry row, and there is no in-place upgrade route. For a structured
809
+ plugin, take the snapshot path seriously: the uninstall snapshot is what
810
+ you restore from afterwards.</p>
811
+ <div class="sl-heading-wrapper level-h2"><h2 id="marketplace-terms-briefly">Marketplace terms, briefly</h2><a class="sl-anchor-link" href="#marketplace-terms-briefly"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Marketplace terms, briefly”</span></a></div>
812
+ <p>For the person choosing a plugin: <strong>free listings cost nothing, forever</strong>,
813
+ and paid plugins are sold as a <strong>one-time, per-site license</strong> — a key that
814
+ binds to your site’s domain, which is why <code dir="auto">VELORA_SITE_DOMAIN</code> has to be set
815
+ before a paid install. Marketplace distribution requires submission review
816
+ and signing, which is what the <strong>Verified</strong> tier means; review is measured in
817
+ days, not weeks. Publishers keep 75% of a paid sale. Malicious or broken
818
+ listings are delisted and their keys revoked, and a refund revokes the
819
+ license. Sideloading stays allowed and free — your instance, your risk.</p>
820
+ <div class="sl-heading-wrapper level-h2"><h2 id="writing-your-own">Writing your own</h2><a class="sl-anchor-link" href="#writing-your-own"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Writing your own”</span></a></div>
821
+ <p>Building a plugin is a different job from installing one, with its own
822
+ toolchain (<code dir="auto">create-velora-plugin</code>, <code dir="auto">velora-plugin</code>, <code dir="auto">velora-dev</code>), the SDK’s
823
+ manifest and storage contracts, and the publish-and-review flow that ends in
824
+ a signed, verified listing. All of it lives in the plugin author
825
+ documentation at
826
+ <a href="https://docs.velora-cms.com/v1/building-plugins/">docs.velora-cms.com/v1/building-plugins</a>,
827
+ which is hosted rather than bundled with your site.</p>
828
+ <div class="sl-heading-wrapper level-h2"><h2 id="next">Next</h2><a class="sl-anchor-link" href="#next"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Next”</span></a></div>
829
+ <ul>
830
+ <li><a href="/docs/v1/using-velora/users-and-roles/">Users and roles</a> — why every route on
831
+ this page needs the admin role.</li>
832
+ <li><a href="/docs/v1/using-velora/content-model/">Document types</a> — the document types a
833
+ template or section plugin provisions when it installs.</li>
834
+ <li><a href="/docs/v1/using-velora/headless-api/">Headless API</a> — reading content a plugin
835
+ contributed to, from your own frontend.</li>
836
+ </ul></div><footer class="sl-flex astro-gjkl2a5w"><div class="meta sl-flex astro-gjkl2a5w"></div><div class="pagination-links print:hidden astro-3tj6ibx2" dir="ltr"><a href="/docs/v1/using-velora/users-and-roles/" rel="prev" class="astro-3tj6ibx2"><svg aria-hidden="true" class="astro-3tj6ibx2 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17 11H9.41l3.3-3.29a1.004 1.004 0 1 0-1.42-1.42l-5 5a1 1 0 0 0-.21.33 1 1 0 0 0 0 .76 1 1 0 0 0 .21.33l5 5a1.002 1.002 0 0 0 1.639-.325 1 1 0 0 0-.219-1.095L9.41 13H17a1 1 0 0 0 0-2Z"/></svg><span class="astro-3tj6ibx2">Previous<br class="astro-3tj6ibx2"><span class="link-title astro-3tj6ibx2">Users and roles</span></span></a><a href="/docs/v1/using-velora/headless-api/" rel="next" class="astro-3tj6ibx2"><svg aria-hidden="true" class="astro-3tj6ibx2 astro-24n5ceuf" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg><span class="astro-3tj6ibx2">Next<br class="astro-3tj6ibx2"><span class="link-title astro-3tj6ibx2">Headless API</span></span></a></div></footer><div class="velora-bundle-stamp astro-llmj63sw">Velora 0.9.0 &middot; bundled documentation</div></div></div></main></div></div></div></div></body></html>