@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,5 @@
1
+ import type { GraphQLError, ValidationRule } from "graphql";
2
+ export interface GraphQLErrorConstructor {
3
+ new (message: string): GraphQLError;
4
+ }
5
+ export declare function createFieldCountRule(max: number, GraphQLErrorCtor: GraphQLErrorConstructor): ValidationRule;
@@ -0,0 +1,59 @@
1
+ export function createFieldCountRule(max, GraphQLErrorCtor) {
2
+ return function FieldCountRule(context) {
3
+ return {
4
+ Document: {
5
+ leave(document) {
6
+ const fragments = new Map();
7
+ for (const definition of document.definitions) {
8
+ if (definition.kind === "FragmentDefinition") {
9
+ fragments.set(definition.name.value, definition);
10
+ }
11
+ }
12
+ let count = 0;
13
+ const activeSpreads = new Set();
14
+ function countSelectionSet(selectionSet) {
15
+ if (!selectionSet)
16
+ return;
17
+ for (const selection of selectionSet.selections) {
18
+ switch (selection.kind) {
19
+ case "Field": {
20
+ count++;
21
+ countSelectionSet(selection.selectionSet);
22
+ break;
23
+ }
24
+ case "InlineFragment": {
25
+ countSelectionSet(selection.selectionSet);
26
+ break;
27
+ }
28
+ case "FragmentSpread": {
29
+ const name = selection.name.value;
30
+ // Guard (b): cycle — stop recursing here, don't loop
31
+ // forever. NoFragmentCyclesRule reports the cycle.
32
+ if (activeSpreads.has(name))
33
+ break;
34
+ const fragment = fragments.get(name);
35
+ // Guard (a): unknown fragment — count 0.
36
+ // KnownFragmentNamesRule reports it separately.
37
+ if (!fragment)
38
+ break;
39
+ activeSpreads.add(name);
40
+ countSelectionSet(fragment.selectionSet);
41
+ activeSpreads.delete(name);
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ }
47
+ for (const definition of document.definitions) {
48
+ if (definition.kind === "OperationDefinition") {
49
+ countSelectionSet(definition.selectionSet);
50
+ }
51
+ }
52
+ if (count > max) {
53
+ context.reportError(new GraphQLErrorCtor(`Query field count of ${count} exceeds the maximum allowed complexity of ${max}`));
54
+ }
55
+ },
56
+ },
57
+ };
58
+ };
59
+ }
@@ -0,0 +1,12 @@
1
+ import type { GraphQLSchema } from "graphql";
2
+ import type { ContentService } from "@velora-cms/content-service";
3
+ import { type ContentNode } from "@velora-cms/api-schemas";
4
+ import type { MediaService } from "../media/media-service.js";
5
+ import { type PublishedItemDeps } from "../routes/published-item.js";
6
+ export interface GraphqlContext {
7
+ deps: PublishedItemDeps;
8
+ contentService: ContentService;
9
+ mediaService: MediaService;
10
+ getContentNode: (id: string) => Promise<ContentNode | null>;
11
+ }
12
+ export declare function buildGraphqlSchema(): GraphQLSchema;
@@ -0,0 +1,330 @@
1
+ import SchemaBuilder from "@pothos/core";
2
+ import { JSONResolver } from "graphql-scalars";
3
+ import { PublicContentByPathQuerySchema, PublicContentItemQuerySchema, PublicContentListQuerySchema, PublicContentSearchQuerySchema, PublicDocumentTypeListQuerySchema, PublicMediaListQuerySchema, PublicTemplateListQuerySchema, } from "@velora-cms/api-schemas";
4
+ import { verifyPreviewToken } from "../auth/preview-tokens.js";
5
+ import { computeExtensions, preparePublishedItem, resolveItemNode, resolveSubtreeFilter, toPublicDocumentType, toPublicMediaFile, toSummaries, } from "../routes/published-item.js";
6
+ // Re-parses a GraphQL args object through the exact REST querystring Zod
7
+ // schema for the sibling endpoint. `undefined` fields fall through to the
8
+ // schema's own `.default()`s (same as an omitted REST querystring key);
9
+ // an out-of-bounds/malformed value fails validation exactly like REST's
10
+ // Fastify schema compiler does — the caller gets a GraphQL error, not a
11
+ // silent clamp.
12
+ function parseArgs(schema, value, label) {
13
+ const result = schema.safeParse(value);
14
+ if (!result.success) {
15
+ throw new Error(`Invalid ${label}: ${result.error?.message}`);
16
+ }
17
+ return result.data;
18
+ }
19
+ const builder = new SchemaBuilder({});
20
+ builder.addScalarType("JSON", JSONResolver, {});
21
+ const PublicContentItem = builder.objectRef("PublicContentItem").implement({
22
+ fields: (t) => ({
23
+ id: t.exposeID("id"),
24
+ documentTypeId: t.exposeID("documentTypeId"),
25
+ locale: t.exposeString("locale"),
26
+ publishedAt: t.exposeString("publishedAt", { nullable: true }),
27
+ version: t.exposeInt("version"),
28
+ data: t.expose("data", { type: "JSON" }),
29
+ extensions: t.expose("extensions", { type: "JSON", nullable: true }),
30
+ }),
31
+ });
32
+ const PublicContentNodeSummaryRef = builder
33
+ .objectRef("PublicContentNodeSummary")
34
+ .implement({
35
+ fields: (t) => ({
36
+ id: t.exposeID("id"),
37
+ parentId: t.exposeID("parentId", { nullable: true }),
38
+ path: t.exposeString("path"),
39
+ depth: t.exposeInt("depth"),
40
+ sortOrder: t.exposeInt("sortOrder"),
41
+ documentTypeId: t.exposeID("documentTypeId"),
42
+ locale: t.exposeString("locale"),
43
+ publishedAt: t.exposeString("publishedAt"),
44
+ }),
45
+ });
46
+ const PublicFieldValidationRef = builder
47
+ .objectRef("PublicFieldValidation")
48
+ .implement({
49
+ fields: (t) => ({
50
+ required: t.exposeBoolean("required", { nullable: true }),
51
+ minLength: t.exposeInt("minLength", { nullable: true }),
52
+ maxLength: t.exposeInt("maxLength", { nullable: true }),
53
+ min: t.exposeFloat("min", { nullable: true }),
54
+ max: t.exposeFloat("max", { nullable: true }),
55
+ pattern: t.exposeString("pattern", { nullable: true }),
56
+ }),
57
+ });
58
+ const PublicFieldDefinitionRef = builder.objectRef("PublicFieldDefinition").implement({
59
+ fields: (t) => ({
60
+ id: t.exposeString("id"),
61
+ name: t.exposeString("name"),
62
+ datatypeId: t.exposeString("datatypeId"),
63
+ validation: t.expose("validation", { type: PublicFieldValidationRef, nullable: true }),
64
+ }),
65
+ });
66
+ const PublicDocumentTypeRef = builder.objectRef("PublicDocumentType").implement({
67
+ fields: (t) => ({
68
+ id: t.exposeID("id"),
69
+ name: t.exposeString("name"),
70
+ icon: t.exposeString("icon"),
71
+ kind: t.exposeString("kind"),
72
+ fields: t.expose("fields", { type: [PublicFieldDefinitionRef] }),
73
+ }),
74
+ });
75
+ const PublicTemplateRef = builder.objectRef("PublicTemplate").implement({
76
+ fields: (t) => ({
77
+ id: t.exposeID("id"),
78
+ name: t.exposeString("name"),
79
+ documentTypeId: t.exposeID("documentTypeId"),
80
+ }),
81
+ });
82
+ const PublicMediaFileRef = builder.objectRef("PublicMediaFile").implement({
83
+ fields: (t) => ({
84
+ id: t.exposeID("id"),
85
+ filename: t.exposeString("filename"),
86
+ mimeType: t.exposeString("mimeType"),
87
+ size: t.exposeInt("size"),
88
+ downloadUrl: t.exposeString("downloadUrl"),
89
+ uploadedAt: t.exposeString("uploadedAt"),
90
+ }),
91
+ });
92
+ const ContentNodeConnectionRef = builder
93
+ .objectRef("ContentNodeConnection")
94
+ .implement({
95
+ fields: (t) => ({
96
+ items: t.expose("items", { type: [PublicContentNodeSummaryRef] }),
97
+ nextCursor: t.exposeID("nextCursor", { nullable: true }),
98
+ }),
99
+ });
100
+ const DocumentTypeConnectionRef = builder
101
+ .objectRef("DocumentTypeConnection")
102
+ .implement({
103
+ fields: (t) => ({
104
+ items: t.expose("items", { type: [PublicDocumentTypeRef] }),
105
+ nextCursor: t.exposeID("nextCursor", { nullable: true }),
106
+ }),
107
+ });
108
+ const TemplateConnectionRef = builder
109
+ .objectRef("TemplateConnection")
110
+ .implement({
111
+ fields: (t) => ({
112
+ items: t.expose("items", { type: [PublicTemplateRef] }),
113
+ nextCursor: t.exposeID("nextCursor", { nullable: true }),
114
+ }),
115
+ });
116
+ const MediaConnectionRef = builder
117
+ .objectRef("MediaConnection")
118
+ .implement({
119
+ fields: (t) => ({
120
+ items: t.expose("items", { type: [PublicMediaFileRef] }),
121
+ nextCursor: t.exposeID("nextCursor", { nullable: true }),
122
+ }),
123
+ });
124
+ builder.queryType({
125
+ fields: (t) => ({
126
+ // GET /api/v1/content/:id analog. Uniform null for unknown id, draft,
127
+ // and (once locale/fallback are set) an unresolvable/unpublished
128
+ // translation — same "no oracle" contract as REST's 404.
129
+ content: t.field({
130
+ type: PublicContentItem,
131
+ nullable: true,
132
+ args: {
133
+ id: t.arg.id({ required: true }),
134
+ locale: t.arg.string(),
135
+ fallback: t.arg.string(),
136
+ // Session 116: GraphQL analog of REST's ?previewToken= — same
137
+ // core (resolveItemNode + preparePublishedItem), verified once,
138
+ // matched against the FINAL resolved node. Deliberately not
139
+ // added to contentByPath or any list/connection query this
140
+ // session.
141
+ previewToken: t.arg.string(),
142
+ },
143
+ resolve: async (_root, args, ctx) => {
144
+ const query = parseArgs(PublicContentItemQuerySchema, {
145
+ locale: args.locale ?? undefined,
146
+ fallback: args.fallback ?? undefined,
147
+ previewToken: args.previewToken ?? undefined,
148
+ }, "content arguments");
149
+ const previewContentId = query.previewToken ? (verifyPreviewToken(query.previewToken)?.contentId ?? null) : null;
150
+ const anchor = await ctx.getContentNode(String(args.id));
151
+ const node = await resolveItemNode({ adapter: ctx.deps.adapter, contentService: ctx.contentService }, anchor, query, { previewContentId });
152
+ const prepared = await preparePublishedItem(ctx.deps, node, { previewContentId });
153
+ if (prepared.status === "notFound")
154
+ return null; // uniform: unknown AND draft
155
+ if (prepared.status === "brokenVersion")
156
+ throw new Error(prepared.message); // REST-500 analog
157
+ const extensions = await computeExtensions(prepared, ctx.deps.warn);
158
+ return { ...prepared.core, data: prepared.data, extensions: extensions ?? null };
159
+ },
160
+ }),
161
+ // GET /api/v1/content/by-path analog. Same uniform-null contract as
162
+ // `content`; the by-path anchor lookup is already publishedOnly.
163
+ contentByPath: t.field({
164
+ type: PublicContentItem,
165
+ nullable: true,
166
+ args: {
167
+ path: t.arg.string({ required: true }),
168
+ locale: t.arg.string(),
169
+ fallback: t.arg.string(),
170
+ },
171
+ resolve: async (_root, args, ctx) => {
172
+ const query = parseArgs(PublicContentByPathQuerySchema, { path: args.path, locale: args.locale ?? undefined, fallback: args.fallback ?? undefined }, "contentByPath arguments");
173
+ const anchor = await ctx.deps.adapter.getContentNodeByPath(query.path, { publishedOnly: true });
174
+ const node = await resolveItemNode({ adapter: ctx.deps.adapter, contentService: ctx.contentService }, anchor, query);
175
+ const prepared = await preparePublishedItem(ctx.deps, node);
176
+ if (prepared.status === "notFound")
177
+ return null;
178
+ if (prepared.status === "brokenVersion")
179
+ throw new Error(prepared.message);
180
+ const extensions = await computeExtensions(prepared, ctx.deps.warn);
181
+ return { ...prepared.core, data: prepared.data, extensions: extensions ?? null };
182
+ },
183
+ }),
184
+ // GET /api/v1/content/roots analog — REST never 404s this one, so the
185
+ // connection is always returned (never null).
186
+ contentRoots: t.field({
187
+ type: ContentNodeConnectionRef,
188
+ nullable: false,
189
+ args: { cursor: t.arg.id(), limit: t.arg.int() },
190
+ resolve: async (_root, args, ctx) => {
191
+ const { cursor, limit } = parseArgs(PublicContentListQuerySchema, { cursor: args.cursor ?? undefined, limit: args.limit ?? undefined }, "contentRoots arguments");
192
+ const items = await ctx.deps.adapter.getRootNodes({ cursor, limit, publishedOnly: true });
193
+ const nextCursor = items.length === limit ? (items[items.length - 1]?.id ?? null) : null;
194
+ return { items: toSummaries(items), nextCursor };
195
+ },
196
+ }),
197
+ // GET /api/v1/content/:id/children analog. Null connection (not an
198
+ // empty page) when the parent is unknown/draft, mirroring REST's 404.
199
+ contentChildren: t.field({
200
+ type: ContentNodeConnectionRef,
201
+ nullable: true,
202
+ args: { id: t.arg.id({ required: true }), cursor: t.arg.id(), limit: t.arg.int() },
203
+ resolve: async (_root, args, ctx) => {
204
+ const { cursor, limit } = parseArgs(PublicContentListQuerySchema, { cursor: args.cursor ?? undefined, limit: args.limit ?? undefined }, "contentChildren arguments");
205
+ const parent = await ctx.getContentNode(String(args.id));
206
+ if (!parent || parent.publishedAt === null)
207
+ return null;
208
+ const items = await ctx.deps.adapter.getChildren(parent.id, { cursor, limit, publishedOnly: true });
209
+ const nextCursor = items.length === limit ? (items[items.length - 1]?.id ?? null) : null;
210
+ return { items: toSummaries(items), nextCursor };
211
+ },
212
+ }),
213
+ // GET /api/v1/content analog (Session 115, Task 1) — combinable
214
+ // filters over the published surface: documentTypeId, a subtree
215
+ // anchor (under), and a case-insensitive substring (q), matching
216
+ // REST's PublicContentSearchQuerySchema-validated querystring
217
+ // exactly for documentTypeId/q/cursor/limit. `under` is deliberately
218
+ // NOT part of that parseArgs call — it's resolved via the same
219
+ // resolveSubtreeFilter helper REST's route now shares, unvalidated
220
+ // by the schema's `.uuid()` check, the same convention `content`/
221
+ // `documentType`/`mediaItem`/`contentChildren` already use for their
222
+ // own id args (a malformed value is a lookup miss, not a thrown
223
+ // validation error). Null (not an empty page) whenever `under`
224
+ // doesn't resolve to a published anchor — unknown, unpublished, or
225
+ // malformed — mirroring REST's 404 for the valid-format misses
226
+ // (unknown/unpublished); a malformed-format `under` never reaches
227
+ // REST's handler at all, since Fastify's querystring schema 400s it
228
+ // before the route runs.
229
+ contents: t.field({
230
+ type: ContentNodeConnectionRef,
231
+ nullable: true,
232
+ args: {
233
+ documentTypeId: t.arg.id(),
234
+ under: t.arg.id(),
235
+ q: t.arg.string(),
236
+ cursor: t.arg.id(),
237
+ limit: t.arg.int(),
238
+ },
239
+ resolve: async (_root, args, ctx) => {
240
+ const { documentTypeId, q, cursor, limit } = parseArgs(PublicContentSearchQuerySchema, {
241
+ documentTypeId: args.documentTypeId ?? undefined,
242
+ q: args.q ?? undefined,
243
+ cursor: args.cursor ?? undefined,
244
+ limit: args.limit ?? undefined,
245
+ }, "contents arguments");
246
+ let pathPrefix;
247
+ if (args.under) {
248
+ const resolved = await resolveSubtreeFilter(ctx.deps.adapter, args.under);
249
+ if (!resolved)
250
+ return null;
251
+ pathPrefix = resolved.pathPrefix;
252
+ }
253
+ const items = await ctx.deps.adapter.searchPublishedContent({
254
+ cursor,
255
+ limit,
256
+ documentTypeId,
257
+ pathPrefix,
258
+ text: q,
259
+ });
260
+ const nextCursor = items.length === limit ? (items[items.length - 1]?.id ?? null) : null;
261
+ return { items: toSummaries(items), nextCursor };
262
+ },
263
+ }),
264
+ // GET /api/v1/document-types/:id analog. Uniform null for unknown id.
265
+ documentType: t.field({
266
+ type: PublicDocumentTypeRef,
267
+ nullable: true,
268
+ args: { id: t.arg.id({ required: true }) },
269
+ resolve: async (_root, args, ctx) => {
270
+ const doc = await ctx.deps.adapter.getDocumentType(String(args.id));
271
+ return doc ? toPublicDocumentType(doc) : null;
272
+ },
273
+ }),
274
+ // GET /api/v1/document-types analog — never null, same as contentRoots.
275
+ documentTypes: t.field({
276
+ type: DocumentTypeConnectionRef,
277
+ nullable: false,
278
+ args: { cursor: t.arg.id(), limit: t.arg.int() },
279
+ resolve: async (_root, args, ctx) => {
280
+ const { cursor, limit } = parseArgs(PublicDocumentTypeListQuerySchema, { cursor: args.cursor ?? undefined, limit: args.limit ?? undefined }, "documentTypes arguments");
281
+ const items = await ctx.deps.adapter.listDocumentTypes({ cursor, limit });
282
+ const nextCursor = items.length === limit ? (items[items.length - 1]?.id ?? null) : null;
283
+ return { items: items.map(toPublicDocumentType), nextCursor };
284
+ },
285
+ }),
286
+ // GET /api/v1/templates analog — never null; no by-id REST route
287
+ // exists for templates, so there is no singular `template(id)` query.
288
+ templates: t.field({
289
+ type: TemplateConnectionRef,
290
+ nullable: false,
291
+ args: { cursor: t.arg.id(), limit: t.arg.int(), documentTypeId: t.arg.id() },
292
+ resolve: async (_root, args, ctx) => {
293
+ const { cursor, limit, documentTypeId } = parseArgs(PublicTemplateListQuerySchema, {
294
+ cursor: args.cursor ?? undefined,
295
+ limit: args.limit ?? undefined,
296
+ documentTypeId: args.documentTypeId ?? undefined,
297
+ }, "templates arguments");
298
+ const items = await ctx.deps.adapter.listTemplates({ cursor, limit, documentTypeId });
299
+ const nextCursor = items.length === limit ? (items[items.length - 1]?.id ?? null) : null;
300
+ return { items, nextCursor };
301
+ },
302
+ }),
303
+ // GET /api/v1/media/:id analog. Uniform null for unknown id.
304
+ mediaItem: t.field({
305
+ type: PublicMediaFileRef,
306
+ nullable: true,
307
+ args: { id: t.arg.id({ required: true }) },
308
+ resolve: async (_root, args, ctx) => {
309
+ const media = await ctx.mediaService.getById(String(args.id));
310
+ return media ? toPublicMediaFile(ctx.mediaService, media) : null;
311
+ },
312
+ }),
313
+ // GET /api/v1/media analog — never null, same as contentRoots.
314
+ media: t.field({
315
+ type: MediaConnectionRef,
316
+ nullable: false,
317
+ args: { cursor: t.arg.id(), limit: t.arg.int(), search: t.arg.string() },
318
+ resolve: async (_root, args, ctx) => {
319
+ const { cursor, limit, search } = parseArgs(PublicMediaListQuerySchema, { cursor: args.cursor ?? undefined, limit: args.limit ?? undefined, search: args.search ?? undefined }, "media arguments");
320
+ const files = await ctx.mediaService.list({ cursor, limit, search });
321
+ const items = await Promise.all(files.map((file) => toPublicMediaFile(ctx.mediaService, file)));
322
+ const nextCursor = files.length === limit ? (files[files.length - 1]?.id ?? null) : null;
323
+ return { items, nextCursor };
324
+ },
325
+ }),
326
+ }),
327
+ });
328
+ export function buildGraphqlSchema() {
329
+ return builder.toSchema();
330
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,180 @@
1
+ import { loadEnvFile } from "./config/load-env.js";
2
+ import { normalizeDatabaseUrl } from "./setup/normalize-database-url.js";
3
+ import { countAdminUsers, resolveBootMode } from "./boot/resolve-boot-mode.js";
4
+ import { judgeCoreMigrationFailure } from "./boot/core-migration-gate.js";
5
+ // FIRST, before anything reads process.env. app.js's import graph reaches
6
+ // db/prisma.ts, whose module body is `export const prisma = await
7
+ // loadPrismaClient(resolveClientDir())` — a top-level await that runs as a
8
+ // side effect of the import. If that module were imported before the env
9
+ // file is merged, it would connect with whatever DATABASE_URL happened to
10
+ // already be set. Hence a static import of the loader here and DYNAMIC
11
+ // imports of the apps below, deferred until after the boot mode is known.
12
+ loadEnvFile();
13
+ // An externally injected DATABASE_URL gets the same treatment the wizard's
14
+ // own input gets — a relative sqlite path becomes absolute exactly once,
15
+ // here, before anything downstream reads it. Doing it in place means the
16
+ // Prisma CLI (setup/provision-database.ts), the content-db adapter and
17
+ // every other reader see one identical absolute string.
18
+ if (process.env.DATABASE_URL) {
19
+ process.env.DATABASE_URL = normalizeDatabaseUrl(process.env.DATABASE_URL);
20
+ }
21
+ // S185: self-heal the Prisma client and bring the Prisma-owned schema's
22
+ // migration ledger up to date BEFORE resolveBootMode below — its
23
+ // countAdminUsers builds a Prisma client of its own, which needs both the
24
+ // generated client and the migrated schema to exist. Still dynamic imports,
25
+ // for the same reason as the app-selection block further down: nothing
26
+ // Prisma-shaped may load before loadEnvFile()/normalizeDatabaseUrl() have
27
+ // settled process.env.DATABASE_URL. An unset or dialect-less DATABASE_URL
28
+ // falls through untouched — the setup app path (no DATABASE_URL yet) is
29
+ // unchanged. An injected DATABASE_URL may point at a completely empty
30
+ // database the wizard hasn't provisioned yet; applyCoreMigrations(mode:
31
+ // "boot") handles that itself (outcome "skipped-empty"), so nothing here
32
+ // pre-checks for it.
33
+ //
34
+ // Fix wave (review): migrations are attempted FIRST, before resolveBootMode
35
+ // runs, so a "full" (configured) boot never proceeds against an
36
+ // un-migrated schema. But refusal on failure is deferred until AFTER mode
37
+ // is known — resolveBootMode is the actual decision-maker here and is
38
+ // fail-closed by design (see its own header): a DATABASE_URL pointing at a
39
+ // database that doesn't exist as a catalog entry at all (P1003) is a
40
+ // deliberately supported shape, not a crash — it reads as zero admins and
41
+ // resolves to a setup-* mode so the wizard can create the database. Any
42
+ // error here is therefore captured and remembered rather than thrown, and
43
+ // only judged once the mode is known: it refuses "full" (a configured
44
+ // install must never run the app against a database whose core schema
45
+ // didn't or couldn't migrate) but is expected, and logged quietly, for the
46
+ // setup-* modes, where an empty or missing database is exactly why the
47
+ // wizard exists.
48
+ let coreMigrationError;
49
+ let coreMigrationPhase;
50
+ if (process.env.DATABASE_URL) {
51
+ const { dialectFromUrlScheme } = await import("./db/content-db.js");
52
+ const dialect = dialectFromUrlScheme(process.env.DATABASE_URL);
53
+ if (dialect) {
54
+ // Which of the two awaits below was in flight when/if the catch fires —
55
+ // set right before each one starts, so a throw from either leaves the
56
+ // right phase behind for judgeCoreMigrationFailure to word correctly.
57
+ let phase = "client-generation";
58
+ try {
59
+ const { ensurePrismaClientGenerated } = await import("./setup/ensure-prisma-client.js");
60
+ const { applyCoreMigrations } = await import("./db/core-migrations/index.js");
61
+ await ensurePrismaClientGenerated(dialect);
62
+ phase = "core-migrations";
63
+ await applyCoreMigrations({ dialect, databaseUrl: process.env.DATABASE_URL, mode: "boot" });
64
+ }
65
+ catch (err) {
66
+ coreMigrationError = err instanceof Error ? err : new Error(String(err));
67
+ coreMigrationPhase = phase;
68
+ }
69
+ }
70
+ }
71
+ let mode;
72
+ try {
73
+ mode = await resolveBootMode(process.env, countAdminUsers);
74
+ }
75
+ catch (err) {
76
+ // A plain process.stderr.write (what console.error calls internally) can
77
+ // be buffered (notably on Windows, and on any piped stderr) — an
78
+ // immediately following process.exit(1) can cut the write off before it
79
+ // flushes, and this message is the ONLY explanation the operator gets for
80
+ // a refused boot. Wait for the write's own callback so it has actually
81
+ // left the process before exiting.
82
+ const message = err instanceof Error ? err.message : String(err);
83
+ // If a core-migration/client-generation error was ALSO captured above,
84
+ // don't let resolveBootMode's own failure bury it: that earlier error is
85
+ // frequently the actual root cause (e.g. an un-migrated schema is exactly
86
+ // the kind of thing that can make the admin-count probe below it fail
87
+ // too), and without this line it would be silently dropped — the operator
88
+ // would see only the downstream symptom.
89
+ const lines = [message];
90
+ if (coreMigrationError && coreMigrationPhase) {
91
+ lines.push(`Earlier failure while preparing the database (${coreMigrationPhase}): ${coreMigrationError.message}`);
92
+ }
93
+ await new Promise((resolve) => {
94
+ process.stderr.write(`${lines.join("\n")}\n`, () => resolve());
95
+ });
96
+ process.exit(1);
97
+ }
98
+ // A captured core-migration/client-generation error only matters once mode
99
+ // is known — see the comment above the capture. judgeCoreMigrationFailure
100
+ // is the pure decision (unit-tested in boot/core-migration-gate.test.ts,
101
+ // including the never-boot-un-migrated invariant for mode "full"); this is
102
+ // just the process.exit/console plumbing around its answer, using the same
103
+ // flushed-stderr + exit shape the resolveBootMode catch above uses so the
104
+ // operator always gets the named cause.
105
+ if (coreMigrationError && coreMigrationPhase) {
106
+ const gate = judgeCoreMigrationFailure(coreMigrationError, mode, coreMigrationPhase);
107
+ if (gate.action === "refuse") {
108
+ await new Promise((resolve) => {
109
+ process.stderr.write(`${gate.message}\n`, () => resolve());
110
+ });
111
+ process.exit(1);
112
+ }
113
+ else if (gate.action === "log") {
114
+ console.log(gate.message);
115
+ }
116
+ }
117
+ // Deferred until the mode is known, and still dynamic, for two reasons:
118
+ // (1) db/prisma.ts's top-level-await `prisma` singleton (see above) must
119
+ // not be constructed before loadEnvFile()/normalizeDatabaseUrl() have
120
+ // settled process.env.DATABASE_URL, and (2) resolve-boot-mode.ts's
121
+ // countAdminUsers deliberately builds its own short-lived client instead of
122
+ // importing that singleton, specifically so the mode decision can be made
123
+ // before committing to a connection — importing app.js (which statically
124
+ // imports db/prisma.ts) unconditionally, before that decision ran, would
125
+ // construct the singleton anyway and defeat the point. This also means
126
+ // setup-full/setup-admin-only no longer load the entire buildApp() import
127
+ // graph at all.
128
+ let app;
129
+ if (mode === "full") {
130
+ const { buildApp } = await import("./app.js");
131
+ app = await buildApp();
132
+ }
133
+ else {
134
+ const { buildSetupOnlyApp } = await import("./setup-app.js");
135
+ app = await buildSetupOnlyApp({ databaseConfigured: mode === "setup-admin-only" });
136
+ }
137
+ const port = Number(process.env.PORT ?? 3000);
138
+ const host = process.env.HOST ?? "127.0.0.1";
139
+ try {
140
+ await app.listen({ port, host });
141
+ }
142
+ catch (err) {
143
+ app.log.error(err);
144
+ process.exit(1);
145
+ }
146
+ // Without this, SIGTERM/SIGINT (Docker stop, systemd, a Windows service, or a
147
+ // plain Ctrl-C) hit Node's default signal action — immediate termination —
148
+ // and app.close() never runs. That means every onClose hook (content DB
149
+ // disconnect, the license-revalidation job's own bounded drain) is dead code
150
+ // in production, only ever exercised by tests that call app.close() directly.
151
+ // Verified live against a running server, Session 139.
152
+ //
153
+ // SHUTDOWN_TIMEOUT_MS sits above the license job's own 15s pass-timeout bound
154
+ // (license-revalidation-job.ts) so that job's own drain has room to give up
155
+ // cleanly and log first; this is the outer safety net for the rest of
156
+ // app.close() (e.g. the content DB disconnect) hanging too.
157
+ const SHUTDOWN_TIMEOUT_MS = 20_000;
158
+ let shuttingDown = false;
159
+ function shutdown(signal) {
160
+ // A second signal while already closing must not start a second close.
161
+ if (shuttingDown)
162
+ return;
163
+ shuttingDown = true;
164
+ app.log.info(`[shutdown] received ${signal}, closing…`);
165
+ const forceExit = setTimeout(() => {
166
+ app.log.error(`[shutdown] app.close() did not resolve within ${SHUTDOWN_TIMEOUT_MS}ms — forcing exit`);
167
+ process.exit(1);
168
+ }, SHUTDOWN_TIMEOUT_MS);
169
+ app.close().then(() => {
170
+ app.log.info("[shutdown] closed cleanly");
171
+ clearTimeout(forceExit);
172
+ process.exit(0);
173
+ }, (closeErr) => {
174
+ app.log.error(closeErr, "[shutdown] error while closing");
175
+ clearTimeout(forceExit);
176
+ process.exit(1);
177
+ });
178
+ }
179
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
180
+ process.on("SIGINT", () => shutdown("SIGINT"));
package/dist/lib.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function createApp(): Promise<import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>>;
2
+ export declare const buildApp: typeof createApp;
package/dist/lib.js ADDED
@@ -0,0 +1,39 @@
1
+ // The embed surface (S185). createApp() mirrors the preparation the
2
+ // `velora-server` bin (index.ts) performs before building the app — env
3
+ // file load, DATABASE_URL normalization, Prisma-client self-heal, core
4
+ // migrations — then returns the built (not-listening) Fastify instance for
5
+ // the caller to mount or listen on themselves.
6
+ //
7
+ // Everything below is imported DYNAMICALLY and only inside the call:
8
+ // db/prisma.ts holds a top-level-await Prisma client that must not be
9
+ // constructed at import time (see index.ts's own comments on the same
10
+ // point), and a consumer must be able to set process.env AFTER importing
11
+ // this module and BEFORE calling createApp().
12
+ //
13
+ // Unlike index.ts, this does NOT reproduce the bin's boot-mode gate
14
+ // (resolveBootMode / judgeCoreMigrationFailure) or its process.exit
15
+ // refusal behavior — those belong to the standalone server process, not to
16
+ // a library call. Here, any failure (env parsing, client generation,
17
+ // migrations, or buildApp itself) simply propagates as a rejected promise
18
+ // for the caller to catch. That IS the right embed behavior: a library
19
+ // function must never call process.exit or decide a host process's fate.
20
+ export async function createApp() {
21
+ const { loadEnvFile } = await import("./config/load-env.js");
22
+ const { normalizeDatabaseUrl } = await import("./setup/normalize-database-url.js");
23
+ loadEnvFile();
24
+ if (process.env.DATABASE_URL) {
25
+ process.env.DATABASE_URL = normalizeDatabaseUrl(process.env.DATABASE_URL);
26
+ const { dialectFromUrlScheme } = await import("./db/content-db.js");
27
+ const dialect = dialectFromUrlScheme(process.env.DATABASE_URL);
28
+ if (dialect) {
29
+ const { ensurePrismaClientGenerated } = await import("./setup/ensure-prisma-client.js");
30
+ const { applyCoreMigrations } = await import("./db/core-migrations/index.js");
31
+ await ensurePrismaClientGenerated(dialect);
32
+ await applyCoreMigrations({ dialect, databaseUrl: process.env.DATABASE_URL, mode: "boot" });
33
+ }
34
+ }
35
+ const { buildApp } = await import("./app.js");
36
+ return buildApp();
37
+ }
38
+ // Alias kept for symmetry with app.ts's internal name.
39
+ export const buildApp = createApp;