@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,198 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { z } from "zod";
4
+ import { ContentService } from "@velora-cms/content-service";
5
+ // Session 149, Task 2 — D1: sample content is a PACKAGE DATA FILE
6
+ // (sample-content.json, next to manifest.json at the artifact root —
7
+ // packages/velora-plugin/src/copy-sample-content.ts puts it there at
8
+ // build time), read from the STORED package dir (plain readFileSync —
9
+ // the file is never tar-extracted separately) and seeded HOST-SIDE,
10
+ // AFTER PluginRegistryService.install() has already returned. The S88
11
+ // documentTypes install path (plugin-registry-service.ts) stays
12
+ // untouched by this module — it is invoked by the two install
13
+ // orchestrators (install-built-package.ts, install-from-marketplace.ts)
14
+ // instead, never from inside install() itself.
15
+ // Deliberately local to this module, not packages/api-schemas — this is
16
+ // PACKAGE DATA (an artifact-internal file format), not an API surface.
17
+ const SampleContentNodeSchema = z
18
+ .object({
19
+ documentType: z.string().min(1),
20
+ slug: z.string().min(1),
21
+ parent: z.string().nullable(),
22
+ data: z.record(z.string(), z.unknown()),
23
+ })
24
+ .strict();
25
+ const SampleContentFileSchema = z
26
+ .object({
27
+ nodes: z.array(SampleContentNodeSchema),
28
+ })
29
+ .strict();
30
+ /**
31
+ * Seeds a template plugin's sample-content.json as real, published
32
+ * content — creation order in the file IS the seed order (parents
33
+ * precede children per D1's documented contract), and every node is
34
+ * created THEN published, so it lands as version 1, currently published,
35
+ * matching the immutable-versioning path exactly the way a human editor
36
+ * publishing through the admin UI would produce.
37
+ *
38
+ * D2 governs every early return here: idempotent-by-skip (no duplicates
39
+ * on a second install/second call) and non-fatal (a seeding problem never
40
+ * unwinds an otherwise-successful plugin install — the caller's install
41
+ * stands regardless of what this function returns).
42
+ */
43
+ export async function seedTemplateSampleContent(deps, pluginId, storedPackageDir, createdBy) {
44
+ const filePath = join(storedPackageDir, "sample-content.json");
45
+ if (!existsSync(filePath)) {
46
+ return "none"; // Most plugins never ship this file — not worth a log line.
47
+ }
48
+ // Guard: only template-type manifests get seeded, even if a
49
+ // sample-content.json somehow sits next to a differently-typed
50
+ // package's manifest.json. Missing row is defensive only — the caller
51
+ // always invokes this after a successful install, so the row exists in
52
+ // practice.
53
+ const registryRow = await deps.prisma.pluginRegistry.findUnique({ where: { pluginId } });
54
+ if (!registryRow || registryRow.type !== "template") {
55
+ return "none";
56
+ }
57
+ let sampleContent;
58
+ try {
59
+ const raw = JSON.parse(readFileSync(filePath, "utf8"));
60
+ const result = SampleContentFileSchema.safeParse(raw);
61
+ if (!result.success) {
62
+ console.error(`[seed-template-content] "${pluginId}"'s sample-content.json failed validation: ${result.error.message}`);
63
+ return "invalid";
64
+ }
65
+ sampleContent = result.data;
66
+ }
67
+ catch (error) {
68
+ console.error(`[seed-template-content] "${pluginId}"'s sample-content.json is not valid JSON:`, error);
69
+ return "invalid";
70
+ }
71
+ // Name -> minted id, via THIS plugin's own tracked document types —
72
+ // never a bare name lookup across every document type in the system,
73
+ // which could silently match an unrelated plugin's same-named type.
74
+ const tracked = await deps.prisma.pluginDocumentType.findMany({ where: { pluginId } });
75
+ const idByTypeName = new Map();
76
+ for (const row of tracked) {
77
+ const documentType = await deps.adapter.getDocumentType(row.documentTypeId);
78
+ if (documentType) {
79
+ idByTypeName.set(documentType.name, documentType.id);
80
+ }
81
+ }
82
+ const unknownTypeNames = [...new Set(sampleContent.nodes.map((node) => node.documentType))].filter((name) => !idByTypeName.has(name));
83
+ if (unknownTypeNames.length > 0) {
84
+ console.error(`[seed-template-content] "${pluginId}"'s sample-content.json references document type name(s) not declared ` +
85
+ `by this plugin: ${unknownTypeNames.join(", ")}`);
86
+ return "invalid";
87
+ }
88
+ // Structural validation, BEFORE any create: creation order in the file
89
+ // IS the seed order (D1), so a node's parent slug must already have been
90
+ // seen — i.e. declared strictly earlier in the array. Without this check,
91
+ // the create loop below resolves an unresolved parent slug via
92
+ // `nodeIdBySlug.get(parent) ?? null`, which silently roots the node
93
+ // instead of failing (catching an unknown parent only by luck, if that
94
+ // document type happens to reject root placement) — and a duplicate slug
95
+ // silently mis-parents later nodes, since every lookup map below is
96
+ // slug-keyed globally. Both are caught here, in one pass, before the
97
+ // loop that actually creates anything runs.
98
+ const seenSlugs = new Set();
99
+ for (const node of sampleContent.nodes) {
100
+ if (seenSlugs.has(node.slug)) {
101
+ console.error(`[seed-template-content] "${pluginId}"'s sample-content.json declares slug "${node.slug}" more than once`);
102
+ return "invalid";
103
+ }
104
+ if (node.parent !== null && !seenSlugs.has(node.parent)) {
105
+ console.error(`[seed-template-content] "${pluginId}"'s sample-content.json node "${node.slug}" declares parent "${node.parent}", ` +
106
+ `which does not name a slug declared earlier in the file`);
107
+ return "invalid";
108
+ }
109
+ seenSlugs.add(node.slug);
110
+ }
111
+ // Skip-if-exists: any ROOT node already at its declared path means a
112
+ // previous install/seed run already created this tree — re-seeding
113
+ // would create duplicates, so the whole step is skipped, not merged or
114
+ // partially retried.
115
+ for (const node of sampleContent.nodes) {
116
+ if (node.parent === null) {
117
+ const path = `/${node.slug}`;
118
+ if (await deps.adapter.getContentNodeByPath(path)) {
119
+ console.log(`[seed-template-content] "${pluginId}" sample content already exists at "${path}" — skipping`);
120
+ return "skipped";
121
+ }
122
+ }
123
+ }
124
+ // D2: the requesting admin's id where the caller has one; otherwise the
125
+ // first admin user (the seed-sandbox precedent — a REAL uuid; a
126
+ // placeholder string writes fine here but 500s every later GET of this
127
+ // content, per the S102-era gotcha). No admin at all -> skip, warn, and
128
+ // change nothing, exactly like the already-exists case above — there is
129
+ // no "system" user to attribute sample content to.
130
+ let resolvedCreatedBy = createdBy;
131
+ if (!resolvedCreatedBy) {
132
+ const firstAdmin = await deps.prisma.user.findFirst({
133
+ where: { role: "admin" },
134
+ orderBy: { createdAt: "asc" },
135
+ });
136
+ if (!firstAdmin) {
137
+ console.warn(`[seed-template-content] "${pluginId}" — no admin user exists to attribute sample content to; skipping seeding`);
138
+ return "skipped";
139
+ }
140
+ resolvedCreatedBy = firstAdmin.id;
141
+ }
142
+ // Deliberately un-wired: this ContentService is `new`-ed straight from
143
+ // the adapter, not read off app.ts's contentDb — so it never gets
144
+ // setOnContentEvent(createHookDispatcher(...)) called on it (S159). No
145
+ // content:afterPublish hook fires for the publishContent() calls below;
146
+ // template seeding is a one-shot data burst, not an editorial action a
147
+ // plugin should react to. Every path that reaches this function
148
+ // (install-from-marketplace.ts directly, install-built-package.ts —
149
+ // which the wizard's starter step also goes through) constructs its
150
+ // own instance the same un-wired way, so none of them fire hooks during
151
+ // seeding either. Contrast: a later EDITORIAL publish — a human
152
+ // republishing one of these seeded nodes through /api/content — goes
153
+ // through the app's own wired contentDb.contentService and DOES fire
154
+ // hooks.
155
+ const contentService = new ContentService(deps.adapter);
156
+ const nodeIdBySlug = new Map();
157
+ const pathBySlug = new Map();
158
+ const depthBySlug = new Map();
159
+ const nextSortOrderByParentSlug = new Map();
160
+ let created = 0;
161
+ try {
162
+ for (const node of sampleContent.nodes) {
163
+ const documentTypeId = idByTypeName.get(node.documentType);
164
+ const parentId = node.parent === null ? null : (nodeIdBySlug.get(node.parent) ?? null);
165
+ const parentPath = node.parent === null ? undefined : pathBySlug.get(node.parent);
166
+ const path = parentPath ? `${parentPath}/${node.slug}` : `/${node.slug}`;
167
+ const depth = node.parent === null ? 0 : (depthBySlug.get(node.parent) ?? 0) + 1;
168
+ const sortOrder = nextSortOrderByParentSlug.get(node.parent) ?? 0;
169
+ nextSortOrderByParentSlug.set(node.parent, sortOrder + 1);
170
+ const { node: createdNode } = await contentService.createContent({
171
+ documentTypeId,
172
+ parentId,
173
+ path,
174
+ depth,
175
+ sortOrder,
176
+ locale: "en",
177
+ isDefaultLocale: true,
178
+ data: node.data,
179
+ createdBy: resolvedCreatedBy,
180
+ });
181
+ await contentService.publishContent(createdNode.id);
182
+ nodeIdBySlug.set(node.slug, createdNode.id);
183
+ pathBySlug.set(node.slug, path);
184
+ depthBySlug.set(node.slug, depth);
185
+ created++;
186
+ }
187
+ }
188
+ catch (error) {
189
+ // D2: non-fatal — the install already stands by the time this runs,
190
+ // and the never-lose-data ethos cuts the other way here: don't tear
191
+ // down a healthy install over sample data. Whatever nodes were
192
+ // created before the failure are left in place (createContent +
193
+ // publishContent are each already immutable/atomic per node).
194
+ console.error(`[seed-template-content] seeding sample content for "${pluginId}" failed after creating ${created} node(s):`, error);
195
+ return "invalid";
196
+ }
197
+ return { created };
198
+ }
@@ -0,0 +1,3 @@
1
+ import { type DataTypeSerializer } from "@velora-cms/plugin-sdk/datatypes";
2
+ export declare function getServerSerializer(editorId: string): DataTypeSerializer | null;
3
+ export declare function registerServerSerializer(editorId: string, serializer: DataTypeSerializer): void;
@@ -0,0 +1,16 @@
1
+ // The server process's one datatype-serializer lookup (Session 111).
2
+ // Seeded with the built-ins from the React-free datatypes subpath; a
3
+ // remote/third-party plugin's serializer is unreachable server-side
4
+ // (Module Federation remotes only load in the browser — Session 69's
5
+ // scoping), so lookups for unknown editor ids return null and the
6
+ // pipeline passes the stored value through. registerServerSerializer
7
+ // exists for server-side registration (integration tests today; Session
8
+ // 112's serializer contributions are its intended real consumer).
9
+ import { BUILT_IN_SERIALIZERS } from "@velora-cms/plugin-sdk/datatypes";
10
+ const registry = new Map(Object.entries(BUILT_IN_SERIALIZERS));
11
+ export function getServerSerializer(editorId) {
12
+ return registry.get(editorId) ?? null;
13
+ }
14
+ export function registerServerSerializer(editorId, serializer) {
15
+ registry.set(editorId, serializer);
16
+ }
@@ -0,0 +1,9 @@
1
+ import type { DatabaseAdapter } from "@velora-cms/db-adapter";
2
+ import type { PluginRegistryService } from "./plugin-registry-service.js";
3
+ export declare class SimpleStorageAPI {
4
+ private readonly adapter;
5
+ private readonly registry;
6
+ constructor(adapter: DatabaseAdapter, registry: PluginRegistryService);
7
+ get(contentId: string, fieldId: string, pluginId: string): Promise<unknown>;
8
+ set(contentId: string, fieldId: string, pluginId: string, value: unknown): Promise<void>;
9
+ }
@@ -0,0 +1,26 @@
1
+ // SimpleStorageAPI: the JSON key-value storage tier plugins default to
2
+ // (get/set by contentId+fieldId), as opposed to the opt-in, reviewed
3
+ // StructuredStorageAPI tier for relational needs.
4
+ // A thin pass-through: gate on the plugin being installed+active (the
5
+ // registry state a disabled plugin has no business touching storage
6
+ // through), then delegate to the adapter. All persistence logic lives in
7
+ // DatabaseAdapter.get/setPluginFieldValue — this class exists only to
8
+ // make the registry check impossible to forget at a call site, matching
9
+ // the "either tier goes through [this], never raw SQL" rule
10
+ // (plugin-sdk.md); business logic here never touches SQL directly.
11
+ export class SimpleStorageAPI {
12
+ adapter;
13
+ registry;
14
+ constructor(adapter, registry) {
15
+ this.adapter = adapter;
16
+ this.registry = registry;
17
+ }
18
+ async get(contentId, fieldId, pluginId) {
19
+ await this.registry.requireActivePlugin(pluginId);
20
+ return this.adapter.getPluginFieldValue(contentId, fieldId, pluginId);
21
+ }
22
+ async set(contentId, fieldId, pluginId, value) {
23
+ await this.registry.requireActivePlugin(pluginId);
24
+ await this.adapter.setPluginFieldValue(contentId, fieldId, pluginId, value);
25
+ }
26
+ }
@@ -0,0 +1,16 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ import type { SnapshotGroup } from "@velora-cms/api-schemas";
3
+ export interface SnapshotRowFacts {
4
+ snapshotGroupId: string;
5
+ tableName: string;
6
+ trigger: string | null;
7
+ createdAt: Date;
8
+ }
9
+ export declare function deriveSnapshotGroups(rows: SnapshotRowFacts[]): SnapshotGroup[];
10
+ export declare function listSnapshotGroups(prisma: PrismaClient, pluginId: string, page: {
11
+ cursor?: string;
12
+ limit: number;
13
+ }): Promise<{
14
+ items: SnapshotGroup[];
15
+ nextCursor: string | null;
16
+ }>;
@@ -0,0 +1,81 @@
1
+ // S154 Task 4: snapshot GROUPS are derived, not tracked — there is no
2
+ // SnapshotGroup table. A group is every PluginStructuredSnapshot row
3
+ // sharing one snapshotGroupId (one snapshotPluginTables() call writes one
4
+ // row per tracked table, all under the same group id and trigger).
5
+ //
6
+ // The "complete vs partial" status is the whole point of Task 4: it
7
+ // compares a group's own tableNames against the UNION of distinct
8
+ // tableNames across ALL of the plugin's snapshot rows (every group, not
9
+ // just this one) — never against the plugin's CURRENT tracked-table count.
10
+ // PluginStructuredTable (the live tracking table) gets wiped by
11
+ // dropPluginTables() at uninstall, which is exactly when a group listing
12
+ // matters most, so it can't be the denominator. The union of everything
13
+ // this plugin ever snapshotted is the only count that survives that wipe
14
+ // and stays honest across a failed-then-retried uninstall (S87's wedge):
15
+ // an earlier attempt that captured all N tables reads "complete", a later
16
+ // retry that could only re-capture the tables still physically present
17
+ // (Task 3's tolerant skip-a-missing-table behavior) reads "partial" —
18
+ // never a false "complete" claim for a group that's missing rows another
19
+ // group in the same plugin's history actually has.
20
+ export function deriveSnapshotGroups(rows) {
21
+ const totalTableCount = new Set(rows.map((row) => row.tableName)).size;
22
+ const rowsByGroup = new Map();
23
+ for (const row of rows) {
24
+ const bucket = rowsByGroup.get(row.snapshotGroupId);
25
+ if (bucket) {
26
+ bucket.push(row);
27
+ }
28
+ else {
29
+ rowsByGroup.set(row.snapshotGroupId, [row]);
30
+ }
31
+ }
32
+ const groups = [];
33
+ for (const [snapshotGroupId, groupRows] of rowsByGroup) {
34
+ const tableNames = [...new Set(groupRows.map((row) => row.tableName))].sort();
35
+ const takenAtMs = Math.min(...groupRows.map((row) => row.createdAt.getTime()));
36
+ groups.push({
37
+ snapshotGroupId,
38
+ takenAt: new Date(takenAtMs).toISOString(),
39
+ // Every row written by one snapshotPluginTables() call carries the
40
+ // same trigger — reading it off the first row in the bucket is safe,
41
+ // not an arbitrary pick among differing values.
42
+ trigger: groupRows[0].trigger,
43
+ tableNames,
44
+ totalTableCount,
45
+ status: tableNames.length === totalTableCount ? "complete" : "partial",
46
+ });
47
+ }
48
+ // Newest first.
49
+ groups.sort((a, b) => new Date(b.takenAt).getTime() - new Date(a.takenAt).getTime());
50
+ return groups;
51
+ }
52
+ // The DB read + in-memory pagination over derived groups. Deliberately ONE
53
+ // indexed findMany (PluginStructuredSnapshot.pluginId is indexed) rather
54
+ // than a `GROUP BY snapshotGroupId` query plus a second query per page:
55
+ // the per-plugin group count is bounded by how many times an admin has
56
+ // attempted to uninstall that plugin, not by content or row volume, so
57
+ // pulling every row for one plugin and deriving+paginating groups in
58
+ // memory is honest — this can never become an unbounded scan the way
59
+ // loading a whole content subtree would be. The wire contract still
60
+ // exposes cursor+limit (not just "return everything") so the route stays
61
+ // pagination-shaped like every other list endpoint in this codebase, and
62
+ // so a future plugin with a genuinely large uninstall-retry history
63
+ // doesn't require a client-visible contract change to fix.
64
+ export async function listSnapshotGroups(prisma, pluginId, page) {
65
+ const rows = await prisma.pluginStructuredSnapshot.findMany({
66
+ where: { pluginId },
67
+ select: { snapshotGroupId: true, tableName: true, trigger: true, createdAt: true },
68
+ });
69
+ const allGroups = deriveSnapshotGroups(rows);
70
+ let startIndex = 0;
71
+ if (page.cursor) {
72
+ const cursorIndex = allGroups.findIndex((group) => group.snapshotGroupId === page.cursor);
73
+ // A cursor that doesn't match any derived group (stale link, or the
74
+ // underlying rows are gone) walks to the end rather than silently
75
+ // restarting the page from the top.
76
+ startIndex = cursorIndex === -1 ? allGroups.length : cursorIndex + 1;
77
+ }
78
+ const items = allGroups.slice(startIndex, startIndex + page.limit);
79
+ const nextCursor = startIndex + items.length < allGroups.length ? (items[items.length - 1]?.snapshotGroupId ?? null) : null;
80
+ return { items, nextCursor };
81
+ }
@@ -0,0 +1,21 @@
1
+ import type { StructuredQueryOptions } from "@velora-cms/db-adapter";
2
+ export declare class InvalidStructuredQueryError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare class StructuredQueryBuilder<T = Record<string, unknown>> implements PromiseLike<T[]> {
6
+ private readonly runQuery;
7
+ private whereConditions;
8
+ private orderBySpec?;
9
+ private limitValue?;
10
+ private paginateOptions?;
11
+ constructor(runQuery: (options: StructuredQueryOptions) => Promise<Record<string, unknown>[]>);
12
+ where(conditions: Record<string, unknown>): this;
13
+ orderBy(column: string, direction?: "asc" | "desc"): this;
14
+ limit(n: number): this;
15
+ paginate(options: {
16
+ cursor?: string;
17
+ limit: number;
18
+ }): this;
19
+ then<TResult1 = T[], TResult2 = never>(onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
20
+ private exec;
21
+ }
@@ -0,0 +1,60 @@
1
+ export class InvalidStructuredQueryError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "InvalidStructuredQueryError";
5
+ }
6
+ }
7
+ // Plugin-facing fluent query builder for StructuredStorageAPI.query().
8
+ // Deliberately dialect-unaware and DB-unaware — it just accumulates
9
+ // where/orderBy/limit/paginate state and, on await, hands a single
10
+ // StructuredQueryOptions object to whatever `runQuery` function its
11
+ // caller supplied. This is what lets the exact same builder be used
12
+ // both by the top-level StructuredStorageAPI (Task 8) and by
13
+ // StructuredStorageTransaction (Task 7) — only `runQuery`'s
14
+ // implementation differs between the two.
15
+ export class StructuredQueryBuilder {
16
+ runQuery;
17
+ whereConditions = {};
18
+ orderBySpec;
19
+ limitValue;
20
+ paginateOptions;
21
+ constructor(runQuery) {
22
+ this.runQuery = runQuery;
23
+ }
24
+ where(conditions) {
25
+ this.whereConditions = { ...this.whereConditions, ...conditions };
26
+ return this;
27
+ }
28
+ orderBy(column, direction = "asc") {
29
+ this.orderBySpec = { column, direction };
30
+ return this;
31
+ }
32
+ limit(n) {
33
+ this.limitValue = n;
34
+ return this;
35
+ }
36
+ paginate(options) {
37
+ this.paginateOptions = options;
38
+ return this;
39
+ }
40
+ then(onfulfilled, onrejected) {
41
+ return this.exec().then(onfulfilled, onrejected);
42
+ }
43
+ async exec() {
44
+ if (this.orderBySpec && this.paginateOptions) {
45
+ throw new InvalidStructuredQueryError("orderBy() and paginate() cannot be used together");
46
+ }
47
+ if (this.limitValue === undefined && this.paginateOptions === undefined) {
48
+ throw new InvalidStructuredQueryError("call limit(n) or paginate({ cursor, limit }) before awaiting a query");
49
+ }
50
+ const options = this.paginateOptions
51
+ ? {
52
+ where: this.whereConditions,
53
+ cursor: this.paginateOptions.cursor,
54
+ limit: this.paginateOptions.limit,
55
+ }
56
+ : { where: this.whereConditions, orderBy: this.orderBySpec, limit: this.limitValue };
57
+ const rows = await this.runQuery(options);
58
+ return rows;
59
+ }
60
+ }
@@ -0,0 +1,16 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ import type { DatabaseAdapter } from "@velora-cms/db-adapter";
3
+ import type { RestorePlanEntry } from "@velora-cms/api-schemas";
4
+ export declare class StructuredSnapshotService {
5
+ private readonly adapter;
6
+ private readonly prisma;
7
+ constructor(adapter: DatabaseAdapter, prisma: PrismaClient);
8
+ snapshotPluginTables(pluginId: string, trigger?: string): Promise<string>;
9
+ restoreSnapshot(snapshotGroupId: string): Promise<void>;
10
+ dropPluginTables(pluginId: string): Promise<void>;
11
+ planRestore(pluginId: string): Promise<RestorePlanEntry[]>;
12
+ restorePluginData(pluginId: string): Promise<{
13
+ preRestoreSnapshotGroupId: string | null;
14
+ restoredTables: string[];
15
+ }>;
16
+ }