emdash 0.11.1 → 0.13.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 (1016) hide show
  1. package/dist/{adapters-BktHA7EO.d.mts → adapters-9DybjTO6.d.mts} +1 -1
  2. package/dist/{adapters-BktHA7EO.d.mts.map → adapters-9DybjTO6.d.mts.map} +1 -1
  3. package/dist/allowed-origins-CDdG-4Gd.mjs +116 -0
  4. package/dist/allowed-origins-CDdG-4Gd.mjs.map +1 -0
  5. package/dist/api/route-utils.d.mts +68 -0
  6. package/dist/api/route-utils.d.mts.map +1 -0
  7. package/dist/api/route-utils.mjs +44 -0
  8. package/dist/api/route-utils.mjs.map +1 -0
  9. package/dist/api/schemas/index.d.mts +2 -0
  10. package/dist/api/schemas/index.mjs +4 -0
  11. package/dist/api-ayIQ7rIe.mjs +3941 -0
  12. package/dist/api-ayIQ7rIe.mjs.map +1 -0
  13. package/dist/api-tokens-D3C9v02m.mjs +3 -0
  14. package/dist/api-tokens-eYymBhIT.mjs +153 -0
  15. package/dist/api-tokens-eYymBhIT.mjs.map +1 -0
  16. package/dist/{apply-Ded_1vng.mjs → apply-v4DBgjPw.mjs} +19 -566
  17. package/dist/apply-v4DBgjPw.mjs.map +1 -0
  18. package/dist/astro/index.d.mts +10 -6
  19. package/dist/astro/index.d.mts.map +1 -1
  20. package/dist/astro/index.mjs +42 -83
  21. package/dist/astro/index.mjs.map +1 -1
  22. package/dist/astro/middleware/auth.d.mts +9 -5
  23. package/dist/astro/middleware/auth.d.mts.map +1 -1
  24. package/dist/astro/middleware/auth.mjs +25 -65
  25. package/dist/astro/middleware/auth.mjs.map +1 -1
  26. package/dist/astro/middleware/redirect.mjs +5 -5
  27. package/dist/astro/middleware/request-context.mjs +4 -4
  28. package/dist/astro/middleware/setup.mjs +1 -1
  29. package/dist/astro/middleware.d.mts.map +1 -1
  30. package/dist/astro/middleware.mjs +146 -71
  31. package/dist/astro/middleware.mjs.map +1 -1
  32. package/dist/astro/routes/PluginRegistry.d.mts +15 -0
  33. package/dist/astro/routes/PluginRegistry.d.mts.map +1 -0
  34. package/dist/astro/routes/PluginRegistry.mjs +25 -0
  35. package/dist/astro/routes/PluginRegistry.mjs.map +1 -0
  36. package/dist/astro/routes/api/admin/allowed-domains/_domain_.d.mts +15 -0
  37. package/dist/astro/routes/api/admin/allowed-domains/_domain_.d.mts.map +1 -0
  38. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +67 -0
  39. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs.map +1 -0
  40. package/dist/astro/routes/api/admin/allowed-domains/index.d.mts +15 -0
  41. package/dist/astro/routes/api/admin/allowed-domains/index.d.mts.map +1 -0
  42. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +67 -0
  43. package/dist/astro/routes/api/admin/allowed-domains/index.mjs.map +1 -0
  44. package/dist/astro/routes/api/admin/api-tokens/_id_.d.mts +11 -0
  45. package/dist/astro/routes/api/admin/api-tokens/_id_.d.mts.map +1 -0
  46. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +33 -0
  47. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs.map +1 -0
  48. package/dist/astro/routes/api/admin/api-tokens/index.d.mts +17 -0
  49. package/dist/astro/routes/api/admin/api-tokens/index.d.mts.map +1 -0
  50. package/dist/astro/routes/api/admin/api-tokens/index.mjs +52 -0
  51. package/dist/astro/routes/api/admin/api-tokens/index.mjs.map +1 -0
  52. package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts +10 -0
  53. package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -0
  54. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +74 -0
  55. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -0
  56. package/dist/astro/routes/api/admin/bylines/index.d.mts +9 -0
  57. package/dist/astro/routes/api/admin/bylines/index.d.mts.map +1 -0
  58. package/dist/astro/routes/api/admin/bylines/index.mjs +61 -0
  59. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -0
  60. package/dist/astro/routes/api/admin/comments/_id_/status.d.mts +8 -0
  61. package/dist/astro/routes/api/admin/comments/_id_/status.d.mts.map +1 -0
  62. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +80 -0
  63. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -0
  64. package/dist/astro/routes/api/admin/comments/_id_.d.mts +15 -0
  65. package/dist/astro/routes/api/admin/comments/_id_.d.mts.map +1 -0
  66. package/dist/astro/routes/api/admin/comments/_id_.mjs +47 -0
  67. package/dist/astro/routes/api/admin/comments/_id_.mjs.map +1 -0
  68. package/dist/astro/routes/api/admin/comments/bulk.d.mts +8 -0
  69. package/dist/astro/routes/api/admin/comments/bulk.d.mts.map +1 -0
  70. package/dist/astro/routes/api/admin/comments/bulk.mjs +36 -0
  71. package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -0
  72. package/dist/astro/routes/api/admin/comments/counts.d.mts +8 -0
  73. package/dist/astro/routes/api/admin/comments/counts.d.mts.map +1 -0
  74. package/dist/astro/routes/api/admin/comments/counts.mjs +25 -0
  75. package/dist/astro/routes/api/admin/comments/counts.mjs.map +1 -0
  76. package/dist/astro/routes/api/admin/comments/index.d.mts +11 -0
  77. package/dist/astro/routes/api/admin/comments/index.d.mts.map +1 -0
  78. package/dist/astro/routes/api/admin/comments/index.mjs +40 -0
  79. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -0
  80. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.d.mts +8 -0
  81. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.d.mts.map +1 -0
  82. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +48 -0
  83. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs.map +1 -0
  84. package/dist/astro/routes/api/admin/hooks/exclusive/index.d.mts +8 -0
  85. package/dist/astro/routes/api/admin/hooks/exclusive/index.d.mts.map +1 -0
  86. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +36 -0
  87. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs.map +1 -0
  88. package/dist/astro/routes/api/admin/oauth-clients/_id_.d.mts +19 -0
  89. package/dist/astro/routes/api/admin/oauth-clients/_id_.d.mts.map +1 -0
  90. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +69 -0
  91. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs.map +1 -0
  92. package/dist/astro/routes/api/admin/oauth-clients/index.d.mts +15 -0
  93. package/dist/astro/routes/api/admin/oauth-clients/index.d.mts.map +1 -0
  94. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +50 -0
  95. package/dist/astro/routes/api/admin/oauth-clients/index.mjs.map +1 -0
  96. package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts +8 -0
  97. package/dist/astro/routes/api/admin/plugins/_id_/disable.d.mts.map +1 -0
  98. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -0
  99. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -0
  100. package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts +8 -0
  101. package/dist/astro/routes/api/admin/plugins/_id_/enable.d.mts.map +1 -0
  102. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +59 -0
  103. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -0
  104. package/dist/astro/routes/api/admin/plugins/_id_/index.d.mts +8 -0
  105. package/dist/astro/routes/api/admin/plugins/_id_/index.d.mts.map +1 -0
  106. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +51 -0
  107. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -0
  108. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.d.mts +8 -0
  109. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.d.mts.map +1 -0
  110. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +58 -0
  111. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -0
  112. package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts +8 -0
  113. package/dist/astro/routes/api/admin/plugins/_id_/update.d.mts.map +1 -0
  114. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +66 -0
  115. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -0
  116. package/dist/astro/routes/api/admin/plugins/index.d.mts +8 -0
  117. package/dist/astro/routes/api/admin/plugins/index.d.mts.map +1 -0
  118. package/dist/astro/routes/api/admin/plugins/index.mjs +49 -0
  119. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -0
  120. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.d.mts +8 -0
  121. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.d.mts.map +1 -0
  122. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +39 -0
  123. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs.map +1 -0
  124. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.d.mts +8 -0
  125. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.d.mts.map +1 -0
  126. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +51 -0
  127. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -0
  128. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts +8 -0
  129. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.d.mts.map +1 -0
  130. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +69 -0
  131. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -0
  132. package/dist/astro/routes/api/admin/plugins/marketplace/index.d.mts +8 -0
  133. package/dist/astro/routes/api/admin/plugins/marketplace/index.d.mts.map +1 -0
  134. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +58 -0
  135. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -0
  136. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts +8 -0
  137. package/dist/astro/routes/api/admin/plugins/registry/install.d.mts.map +1 -0
  138. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +72 -0
  139. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -0
  140. package/dist/astro/routes/api/admin/plugins/updates.d.mts +8 -0
  141. package/dist/astro/routes/api/admin/plugins/updates.d.mts.map +1 -0
  142. package/dist/astro/routes/api/admin/plugins/updates.mjs +49 -0
  143. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -0
  144. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.d.mts +8 -0
  145. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.d.mts.map +1 -0
  146. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +51 -0
  147. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -0
  148. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.d.mts +8 -0
  149. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.d.mts.map +1 -0
  150. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +39 -0
  151. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs.map +1 -0
  152. package/dist/astro/routes/api/admin/themes/marketplace/index.d.mts +8 -0
  153. package/dist/astro/routes/api/admin/themes/marketplace/index.d.mts.map +1 -0
  154. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +67 -0
  155. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -0
  156. package/dist/astro/routes/api/admin/users/_id_/disable.d.mts +8 -0
  157. package/dist/astro/routes/api/admin/users/_id_/disable.d.mts.map +1 -0
  158. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +43 -0
  159. package/dist/astro/routes/api/admin/users/_id_/disable.mjs.map +1 -0
  160. package/dist/astro/routes/api/admin/users/_id_/enable.d.mts +8 -0
  161. package/dist/astro/routes/api/admin/users/_id_/enable.d.mts.map +1 -0
  162. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +32 -0
  163. package/dist/astro/routes/api/admin/users/_id_/enable.mjs.map +1 -0
  164. package/dist/astro/routes/api/admin/users/_id_/index.d.mts +9 -0
  165. package/dist/astro/routes/api/admin/users/_id_/index.d.mts.map +1 -0
  166. package/dist/astro/routes/api/admin/users/_id_/index.mjs +106 -0
  167. package/dist/astro/routes/api/admin/users/_id_/index.mjs.map +1 -0
  168. package/dist/astro/routes/api/admin/users/_id_/send-recovery.d.mts +8 -0
  169. package/dist/astro/routes/api/admin/users/_id_/send-recovery.d.mts.map +1 -0
  170. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +46 -0
  171. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs.map +1 -0
  172. package/dist/astro/routes/api/admin/users/index.d.mts +8 -0
  173. package/dist/astro/routes/api/admin/users/index.d.mts.map +1 -0
  174. package/dist/astro/routes/api/admin/users/index.mjs +56 -0
  175. package/dist/astro/routes/api/admin/users/index.mjs.map +1 -0
  176. package/dist/astro/routes/api/auth/dev-bypass.d.mts +9 -0
  177. package/dist/astro/routes/api/auth/dev-bypass.d.mts.map +1 -0
  178. package/dist/astro/routes/api/auth/dev-bypass.mjs +84 -0
  179. package/dist/astro/routes/api/auth/dev-bypass.mjs.map +1 -0
  180. package/dist/astro/routes/api/auth/invite/accept.d.mts +8 -0
  181. package/dist/astro/routes/api/auth/invite/accept.d.mts.map +1 -0
  182. package/dist/astro/routes/api/auth/invite/accept.mjs +34 -0
  183. package/dist/astro/routes/api/auth/invite/accept.mjs.map +1 -0
  184. package/dist/astro/routes/api/auth/invite/complete.d.mts +8 -0
  185. package/dist/astro/routes/api/auth/invite/complete.d.mts.map +1 -0
  186. package/dist/astro/routes/api/auth/invite/complete.mjs +56 -0
  187. package/dist/astro/routes/api/auth/invite/complete.mjs.map +1 -0
  188. package/dist/astro/routes/api/auth/invite/index.d.mts +8 -0
  189. package/dist/astro/routes/api/auth/invite/index.d.mts.map +1 -0
  190. package/dist/astro/routes/api/auth/invite/index.mjs +53 -0
  191. package/dist/astro/routes/api/auth/invite/index.mjs.map +1 -0
  192. package/dist/astro/routes/api/auth/invite/register-options.d.mts +8 -0
  193. package/dist/astro/routes/api/auth/invite/register-options.d.mts.map +1 -0
  194. package/dist/astro/routes/api/auth/invite/register-options.mjs +46 -0
  195. package/dist/astro/routes/api/auth/invite/register-options.mjs.map +1 -0
  196. package/dist/astro/routes/api/auth/logout.d.mts +8 -0
  197. package/dist/astro/routes/api/auth/logout.d.mts.map +1 -0
  198. package/dist/astro/routes/api/auth/logout.mjs +27 -0
  199. package/dist/astro/routes/api/auth/logout.mjs.map +1 -0
  200. package/dist/astro/routes/api/auth/magic-link/send.d.mts +8 -0
  201. package/dist/astro/routes/api/auth/magic-link/send.d.mts.map +1 -0
  202. package/dist/astro/routes/api/auth/magic-link/send.mjs +50 -0
  203. package/dist/astro/routes/api/auth/magic-link/send.mjs.map +1 -0
  204. package/dist/astro/routes/api/auth/magic-link/verify.d.mts +8 -0
  205. package/dist/astro/routes/api/auth/magic-link/verify.d.mts.map +1 -0
  206. package/dist/astro/routes/api/auth/magic-link/verify.mjs +35 -0
  207. package/dist/astro/routes/api/auth/magic-link/verify.mjs.map +1 -0
  208. package/dist/astro/routes/api/auth/me.d.mts +14 -0
  209. package/dist/astro/routes/api/auth/me.d.mts.map +1 -0
  210. package/dist/astro/routes/api/auth/me.mjs +43 -0
  211. package/dist/astro/routes/api/auth/me.mjs.map +1 -0
  212. package/dist/astro/routes/api/auth/mode.d.mts +8 -0
  213. package/dist/astro/routes/api/auth/mode.d.mts.map +1 -0
  214. package/dist/astro/routes/api/auth/mode.mjs +29 -0
  215. package/dist/astro/routes/api/auth/mode.mjs.map +1 -0
  216. package/dist/astro/routes/api/auth/oauth/_provider_/callback.d.mts +8 -0
  217. package/dist/astro/routes/api/auth/oauth/_provider_/callback.d.mts.map +1 -0
  218. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +130 -0
  219. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs.map +1 -0
  220. package/dist/astro/routes/api/auth/oauth/_provider_.d.mts +8 -0
  221. package/dist/astro/routes/api/auth/oauth/_provider_.d.mts.map +1 -0
  222. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +60 -0
  223. package/dist/astro/routes/api/auth/oauth/_provider_.mjs.map +1 -0
  224. package/dist/astro/routes/api/auth/passkey/_id_.d.mts +15 -0
  225. package/dist/astro/routes/api/auth/passkey/_id_.d.mts.map +1 -0
  226. package/dist/astro/routes/api/auth/passkey/_id_.mjs +64 -0
  227. package/dist/astro/routes/api/auth/passkey/_id_.mjs.map +1 -0
  228. package/dist/astro/routes/api/auth/passkey/index.d.mts +8 -0
  229. package/dist/astro/routes/api/auth/passkey/index.d.mts.map +1 -0
  230. package/dist/astro/routes/api/auth/passkey/index.mjs +28 -0
  231. package/dist/astro/routes/api/auth/passkey/index.mjs.map +1 -0
  232. package/dist/astro/routes/api/auth/passkey/options.d.mts +8 -0
  233. package/dist/astro/routes/api/auth/passkey/options.d.mts.map +1 -0
  234. package/dist/astro/routes/api/auth/passkey/options.mjs +48 -0
  235. package/dist/astro/routes/api/auth/passkey/options.mjs.map +1 -0
  236. package/dist/astro/routes/api/auth/passkey/register/options.d.mts +8 -0
  237. package/dist/astro/routes/api/auth/passkey/register/options.d.mts.map +1 -0
  238. package/dist/astro/routes/api/auth/passkey/register/options.mjs +46 -0
  239. package/dist/astro/routes/api/auth/passkey/register/options.mjs.map +1 -0
  240. package/dist/astro/routes/api/auth/passkey/register/verify.d.mts +8 -0
  241. package/dist/astro/routes/api/auth/passkey/register/verify.d.mts.map +1 -0
  242. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +61 -0
  243. package/dist/astro/routes/api/auth/passkey/register/verify.mjs.map +1 -0
  244. package/dist/astro/routes/api/auth/passkey/verify.d.mts +8 -0
  245. package/dist/astro/routes/api/auth/passkey/verify.d.mts.map +1 -0
  246. package/dist/astro/routes/api/auth/passkey/verify.mjs +49 -0
  247. package/dist/astro/routes/api/auth/passkey/verify.mjs.map +1 -0
  248. package/dist/astro/routes/api/auth/signup/complete.d.mts +8 -0
  249. package/dist/astro/routes/api/auth/signup/complete.d.mts.map +1 -0
  250. package/dist/astro/routes/api/auth/signup/complete.mjs +57 -0
  251. package/dist/astro/routes/api/auth/signup/complete.mjs.map +1 -0
  252. package/dist/astro/routes/api/auth/signup/request.d.mts +8 -0
  253. package/dist/astro/routes/api/auth/signup/request.d.mts.map +1 -0
  254. package/dist/astro/routes/api/auth/signup/request.mjs +46 -0
  255. package/dist/astro/routes/api/auth/signup/request.mjs.map +1 -0
  256. package/dist/astro/routes/api/auth/signup/verify.d.mts +8 -0
  257. package/dist/astro/routes/api/auth/signup/verify.d.mts.map +1 -0
  258. package/dist/astro/routes/api/auth/signup/verify.mjs +35 -0
  259. package/dist/astro/routes/api/auth/signup/verify.mjs.map +1 -0
  260. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts +15 -0
  261. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts.map +1 -0
  262. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +193 -0
  263. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -0
  264. package/dist/astro/routes/api/content/_collection_/_id_/compare.d.mts +8 -0
  265. package/dist/astro/routes/api/content/_collection_/_id_/compare.d.mts.map +1 -0
  266. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +20 -0
  267. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs.map +1 -0
  268. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts +8 -0
  269. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.d.mts.map +1 -0
  270. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +28 -0
  271. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -0
  272. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.d.mts +8 -0
  273. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.d.mts.map +1 -0
  274. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +30 -0
  275. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs.map +1 -0
  276. package/dist/astro/routes/api/content/_collection_/_id_/permanent.d.mts +8 -0
  277. package/dist/astro/routes/api/content/_collection_/_id_/permanent.d.mts.map +1 -0
  278. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +23 -0
  279. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs.map +1 -0
  280. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.d.mts +8 -0
  281. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.d.mts.map +1 -0
  282. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +78 -0
  283. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -0
  284. package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts +8 -0
  285. package/dist/astro/routes/api/content/_collection_/_id_/publish.d.mts.map +1 -0
  286. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +48 -0
  287. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -0
  288. package/dist/astro/routes/api/content/_collection_/_id_/restore.d.mts +8 -0
  289. package/dist/astro/routes/api/content/_collection_/_id_/restore.d.mts.map +1 -0
  290. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +28 -0
  291. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs.map +1 -0
  292. package/dist/astro/routes/api/content/_collection_/_id_/revisions.d.mts +8 -0
  293. package/dist/astro/routes/api/content/_collection_/_id_/revisions.d.mts.map +1 -0
  294. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +22 -0
  295. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs.map +1 -0
  296. package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts +9 -0
  297. package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -0
  298. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +58 -0
  299. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -0
  300. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts +15 -0
  301. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -0
  302. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +85 -0
  303. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -0
  304. package/dist/astro/routes/api/content/_collection_/_id_/translations.d.mts +8 -0
  305. package/dist/astro/routes/api/content/_collection_/_id_/translations.d.mts.map +1 -0
  306. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +43 -0
  307. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -0
  308. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts +8 -0
  309. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.d.mts.map +1 -0
  310. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +28 -0
  311. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -0
  312. package/dist/astro/routes/api/content/_collection_/_id_.d.mts +10 -0
  313. package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -0
  314. package/dist/astro/routes/api/content/_collection_/_id_.mjs +88 -0
  315. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -0
  316. package/dist/astro/routes/api/content/_collection_/index.d.mts +9 -0
  317. package/dist/astro/routes/api/content/_collection_/index.d.mts.map +1 -0
  318. package/dist/astro/routes/api/content/_collection_/index.mjs +61 -0
  319. package/dist/astro/routes/api/content/_collection_/index.mjs.map +1 -0
  320. package/dist/astro/routes/api/content/_collection_/trash.d.mts +8 -0
  321. package/dist/astro/routes/api/content/_collection_/trash.d.mts.map +1 -0
  322. package/dist/astro/routes/api/content/_collection_/trash.mjs +25 -0
  323. package/dist/astro/routes/api/content/_collection_/trash.mjs.map +1 -0
  324. package/dist/astro/routes/api/dashboard.d.mts +8 -0
  325. package/dist/astro/routes/api/dashboard.d.mts.map +1 -0
  326. package/dist/astro/routes/api/dashboard.mjs +26 -0
  327. package/dist/astro/routes/api/dashboard.mjs.map +1 -0
  328. package/dist/astro/routes/api/dev/emails.d.mts +9 -0
  329. package/dist/astro/routes/api/dev/emails.d.mts.map +1 -0
  330. package/dist/astro/routes/api/dev/emails.mjs +20 -0
  331. package/dist/astro/routes/api/dev/emails.mjs.map +1 -0
  332. package/dist/astro/routes/api/import/probe.d.mts +18 -0
  333. package/dist/astro/routes/api/import/probe.d.mts.map +1 -0
  334. package/dist/astro/routes/api/import/probe.mjs +35 -0
  335. package/dist/astro/routes/api/import/probe.mjs.map +1 -0
  336. package/dist/astro/routes/api/import/wordpress/analyze.d.mts +88 -0
  337. package/dist/astro/routes/api/import/wordpress/analyze.d.mts.map +1 -0
  338. package/dist/astro/routes/api/import/wordpress/analyze.mjs +313 -0
  339. package/dist/astro/routes/api/import/wordpress/analyze.mjs.map +1 -0
  340. package/dist/astro/routes/api/import/wordpress/execute.d.mts +93 -0
  341. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -0
  342. package/dist/astro/routes/api/import/wordpress/execute.mjs +593 -0
  343. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -0
  344. package/dist/astro/routes/api/import/wordpress/media.d.mts +36 -0
  345. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -0
  346. package/dist/astro/routes/api/import/wordpress/media.mjs +225 -0
  347. package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -0
  348. package/dist/astro/routes/api/import/wordpress/prepare.d.mts +20 -0
  349. package/dist/astro/routes/api/import/wordpress/prepare.d.mts.map +1 -0
  350. package/dist/astro/routes/api/import/wordpress/prepare.mjs +120 -0
  351. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -0
  352. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts +49 -0
  353. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.d.mts.map +1 -0
  354. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs +131 -0
  355. package/dist/astro/routes/api/import/wordpress/rewrite-url-helpers.mjs.map +1 -0
  356. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +22 -0
  357. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -0
  358. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +139 -0
  359. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -0
  360. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +16 -0
  361. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts.map +1 -0
  362. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +71 -0
  363. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -0
  364. package/dist/astro/routes/api/import/wordpress-plugin/callback.d.mts +8 -0
  365. package/dist/astro/routes/api/import/wordpress-plugin/callback.d.mts.map +1 -0
  366. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +29 -0
  367. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs.map +1 -0
  368. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +20 -0
  369. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -0
  370. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +219 -0
  371. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -0
  372. package/dist/astro/routes/api/manifest.d.mts +8 -0
  373. package/dist/astro/routes/api/manifest.d.mts.map +1 -0
  374. package/dist/astro/routes/api/manifest.mjs +47 -0
  375. package/dist/astro/routes/api/manifest.mjs.map +1 -0
  376. package/dist/astro/routes/api/mcp.d.mts +16 -0
  377. package/dist/astro/routes/api/mcp.d.mts.map +1 -0
  378. package/dist/astro/routes/api/mcp.mjs +1414 -0
  379. package/dist/astro/routes/api/mcp.mjs.map +1 -0
  380. package/dist/astro/routes/api/media/_id_/confirm.d.mts +11 -0
  381. package/dist/astro/routes/api/media/_id_/confirm.d.mts.map +1 -0
  382. package/dist/astro/routes/api/media/_id_/confirm.mjs +61 -0
  383. package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -0
  384. package/dist/astro/routes/api/media/_id_.d.mts +23 -0
  385. package/dist/astro/routes/api/media/_id_.d.mts.map +1 -0
  386. package/dist/astro/routes/api/media/_id_.mjs +83 -0
  387. package/dist/astro/routes/api/media/_id_.mjs.map +1 -0
  388. package/dist/astro/routes/api/media/file/_...key_.d.mts +8 -0
  389. package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -0
  390. package/dist/astro/routes/api/media/file/_...key_.mjs +52 -0
  391. package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -0
  392. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.d.mts +15 -0
  393. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.d.mts.map +1 -0
  394. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +52 -0
  395. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs.map +1 -0
  396. package/dist/astro/routes/api/media/providers/_providerId_/index.d.mts +15 -0
  397. package/dist/astro/routes/api/media/providers/_providerId_/index.d.mts.map +1 -0
  398. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +75 -0
  399. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs.map +1 -0
  400. package/dist/astro/routes/api/media/providers/index.d.mts +11 -0
  401. package/dist/astro/routes/api/media/providers/index.d.mts.map +1 -0
  402. package/dist/astro/routes/api/media/providers/index.mjs +21 -0
  403. package/dist/astro/routes/api/media/providers/index.mjs.map +1 -0
  404. package/dist/astro/routes/api/media/upload-url.d.mts +11 -0
  405. package/dist/astro/routes/api/media/upload-url.d.mts.map +1 -0
  406. package/dist/astro/routes/api/media/upload-url.mjs +82 -0
  407. package/dist/astro/routes/api/media/upload-url.mjs.map +1 -0
  408. package/dist/astro/routes/api/media.d.mts +17 -0
  409. package/dist/astro/routes/api/media.d.mts.map +1 -0
  410. package/dist/astro/routes/api/media.mjs +138 -0
  411. package/dist/astro/routes/api/media.mjs.map +1 -0
  412. package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts +9 -0
  413. package/dist/astro/routes/api/menus/_name_/items/_id_.d.mts.map +1 -0
  414. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +48 -0
  415. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -0
  416. package/dist/astro/routes/api/menus/_name_/items.d.mts +8 -0
  417. package/dist/astro/routes/api/menus/_name_/items.d.mts.map +1 -0
  418. package/dist/astro/routes/api/menus/_name_/items.mjs +31 -0
  419. package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -0
  420. package/dist/astro/routes/api/menus/_name_/reorder.d.mts +8 -0
  421. package/dist/astro/routes/api/menus/_name_/reorder.d.mts.map +1 -0
  422. package/dist/astro/routes/api/menus/_name_/reorder.mjs +31 -0
  423. package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -0
  424. package/dist/astro/routes/api/menus/_name_/translations.d.mts +9 -0
  425. package/dist/astro/routes/api/menus/_name_/translations.d.mts.map +1 -0
  426. package/dist/astro/routes/api/menus/_name_/translations.mjs +62 -0
  427. package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -0
  428. package/dist/astro/routes/api/menus/_name_.d.mts +10 -0
  429. package/dist/astro/routes/api/menus/_name_.d.mts.map +1 -0
  430. package/dist/astro/routes/api/menus/_name_.mjs +60 -0
  431. package/dist/astro/routes/api/menus/_name_.mjs.map +1 -0
  432. package/dist/astro/routes/api/menus/index.d.mts +9 -0
  433. package/dist/astro/routes/api/menus/index.d.mts.map +1 -0
  434. package/dist/astro/routes/api/menus/index.mjs +40 -0
  435. package/dist/astro/routes/api/menus/index.mjs.map +1 -0
  436. package/dist/astro/routes/api/oauth/authorize.d.mts +9 -0
  437. package/dist/astro/routes/api/oauth/authorize.d.mts.map +1 -0
  438. package/dist/astro/routes/api/oauth/authorize.mjs +260 -0
  439. package/dist/astro/routes/api/oauth/authorize.mjs.map +1 -0
  440. package/dist/astro/routes/api/oauth/device/authorize.d.mts +8 -0
  441. package/dist/astro/routes/api/oauth/device/authorize.d.mts.map +1 -0
  442. package/dist/astro/routes/api/oauth/device/authorize.mjs +32 -0
  443. package/dist/astro/routes/api/oauth/device/authorize.mjs.map +1 -0
  444. package/dist/astro/routes/api/oauth/device/code.d.mts +8 -0
  445. package/dist/astro/routes/api/oauth/device/code.d.mts.map +1 -0
  446. package/dist/astro/routes/api/oauth/device/code.mjs +36 -0
  447. package/dist/astro/routes/api/oauth/device/code.mjs.map +1 -0
  448. package/dist/astro/routes/api/oauth/device/token.d.mts +8 -0
  449. package/dist/astro/routes/api/oauth/device/token.d.mts.map +1 -0
  450. package/dist/astro/routes/api/oauth/device/token.mjs +47 -0
  451. package/dist/astro/routes/api/oauth/device/token.mjs.map +1 -0
  452. package/dist/astro/routes/api/oauth/register.d.mts +9 -0
  453. package/dist/astro/routes/api/oauth/register.d.mts.map +1 -0
  454. package/dist/astro/routes/api/oauth/register.mjs +113 -0
  455. package/dist/astro/routes/api/oauth/register.mjs.map +1 -0
  456. package/dist/astro/routes/api/oauth/token/refresh.d.mts +8 -0
  457. package/dist/astro/routes/api/oauth/token/refresh.d.mts.map +1 -0
  458. package/dist/astro/routes/api/oauth/token/refresh.mjs +30 -0
  459. package/dist/astro/routes/api/oauth/token/refresh.mjs.map +1 -0
  460. package/dist/astro/routes/api/oauth/token/revoke.d.mts +8 -0
  461. package/dist/astro/routes/api/oauth/token/revoke.d.mts.map +1 -0
  462. package/dist/astro/routes/api/oauth/token/revoke.mjs +27 -0
  463. package/dist/astro/routes/api/oauth/token/revoke.mjs.map +1 -0
  464. package/dist/astro/routes/api/oauth/token.d.mts +9 -0
  465. package/dist/astro/routes/api/oauth/token.d.mts.map +1 -0
  466. package/dist/astro/routes/api/oauth/token.mjs +141 -0
  467. package/dist/astro/routes/api/oauth/token.mjs.map +1 -0
  468. package/dist/astro/routes/api/openapi.json.d.mts +8 -0
  469. package/dist/astro/routes/api/openapi.json.d.mts.map +1 -0
  470. package/dist/astro/routes/api/openapi.json.mjs +2642 -0
  471. package/dist/astro/routes/api/openapi.json.mjs.map +1 -0
  472. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts +12 -0
  473. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.d.mts.map +1 -0
  474. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +78 -0
  475. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs.map +1 -0
  476. package/dist/astro/routes/api/redirects/404s/index.d.mts +10 -0
  477. package/dist/astro/routes/api/redirects/404s/index.d.mts.map +1 -0
  478. package/dist/astro/routes/api/redirects/404s/index.mjs +62 -0
  479. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -0
  480. package/dist/astro/routes/api/redirects/404s/summary.d.mts +8 -0
  481. package/dist/astro/routes/api/redirects/404s/summary.d.mts.map +1 -0
  482. package/dist/astro/routes/api/redirects/404s/summary.mjs +34 -0
  483. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -0
  484. package/dist/astro/routes/api/redirects/_id_.d.mts +10 -0
  485. package/dist/astro/routes/api/redirects/_id_.d.mts.map +1 -0
  486. package/dist/astro/routes/api/redirects/_id_.mjs +71 -0
  487. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -0
  488. package/dist/astro/routes/api/redirects/index.d.mts +9 -0
  489. package/dist/astro/routes/api/redirects/index.d.mts.map +1 -0
  490. package/dist/astro/routes/api/redirects/index.mjs +52 -0
  491. package/dist/astro/routes/api/redirects/index.mjs.map +1 -0
  492. package/dist/astro/routes/api/revisions/_revisionId_/index.d.mts +8 -0
  493. package/dist/astro/routes/api/revisions/_revisionId_/index.d.mts.map +1 -0
  494. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +19 -0
  495. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs.map +1 -0
  496. package/dist/astro/routes/api/revisions/_revisionId_/restore.d.mts +8 -0
  497. package/dist/astro/routes/api/revisions/_revisionId_/restore.d.mts.map +1 -0
  498. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +26 -0
  499. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs.map +1 -0
  500. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.d.mts +10 -0
  501. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.d.mts.map +1 -0
  502. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +75 -0
  503. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -0
  504. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.d.mts +9 -0
  505. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.d.mts.map +1 -0
  506. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +63 -0
  507. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -0
  508. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.d.mts +8 -0
  509. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.d.mts.map +1 -0
  510. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +54 -0
  511. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -0
  512. package/dist/astro/routes/api/schema/collections/_slug_/index.d.mts +10 -0
  513. package/dist/astro/routes/api/schema/collections/_slug_/index.d.mts.map +1 -0
  514. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +79 -0
  515. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -0
  516. package/dist/astro/routes/api/schema/collections/index.d.mts +9 -0
  517. package/dist/astro/routes/api/schema/collections/index.d.mts.map +1 -0
  518. package/dist/astro/routes/api/schema/collections/index.mjs +63 -0
  519. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -0
  520. package/dist/astro/routes/api/schema/index.d.mts +8 -0
  521. package/dist/astro/routes/api/schema/index.d.mts.map +1 -0
  522. package/dist/astro/routes/api/schema/index.mjs +82 -0
  523. package/dist/astro/routes/api/schema/index.mjs.map +1 -0
  524. package/dist/astro/routes/api/schema/orphans/_slug_.d.mts +8 -0
  525. package/dist/astro/routes/api/schema/orphans/_slug_.d.mts.map +1 -0
  526. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +55 -0
  527. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -0
  528. package/dist/astro/routes/api/schema/orphans/index.d.mts +8 -0
  529. package/dist/astro/routes/api/schema/orphans/index.d.mts.map +1 -0
  530. package/dist/astro/routes/api/schema/orphans/index.mjs +50 -0
  531. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -0
  532. package/dist/astro/routes/api/search/enable.d.mts +16 -0
  533. package/dist/astro/routes/api/search/enable.d.mts.map +1 -0
  534. package/dist/astro/routes/api/search/enable.mjs +55 -0
  535. package/dist/astro/routes/api/search/enable.mjs.map +1 -0
  536. package/dist/astro/routes/api/search/index.d.mts +17 -0
  537. package/dist/astro/routes/api/search/index.d.mts.map +1 -0
  538. package/dist/astro/routes/api/search/index.mjs +52 -0
  539. package/dist/astro/routes/api/search/index.mjs.map +1 -0
  540. package/dist/astro/routes/api/search/rebuild.d.mts +14 -0
  541. package/dist/astro/routes/api/search/rebuild.d.mts.map +1 -0
  542. package/dist/astro/routes/api/search/rebuild.mjs +48 -0
  543. package/dist/astro/routes/api/search/rebuild.mjs.map +1 -0
  544. package/dist/astro/routes/api/search/stats.d.mts +11 -0
  545. package/dist/astro/routes/api/search/stats.d.mts.map +1 -0
  546. package/dist/astro/routes/api/search/stats.mjs +29 -0
  547. package/dist/astro/routes/api/search/stats.mjs.map +1 -0
  548. package/dist/astro/routes/api/search/suggest.d.mts +16 -0
  549. package/dist/astro/routes/api/search/suggest.d.mts.map +1 -0
  550. package/dist/astro/routes/api/search/suggest.mjs +43 -0
  551. package/dist/astro/routes/api/search/suggest.mjs.map +1 -0
  552. package/dist/astro/routes/api/sections/_slug_.d.mts +10 -0
  553. package/dist/astro/routes/api/sections/_slug_.d.mts.map +1 -0
  554. package/dist/astro/routes/api/sections/_slug_.mjs +65 -0
  555. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -0
  556. package/dist/astro/routes/api/sections/index.d.mts +9 -0
  557. package/dist/astro/routes/api/sections/index.d.mts.map +1 -0
  558. package/dist/astro/routes/api/sections/index.mjs +48 -0
  559. package/dist/astro/routes/api/sections/index.mjs.map +1 -0
  560. package/dist/astro/routes/api/settings/email.d.mts +18 -0
  561. package/dist/astro/routes/api/settings/email.d.mts.map +1 -0
  562. package/dist/astro/routes/api/settings/email.mjs +105 -0
  563. package/dist/astro/routes/api/settings/email.mjs.map +1 -0
  564. package/dist/astro/routes/api/settings.d.mts +21 -0
  565. package/dist/astro/routes/api/settings.d.mts.map +1 -0
  566. package/dist/astro/routes/api/settings.mjs +58 -0
  567. package/dist/astro/routes/api/settings.mjs.map +1 -0
  568. package/dist/astro/routes/api/setup/admin-verify.d.mts +8 -0
  569. package/dist/astro/routes/api/setup/admin-verify.d.mts.map +1 -0
  570. package/dist/astro/routes/api/setup/admin-verify.mjs +68 -0
  571. package/dist/astro/routes/api/setup/admin-verify.mjs.map +1 -0
  572. package/dist/astro/routes/api/setup/admin.d.mts +8 -0
  573. package/dist/astro/routes/api/setup/admin.d.mts.map +1 -0
  574. package/dist/astro/routes/api/setup/admin.mjs +69 -0
  575. package/dist/astro/routes/api/setup/admin.mjs.map +1 -0
  576. package/dist/astro/routes/api/setup/dev-bypass.d.mts +9 -0
  577. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -0
  578. package/dist/astro/routes/api/setup/dev-bypass.mjs +139 -0
  579. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -0
  580. package/dist/astro/routes/api/setup/dev-reset.d.mts +8 -0
  581. package/dist/astro/routes/api/setup/dev-reset.d.mts.map +1 -0
  582. package/dist/astro/routes/api/setup/dev-reset.mjs +25 -0
  583. package/dist/astro/routes/api/setup/dev-reset.mjs.map +1 -0
  584. package/dist/astro/routes/api/setup/index.d.mts +8 -0
  585. package/dist/astro/routes/api/setup/index.d.mts.map +1 -0
  586. package/dist/astro/routes/api/setup/index.mjs +93 -0
  587. package/dist/astro/routes/api/setup/index.mjs.map +1 -0
  588. package/dist/astro/routes/api/setup/status.d.mts +8 -0
  589. package/dist/astro/routes/api/setup/status.d.mts.map +1 -0
  590. package/dist/astro/routes/api/setup/status.mjs +60 -0
  591. package/dist/astro/routes/api/setup/status.mjs.map +1 -0
  592. package/dist/astro/routes/api/snapshot.d.mts +8 -0
  593. package/dist/astro/routes/api/snapshot.d.mts.map +1 -0
  594. package/dist/astro/routes/api/snapshot.mjs +270 -0
  595. package/dist/astro/routes/api/snapshot.mjs.map +1 -0
  596. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts +9 -0
  597. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.d.mts.map +1 -0
  598. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +72 -0
  599. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -0
  600. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts +19 -0
  601. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.d.mts.map +1 -0
  602. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +80 -0
  603. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -0
  604. package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts +15 -0
  605. package/dist/astro/routes/api/taxonomies/_name_/terms/index.d.mts.map +1 -0
  606. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +59 -0
  607. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -0
  608. package/dist/astro/routes/api/taxonomies/index.d.mts +15 -0
  609. package/dist/astro/routes/api/taxonomies/index.d.mts.map +1 -0
  610. package/dist/astro/routes/api/taxonomies/index.mjs +55 -0
  611. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -0
  612. package/dist/astro/routes/api/themes/preview.d.mts +8 -0
  613. package/dist/astro/routes/api/themes/preview.d.mts.map +1 -0
  614. package/dist/astro/routes/api/themes/preview.mjs +49 -0
  615. package/dist/astro/routes/api/themes/preview.mjs.map +1 -0
  616. package/dist/astro/routes/api/typegen.d.mts +18 -0
  617. package/dist/astro/routes/api/typegen.d.mts.map +1 -0
  618. package/dist/astro/routes/api/typegen.mjs +78 -0
  619. package/dist/astro/routes/api/typegen.mjs.map +1 -0
  620. package/dist/astro/routes/api/well-known/auth.d.mts +8 -0
  621. package/dist/astro/routes/api/well-known/auth.d.mts.map +1 -0
  622. package/dist/astro/routes/api/well-known/auth.mjs +42 -0
  623. package/dist/astro/routes/api/well-known/auth.mjs.map +1 -0
  624. package/dist/astro/routes/api/well-known/oauth-authorization-server.d.mts +8 -0
  625. package/dist/astro/routes/api/well-known/oauth-authorization-server.d.mts.map +1 -0
  626. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +32 -0
  627. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs.map +1 -0
  628. package/dist/astro/routes/api/well-known/oauth-protected-resource.d.mts +8 -0
  629. package/dist/astro/routes/api/well-known/oauth-protected-resource.d.mts.map +1 -0
  630. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +21 -0
  631. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs.map +1 -0
  632. package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts +8 -0
  633. package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -0
  634. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +36 -0
  635. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -0
  636. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts +9 -0
  637. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -0
  638. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +62 -0
  639. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -0
  640. package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts +8 -0
  641. package/dist/astro/routes/api/widget-areas/_name_/widgets.d.mts.map +1 -0
  642. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +49 -0
  643. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -0
  644. package/dist/astro/routes/api/widget-areas/_name_.d.mts +9 -0
  645. package/dist/astro/routes/api/widget-areas/_name_.d.mts.map +1 -0
  646. package/dist/astro/routes/api/widget-areas/_name_.mjs +49 -0
  647. package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -0
  648. package/dist/astro/routes/api/widget-areas/index.d.mts +9 -0
  649. package/dist/astro/routes/api/widget-areas/index.d.mts.map +1 -0
  650. package/dist/astro/routes/api/widget-areas/index.mjs +59 -0
  651. package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -0
  652. package/dist/astro/routes/api/widget-components.d.mts +8 -0
  653. package/dist/astro/routes/api/widget-components.d.mts.map +1 -0
  654. package/dist/astro/routes/api/widget-components.mjs +18 -0
  655. package/dist/astro/routes/api/widget-components.mjs.map +1 -0
  656. package/dist/astro/routes/robots.txt.d.mts +8 -0
  657. package/dist/astro/routes/robots.txt.d.mts.map +1 -0
  658. package/dist/astro/routes/robots.txt.mjs +61 -0
  659. package/dist/astro/routes/robots.txt.mjs.map +1 -0
  660. package/dist/astro/routes/sitemap-_collection_.xml.d.mts +8 -0
  661. package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -0
  662. package/dist/astro/routes/sitemap-_collection_.xml.mjs +71 -0
  663. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -0
  664. package/dist/astro/routes/sitemap.xml.d.mts +8 -0
  665. package/dist/astro/routes/sitemap.xml.d.mts.map +1 -0
  666. package/dist/astro/routes/sitemap.xml.mjs +64 -0
  667. package/dist/astro/routes/sitemap.xml.mjs.map +1 -0
  668. package/dist/astro/types.d.mts +48 -9
  669. package/dist/astro/types.d.mts.map +1 -1
  670. package/dist/auth/providers/github.d.mts +13 -0
  671. package/dist/auth/providers/github.d.mts.map +1 -0
  672. package/dist/auth/providers/github.mjs +18 -0
  673. package/dist/auth/providers/github.mjs.map +1 -0
  674. package/dist/auth/providers/google.d.mts +13 -0
  675. package/dist/auth/providers/google.d.mts.map +1 -0
  676. package/dist/auth/providers/google.mjs +18 -0
  677. package/dist/auth/providers/google.mjs.map +1 -0
  678. package/dist/authorize-BlyCH-96.mjs +37 -0
  679. package/dist/authorize-BlyCH-96.mjs.map +1 -0
  680. package/dist/{base64-MBPo9ozB.mjs → base64-CqR-7kqF.mjs} +1 -1
  681. package/dist/{base64-MBPo9ozB.mjs.map → base64-CqR-7kqF.mjs.map} +1 -1
  682. package/dist/{byline-gFn1r0vA.mjs → byline-D09BaS4j.mjs} +4 -4
  683. package/dist/{byline-gFn1r0vA.mjs.map → byline-D09BaS4j.mjs.map} +1 -1
  684. package/dist/{bylines-DTFI8nDM.mjs → bylines-BTM2xtP8.mjs} +6 -6
  685. package/dist/{bylines-DTFI8nDM.mjs.map → bylines-BTM2xtP8.mjs.map} +1 -1
  686. package/dist/bylines-C6eYUWlZ.d.mts +1971 -0
  687. package/dist/bylines-C6eYUWlZ.d.mts.map +1 -0
  688. package/dist/{cache-BAJbeoZ8.mjs → cache-CXCpjWiL.mjs} +3 -3
  689. package/dist/{cache-BAJbeoZ8.mjs.map → cache-CXCpjWiL.mjs.map} +1 -1
  690. package/dist/challenge-store-CJ0OOHOr.mjs +49 -0
  691. package/dist/challenge-store-CJ0OOHOr.mjs.map +1 -0
  692. package/dist/{chunks-BK1oZS-l.mjs → chunks-DyGtu1Bv.mjs} +2 -2
  693. package/dist/{chunks-BK1oZS-l.mjs.map → chunks-DyGtu1Bv.mjs.map} +1 -1
  694. package/dist/cli/index.mjs +23 -18
  695. package/dist/cli/index.mjs.map +1 -1
  696. package/dist/client/cf-access.d.mts +1 -1
  697. package/dist/client/index.d.mts +1 -1
  698. package/dist/client/index.d.mts.map +1 -1
  699. package/dist/client/index.mjs +2 -2
  700. package/dist/client/index.mjs.map +1 -1
  701. package/dist/comment-Dd9MI82-.mjs +247 -0
  702. package/dist/comment-Dd9MI82-.mjs.map +1 -0
  703. package/dist/comments-koGI0FrK.mjs +204 -0
  704. package/dist/comments-koGI0FrK.mjs.map +1 -0
  705. package/dist/components-mZem7pbe.mjs +108 -0
  706. package/dist/components-mZem7pbe.mjs.map +1 -0
  707. package/dist/{content-CERxPUN0.mjs → content-D6YG26WG.mjs} +10 -34
  708. package/dist/content-D6YG26WG.mjs.map +1 -0
  709. package/dist/context-qF8d3IPR.mjs +879 -0
  710. package/dist/context-qF8d3IPR.mjs.map +1 -0
  711. package/dist/cron-H8eJ46dv.mjs +264 -0
  712. package/dist/cron-H8eJ46dv.mjs.map +1 -0
  713. package/dist/dashboard-BmWSIUwY.mjs +105 -0
  714. package/dist/dashboard-BmWSIUwY.mjs.map +1 -0
  715. package/dist/db/index.d.mts +3 -3
  716. package/dist/db/index.mjs +1 -1
  717. package/dist/db/libsql.d.mts +1 -1
  718. package/dist/db/postgres.d.mts +1 -1
  719. package/dist/db/sqlite.d.mts +1 -1
  720. package/dist/{db-errors-B7P2pSCn.mjs → db-errors-CGN9kJfo.mjs} +1 -1
  721. package/dist/{db-errors-B7P2pSCn.mjs.map → db-errors-CGN9kJfo.mjs.map} +1 -1
  722. package/dist/{default-pHuz9WF6.mjs → default-Dbs22Gg4.mjs} +1 -1
  723. package/dist/{default-pHuz9WF6.mjs.map → default-Dbs22Gg4.mjs.map} +1 -1
  724. package/dist/device-flow-BqJRxa0Q.mjs +467 -0
  725. package/dist/device-flow-BqJRxa0Q.mjs.map +1 -0
  726. package/dist/email-console-Dmp5Q-P2.mjs +50 -0
  727. package/dist/email-console-Dmp5Q-P2.mjs.map +1 -0
  728. package/dist/error-tSQWIl5U.mjs +437 -0
  729. package/dist/error-tSQWIl5U.mjs.map +1 -0
  730. package/dist/escape-B8bdIryO.mjs +9 -0
  731. package/dist/escape-B8bdIryO.mjs.map +1 -0
  732. package/dist/fts-manager-B633C-kQ.mjs +339 -0
  733. package/dist/fts-manager-B633C-kQ.mjs.map +1 -0
  734. package/dist/hash-DlUxGhQS.mjs +33 -0
  735. package/dist/hash-DlUxGhQS.mjs.map +1 -0
  736. package/dist/import-CNfLOgDE.mjs +1531 -0
  737. package/dist/import-CNfLOgDE.mjs.map +1 -0
  738. package/dist/index-D2gvztOP.d.mts +262 -0
  739. package/dist/index-D2gvztOP.d.mts.map +1 -0
  740. package/dist/{index-BogfvE-z.d.mts → index-UmOMt9T-.d.mts} +310 -911
  741. package/dist/index-UmOMt9T-.d.mts.map +1 -0
  742. package/dist/index.d.mts +17 -11
  743. package/dist/index.mjs +57 -28
  744. package/dist/{load-DR1VwFXR.mjs → load-QzYRpVN3.mjs} +2 -2
  745. package/dist/{load-DR1VwFXR.mjs.map → load-QzYRpVN3.mjs.map} +1 -1
  746. package/dist/{loader-ou_PXAjg.mjs → loader-Cs6-Bqe6.mjs} +4 -4
  747. package/dist/{loader-ou_PXAjg.mjs.map → loader-Cs6-Bqe6.mjs.map} +1 -1
  748. package/dist/{manifest-schema-CXAbd1vH.mjs → manifest-schema-HCtSh4Jq.mjs} +1 -1
  749. package/dist/{manifest-schema-CXAbd1vH.mjs.map → manifest-schema-HCtSh4Jq.mjs.map} +1 -1
  750. package/dist/media/index.d.mts +1 -1
  751. package/dist/media/index.mjs +2 -1
  752. package/dist/media/index.mjs.map +1 -1
  753. package/dist/media/local-runtime.d.mts +11 -7
  754. package/dist/media/local-runtime.d.mts.map +1 -1
  755. package/dist/media/local-runtime.mjs +9 -3
  756. package/dist/media/local-runtime.mjs.map +1 -1
  757. package/dist/{media-1fFhub9c.mjs → media-Dg7he9uK.mjs} +2 -2
  758. package/dist/{media-1fFhub9c.mjs.map → media-Dg7he9uK.mjs.map} +1 -1
  759. package/dist/media-allowlist-B8EX01DH.mjs +32 -0
  760. package/dist/media-allowlist-B8EX01DH.mjs.map +1 -0
  761. package/dist/menus-DOzIecHi.mjs +723 -0
  762. package/dist/menus-DOzIecHi.mjs.map +1 -0
  763. package/dist/menus-X4Z-eBA1.mjs +2788 -0
  764. package/dist/menus-X4Z-eBA1.mjs.map +1 -0
  765. package/dist/mime-KV5TqkMN.mjs +36 -0
  766. package/dist/mime-KV5TqkMN.mjs.map +1 -0
  767. package/dist/{mode-YhqNVef_.mjs → mode-DPRPvJYm.mjs} +1 -1
  768. package/dist/{mode-YhqNVef_.mjs.map → mode-DPRPvJYm.mjs.map} +1 -1
  769. package/dist/normalize-CN5kRSMC.mjs +151 -0
  770. package/dist/normalize-CN5kRSMC.mjs.map +1 -0
  771. package/dist/oauth-authorization-62GmpGIH.mjs +275 -0
  772. package/dist/oauth-authorization-62GmpGIH.mjs.map +1 -0
  773. package/dist/oauth-clients-D_B0_-Bz.mjs +266 -0
  774. package/dist/oauth-clients-D_B0_-Bz.mjs.map +1 -0
  775. package/dist/oauth-state-store-DpsZViTu.mjs +49 -0
  776. package/dist/oauth-state-store-DpsZViTu.mjs.map +1 -0
  777. package/dist/oauth-user-lookup-meyS2oB1.mjs +26 -0
  778. package/dist/oauth-user-lookup-meyS2oB1.mjs.map +1 -0
  779. package/dist/{options-nPxWnrya.mjs → options-BL4X94qY.mjs} +1 -1
  780. package/dist/{options-nPxWnrya.mjs.map → options-BL4X94qY.mjs.map} +1 -1
  781. package/dist/options-Cq64Wx0O.d.mts +207 -0
  782. package/dist/options-Cq64Wx0O.d.mts.map +1 -0
  783. package/dist/page/index.d.mts +15 -4
  784. package/dist/page/index.d.mts.map +1 -1
  785. package/dist/page/index.mjs +16 -5
  786. package/dist/page/index.mjs.map +1 -1
  787. package/dist/parse-BFTPon-J.mjs +89 -0
  788. package/dist/parse-BFTPon-J.mjs.map +1 -0
  789. package/dist/passkey-config-Cg86_ISa.mjs +46 -0
  790. package/dist/passkey-config-Cg86_ISa.mjs.map +1 -0
  791. package/dist/{patterns-DsUZ4uxI.mjs → patterns-CqG5Ya3i.mjs} +54 -2
  792. package/dist/{patterns-DsUZ4uxI.mjs.map → patterns-CqG5Ya3i.mjs.map} +1 -1
  793. package/dist/{placeholder-CDPtkelt.d.mts → placeholder-D3cFCU9y.d.mts} +2 -1
  794. package/dist/{placeholder-CDPtkelt.d.mts.map → placeholder-D3cFCU9y.d.mts.map} +1 -1
  795. package/dist/placeholder-LqmHqvBw.mjs +143 -0
  796. package/dist/placeholder-LqmHqvBw.mjs.map +1 -0
  797. package/dist/plugin-types.d.mts +122 -0
  798. package/dist/plugin-types.d.mts.map +1 -0
  799. package/dist/plugin-types.mjs +1 -0
  800. package/dist/plugins/adapt-sandbox-entry.d.mts +20 -12
  801. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  802. package/dist/plugins/adapt-sandbox-entry.mjs +46 -23
  803. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  804. package/dist/preview-C1LOEbWZ.mjs +107 -0
  805. package/dist/preview-C1LOEbWZ.mjs.map +1 -0
  806. package/dist/{public-url-B1AxbbbQ.mjs → public-url-CseXl9Fv.mjs} +39 -2
  807. package/dist/{public-url-B1AxbbbQ.mjs.map → public-url-CseXl9Fv.mjs.map} +1 -1
  808. package/dist/{query-8c_meo_K.mjs → query-axZmO6Tn.mjs} +23 -12
  809. package/dist/query-axZmO6Tn.mjs.map +1 -0
  810. package/dist/rate-limit-t5CVjCO6.mjs +120 -0
  811. package/dist/rate-limit-t5CVjCO6.mjs.map +1 -0
  812. package/dist/redirect-DGRsLO2I.mjs +17 -0
  813. package/dist/redirect-DGRsLO2I.mjs.map +1 -0
  814. package/dist/{redirect-C5H7VGIX.mjs → redirect-DkaDxq8e.mjs} +3 -3
  815. package/dist/{redirect-C5H7VGIX.mjs.map → redirect-DkaDxq8e.mjs.map} +1 -1
  816. package/dist/redirects-D1fdd68T.mjs +573 -0
  817. package/dist/redirects-D1fdd68T.mjs.map +1 -0
  818. package/dist/redirects-Dmj6KRU3.mjs +1141 -0
  819. package/dist/redirects-Dmj6KRU3.mjs.map +1 -0
  820. package/dist/{registry-Do34mz_P.mjs → registry-BnCeHYsf.mjs} +8 -300
  821. package/dist/registry-BnCeHYsf.mjs.map +1 -0
  822. package/dist/{request-cache-D4I69LeL.mjs → request-cache-dzCt8TZB.mjs} +1 -1
  823. package/dist/{request-cache-D4I69LeL.mjs.map → request-cache-dzCt8TZB.mjs.map} +1 -1
  824. package/dist/request-meta-CLCwSQOS.mjs +140 -0
  825. package/dist/request-meta-CLCwSQOS.mjs.map +1 -0
  826. package/dist/{runner-Iu3IZSDM.d.mts → runner-DcfZewkO.d.mts} +2 -2
  827. package/dist/{runner-Iu3IZSDM.d.mts.map → runner-DcfZewkO.d.mts.map} +1 -1
  828. package/dist/{runner-DIcU2UCC.mjs → runner-DdnQIwz_.mjs} +436 -187
  829. package/dist/runner-DdnQIwz_.mjs.map +1 -0
  830. package/dist/runtime.d.mts +10 -6
  831. package/dist/runtime.d.mts.map +1 -1
  832. package/dist/runtime.mjs +3 -3
  833. package/dist/schema-BmqagCwG.mjs +41 -0
  834. package/dist/schema-BmqagCwG.mjs.map +1 -0
  835. package/dist/search-CPrvO5u8.mjs +376 -0
  836. package/dist/search-CPrvO5u8.mjs.map +1 -0
  837. package/dist/{secrets-CZ8rxLX3.mjs → secrets-6pgZyq0K.mjs} +3 -3
  838. package/dist/{secrets-CZ8rxLX3.mjs.map → secrets-6pgZyq0K.mjs.map} +1 -1
  839. package/dist/sections-Cm-zb-gZ.mjs +346 -0
  840. package/dist/sections-Cm-zb-gZ.mjs.map +1 -0
  841. package/dist/seed/index.d.mts +2 -2
  842. package/dist/seed/index.mjs +19 -15
  843. package/dist/seo/index.d.mts +1 -1
  844. package/dist/seo-BoR4wCUh.mjs +86 -0
  845. package/dist/seo-BoR4wCUh.mjs.map +1 -0
  846. package/dist/seo-DRq9-EPP.mjs +130 -0
  847. package/dist/seo-DRq9-EPP.mjs.map +1 -0
  848. package/dist/service-vByySp-2.mjs +195 -0
  849. package/dist/service-vByySp-2.mjs.map +1 -0
  850. package/dist/settings-CBBj7HUd.mjs +51 -0
  851. package/dist/settings-CBBj7HUd.mjs.map +1 -0
  852. package/dist/settings-xQKsWnzQ.mjs +235 -0
  853. package/dist/settings-xQKsWnzQ.mjs.map +1 -0
  854. package/dist/setup-BGAJ2uXs.mjs +137 -0
  855. package/dist/setup-BGAJ2uXs.mjs.map +1 -0
  856. package/dist/setup-complete-C6ZCLhKo.mjs +26 -0
  857. package/dist/setup-complete-C6ZCLhKo.mjs.map +1 -0
  858. package/dist/setup-nonce-CY1gQiAU.mjs +25 -0
  859. package/dist/setup-nonce-CY1gQiAU.mjs.map +1 -0
  860. package/dist/site-url-D-M4Fd8O.mjs +13 -0
  861. package/dist/site-url-D-M4Fd8O.mjs.map +1 -0
  862. package/dist/slugify-Cjh1ssOZ.mjs +30 -0
  863. package/dist/slugify-Cjh1ssOZ.mjs.map +1 -0
  864. package/dist/ssrf-CTul4uQi.mjs +1 -0
  865. package/dist/ssrf-DzFN_qV-.mjs +332 -0
  866. package/dist/ssrf-DzFN_qV-.mjs.map +1 -0
  867. package/dist/storage/local.d.mts +1 -1
  868. package/dist/storage/local.mjs +1 -1
  869. package/dist/storage/s3.d.mts +1 -1
  870. package/dist/storage/s3.mjs +1 -1
  871. package/dist/{taxonomies-Bw76xAxo.mjs → taxonomies-Cn9UpaR2.mjs} +7 -7
  872. package/dist/{taxonomies-Bw76xAxo.mjs.map → taxonomies-Cn9UpaR2.mjs.map} +1 -1
  873. package/dist/taxonomies-Dc0mzlms.mjs +508 -0
  874. package/dist/taxonomies-Dc0mzlms.mjs.map +1 -0
  875. package/dist/{taxonomy-D6NvlKo8.mjs → taxonomy-wPfusMK9.mjs} +3 -3
  876. package/dist/{taxonomy-D6NvlKo8.mjs.map → taxonomy-wPfusMK9.mjs.map} +1 -1
  877. package/dist/{tokens-CyRDPVW2.mjs → tokens-DILYNZMi.mjs} +2 -2
  878. package/dist/{tokens-CyRDPVW2.mjs.map → tokens-DILYNZMi.mjs.map} +1 -1
  879. package/dist/{transaction-D44LBXvU.mjs → transaction-NQj4VJ7Z.mjs} +1 -1
  880. package/dist/{transaction-D44LBXvU.mjs.map → transaction-NQj4VJ7Z.mjs.map} +1 -1
  881. package/dist/{transport-DX_5rpsq.d.mts → transport-GeXlLscf.d.mts} +1 -1
  882. package/dist/{transport-DX_5rpsq.d.mts.map → transport-GeXlLscf.d.mts.map} +1 -1
  883. package/dist/{transport-xpzIjCIB.mjs → transport-fw-mKJzT.mjs} +1 -1
  884. package/dist/{transport-xpzIjCIB.mjs.map → transport-fw-mKJzT.mjs.map} +1 -1
  885. package/dist/trusted-proxy-CJhQIk65.mjs +51 -0
  886. package/dist/trusted-proxy-CJhQIk65.mjs.map +1 -0
  887. package/dist/{types-IjUrQMVe.d.mts → types-B05e2naf.d.mts} +151 -60
  888. package/dist/types-B05e2naf.d.mts.map +1 -0
  889. package/dist/{types-BTe41zL6.d.mts → types-BWhaSS7U.d.mts} +2 -71
  890. package/dist/types-BWhaSS7U.d.mts.map +1 -0
  891. package/dist/{types-BQx6ZXpR.d.mts → types-C1KKK4VP.d.mts} +3 -1
  892. package/dist/{types-BQx6ZXpR.d.mts.map → types-C1KKK4VP.d.mts.map} +1 -1
  893. package/dist/types-Cb2UCDJg.d.mts +345 -0
  894. package/dist/types-Cb2UCDJg.d.mts.map +1 -0
  895. package/dist/{types-BIgulNsW.mjs → types-CwXMEPRr.mjs} +10 -3
  896. package/dist/types-CwXMEPRr.mjs.map +1 -0
  897. package/dist/{types-B_CXXnzh.d.mts → types-CzvJd1ND.d.mts} +7 -1
  898. package/dist/{types-B_CXXnzh.d.mts.map → types-CzvJd1ND.d.mts.map} +1 -1
  899. package/dist/types-DFowNO60.d.mts +198 -0
  900. package/dist/types-DFowNO60.d.mts.map +1 -0
  901. package/dist/{types-56BKbld_.mjs → types-DSZl1Dsv.mjs} +1 -1
  902. package/dist/{types-56BKbld_.mjs.map → types-DSZl1Dsv.mjs.map} +1 -1
  903. package/dist/types-DW1l0gCv.d.mts +75 -0
  904. package/dist/types-DW1l0gCv.d.mts.map +1 -0
  905. package/dist/types-Db67HHlU.mjs +3 -0
  906. package/dist/{types-C-aFbqmA.d.mts → types-DmxPPXGf.d.mts} +1 -1
  907. package/dist/{types-C-aFbqmA.d.mts.map → types-DmxPPXGf.d.mts.map} +1 -1
  908. package/dist/{types-K-EkEQCI.mjs → types-Dz9CGX_d.mjs} +1 -1
  909. package/dist/{types-K-EkEQCI.mjs.map → types-Dz9CGX_d.mjs.map} +1 -1
  910. package/dist/user-Dr1bOCqS.mjs +155 -0
  911. package/dist/user-Dr1bOCqS.mjs.map +1 -0
  912. package/dist/utils-_F-rWBTN.mjs +286 -0
  913. package/dist/utils-_F-rWBTN.mjs.map +1 -0
  914. package/dist/{validate-CcVQQpmH.d.mts → validate-BpQGsmd7.d.mts} +5 -4
  915. package/dist/validate-BpQGsmd7.d.mts.map +1 -0
  916. package/dist/{validate-UK4Ja1uo.mjs → validate-DlFxcVVK.mjs} +3 -3
  917. package/dist/{validate-UK4Ja1uo.mjs.map → validate-DlFxcVVK.mjs.map} +1 -1
  918. package/dist/{validation-Vc5DQkJa.mjs → validation-BiFJqUp5.mjs} +6 -5
  919. package/dist/{validation-Vc5DQkJa.mjs.map → validation-BiFJqUp5.mjs.map} +1 -1
  920. package/dist/version-Dw7Z5PVU.mjs +7 -0
  921. package/dist/{version-JjSqv90m.mjs.map → version-Dw7Z5PVU.mjs.map} +1 -1
  922. package/dist/widgets-B9j_yzlk.mjs +106 -0
  923. package/dist/widgets-B9j_yzlk.mjs.map +1 -0
  924. package/dist/zod-generator-DSyz01KE.mjs +234 -0
  925. package/dist/zod-generator-DSyz01KE.mjs.map +1 -0
  926. package/locals.d.ts +1 -1
  927. package/package.json +37 -14
  928. package/src/api/handlers/content.ts +1 -0
  929. package/src/api/handlers/index.ts +7 -0
  930. package/src/api/handlers/marketplace.ts +27 -6
  931. package/src/api/handlers/menus.ts +157 -580
  932. package/src/api/handlers/plugins.ts +77 -31
  933. package/src/api/handlers/registry.ts +1086 -0
  934. package/src/api/openapi/document.ts +10 -4
  935. package/src/api/schemas/content.ts +1 -0
  936. package/src/api/schemas/menus.ts +27 -23
  937. package/src/api/schemas/settings.ts +41 -9
  938. package/src/api/types.ts +6 -0
  939. package/src/astro/integration/index.ts +1 -0
  940. package/src/astro/integration/route-naming.ts +19 -0
  941. package/src/astro/integration/routes.ts +25 -3
  942. package/src/astro/integration/runtime.ts +35 -8
  943. package/src/astro/middleware/auth.ts +8 -2
  944. package/src/astro/middleware/csp.ts +25 -3
  945. package/src/astro/middleware.ts +3 -0
  946. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +10 -0
  947. package/src/astro/routes/api/admin/plugins/registry/install.ts +107 -0
  948. package/src/astro/routes/api/auth/invite/register-options.ts +8 -1
  949. package/src/astro/routes/api/import/wordpress/execute.ts +185 -6
  950. package/src/astro/routes/api/media/[id].ts +2 -1
  951. package/src/astro/routes/api/menus/[name]/items/[id].ts +69 -0
  952. package/src/astro/routes/api/menus/[name]/items.ts +4 -65
  953. package/src/astro/types.ts +38 -0
  954. package/src/cli/wxr/parser.ts +263 -0
  955. package/src/client/index.ts +2 -1
  956. package/src/components/EmDashHead.astro +26 -5
  957. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +166 -49
  958. package/src/database/migrations/038_registry_plugin_state.ts +130 -0
  959. package/src/database/migrations/039_fix_fts5_triggers.ts +264 -0
  960. package/src/database/migrations/runner.ts +4 -0
  961. package/src/database/repositories/content.ts +5 -1
  962. package/src/database/repositories/index.ts +14 -0
  963. package/src/database/repositories/menu.ts +644 -0
  964. package/src/database/repositories/types.ts +6 -0
  965. package/src/database/types.ts +5 -1
  966. package/src/emdash-runtime.ts +143 -36
  967. package/src/import/sources/wordpress-plugin.ts +9 -2
  968. package/src/import/sources/wxr.ts +16 -2
  969. package/src/import/ssrf.ts +20 -500
  970. package/src/import/wxr-taxonomies.ts +730 -0
  971. package/src/index.ts +3 -10
  972. package/src/media/local-runtime.ts +7 -0
  973. package/src/media/normalize.ts +37 -4
  974. package/src/page/absolute-url.ts +146 -0
  975. package/src/page/jsonld.ts +10 -2
  976. package/src/page/seo-contributions.ts +17 -6
  977. package/src/plugin-types.ts +240 -0
  978. package/src/plugins/adapt-sandbox-entry.ts +115 -39
  979. package/src/plugins/context.ts +11 -1
  980. package/src/plugins/define-plugin.ts +34 -56
  981. package/src/plugins/index.ts +1 -9
  982. package/src/plugins/marketplace.ts +63 -4
  983. package/src/plugins/sandbox/index.ts +1 -1
  984. package/src/plugins/sandbox/noop.ts +2 -2
  985. package/src/plugins/sandbox/types.ts +7 -4
  986. package/src/plugins/state.ts +84 -38
  987. package/src/plugins/types.ts +2 -79
  988. package/src/query.ts +12 -0
  989. package/src/registry/config.ts +311 -0
  990. package/src/registry/plugin-id.ts +116 -0
  991. package/src/registry/types.ts +206 -0
  992. package/src/search/fts-manager.ts +77 -15
  993. package/src/security/ssrf.ts +501 -0
  994. package/src/settings/index.ts +20 -1
  995. package/src/settings/types.ts +12 -8
  996. package/dist/apply-Ded_1vng.mjs.map +0 -1
  997. package/dist/content-CERxPUN0.mjs.map +0 -1
  998. package/dist/error-DqnRMM5z.mjs +0 -27
  999. package/dist/error-DqnRMM5z.mjs.map +0 -1
  1000. package/dist/index-BogfvE-z.d.mts.map +0 -1
  1001. package/dist/placeholder-Ci0RLeCk.mjs +0 -268
  1002. package/dist/placeholder-Ci0RLeCk.mjs.map +0 -1
  1003. package/dist/query-8c_meo_K.mjs.map +0 -1
  1004. package/dist/registry-Do34mz_P.mjs.map +0 -1
  1005. package/dist/runner-DIcU2UCC.mjs.map +0 -1
  1006. package/dist/search-DuWhx4NG.mjs +0 -9897
  1007. package/dist/search-DuWhx4NG.mjs.map +0 -1
  1008. package/dist/types-BIgulNsW.mjs.map +0 -1
  1009. package/dist/types-BTe41zL6.d.mts.map +0 -1
  1010. package/dist/types-DiI8NOG_.mjs +0 -16
  1011. package/dist/types-DiI8NOG_.mjs.map +0 -1
  1012. package/dist/types-IjUrQMVe.d.mts.map +0 -1
  1013. package/dist/validate-CcVQQpmH.d.mts.map +0 -1
  1014. package/dist/version-JjSqv90m.mjs +0 -7
  1015. package/dist/zod-generator-CHnJUP2l.mjs +0 -137
  1016. package/dist/zod-generator-CHnJUP2l.mjs.map +0 -1
@@ -0,0 +1,2788 @@
1
+ import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
2
+ import { t as CommentRepository } from "./comment-Dd9MI82-.mjs";
3
+ import { t as OptionsRepository } from "./options-BL4X94qY.mjs";
4
+ import { t as PluginContextFactory } from "./context-qF8d3IPR.mjs";
5
+ import { n as requestCached } from "./request-cache-dzCt8TZB.mjs";
6
+ import { r as getDb } from "./loader-Cs6-Bqe6.mjs";
7
+ import { d as resolveLocale, f as resolveLocaleChain } from "./taxonomies-Cn9UpaR2.mjs";
8
+ import { r as normalizeCapabilities } from "./types-Db67HHlU.mjs";
9
+ import { dt as sanitizeHref } from "./redirects-Dmj6KRU3.mjs";
10
+ import { t as extractRequestMeta } from "./request-meta-CLCwSQOS.mjs";
11
+ import { r as setCronTasksEnabled } from "./cron-H8eJ46dv.mjs";
12
+ import { sql } from "kysely";
13
+ import { AsyncLocalStorage } from "node:async_hooks";
14
+ import { ulid } from "ulidx";
15
+ import { z } from "astro/zod";
16
+
17
+ //#region src/fields/image.ts
18
+ const imageSchema = z.object({
19
+ id: z.string(),
20
+ src: z.string(),
21
+ alt: z.string().optional(),
22
+ width: z.number().optional(),
23
+ height: z.number().optional()
24
+ });
25
+ function image(options = {}) {
26
+ const validation = options.allowedTypes && options.allowedTypes.length > 0 ? { allowedMimeTypes: [...options.allowedTypes] } : void 0;
27
+ return {
28
+ type: "image",
29
+ columnType: "TEXT",
30
+ schema: options.required === false ? imageSchema.optional() : imageSchema,
31
+ options,
32
+ ui: { widget: "image" },
33
+ validation
34
+ };
35
+ }
36
+
37
+ //#endregion
38
+ //#region src/fields/file.ts
39
+ function file(options = {}) {
40
+ const fileObjSchema = z.object({
41
+ id: z.string(),
42
+ url: z.string(),
43
+ filename: z.string(),
44
+ mimeType: z.string(),
45
+ size: z.number()
46
+ });
47
+ return {
48
+ type: "file",
49
+ columnType: "TEXT",
50
+ schema: options.required ? fileObjSchema : fileObjSchema.optional(),
51
+ options,
52
+ ui: {
53
+ widget: "file",
54
+ helpText: options.helpText,
55
+ maxSize: options.maxSize
56
+ },
57
+ validation: options.allowedTypes && options.allowedTypes.length > 0 ? { allowedMimeTypes: [...options.allowedTypes] } : void 0
58
+ };
59
+ }
60
+
61
+ //#endregion
62
+ //#region src/fields/reference.ts
63
+ /**
64
+ * Reference field
65
+ * References another content item by ID
66
+ */
67
+ function reference(collection, options) {
68
+ const schema = z.string();
69
+ return {
70
+ type: "reference",
71
+ columnType: "TEXT",
72
+ schema: options?.required === false ? schema.optional() : schema,
73
+ options: {
74
+ ...options,
75
+ collection
76
+ },
77
+ ui: { widget: "reference" }
78
+ };
79
+ }
80
+
81
+ //#endregion
82
+ //#region src/fields/portable-text.ts
83
+ /**
84
+ * Portable Text block schema
85
+ */
86
+ const portableTextBlockSchema = z.object({
87
+ _type: z.string(),
88
+ _key: z.string()
89
+ }).passthrough();
90
+ /**
91
+ * Portable Text field
92
+ * Stores structured content in Portable Text format
93
+ */
94
+ function portableText(options) {
95
+ const schema = z.array(portableTextBlockSchema);
96
+ return {
97
+ type: "portableText",
98
+ columnType: "JSON",
99
+ schema: options?.required === false ? schema.optional() : schema,
100
+ options,
101
+ ui: { widget: "portableText" }
102
+ };
103
+ }
104
+
105
+ //#endregion
106
+ //#region src/content/converters/prosemirror-to-portable-text.ts
107
+ /**
108
+ * Generate a unique key for Portable Text blocks
109
+ */
110
+ function generateKey() {
111
+ return Math.random().toString(36).substring(2, 11);
112
+ }
113
+ /**
114
+ * Convert ProseMirror document to Portable Text
115
+ */
116
+ function prosemirrorToPortableText(doc) {
117
+ if (!doc || doc.type !== "doc" || !doc.content) return [];
118
+ const blocks = [];
119
+ for (const node of doc.content) {
120
+ const converted = convertNode(node);
121
+ if (converted) if (Array.isArray(converted)) blocks.push(...converted);
122
+ else blocks.push(converted);
123
+ }
124
+ return blocks;
125
+ }
126
+ /**
127
+ * Convert a single ProseMirror node to Portable Text block(s)
128
+ */
129
+ function convertNode(node) {
130
+ switch (node.type) {
131
+ case "paragraph": return convertParagraph(node);
132
+ case "heading": return convertHeading(node);
133
+ case "bulletList": return convertList$1(node, "bullet");
134
+ case "orderedList": return convertList$1(node, "number");
135
+ case "blockquote": return convertBlockquote(node);
136
+ case "codeBlock": return convertCodeBlock$1(node);
137
+ case "image": return convertImage$1(node);
138
+ case "horizontalRule": return {
139
+ _type: "break",
140
+ _key: generateKey(),
141
+ style: "lineBreak"
142
+ };
143
+ default: return {
144
+ _type: node.type,
145
+ _key: generateKey(),
146
+ ...node.attrs,
147
+ _pmContent: node.content
148
+ };
149
+ }
150
+ }
151
+ /**
152
+ * Convert paragraph to Portable Text block
153
+ */
154
+ function convertParagraph(node) {
155
+ const { children, markDefs } = convertInlineContent(node.content || []);
156
+ if (children.length === 0) return null;
157
+ return {
158
+ _type: "block",
159
+ _key: generateKey(),
160
+ style: "normal",
161
+ children,
162
+ markDefs: markDefs.length > 0 ? markDefs : void 0
163
+ };
164
+ }
165
+ /** Map heading level number to Portable Text style */
166
+ function headingLevelToStyle(level) {
167
+ switch (level) {
168
+ case 1: return "h1";
169
+ case 2: return "h2";
170
+ case 3: return "h3";
171
+ case 4: return "h4";
172
+ case 5: return "h5";
173
+ case 6: return "h6";
174
+ default: return "h1";
175
+ }
176
+ }
177
+ /**
178
+ * Convert heading to Portable Text block
179
+ */
180
+ function convertHeading(node) {
181
+ const { children, markDefs } = convertInlineContent(node.content || []);
182
+ const style = headingLevelToStyle(typeof node.attrs?.level === "number" ? node.attrs.level : 1);
183
+ if (children.length === 0) return null;
184
+ return {
185
+ _type: "block",
186
+ _key: generateKey(),
187
+ style,
188
+ children,
189
+ markDefs: markDefs.length > 0 ? markDefs : void 0
190
+ };
191
+ }
192
+ /**
193
+ * Convert list to Portable Text blocks
194
+ */
195
+ function convertList$1(node, listItem) {
196
+ const blocks = [];
197
+ for (const item of node.content || []) if (item.type === "listItem") {
198
+ const itemBlocks = convertListItem$1(item, listItem, 1);
199
+ blocks.push(...itemBlocks);
200
+ }
201
+ return blocks;
202
+ }
203
+ /**
204
+ * Convert list item to Portable Text blocks
205
+ */
206
+ function convertListItem$1(item, listItem, level) {
207
+ const blocks = [];
208
+ for (const child of item.content || []) if (child.type === "paragraph") {
209
+ const { children, markDefs } = convertInlineContent(child.content || []);
210
+ if (children.length > 0) blocks.push({
211
+ _type: "block",
212
+ _key: generateKey(),
213
+ style: "normal",
214
+ listItem,
215
+ level,
216
+ children,
217
+ markDefs: markDefs.length > 0 ? markDefs : void 0
218
+ });
219
+ } else if (child.type === "bulletList") blocks.push(...convertListItemNested(child, "bullet", level + 1));
220
+ else if (child.type === "orderedList") blocks.push(...convertListItemNested(child, "number", level + 1));
221
+ return blocks;
222
+ }
223
+ /**
224
+ * Convert nested list
225
+ */
226
+ function convertListItemNested(node, listItem, level) {
227
+ const blocks = [];
228
+ for (const item of node.content || []) if (item.type === "listItem") blocks.push(...convertListItem$1(item, listItem, level));
229
+ return blocks;
230
+ }
231
+ /**
232
+ * Convert blockquote to Portable Text blocks
233
+ */
234
+ function convertBlockquote(node) {
235
+ const blocks = [];
236
+ for (const child of node.content || []) if (child.type === "paragraph") {
237
+ const { children, markDefs } = convertInlineContent(child.content || []);
238
+ if (children.length > 0) blocks.push({
239
+ _type: "block",
240
+ _key: generateKey(),
241
+ style: "blockquote",
242
+ children,
243
+ markDefs: markDefs.length > 0 ? markDefs : void 0
244
+ });
245
+ }
246
+ return blocks.length === 1 ? blocks[0] : blocks.length > 0 ? blocks : null;
247
+ }
248
+ /**
249
+ * Convert code block to Portable Text
250
+ */
251
+ function convertCodeBlock$1(node) {
252
+ const code = node.content?.map((n) => n.text || "").join("") || "";
253
+ const language = typeof node.attrs?.language === "string" ? node.attrs.language : void 0;
254
+ return {
255
+ _type: "code",
256
+ _key: generateKey(),
257
+ code,
258
+ language: language || void 0
259
+ };
260
+ }
261
+ /**
262
+ * Convert image to Portable Text
263
+ */
264
+ function convertImage$1(node) {
265
+ const attrs = node.attrs;
266
+ const provider = typeof attrs?.provider === "string" ? attrs.provider : void 0;
267
+ const mediaId = typeof attrs?.mediaId === "string" ? attrs.mediaId : void 0;
268
+ const src = typeof attrs?.src === "string" ? attrs.src : "";
269
+ const alt = typeof attrs?.alt === "string" ? attrs.alt : void 0;
270
+ const title = typeof attrs?.title === "string" ? attrs.title : void 0;
271
+ const width = typeof attrs?.width === "number" ? attrs.width : void 0;
272
+ const height = typeof attrs?.height === "number" ? attrs.height : void 0;
273
+ const displayWidth = typeof attrs?.displayWidth === "number" ? attrs.displayWidth : void 0;
274
+ const displayHeight = typeof attrs?.displayHeight === "number" ? attrs.displayHeight : void 0;
275
+ return {
276
+ _type: "image",
277
+ _key: generateKey(),
278
+ asset: {
279
+ _ref: mediaId || src || "",
280
+ url: src || "",
281
+ provider: provider && provider !== "local" ? provider : void 0
282
+ },
283
+ alt: alt || void 0,
284
+ caption: title || void 0,
285
+ width: width || void 0,
286
+ height: height || void 0,
287
+ displayWidth: displayWidth || void 0,
288
+ displayHeight: displayHeight || void 0
289
+ };
290
+ }
291
+ /**
292
+ * Convert inline content (text nodes with marks) to Portable Text spans
293
+ */
294
+ function convertInlineContent(nodes) {
295
+ const children = [];
296
+ const markDefs = [];
297
+ const markDefMap = /* @__PURE__ */ new Map();
298
+ for (const node of nodes) if (node.type === "text" && node.text) {
299
+ const marks = [];
300
+ for (const mark of node.marks || []) {
301
+ const markType = convertMark(mark, markDefs, markDefMap);
302
+ if (markType) marks.push(markType);
303
+ }
304
+ children.push({
305
+ _type: "span",
306
+ _key: generateKey(),
307
+ text: node.text,
308
+ marks: marks.length > 0 ? marks : void 0
309
+ });
310
+ } else if (node.type === "hardBreak") if (children.length > 0) {
311
+ const lastChild = children.at(-1);
312
+ lastChild.text += "\n";
313
+ } else children.push({
314
+ _type: "span",
315
+ _key: generateKey(),
316
+ text: "\n"
317
+ });
318
+ if (children.length === 0) children.push({
319
+ _type: "span",
320
+ _key: generateKey(),
321
+ text: ""
322
+ });
323
+ return {
324
+ children,
325
+ markDefs
326
+ };
327
+ }
328
+ /**
329
+ * Convert a ProseMirror mark to Portable Text mark
330
+ */
331
+ function convertMark(mark, markDefs, markDefMap) {
332
+ switch (mark.type) {
333
+ case "bold":
334
+ case "strong": return "strong";
335
+ case "italic":
336
+ case "em": return "em";
337
+ case "underline": return "underline";
338
+ case "strike":
339
+ case "strikethrough": return "strike-through";
340
+ case "code": return "code";
341
+ case "link": {
342
+ const href = (typeof mark.attrs?.href === "string" ? mark.attrs.href : "") || "";
343
+ if (markDefMap.has(href)) return markDefMap.get(href);
344
+ const key = generateKey();
345
+ markDefs.push({
346
+ _type: "link",
347
+ _key: key,
348
+ href,
349
+ blank: mark.attrs?.target === "_blank"
350
+ });
351
+ markDefMap.set(href, key);
352
+ return key;
353
+ }
354
+ default: return mark.type;
355
+ }
356
+ }
357
+
358
+ //#endregion
359
+ //#region src/content/converters/portable-text-to-prosemirror.ts
360
+ /**
361
+ * Convert Portable Text to ProseMirror document
362
+ */
363
+ function portableTextToProsemirror(blocks) {
364
+ if (!blocks || blocks.length === 0) return {
365
+ type: "doc",
366
+ content: [{ type: "paragraph" }]
367
+ };
368
+ const content = [];
369
+ let i = 0;
370
+ while (i < blocks.length) {
371
+ const block = blocks[i];
372
+ if (isTextBlock(block) && block.listItem) {
373
+ const listBlocks = [];
374
+ const listType = block.listItem;
375
+ while (i < blocks.length) {
376
+ const current = blocks[i];
377
+ if (isTextBlock(current) && current.listItem === listType) {
378
+ listBlocks.push(current);
379
+ i++;
380
+ } else break;
381
+ }
382
+ content.push(convertList(listBlocks, listType));
383
+ } else {
384
+ const converted = convertBlock(block);
385
+ if (converted) content.push(converted);
386
+ i++;
387
+ }
388
+ }
389
+ return {
390
+ type: "doc",
391
+ content: content.length > 0 ? content : [{ type: "paragraph" }]
392
+ };
393
+ }
394
+ /**
395
+ * Type guard for text blocks
396
+ */
397
+ function isTextBlock(block) {
398
+ return block._type === "block";
399
+ }
400
+ /**
401
+ * Type guard for image blocks.
402
+ * Checks both `_type` and that `asset` is a valid object — image blocks
403
+ * without an `asset` wrapper (e.g. `{ _type: "image", url: "..." }`) are
404
+ * malformed and should not be cast to `PortableTextImageBlock`.
405
+ */
406
+ function isImageBlock(block) {
407
+ return block._type === "image" && "asset" in block && typeof block.asset === "object" && block.asset !== null;
408
+ }
409
+ /**
410
+ * Type guard for code blocks
411
+ */
412
+ function isCodeBlock(block) {
413
+ return block._type === "code";
414
+ }
415
+ /**
416
+ * Convert a single Portable Text block to ProseMirror node
417
+ */
418
+ function convertBlock(block) {
419
+ if (isTextBlock(block)) return convertTextBlock(block);
420
+ if (isImageBlock(block)) return convertImage(block);
421
+ if (block._type === "image") return convertMalformedImage(block);
422
+ if (isCodeBlock(block)) return convertCodeBlock(block);
423
+ if (block._type === "break") return { type: "horizontalRule" };
424
+ return {
425
+ type: "paragraph",
426
+ content: [{
427
+ type: "text",
428
+ text: `[Unknown block type: ${block._type}]`,
429
+ marks: [{ type: "code" }]
430
+ }]
431
+ };
432
+ }
433
+ /**
434
+ * Convert text block to ProseMirror paragraph or heading
435
+ */
436
+ function convertTextBlock(block) {
437
+ const { style = "normal", children, markDefs = [] } = block;
438
+ const content = convertSpans(children, markDefs);
439
+ switch (style) {
440
+ case "h1":
441
+ case "h2":
442
+ case "h3":
443
+ case "h4":
444
+ case "h5":
445
+ case "h6": return {
446
+ type: "heading",
447
+ attrs: { level: parseInt(style.substring(1), 10) },
448
+ content: content.length > 0 ? content : void 0
449
+ };
450
+ case "blockquote": return {
451
+ type: "blockquote",
452
+ content: [{
453
+ type: "paragraph",
454
+ content: content.length > 0 ? content : void 0
455
+ }]
456
+ };
457
+ default: return {
458
+ type: "paragraph",
459
+ content: content.length > 0 ? content : void 0
460
+ };
461
+ }
462
+ }
463
+ /**
464
+ * Convert list items to ProseMirror list
465
+ */
466
+ function convertList(items, listType) {
467
+ const rootItems = [];
468
+ let i = 0;
469
+ while (i < items.length) {
470
+ const item = items[i];
471
+ if ((item.level || 1) === 1) {
472
+ const nestedItems = [];
473
+ i++;
474
+ while (i < items.length && (items[i].level || 1) > 1) {
475
+ nestedItems.push(items[i]);
476
+ i++;
477
+ }
478
+ rootItems.push(convertListItem(item, nestedItems, listType));
479
+ } else {
480
+ rootItems.push(convertListItem(item, [], listType));
481
+ i++;
482
+ }
483
+ }
484
+ return {
485
+ type: listType === "bullet" ? "bulletList" : "orderedList",
486
+ content: rootItems
487
+ };
488
+ }
489
+ /**
490
+ * Convert a single list item to ProseMirror
491
+ */
492
+ function convertListItem(item, nestedItems, parentListType) {
493
+ const content = [];
494
+ const spans = convertSpans(item.children, item.markDefs || []);
495
+ content.push({
496
+ type: "paragraph",
497
+ content: spans.length > 0 ? spans : void 0
498
+ });
499
+ if (nestedItems.length > 0) {
500
+ let j = 0;
501
+ while (j < nestedItems.length) {
502
+ const nestedListType = nestedItems[j].listItem || parentListType;
503
+ const nestedGroup = [];
504
+ while (j < nestedItems.length && (nestedItems[j].listItem || parentListType) === nestedListType) {
505
+ nestedGroup.push(nestedItems[j]);
506
+ j++;
507
+ }
508
+ if (nestedGroup.length > 0) {
509
+ const adjustedGroup = nestedGroup.map((ni) => ({
510
+ ...ni,
511
+ level: (ni.level || 2) - 1
512
+ }));
513
+ content.push(convertList(adjustedGroup, nestedListType));
514
+ }
515
+ }
516
+ }
517
+ return {
518
+ type: "listItem",
519
+ content
520
+ };
521
+ }
522
+ /**
523
+ * Convert Portable Text spans to ProseMirror text nodes
524
+ */
525
+ function convertSpans(spans, markDefs) {
526
+ const nodes = [];
527
+ const markDefsMap = new Map(markDefs.map((md) => [md._key, md]));
528
+ for (const span of spans) {
529
+ if (span._type !== "span") continue;
530
+ const parts = span.text.split("\n");
531
+ for (let i = 0; i < parts.length; i++) {
532
+ const text = parts[i];
533
+ if (text.length > 0) {
534
+ const marks = convertMarks(span.marks || [], markDefsMap);
535
+ const node = {
536
+ type: "text",
537
+ text
538
+ };
539
+ if (marks.length > 0) node.marks = marks;
540
+ nodes.push(node);
541
+ }
542
+ if (i < parts.length - 1) nodes.push({ type: "hardBreak" });
543
+ }
544
+ }
545
+ return nodes;
546
+ }
547
+ /**
548
+ * Convert Portable Text marks to ProseMirror marks
549
+ */
550
+ function convertMarks(marks, markDefs) {
551
+ const pmMarks = [];
552
+ for (const mark of marks) switch (mark) {
553
+ case "strong":
554
+ pmMarks.push({ type: "bold" });
555
+ break;
556
+ case "em":
557
+ pmMarks.push({ type: "italic" });
558
+ break;
559
+ case "underline":
560
+ pmMarks.push({ type: "underline" });
561
+ break;
562
+ case "strike-through":
563
+ pmMarks.push({ type: "strike" });
564
+ break;
565
+ case "code":
566
+ pmMarks.push({ type: "code" });
567
+ break;
568
+ default: {
569
+ const markDef = markDefs.get(mark);
570
+ if (markDef) if (markDef._type === "link") pmMarks.push({
571
+ type: "link",
572
+ attrs: {
573
+ href: markDef.href,
574
+ target: markDef.blank ? "_blank" : null
575
+ }
576
+ });
577
+ else pmMarks.push({
578
+ type: markDef._type,
579
+ attrs: markDef
580
+ });
581
+ break;
582
+ }
583
+ }
584
+ return pmMarks;
585
+ }
586
+ /**
587
+ * Convert image block to ProseMirror
588
+ */
589
+ function convertImage(block) {
590
+ return {
591
+ type: "image",
592
+ attrs: {
593
+ src: block.asset.url || block.asset._ref,
594
+ alt: block.alt || "",
595
+ title: block.caption || "",
596
+ mediaId: block.asset._ref,
597
+ provider: block.asset.provider,
598
+ width: block.width,
599
+ height: block.height,
600
+ displayWidth: block.displayWidth,
601
+ displayHeight: block.displayHeight
602
+ }
603
+ };
604
+ }
605
+ /**
606
+ * Convert a malformed image block (missing `asset` wrapper) to ProseMirror.
607
+ * Handles blocks like `{ _type: "image", url: "...", alt: "..." }` that may
608
+ * originate from migrations or third-party imports.
609
+ */
610
+ function convertMalformedImage(block) {
611
+ return {
612
+ type: "image",
613
+ attrs: {
614
+ src: "url" in block && typeof block.url === "string" ? block.url : "",
615
+ alt: "alt" in block && typeof block.alt === "string" ? block.alt : "",
616
+ title: "caption" in block && typeof block.caption === "string" ? block.caption : "",
617
+ mediaId: void 0,
618
+ provider: void 0,
619
+ width: "width" in block && typeof block.width === "number" ? block.width : void 0,
620
+ height: "height" in block && typeof block.height === "number" ? block.height : void 0,
621
+ displayWidth: "displayWidth" in block && typeof block.displayWidth === "number" ? block.displayWidth : void 0,
622
+ displayHeight: "displayHeight" in block && typeof block.displayHeight === "number" ? block.displayHeight : void 0
623
+ }
624
+ };
625
+ }
626
+ /**
627
+ * Convert code block to ProseMirror
628
+ */
629
+ function convertCodeBlock(block) {
630
+ return {
631
+ type: "codeBlock",
632
+ attrs: { language: block.language || null },
633
+ content: block.code ? [{
634
+ type: "text",
635
+ text: block.code
636
+ }] : void 0
637
+ };
638
+ }
639
+
640
+ //#endregion
641
+ //#region src/after.ts
642
+ const waitUntilReady = (async () => {
643
+ try {
644
+ return (await import("virtual:emdash/wait-until")).waitUntil ?? null;
645
+ } catch {
646
+ return null;
647
+ }
648
+ })();
649
+ waitUntilReady.catch(() => {});
650
+ /**
651
+ * Schedule `fn` to run without blocking the response.
652
+ *
653
+ * Errors are caught and logged — a deferred task should never surface
654
+ * as an unhandled rejection because the response is long gone. Callers
655
+ * that care about errors should handle them inside `fn`.
656
+ */
657
+ function after(fn) {
658
+ const promise = Promise.resolve().then(fn).catch((error) => {
659
+ console.error("[emdash] deferred task failed:", error);
660
+ });
661
+ waitUntilReady.then((waitUntil) => {
662
+ if (waitUntil) waitUntil(promise);
663
+ return null;
664
+ });
665
+ }
666
+
667
+ //#endregion
668
+ //#region src/plugins/define-plugin.ts
669
+ /**
670
+ * definePlugin() Helper
671
+ *
672
+ * Native plugin authoring entry. Returns a fully-resolved
673
+ * `ResolvedPlugin` ready for the host integration to mount.
674
+ *
675
+ * Sandboxed plugins do NOT use this function. They default-export
676
+ * a bare `{ hooks?, routes? }` object with a `satisfies SandboxedPlugin`
677
+ * annotation from `emdash/plugin`. See the `emdash` changeset for the
678
+ * authoring shape.
679
+ */
680
+ const SIMPLE_ID = /^[a-z0-9-]+$/;
681
+ const SCOPED_ID = /^@[a-z0-9-]+\/[a-z0-9-]+$/;
682
+ const SEMVER_PATTERN = /^\d+\.\d+\.\d+/;
683
+ /**
684
+ * Define a native EmDash plugin.
685
+ *
686
+ * Native plugins ship as regular npm modules, get installed via
687
+ * `pnpm add` + an `astro.config.mjs` edit, and run in the host
688
+ * process. They have full access to the runtime — capabilities are
689
+ * still enforced by `PluginContextFactory`, but there is no isolation
690
+ * boundary.
691
+ *
692
+ * @example
693
+ * ```typescript
694
+ * import { definePlugin } from "emdash";
695
+ *
696
+ * export default definePlugin({
697
+ * id: "my-plugin",
698
+ * version: "1.0.0",
699
+ * capabilities: ["content:read"],
700
+ * hooks: {
701
+ * "content:beforeSave": async (event, ctx) => {
702
+ * ctx.log.info("Saving content", { collection: event.collection });
703
+ * return event.content;
704
+ * }
705
+ * },
706
+ * routes: {
707
+ * "sync": {
708
+ * handler: async (ctx) => {
709
+ * return { status: "ok" };
710
+ * }
711
+ * }
712
+ * }
713
+ * });
714
+ * ```
715
+ *
716
+ * Sandboxed-format plugins do not use `definePlugin`. They
717
+ * default-export a bare `{ hooks?, routes? }` object with a
718
+ * `satisfies SandboxedPlugin` annotation from `emdash/plugin`. Calling
719
+ * `definePlugin` with an object that has no `id` throws at runtime
720
+ * (the type system already rejects it at compile time — this check is
721
+ * for callers that bypass typechecking).
722
+ */
723
+ function definePlugin(definition) {
724
+ if (typeof definition.id !== "string" || definition.id.length === 0) throw new Error(`definePlugin() requires \`id\` (got ${typeof definition.id}). For native plugins, make sure your definition has both \`id\` and \`version\`. For sandboxed plugins, drop \`definePlugin()\` entirely and \`export default { hooks, routes } satisfies SandboxedPlugin\` from "emdash/plugin" — identity comes from \`emdash-plugin.jsonc\`.`);
725
+ return defineNativePlugin(definition);
726
+ }
727
+ /**
728
+ * Internal: define a native-format plugin with full validation and normalization.
729
+ */
730
+ function defineNativePlugin(definition) {
731
+ const { id, version, capabilities = [], allowedHosts = [], hooks = {}, routes = {}, admin = {} } = definition;
732
+ const storage = definition.storage ?? {};
733
+ if (!SIMPLE_ID.test(id) && !SCOPED_ID.test(id)) throw new Error(`Invalid plugin id "${id}". Must be lowercase alphanumeric with dashes (e.g., "my-plugin" or "@scope/my-plugin").`);
734
+ if (!SEMVER_PATTERN.test(version)) throw new Error(`Invalid plugin version "${version}". Must be semver format (e.g., "1.0.0").`);
735
+ const validCapabilities = new Set([
736
+ "network:request",
737
+ "network:request:unrestricted",
738
+ "content:read",
739
+ "content:write",
740
+ "media:read",
741
+ "media:write",
742
+ "users:read",
743
+ "email:send",
744
+ "hooks.email-transport:register",
745
+ "hooks.email-events:register",
746
+ "hooks.page-fragments:register",
747
+ "network:fetch",
748
+ "network:fetch:any",
749
+ "read:content",
750
+ "write:content",
751
+ "read:media",
752
+ "write:media",
753
+ "read:users",
754
+ "email:provide",
755
+ "email:intercept",
756
+ "page:inject"
757
+ ]);
758
+ for (const cap of capabilities) if (!validCapabilities.has(cap)) throw new Error(`Invalid capability "${cap}" in plugin "${id}".`);
759
+ const canonical = normalizeCapabilities(capabilities);
760
+ const normalizedCapabilities = [...canonical];
761
+ if (canonical.includes("content:write") && !canonical.includes("content:read")) normalizedCapabilities.push("content:read");
762
+ if (canonical.includes("media:write") && !canonical.includes("media:read")) normalizedCapabilities.push("media:read");
763
+ if (canonical.includes("network:request:unrestricted") && !canonical.includes("network:request")) normalizedCapabilities.push("network:request");
764
+ return {
765
+ id,
766
+ version,
767
+ capabilities: normalizedCapabilities,
768
+ allowedHosts,
769
+ storage,
770
+ hooks: resolveHooks(hooks, id),
771
+ routes,
772
+ admin
773
+ };
774
+ }
775
+ /**
776
+ * Resolve hooks to normalized format with defaults.
777
+ *
778
+ * PluginHooks and ResolvedPluginHooks share the same keys — each input value is
779
+ * `HookConfig<H> | H` and the output is `ResolvedHook<H>`. TS can't narrow
780
+ * the handler type through a dynamic key, so we assert at the loop boundary.
781
+ */
782
+ function resolveHooks(hooks, pluginId) {
783
+ const resolved = {};
784
+ for (const key of Object.keys(hooks)) {
785
+ const hook = hooks[key];
786
+ if (hook) resolved[key] = resolveHook(hook, pluginId);
787
+ }
788
+ return resolved;
789
+ }
790
+ /**
791
+ * Check if a hook value is a config object (has a `handler` property)
792
+ */
793
+ function isHookConfig(hook) {
794
+ return typeof hook === "object" && hook !== null && "handler" in hook;
795
+ }
796
+ /**
797
+ * Resolve a single hook to normalized format
798
+ */
799
+ function resolveHook(hook, pluginId) {
800
+ if (isHookConfig(hook)) {
801
+ if (hook.exclusive !== void 0 && typeof hook.exclusive !== "boolean") throw new Error(`Invalid "exclusive" value in hook config for plugin "${pluginId}". Must be boolean.`);
802
+ return {
803
+ priority: hook.priority ?? 100,
804
+ timeout: hook.timeout ?? 5e3,
805
+ dependencies: hook.dependencies ?? [],
806
+ errorPolicy: hook.errorPolicy ?? "abort",
807
+ exclusive: hook.exclusive ?? false,
808
+ handler: hook.handler,
809
+ pluginId
810
+ };
811
+ }
812
+ return {
813
+ priority: 100,
814
+ timeout: 5e3,
815
+ dependencies: [],
816
+ errorPolicy: "abort",
817
+ exclusive: false,
818
+ handler: hook,
819
+ pluginId
820
+ };
821
+ }
822
+
823
+ //#endregion
824
+ //#region src/plugins/hooks.ts
825
+ /**
826
+ * Plugin Hooks System v2
827
+ *
828
+ * Uses the unified PluginContext for all hooks.
829
+ * Manages lifecycle hooks with:
830
+ * - Deterministic ordering via priority + dependencies
831
+ * - Timeout enforcement
832
+ * - Error isolation
833
+ * - Observability
834
+ *
835
+ */
836
+ /**
837
+ * Hook pipeline for executing hooks in order
838
+ */
839
+ var HookPipeline = class HookPipeline {
840
+ hooks = /* @__PURE__ */ new Map();
841
+ pluginMap = /* @__PURE__ */ new Map();
842
+ contextFactory = null;
843
+ /** Stored so setContextFactory can merge incrementally. */
844
+ contextFactoryOptions = {};
845
+ /** Hook names where at least one handler declared exclusive: true */
846
+ exclusiveHookNames = /* @__PURE__ */ new Set();
847
+ /**
848
+ * Selected provider plugin ID for each exclusive hook.
849
+ * Set by the PluginManager after resolution.
850
+ */
851
+ exclusiveSelections = /* @__PURE__ */ new Map();
852
+ constructor(plugins, factoryOptions) {
853
+ if (factoryOptions) {
854
+ this.contextFactory = new PluginContextFactory(factoryOptions);
855
+ this.contextFactoryOptions = { ...factoryOptions };
856
+ }
857
+ for (const plugin of plugins) this.pluginMap.set(plugin.id, plugin);
858
+ this.registerPlugins(plugins);
859
+ }
860
+ /**
861
+ * Set or update the context factory options.
862
+ *
863
+ * When called on a pipeline that already has a factory, the new options
864
+ * are merged on top of the existing ones so that callers don't need to
865
+ * repeat every field (e.g. adding `cronReschedule` without losing
866
+ * `storage` / `getUploadUrl`).
867
+ */
868
+ setContextFactory(options) {
869
+ const merged = {
870
+ ...this.contextFactoryOptions,
871
+ ...options
872
+ };
873
+ this.contextFactory = new PluginContextFactory(merged);
874
+ this.contextFactoryOptions = merged;
875
+ }
876
+ /**
877
+ * Get context for a plugin
878
+ */
879
+ getContext(pluginId) {
880
+ const plugin = this.pluginMap.get(pluginId);
881
+ if (!plugin) throw new Error(`Plugin "${pluginId}" not found`);
882
+ if (!this.contextFactory) throw new Error("Context factory not initialized - call setContextFactory first");
883
+ return this.contextFactory.createContext(plugin);
884
+ }
885
+ /**
886
+ * Get typed hooks for a specific hook name.
887
+ * The internal map stores ResolvedHook<unknown>, but we know each name
888
+ * maps to a specific handler type via HookHandlerMap.
889
+ *
890
+ * Exclusive hooks that have a selected provider are filtered out — they
891
+ * should only run via invokeExclusiveHook(), not in the regular pipeline.
892
+ */
893
+ getTypedHooks(name) {
894
+ const all = this.hooks.get(name) ?? [];
895
+ if (this.exclusiveSelections.has(name)) return all.filter((h) => !h.exclusive);
896
+ return all;
897
+ }
898
+ /**
899
+ * Register all hooks from plugins.
900
+ *
901
+ * Registers each hook name individually to preserve type safety. The
902
+ * internal map stores ResolvedHook<unknown> since it's keyed by string,
903
+ * but getTypedHooks() restores the correct handler type on retrieval.
904
+ */
905
+ registerPlugins(plugins) {
906
+ for (const plugin of plugins) {
907
+ this.registerPluginHook(plugin, "plugin:install");
908
+ this.registerPluginHook(plugin, "plugin:activate");
909
+ this.registerPluginHook(plugin, "plugin:deactivate");
910
+ this.registerPluginHook(plugin, "plugin:uninstall");
911
+ this.registerPluginHook(plugin, "content:beforeSave");
912
+ this.registerPluginHook(plugin, "content:afterSave");
913
+ this.registerPluginHook(plugin, "content:beforeDelete");
914
+ this.registerPluginHook(plugin, "content:afterDelete");
915
+ this.registerPluginHook(plugin, "content:afterPublish");
916
+ this.registerPluginHook(plugin, "content:afterUnpublish");
917
+ this.registerPluginHook(plugin, "media:beforeUpload");
918
+ this.registerPluginHook(plugin, "media:afterUpload");
919
+ this.registerPluginHook(plugin, "cron");
920
+ this.registerPluginHook(plugin, "email:beforeSend");
921
+ this.registerPluginHook(plugin, "email:deliver");
922
+ this.registerPluginHook(plugin, "email:afterSend");
923
+ this.registerPluginHook(plugin, "comment:beforeCreate");
924
+ this.registerPluginHook(plugin, "comment:moderate");
925
+ this.registerPluginHook(plugin, "comment:afterCreate");
926
+ this.registerPluginHook(plugin, "comment:afterModerate");
927
+ this.registerPluginHook(plugin, "page:metadata");
928
+ this.registerPluginHook(plugin, "page:fragments");
929
+ }
930
+ for (const [hookName, hooks] of this.hooks) this.hooks.set(hookName, this.sortHooks(hooks));
931
+ }
932
+ /**
933
+ * Maps hook names to the capability required to register them.
934
+ *
935
+ * Hooks not listed here have no capability requirement (e.g. lifecycle
936
+ * hooks, cron). Any plugin declaring a listed hook without the required
937
+ * capability will have that hook silently skipped at registration time.
938
+ */
939
+ static HOOK_REQUIRED_CAPABILITY = new Map([
940
+ ["email:beforeSend", "hooks.email-events:register"],
941
+ ["email:afterSend", "hooks.email-events:register"],
942
+ ["email:deliver", "hooks.email-transport:register"],
943
+ ["content:beforeSave", "content:write"],
944
+ ["content:afterSave", "content:read"],
945
+ ["content:beforeDelete", "content:read"],
946
+ ["content:afterDelete", "content:read"],
947
+ ["content:afterPublish", "content:read"],
948
+ ["content:afterUnpublish", "content:read"],
949
+ ["media:beforeUpload", "media:write"],
950
+ ["media:afterUpload", "media:read"],
951
+ ["comment:beforeCreate", "users:read"],
952
+ ["comment:moderate", "users:read"],
953
+ ["comment:afterCreate", "users:read"],
954
+ ["comment:afterModerate", "users:read"],
955
+ ["page:fragments", "hooks.page-fragments:register"]
956
+ ]);
957
+ /**
958
+ * Register a single plugin's hook by name
959
+ */
960
+ registerPluginHook(plugin, name) {
961
+ const hook = plugin.hooks[name];
962
+ if (!hook) return;
963
+ const requiredCapability = HookPipeline.HOOK_REQUIRED_CAPABILITY.get(name);
964
+ if (requiredCapability && !plugin.capabilities.includes(requiredCapability)) {
965
+ console.warn(`[hooks] Plugin "${plugin.id}" declares ${name} hook without ${requiredCapability} capability — skipping`);
966
+ return;
967
+ }
968
+ if (hook.exclusive) this.exclusiveHookNames.add(name);
969
+ this.registerHook(name, hook);
970
+ }
971
+ /**
972
+ * Register a single hook
973
+ */
974
+ registerHook(name, hook) {
975
+ const existing = this.hooks.get(name) || [];
976
+ existing.push(hook);
977
+ this.hooks.set(name, existing);
978
+ }
979
+ /**
980
+ * Sort hooks by priority and dependencies
981
+ */
982
+ sortHooks(hooks) {
983
+ const sorted = [];
984
+ const remaining = [...hooks];
985
+ while (remaining.length > 0) {
986
+ const ready = remaining.filter((hook) => hook.dependencies.every((dep) => sorted.some((s) => s.pluginId === dep)));
987
+ if (ready.length === 0) {
988
+ const pluginIds = remaining.map((h) => h.pluginId).join(", ");
989
+ console.warn(`[hooks] Hook dependency cycle or missing dependency detected among plugins: ${pluginIds}. Falling back to priority order.`);
990
+ remaining.sort((a, b) => a.priority - b.priority);
991
+ sorted.push(...remaining);
992
+ break;
993
+ }
994
+ ready.sort((a, b) => a.priority - b.priority);
995
+ const next = ready[0];
996
+ sorted.push(next);
997
+ remaining.splice(remaining.indexOf(next), 1);
998
+ }
999
+ return sorted;
1000
+ }
1001
+ /**
1002
+ * Execute a hook with timeout
1003
+ */
1004
+ async executeWithTimeout(fn, timeout) {
1005
+ let timer;
1006
+ const timeoutPromise = new Promise((_, reject) => timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Hook timeout after ${timeout}ms`)), timeout));
1007
+ try {
1008
+ return await Promise.race([fn(), timeoutPromise]);
1009
+ } finally {
1010
+ clearTimeout(timer);
1011
+ }
1012
+ }
1013
+ /**
1014
+ * Run plugin:install hooks
1015
+ */
1016
+ async runPluginInstall(pluginId) {
1017
+ return this.runLifecycleHook("plugin:install", pluginId);
1018
+ }
1019
+ /**
1020
+ * Run plugin:activate hooks
1021
+ */
1022
+ async runPluginActivate(pluginId) {
1023
+ return this.runLifecycleHook("plugin:activate", pluginId);
1024
+ }
1025
+ /**
1026
+ * Run plugin:deactivate hooks
1027
+ */
1028
+ async runPluginDeactivate(pluginId) {
1029
+ return this.runLifecycleHook("plugin:deactivate", pluginId);
1030
+ }
1031
+ /**
1032
+ * Run plugin:uninstall hooks
1033
+ */
1034
+ async runPluginUninstall(pluginId, deleteData) {
1035
+ const hooks = this.getTypedHooks("plugin:uninstall");
1036
+ const results = [];
1037
+ const hook = hooks.find((h) => h.pluginId === pluginId);
1038
+ if (!hook) return results;
1039
+ const { handler } = hook;
1040
+ const event = { deleteData };
1041
+ const ctx = this.getContext(pluginId);
1042
+ const start = Date.now();
1043
+ try {
1044
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1045
+ results.push({
1046
+ success: true,
1047
+ pluginId: hook.pluginId,
1048
+ duration: Date.now() - start
1049
+ });
1050
+ } catch (error) {
1051
+ results.push({
1052
+ success: false,
1053
+ error: error instanceof Error ? error : new Error(String(error)),
1054
+ pluginId: hook.pluginId,
1055
+ duration: Date.now() - start
1056
+ });
1057
+ }
1058
+ return results;
1059
+ }
1060
+ async runLifecycleHook(hookName, pluginId) {
1061
+ const hooks = this.getTypedHooks(hookName);
1062
+ const results = [];
1063
+ const hook = hooks.find((h) => h.pluginId === pluginId);
1064
+ if (!hook) return results;
1065
+ const { handler } = hook;
1066
+ const event = {};
1067
+ const ctx = this.getContext(pluginId);
1068
+ const start = Date.now();
1069
+ try {
1070
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1071
+ results.push({
1072
+ success: true,
1073
+ pluginId: hook.pluginId,
1074
+ duration: Date.now() - start
1075
+ });
1076
+ } catch (error) {
1077
+ results.push({
1078
+ success: false,
1079
+ error: error instanceof Error ? error : new Error(String(error)),
1080
+ pluginId: hook.pluginId,
1081
+ duration: Date.now() - start
1082
+ });
1083
+ }
1084
+ return results;
1085
+ }
1086
+ /**
1087
+ * Run content:beforeSave hooks
1088
+ * Returns modified content from the pipeline
1089
+ */
1090
+ async runContentBeforeSave(content, collection, isNew) {
1091
+ const hooks = this.getTypedHooks("content:beforeSave");
1092
+ const results = [];
1093
+ let currentContent = content;
1094
+ for (const hook of hooks) {
1095
+ const { handler } = hook;
1096
+ const event = {
1097
+ content: currentContent,
1098
+ collection,
1099
+ isNew
1100
+ };
1101
+ const ctx = this.getContext(hook.pluginId);
1102
+ const start = Date.now();
1103
+ try {
1104
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1105
+ if (result !== void 0) currentContent = result;
1106
+ results.push({
1107
+ success: true,
1108
+ value: currentContent,
1109
+ pluginId: hook.pluginId,
1110
+ duration: Date.now() - start
1111
+ });
1112
+ } catch (error) {
1113
+ results.push({
1114
+ success: false,
1115
+ error: error instanceof Error ? error : new Error(String(error)),
1116
+ pluginId: hook.pluginId,
1117
+ duration: Date.now() - start
1118
+ });
1119
+ if (hook.errorPolicy === "abort") throw error;
1120
+ }
1121
+ }
1122
+ return {
1123
+ content: currentContent,
1124
+ results
1125
+ };
1126
+ }
1127
+ /**
1128
+ * Run content:afterSave hooks
1129
+ */
1130
+ async runContentAfterSave(content, collection, isNew) {
1131
+ const hooks = this.getTypedHooks("content:afterSave");
1132
+ const results = [];
1133
+ for (const hook of hooks) {
1134
+ const { handler } = hook;
1135
+ const event = {
1136
+ content,
1137
+ collection,
1138
+ isNew
1139
+ };
1140
+ const ctx = this.getContext(hook.pluginId);
1141
+ const start = Date.now();
1142
+ try {
1143
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1144
+ results.push({
1145
+ success: true,
1146
+ pluginId: hook.pluginId,
1147
+ duration: Date.now() - start
1148
+ });
1149
+ } catch (error) {
1150
+ results.push({
1151
+ success: false,
1152
+ error: error instanceof Error ? error : new Error(String(error)),
1153
+ pluginId: hook.pluginId,
1154
+ duration: Date.now() - start
1155
+ });
1156
+ if (hook.errorPolicy === "abort") throw error;
1157
+ }
1158
+ }
1159
+ return results;
1160
+ }
1161
+ /**
1162
+ * Run content:beforeDelete hooks
1163
+ * Returns whether deletion is allowed
1164
+ */
1165
+ async runContentBeforeDelete(id, collection) {
1166
+ const hooks = this.getTypedHooks("content:beforeDelete");
1167
+ const results = [];
1168
+ let allowed = true;
1169
+ for (const hook of hooks) {
1170
+ const { handler } = hook;
1171
+ const event = {
1172
+ id,
1173
+ collection,
1174
+ permanent: false
1175
+ };
1176
+ const ctx = this.getContext(hook.pluginId);
1177
+ const start = Date.now();
1178
+ try {
1179
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1180
+ if (result === false) allowed = false;
1181
+ results.push({
1182
+ success: true,
1183
+ value: result !== false,
1184
+ pluginId: hook.pluginId,
1185
+ duration: Date.now() - start
1186
+ });
1187
+ } catch (error) {
1188
+ results.push({
1189
+ success: false,
1190
+ error: error instanceof Error ? error : new Error(String(error)),
1191
+ pluginId: hook.pluginId,
1192
+ duration: Date.now() - start
1193
+ });
1194
+ if (hook.errorPolicy === "abort") throw error;
1195
+ }
1196
+ }
1197
+ return {
1198
+ allowed,
1199
+ results
1200
+ };
1201
+ }
1202
+ /**
1203
+ * Run content:afterDelete hooks
1204
+ */
1205
+ async runContentAfterDelete(id, collection, permanent) {
1206
+ const hooks = this.getTypedHooks("content:afterDelete");
1207
+ const results = [];
1208
+ for (const hook of hooks) {
1209
+ const { handler } = hook;
1210
+ const event = {
1211
+ id,
1212
+ collection,
1213
+ permanent
1214
+ };
1215
+ const ctx = this.getContext(hook.pluginId);
1216
+ const start = Date.now();
1217
+ try {
1218
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1219
+ results.push({
1220
+ success: true,
1221
+ pluginId: hook.pluginId,
1222
+ duration: Date.now() - start
1223
+ });
1224
+ } catch (error) {
1225
+ results.push({
1226
+ success: false,
1227
+ error: error instanceof Error ? error : new Error(String(error)),
1228
+ pluginId: hook.pluginId,
1229
+ duration: Date.now() - start
1230
+ });
1231
+ if (hook.errorPolicy === "abort") throw error;
1232
+ }
1233
+ }
1234
+ return results;
1235
+ }
1236
+ /**
1237
+ * Run content:afterPublish hooks (fire-and-forget).
1238
+ */
1239
+ async runContentAfterPublish(content, collection) {
1240
+ const hooks = this.getTypedHooks("content:afterPublish");
1241
+ const results = [];
1242
+ for (const hook of hooks) {
1243
+ const { handler } = hook;
1244
+ const event = {
1245
+ content,
1246
+ collection
1247
+ };
1248
+ const ctx = this.getContext(hook.pluginId);
1249
+ const start = Date.now();
1250
+ try {
1251
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1252
+ results.push({
1253
+ success: true,
1254
+ pluginId: hook.pluginId,
1255
+ duration: Date.now() - start
1256
+ });
1257
+ } catch (error) {
1258
+ results.push({
1259
+ success: false,
1260
+ error: error instanceof Error ? error : new Error(String(error)),
1261
+ pluginId: hook.pluginId,
1262
+ duration: Date.now() - start
1263
+ });
1264
+ if (hook.errorPolicy === "abort") throw error;
1265
+ }
1266
+ }
1267
+ return results;
1268
+ }
1269
+ /**
1270
+ * Run content:afterUnpublish hooks (fire-and-forget).
1271
+ */
1272
+ async runContentAfterUnpublish(content, collection) {
1273
+ const hooks = this.getTypedHooks("content:afterUnpublish");
1274
+ const results = [];
1275
+ for (const hook of hooks) {
1276
+ const { handler } = hook;
1277
+ const event = {
1278
+ content,
1279
+ collection
1280
+ };
1281
+ const ctx = this.getContext(hook.pluginId);
1282
+ const start = Date.now();
1283
+ try {
1284
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1285
+ results.push({
1286
+ success: true,
1287
+ pluginId: hook.pluginId,
1288
+ duration: Date.now() - start
1289
+ });
1290
+ } catch (error) {
1291
+ results.push({
1292
+ success: false,
1293
+ error: error instanceof Error ? error : new Error(String(error)),
1294
+ pluginId: hook.pluginId,
1295
+ duration: Date.now() - start
1296
+ });
1297
+ if (hook.errorPolicy === "abort") throw error;
1298
+ }
1299
+ }
1300
+ return results;
1301
+ }
1302
+ /**
1303
+ * Run media:beforeUpload hooks
1304
+ */
1305
+ async runMediaBeforeUpload(file) {
1306
+ const hooks = this.getTypedHooks("media:beforeUpload");
1307
+ const results = [];
1308
+ let currentFile = file;
1309
+ for (const hook of hooks) {
1310
+ const { handler } = hook;
1311
+ const event = { file: currentFile };
1312
+ const ctx = this.getContext(hook.pluginId);
1313
+ const start = Date.now();
1314
+ try {
1315
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1316
+ if (result !== void 0) currentFile = result;
1317
+ results.push({
1318
+ success: true,
1319
+ value: currentFile,
1320
+ pluginId: hook.pluginId,
1321
+ duration: Date.now() - start
1322
+ });
1323
+ } catch (error) {
1324
+ results.push({
1325
+ success: false,
1326
+ error: error instanceof Error ? error : new Error(String(error)),
1327
+ pluginId: hook.pluginId,
1328
+ duration: Date.now() - start
1329
+ });
1330
+ if (hook.errorPolicy === "abort") throw error;
1331
+ }
1332
+ }
1333
+ return {
1334
+ file: currentFile,
1335
+ results
1336
+ };
1337
+ }
1338
+ /**
1339
+ * Run media:afterUpload hooks
1340
+ */
1341
+ async runMediaAfterUpload(media) {
1342
+ const hooks = this.getTypedHooks("media:afterUpload");
1343
+ const results = [];
1344
+ for (const hook of hooks) {
1345
+ const { handler } = hook;
1346
+ const event = { media };
1347
+ const ctx = this.getContext(hook.pluginId);
1348
+ const start = Date.now();
1349
+ try {
1350
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1351
+ results.push({
1352
+ success: true,
1353
+ pluginId: hook.pluginId,
1354
+ duration: Date.now() - start
1355
+ });
1356
+ } catch (error) {
1357
+ results.push({
1358
+ success: false,
1359
+ error: error instanceof Error ? error : new Error(String(error)),
1360
+ pluginId: hook.pluginId,
1361
+ duration: Date.now() - start
1362
+ });
1363
+ if (hook.errorPolicy === "abort") throw error;
1364
+ }
1365
+ }
1366
+ return results;
1367
+ }
1368
+ /**
1369
+ * Invoke the cron hook for a specific plugin.
1370
+ *
1371
+ * Unlike other hooks which broadcast to all plugins, the cron hook is
1372
+ * dispatched only to the target plugin — the one that owns the task.
1373
+ */
1374
+ async invokeCronHook(pluginId, event) {
1375
+ const hook = this.getTypedHooks("cron").find((h) => h.pluginId === pluginId);
1376
+ if (!hook) return {
1377
+ success: false,
1378
+ error: /* @__PURE__ */ new Error(`Plugin "${pluginId}" has no cron hook registered`),
1379
+ pluginId,
1380
+ duration: 0
1381
+ };
1382
+ const { handler } = hook;
1383
+ const ctx = this.getContext(pluginId);
1384
+ const start = Date.now();
1385
+ try {
1386
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1387
+ return {
1388
+ success: true,
1389
+ pluginId,
1390
+ duration: Date.now() - start
1391
+ };
1392
+ } catch (error) {
1393
+ return {
1394
+ success: false,
1395
+ error: error instanceof Error ? error : new Error(String(error)),
1396
+ pluginId,
1397
+ duration: Date.now() - start
1398
+ };
1399
+ }
1400
+ }
1401
+ /**
1402
+ * Run email:beforeSend hooks (middleware pipeline).
1403
+ *
1404
+ * Each handler receives the message and returns a modified message or
1405
+ * `false` to cancel delivery. The pipeline chains message transformations —
1406
+ * each handler receives the output of the previous one.
1407
+ */
1408
+ async runEmailBeforeSend(message, source) {
1409
+ const hooks = this.getTypedHooks("email:beforeSend");
1410
+ const results = [];
1411
+ let currentMessage = message;
1412
+ for (const hook of hooks) {
1413
+ const { handler } = hook;
1414
+ const event = {
1415
+ message: { ...currentMessage },
1416
+ source
1417
+ };
1418
+ const ctx = this.getContext(hook.pluginId);
1419
+ const start = Date.now();
1420
+ try {
1421
+ const result = await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1422
+ if (result === false) {
1423
+ results.push({
1424
+ success: true,
1425
+ value: false,
1426
+ pluginId: hook.pluginId,
1427
+ duration: Date.now() - start
1428
+ });
1429
+ return {
1430
+ message: false,
1431
+ results
1432
+ };
1433
+ }
1434
+ if (result && typeof result === "object") currentMessage = result;
1435
+ results.push({
1436
+ success: true,
1437
+ value: currentMessage,
1438
+ pluginId: hook.pluginId,
1439
+ duration: Date.now() - start
1440
+ });
1441
+ } catch (error) {
1442
+ results.push({
1443
+ success: false,
1444
+ error: error instanceof Error ? error : new Error(String(error)),
1445
+ pluginId: hook.pluginId,
1446
+ duration: Date.now() - start
1447
+ });
1448
+ if (hook.errorPolicy === "abort") throw error;
1449
+ }
1450
+ }
1451
+ return {
1452
+ message: currentMessage,
1453
+ results
1454
+ };
1455
+ }
1456
+ /**
1457
+ * Run email:afterSend hooks (fire-and-forget).
1458
+ *
1459
+ * Errors are logged but don't propagate — they don't affect the caller.
1460
+ */
1461
+ async runEmailAfterSend(message, source) {
1462
+ const hooks = this.getTypedHooks("email:afterSend");
1463
+ const results = [];
1464
+ for (const hook of hooks) {
1465
+ const { handler } = hook;
1466
+ const event = {
1467
+ message,
1468
+ source
1469
+ };
1470
+ const ctx = this.getContext(hook.pluginId);
1471
+ const start = Date.now();
1472
+ try {
1473
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1474
+ results.push({
1475
+ success: true,
1476
+ pluginId: hook.pluginId,
1477
+ duration: Date.now() - start
1478
+ });
1479
+ } catch (error) {
1480
+ console.error(`[email:afterSend] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1481
+ results.push({
1482
+ success: false,
1483
+ error: error instanceof Error ? error : new Error(String(error)),
1484
+ pluginId: hook.pluginId,
1485
+ duration: Date.now() - start
1486
+ });
1487
+ }
1488
+ }
1489
+ return results;
1490
+ }
1491
+ /**
1492
+ * Run comment:beforeCreate hooks (middleware pipeline).
1493
+ *
1494
+ * Each handler receives the event and returns a modified event or
1495
+ * `false` to reject the comment. The pipeline chains transformations —
1496
+ * each handler receives the output of the previous one.
1497
+ */
1498
+ async runCommentBeforeCreate(event) {
1499
+ const hooks = this.getTypedHooks("comment:beforeCreate");
1500
+ let currentEvent = event;
1501
+ for (const hook of hooks) {
1502
+ const { handler } = hook;
1503
+ const ctx = this.getContext(hook.pluginId);
1504
+ const start = Date.now();
1505
+ try {
1506
+ const result = await this.executeWithTimeout(() => handler({ ...currentEvent }, ctx), hook.timeout);
1507
+ if (result === false) return false;
1508
+ if (result && typeof result === "object") currentEvent = result;
1509
+ } catch (error) {
1510
+ console.error(`[comment:beforeCreate] Plugin "${hook.pluginId}" error (${Date.now() - start}ms):`, error instanceof Error ? error.message : error);
1511
+ if (hook.errorPolicy === "abort") throw error;
1512
+ }
1513
+ }
1514
+ return currentEvent;
1515
+ }
1516
+ /**
1517
+ * Run comment:afterCreate hooks (fire-and-forget).
1518
+ *
1519
+ * Errors are logged but don't propagate — they don't affect the caller.
1520
+ */
1521
+ async runCommentAfterCreate(event) {
1522
+ const hooks = this.getTypedHooks("comment:afterCreate");
1523
+ for (const hook of hooks) {
1524
+ const { handler } = hook;
1525
+ const ctx = this.getContext(hook.pluginId);
1526
+ try {
1527
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1528
+ } catch (error) {
1529
+ console.error(`[comment:afterCreate] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1530
+ }
1531
+ }
1532
+ }
1533
+ /**
1534
+ * Run comment:afterModerate hooks (fire-and-forget).
1535
+ *
1536
+ * Errors are logged but don't propagate — they don't affect the caller.
1537
+ */
1538
+ async runCommentAfterModerate(event) {
1539
+ const hooks = this.getTypedHooks("comment:afterModerate");
1540
+ for (const hook of hooks) {
1541
+ const { handler } = hook;
1542
+ const ctx = this.getContext(hook.pluginId);
1543
+ try {
1544
+ await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
1545
+ } catch (error) {
1546
+ console.error(`[comment:afterModerate] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1547
+ }
1548
+ }
1549
+ }
1550
+ /**
1551
+ * Run page:metadata hooks. Each handler returns contributions that are
1552
+ * merged by the metadata collector. Errors are logged but don't propagate.
1553
+ */
1554
+ async runPageMetadata(event) {
1555
+ const hooks = this.getTypedHooks("page:metadata");
1556
+ const results = [];
1557
+ for (const hook of hooks) {
1558
+ const { handler } = hook;
1559
+ const ctx = this.getContext(hook.pluginId);
1560
+ try {
1561
+ const result = await this.executeWithTimeout(() => Promise.resolve(handler(event, ctx)), hook.timeout);
1562
+ if (result != null) {
1563
+ const contributions = Array.isArray(result) ? result : [result];
1564
+ results.push({
1565
+ pluginId: hook.pluginId,
1566
+ contributions
1567
+ });
1568
+ }
1569
+ } catch (error) {
1570
+ console.error(`[page:metadata] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1571
+ }
1572
+ }
1573
+ return results;
1574
+ }
1575
+ /**
1576
+ * Run page:fragments hooks. Only trusted plugins should be registered
1577
+ * for this hook. Errors are logged but don't propagate.
1578
+ */
1579
+ async runPageFragments(event) {
1580
+ const hooks = this.getTypedHooks("page:fragments");
1581
+ const results = [];
1582
+ for (const hook of hooks) {
1583
+ const { handler } = hook;
1584
+ const ctx = this.getContext(hook.pluginId);
1585
+ try {
1586
+ const result = await this.executeWithTimeout(() => Promise.resolve(handler(event, ctx)), hook.timeout);
1587
+ if (result != null) {
1588
+ const contributions = Array.isArray(result) ? result : [result];
1589
+ results.push({
1590
+ pluginId: hook.pluginId,
1591
+ contributions
1592
+ });
1593
+ }
1594
+ } catch (error) {
1595
+ console.error(`[page:fragments] Plugin "${hook.pluginId}" error:`, error instanceof Error ? error.message : error);
1596
+ }
1597
+ }
1598
+ return results;
1599
+ }
1600
+ /**
1601
+ * Check if any hooks are registered for a given name
1602
+ */
1603
+ hasHooks(name) {
1604
+ const hooks = this.hooks.get(name);
1605
+ return hooks !== void 0 && hooks.length > 0;
1606
+ }
1607
+ /**
1608
+ * Get hook count for debugging
1609
+ */
1610
+ getHookCount(name) {
1611
+ return this.hooks.get(name)?.length || 0;
1612
+ }
1613
+ /**
1614
+ * Get all registered hook names
1615
+ */
1616
+ getRegisteredHooks() {
1617
+ return [...this.hooks.keys()];
1618
+ }
1619
+ /**
1620
+ * Returns hook names where at least one handler declared exclusive: true
1621
+ */
1622
+ getRegisteredExclusiveHooks() {
1623
+ return [...this.exclusiveHookNames];
1624
+ }
1625
+ /**
1626
+ * Check if a hook is exclusive
1627
+ */
1628
+ isExclusiveHook(name) {
1629
+ return this.exclusiveHookNames.has(name);
1630
+ }
1631
+ /**
1632
+ * Set the selected provider for an exclusive hook.
1633
+ * Called by PluginManager after resolution.
1634
+ */
1635
+ setExclusiveSelection(hookName, pluginId) {
1636
+ this.exclusiveSelections.set(hookName, pluginId);
1637
+ }
1638
+ /**
1639
+ * Clear the selected provider for an exclusive hook.
1640
+ */
1641
+ clearExclusiveSelection(hookName) {
1642
+ this.exclusiveSelections.delete(hookName);
1643
+ }
1644
+ /**
1645
+ * Get the selected provider for an exclusive hook (if any).
1646
+ */
1647
+ getExclusiveSelection(hookName) {
1648
+ return this.exclusiveSelections.get(hookName);
1649
+ }
1650
+ /**
1651
+ * Get all plugins that registered a handler for a given exclusive hook.
1652
+ */
1653
+ getExclusiveHookProviders(hookName) {
1654
+ return (this.hooks.get(hookName) ?? []).filter((h) => h.exclusive).map((h) => ({ pluginId: h.pluginId }));
1655
+ }
1656
+ /**
1657
+ * Get all plugins that registered a non-exclusive handler for a given
1658
+ * hook (e.g. `email:beforeSend`, `email:afterSend`), preserving priority
1659
+ * order. Partitions with `getExclusiveHookProviders()`, which returns
1660
+ * plugins whose registration is marked `exclusive: true`.
1661
+ */
1662
+ getHookProviders(hookName) {
1663
+ return (this.hooks.get(hookName) ?? []).filter((h) => !h.exclusive).map((h) => ({ pluginId: h.pluginId }));
1664
+ }
1665
+ /**
1666
+ * Invoke an exclusive hook — dispatch only to the selected provider.
1667
+ * Returns null if no provider is selected or if the selected hook
1668
+ * is not found in the pipeline.
1669
+ *
1670
+ * This is a generic dispatch used by the email pipeline and other
1671
+ * exclusive hook consumers. The handler type is unknown — callers
1672
+ * must know the expected signature.
1673
+ *
1674
+ * Errors are isolated: a failing handler returns an error result
1675
+ * instead of propagating the exception to the caller.
1676
+ */
1677
+ async invokeExclusiveHook(hookName, event) {
1678
+ const selectedPluginId = this.exclusiveSelections.get(hookName);
1679
+ if (!selectedPluginId) return null;
1680
+ const hook = (this.hooks.get(hookName) ?? []).find((h) => h.pluginId === selectedPluginId && h.exclusive);
1681
+ if (!hook) return null;
1682
+ const start = Date.now();
1683
+ try {
1684
+ const ctx = this.getContext(selectedPluginId);
1685
+ const handler = hook.handler;
1686
+ return {
1687
+ result: await this.executeWithTimeout(() => handler(event, ctx), hook.timeout),
1688
+ pluginId: selectedPluginId,
1689
+ duration: Date.now() - start
1690
+ };
1691
+ } catch (error) {
1692
+ return {
1693
+ result: void 0,
1694
+ pluginId: selectedPluginId,
1695
+ error: error instanceof Error ? error : new Error(String(error)),
1696
+ duration: Date.now() - start
1697
+ };
1698
+ }
1699
+ }
1700
+ };
1701
+ /**
1702
+ * Create a hook pipeline from plugins
1703
+ */
1704
+ function createHookPipeline(plugins, factoryOptions) {
1705
+ return new HookPipeline(plugins, factoryOptions);
1706
+ }
1707
+ /** Options table key prefix for exclusive hook selections */
1708
+ const EXCLUSIVE_HOOK_KEY_PREFIX$1 = "emdash:exclusive_hook:";
1709
+ /**
1710
+ * Resolve exclusive hook selections.
1711
+ *
1712
+ * Shared algorithm used by both PluginManager and EmDashRuntime:
1713
+ * 1. If a DB selection exists and that plugin is active → keep it.
1714
+ * 2. If DB selection is stale (plugin inactive/gone) → clear it.
1715
+ * 3. If no selection and only one active provider → auto-select it.
1716
+ * 4. If preferred hints match an active provider → first match wins.
1717
+ * 5. If multiple providers and no hint → leave unselected (admin must choose).
1718
+ */
1719
+ async function resolveExclusiveHooks(opts) {
1720
+ const { pipeline, isActive, getOption, setOption, deleteOption, preferredHints } = opts;
1721
+ const exclusiveHookNames = pipeline.getRegisteredExclusiveHooks();
1722
+ for (const hookName of exclusiveHookNames) {
1723
+ const providers = pipeline.getExclusiveHookProviders(hookName);
1724
+ const activeProviderIds = new Set(providers.map((p) => p.pluginId).filter((id) => isActive(id)));
1725
+ const key = `${EXCLUSIVE_HOOK_KEY_PREFIX$1}${hookName}`;
1726
+ let currentSelection = null;
1727
+ try {
1728
+ currentSelection = await getOption(key);
1729
+ } catch {
1730
+ continue;
1731
+ }
1732
+ if (currentSelection && activeProviderIds.has(currentSelection)) {
1733
+ pipeline.setExclusiveSelection(hookName, currentSelection);
1734
+ continue;
1735
+ }
1736
+ if (currentSelection) try {
1737
+ await deleteOption(key);
1738
+ } catch {}
1739
+ if (activeProviderIds.size === 1) {
1740
+ const [onlyProvider] = activeProviderIds;
1741
+ try {
1742
+ await setOption(key, onlyProvider);
1743
+ } catch {}
1744
+ pipeline.setExclusiveSelection(hookName, onlyProvider);
1745
+ continue;
1746
+ }
1747
+ if (preferredHints) {
1748
+ let found = false;
1749
+ for (const [pluginId, hooks] of preferredHints) if (hooks.includes(hookName) && activeProviderIds.has(pluginId)) {
1750
+ try {
1751
+ await setOption(key, pluginId);
1752
+ } catch {}
1753
+ pipeline.setExclusiveSelection(hookName, pluginId);
1754
+ found = true;
1755
+ break;
1756
+ }
1757
+ if (found) continue;
1758
+ }
1759
+ pipeline.clearExclusiveSelection(hookName);
1760
+ }
1761
+ }
1762
+
1763
+ //#endregion
1764
+ //#region src/plugins/email.ts
1765
+ /**
1766
+ * Email Pipeline
1767
+ *
1768
+ * Orchestrates the three-stage email pipeline:
1769
+ * 1. email:beforeSend hooks (middleware — transform, validate, cancel)
1770
+ * 2. email:deliver hook (exclusive — exactly one provider delivers)
1771
+ * 3. email:afterSend hooks (logging, analytics, fire-and-forget)
1772
+ *
1773
+ * Security features:
1774
+ * - Recursion guard prevents re-entrant sends (e.g. plugin calling ctx.email.send from a hook)
1775
+ * - System emails (source="system") bypass email:beforeSend and email:afterSend hooks entirely
1776
+ * to protect auth tokens from exfiltration by plugin hooks
1777
+ *
1778
+ */
1779
+ /** Hook name for the exclusive email delivery hook */
1780
+ const EMAIL_DELIVER_HOOK = "email:deliver";
1781
+ /** Source value used for auth emails (magic links, invites, password resets) */
1782
+ const SYSTEM_SOURCE = "system";
1783
+ /**
1784
+ * Error thrown when ctx.email.send() is called but no provider is configured.
1785
+ */
1786
+ var EmailNotConfiguredError = class extends Error {
1787
+ constructor() {
1788
+ super("No email provider is configured. Install and activate an email provider plugin, then select it in Settings > Email.");
1789
+ this.name = "EmailNotConfiguredError";
1790
+ }
1791
+ };
1792
+ /**
1793
+ * Error thrown when a recursive email send is detected.
1794
+ */
1795
+ var EmailRecursionError = class extends Error {
1796
+ constructor() {
1797
+ super("Recursive email send detected. A plugin hook attempted to send an email from within the email pipeline, which would cause infinite recursion.");
1798
+ this.name = "EmailRecursionError";
1799
+ }
1800
+ };
1801
+ /**
1802
+ * Recursion guard using AsyncLocalStorage.
1803
+ *
1804
+ * EmailPipeline is a singleton (worker-lifetime cached via EmDashRuntime).
1805
+ * Instance state like `sendDepth` would false-positive under concurrent
1806
+ * requests because two unrelated sends would increment the same counter.
1807
+ * ALS scopes the guard to the current async execution context, so concurrent
1808
+ * requests each get their own independent recursion tracking.
1809
+ */
1810
+ const emailSendALS = new AsyncLocalStorage();
1811
+ /**
1812
+ * EmailPipeline orchestrates email delivery through the plugin hook system.
1813
+ *
1814
+ * The pipeline runs in three stages:
1815
+ * 1. email:beforeSend — middleware hooks that can transform or cancel messages
1816
+ * 2. email:deliver — exclusive hook dispatching to the selected provider
1817
+ * 3. email:afterSend — fire-and-forget hooks for logging/analytics
1818
+ */
1819
+ var EmailPipeline = class {
1820
+ pipeline;
1821
+ constructor(pipeline) {
1822
+ this.pipeline = pipeline;
1823
+ }
1824
+ /**
1825
+ * Replace the underlying hook pipeline.
1826
+ *
1827
+ * Called by the runtime when rebuilding the hook pipeline after a
1828
+ * plugin is enabled or disabled, so the email pipeline dispatches
1829
+ * to the current set of active hooks.
1830
+ */
1831
+ setPipeline(pipeline) {
1832
+ this.pipeline = pipeline;
1833
+ }
1834
+ /**
1835
+ * Send an email through the full pipeline.
1836
+ *
1837
+ * @param message - The email to send
1838
+ * @param source - Where the email originated ("system" for auth, plugin ID for plugins)
1839
+ * @throws EmailNotConfiguredError if no provider is selected
1840
+ * @throws EmailRecursionError if called re-entrantly from within a hook
1841
+ * @throws Error if the provider handler throws
1842
+ */
1843
+ async send(message, source) {
1844
+ const store = emailSendALS.getStore();
1845
+ if (store && store.depth > 0) throw new EmailRecursionError();
1846
+ const run = () => this.sendInner(message, source);
1847
+ if (store) {
1848
+ store.depth++;
1849
+ try {
1850
+ await run();
1851
+ } finally {
1852
+ store.depth--;
1853
+ }
1854
+ } else await emailSendALS.run({ depth: 1 }, run);
1855
+ }
1856
+ /**
1857
+ * Inner send implementation, separated from the recursion guard.
1858
+ */
1859
+ async sendInner(message, source) {
1860
+ if (!message || typeof message !== "object") throw new Error("Invalid email message: message must be an object");
1861
+ if (!message.to || typeof message.to !== "string") throw new Error("Invalid email message: 'to' is required and must be a string");
1862
+ if (!message.subject || typeof message.subject !== "string") throw new Error("Invalid email message: 'subject' is required and must be a string");
1863
+ if (!message.text || typeof message.text !== "string") throw new Error("Invalid email message: 'text' is required and must be a string");
1864
+ const isSystemEmail = source === SYSTEM_SOURCE;
1865
+ let finalMessage;
1866
+ if (isSystemEmail) finalMessage = message;
1867
+ else {
1868
+ const beforeResult = await this.pipeline.runEmailBeforeSend(message, source);
1869
+ if (beforeResult.message === false) {
1870
+ const cancelledBy = beforeResult.results.find((r) => r.value === false)?.pluginId ?? "unknown";
1871
+ console.info(`[email] Email to "${message.to}" cancelled by plugin "${cancelledBy}"`);
1872
+ return;
1873
+ }
1874
+ finalMessage = beforeResult.message;
1875
+ }
1876
+ const deliverEvent = {
1877
+ message: finalMessage,
1878
+ source
1879
+ };
1880
+ const deliverResult = await this.pipeline.invokeExclusiveHook(EMAIL_DELIVER_HOOK, deliverEvent);
1881
+ if (!deliverResult) throw new EmailNotConfiguredError();
1882
+ if (deliverResult.error) throw deliverResult.error;
1883
+ if (!isSystemEmail) this.pipeline.runEmailAfterSend(finalMessage, source).catch((err) => console.error("[email] afterSend pipeline error:", err instanceof Error ? err.message : err));
1884
+ }
1885
+ /**
1886
+ * Check if an email provider is configured and available.
1887
+ *
1888
+ * Returns true if an email:deliver provider is selected in the exclusive
1889
+ * hook system. Plugins and auth code use this to decide whether to show
1890
+ * "send invite" vs "copy invite link" UI.
1891
+ */
1892
+ isAvailable() {
1893
+ return this.pipeline.getExclusiveSelection(EMAIL_DELIVER_HOOK) !== void 0;
1894
+ }
1895
+ };
1896
+
1897
+ //#endregion
1898
+ //#region src/plugins/routes.ts
1899
+ /**
1900
+ * Plugin Routes v2
1901
+ *
1902
+ * Handles plugin API route invocation with:
1903
+ * - Input validation via Zod schemas
1904
+ * - Route context creation
1905
+ * - Error handling
1906
+ *
1907
+ */
1908
+ /**
1909
+ * Route handler for a plugin
1910
+ */
1911
+ var PluginRouteHandler = class {
1912
+ contextFactory;
1913
+ plugin;
1914
+ trustedProxyHeaders;
1915
+ constructor(plugin, factoryOptions) {
1916
+ this.plugin = plugin;
1917
+ this.contextFactory = new PluginContextFactory(factoryOptions);
1918
+ this.trustedProxyHeaders = factoryOptions.trustedProxyHeaders ?? [];
1919
+ }
1920
+ /**
1921
+ * Invoke a route by name
1922
+ */
1923
+ async invoke(routeName, options) {
1924
+ const route = this.plugin.routes[routeName];
1925
+ if (!route) return {
1926
+ success: false,
1927
+ error: {
1928
+ code: "ROUTE_NOT_FOUND",
1929
+ message: `Route "${routeName}" not found in plugin "${this.plugin.id}"`
1930
+ },
1931
+ status: 404
1932
+ };
1933
+ let validatedInput;
1934
+ if (route.input) {
1935
+ const parseResult = route.input.safeParse(options.body);
1936
+ if (!parseResult.success) return {
1937
+ success: false,
1938
+ error: {
1939
+ code: "VALIDATION_ERROR",
1940
+ message: "Invalid request body",
1941
+ details: parseResult.error.format()
1942
+ },
1943
+ status: 400
1944
+ };
1945
+ validatedInput = parseResult.data;
1946
+ } else validatedInput = options.body;
1947
+ const routeContext = {
1948
+ ...this.contextFactory.createContext(this.plugin),
1949
+ input: validatedInput,
1950
+ request: options.request,
1951
+ requestMeta: extractRequestMeta(options.request, this.trustedProxyHeaders)
1952
+ };
1953
+ try {
1954
+ return {
1955
+ success: true,
1956
+ data: await route.handler(routeContext),
1957
+ status: 200
1958
+ };
1959
+ } catch (error) {
1960
+ if (error instanceof PluginRouteError) return {
1961
+ success: false,
1962
+ error: {
1963
+ code: error.code,
1964
+ message: error.message,
1965
+ details: error.details
1966
+ },
1967
+ status: error.status
1968
+ };
1969
+ console.error(`[plugin:${this.plugin.id}] Route handler failed:`, error);
1970
+ return {
1971
+ success: false,
1972
+ error: {
1973
+ code: "INTERNAL_ERROR",
1974
+ message: "An internal error occurred"
1975
+ },
1976
+ status: 500
1977
+ };
1978
+ }
1979
+ }
1980
+ /**
1981
+ * Get all route names
1982
+ */
1983
+ getRouteNames() {
1984
+ return Object.keys(this.plugin.routes);
1985
+ }
1986
+ /**
1987
+ * Check if a route exists
1988
+ */
1989
+ hasRoute(name) {
1990
+ return name in this.plugin.routes;
1991
+ }
1992
+ /**
1993
+ * Get route metadata without invoking the handler.
1994
+ * Returns null if the route doesn't exist.
1995
+ */
1996
+ getRouteMeta(name) {
1997
+ const route = this.plugin.routes[name];
1998
+ if (!route) return null;
1999
+ return { public: route.public === true };
2000
+ }
2001
+ };
2002
+ /**
2003
+ * Error class for plugin routes
2004
+ * Allows plugins to return structured errors with specific HTTP status codes
2005
+ */
2006
+ var PluginRouteError = class PluginRouteError extends Error {
2007
+ constructor(code, message, status = 400, details) {
2008
+ super(message);
2009
+ this.code = code;
2010
+ this.status = status;
2011
+ this.details = details;
2012
+ this.name = "PluginRouteError";
2013
+ }
2014
+ /**
2015
+ * Create a bad request error (400)
2016
+ */
2017
+ static badRequest(message, details) {
2018
+ return new PluginRouteError("BAD_REQUEST", message, 400, details);
2019
+ }
2020
+ /**
2021
+ * Create an unauthorized error (401)
2022
+ */
2023
+ static unauthorized(message = "Unauthorized") {
2024
+ return new PluginRouteError("UNAUTHORIZED", message, 401);
2025
+ }
2026
+ /**
2027
+ * Create a forbidden error (403)
2028
+ */
2029
+ static forbidden(message = "Forbidden") {
2030
+ return new PluginRouteError("FORBIDDEN", message, 403);
2031
+ }
2032
+ /**
2033
+ * Create a not found error (404)
2034
+ */
2035
+ static notFound(message = "Not found") {
2036
+ return new PluginRouteError("NOT_FOUND", message, 404);
2037
+ }
2038
+ /**
2039
+ * Create a conflict error (409)
2040
+ */
2041
+ static conflict(message, details) {
2042
+ return new PluginRouteError("CONFLICT", message, 409, details);
2043
+ }
2044
+ /**
2045
+ * Create an internal error (500)
2046
+ */
2047
+ static internal(message = "Internal error") {
2048
+ return new PluginRouteError("INTERNAL_ERROR", message, 500);
2049
+ }
2050
+ };
2051
+ /**
2052
+ * Registry for all plugin route handlers
2053
+ */
2054
+ var PluginRouteRegistry = class {
2055
+ handlers = /* @__PURE__ */ new Map();
2056
+ constructor(factoryOptions) {
2057
+ this.factoryOptions = factoryOptions;
2058
+ }
2059
+ /**
2060
+ * Register a plugin's routes
2061
+ */
2062
+ register(plugin) {
2063
+ const handler = new PluginRouteHandler(plugin, this.factoryOptions);
2064
+ this.handlers.set(plugin.id, handler);
2065
+ }
2066
+ /**
2067
+ * Unregister a plugin's routes
2068
+ */
2069
+ unregister(pluginId) {
2070
+ this.handlers.delete(pluginId);
2071
+ }
2072
+ /**
2073
+ * Invoke a plugin route
2074
+ */
2075
+ async invoke(pluginId, routeName, options) {
2076
+ const handler = this.handlers.get(pluginId);
2077
+ if (!handler) return {
2078
+ success: false,
2079
+ error: {
2080
+ code: "PLUGIN_NOT_FOUND",
2081
+ message: `Plugin "${pluginId}" not found`
2082
+ },
2083
+ status: 404
2084
+ };
2085
+ return handler.invoke(routeName, options);
2086
+ }
2087
+ /**
2088
+ * Get all registered plugin IDs
2089
+ */
2090
+ getPluginIds() {
2091
+ return [...this.handlers.keys()];
2092
+ }
2093
+ /**
2094
+ * Get routes for a plugin
2095
+ */
2096
+ getRoutes(pluginId) {
2097
+ return this.handlers.get(pluginId)?.getRouteNames() ?? [];
2098
+ }
2099
+ /**
2100
+ * Get route metadata for a specific plugin route.
2101
+ * Returns null if the plugin or route doesn't exist.
2102
+ */
2103
+ getRouteMeta(pluginId, routeName) {
2104
+ const handler = this.handlers.get(pluginId);
2105
+ if (!handler) return null;
2106
+ return handler.getRouteMeta(routeName);
2107
+ }
2108
+ };
2109
+
2110
+ //#endregion
2111
+ //#region src/plugins/manager.ts
2112
+ /** Options table key prefix for exclusive hook DB reads via PluginManager */
2113
+ const EXCLUSIVE_HOOK_KEY_PREFIX = "emdash:exclusive_hook:";
2114
+ /**
2115
+ * Plugin Manager v2
2116
+ *
2117
+ * Manages the full lifecycle of plugins and coordinates hooks/routes.
2118
+ */
2119
+ var PluginManager = class {
2120
+ plugins = /* @__PURE__ */ new Map();
2121
+ hookPipeline = null;
2122
+ routeRegistry = null;
2123
+ factoryOptions;
2124
+ initialized = false;
2125
+ constructor(options) {
2126
+ this.options = options;
2127
+ this.factoryOptions = {
2128
+ db: options.db,
2129
+ storage: options.storage,
2130
+ getUploadUrl: options.getUploadUrl,
2131
+ trustedProxyHeaders: options.trustedProxyHeaders
2132
+ };
2133
+ }
2134
+ /**
2135
+ * Set the email pipeline used when creating plugin contexts.
2136
+ * Reinitializes routes/hooks if already initialized so ctx.email is available immediately.
2137
+ */
2138
+ setEmailPipeline(pipeline) {
2139
+ this.factoryOptions.emailPipeline = pipeline;
2140
+ if (this.initialized) this.reinitialize();
2141
+ }
2142
+ /**
2143
+ * Register a plugin definition
2144
+ * This resolves the definition and adds it to the manager, but doesn't install it
2145
+ */
2146
+ register(definition) {
2147
+ const resolved = definePlugin(definition);
2148
+ if (this.plugins.has(resolved.id)) throw new Error(`Plugin "${resolved.id}" is already registered`);
2149
+ this.plugins.set(resolved.id, {
2150
+ plugin: resolved,
2151
+ state: "registered"
2152
+ });
2153
+ this.initialized = false;
2154
+ return resolved;
2155
+ }
2156
+ /**
2157
+ * Register multiple plugins
2158
+ */
2159
+ registerAll(definitions) {
2160
+ for (const def of definitions) this.register(def);
2161
+ }
2162
+ /**
2163
+ * Unregister a plugin
2164
+ * Plugin must be inactive or just registered
2165
+ */
2166
+ unregister(pluginId) {
2167
+ const entry = this.plugins.get(pluginId);
2168
+ if (!entry) return false;
2169
+ if (entry.state === "active") throw new Error(`Cannot unregister active plugin "${pluginId}". Deactivate it first.`);
2170
+ this.plugins.delete(pluginId);
2171
+ this.initialized = false;
2172
+ return true;
2173
+ }
2174
+ /**
2175
+ * Install a plugin (run install hooks, set up storage)
2176
+ */
2177
+ async install(pluginId) {
2178
+ const entry = this.plugins.get(pluginId);
2179
+ if (!entry) throw new Error(`Plugin "${pluginId}" not found`);
2180
+ if (entry.state !== "registered") throw new Error(`Plugin "${pluginId}" is already installed (state: ${entry.state})`);
2181
+ this.ensureInitialized();
2182
+ const results = await this.hookPipeline.runPluginInstall(pluginId);
2183
+ const failed = results.find((r) => !r.success);
2184
+ if (failed) throw new Error(`Plugin install failed: ${failed.error?.message ?? "Unknown error"}`);
2185
+ entry.state = "installed";
2186
+ return results;
2187
+ }
2188
+ /**
2189
+ * Activate a plugin (run activate hooks, enable hooks/routes)
2190
+ */
2191
+ async activate(pluginId) {
2192
+ const entry = this.plugins.get(pluginId);
2193
+ if (!entry) throw new Error(`Plugin "${pluginId}" not found`);
2194
+ if (entry.state === "active") return [];
2195
+ if (entry.state === "registered") await this.install(pluginId);
2196
+ this.ensureInitialized();
2197
+ const results = await this.hookPipeline.runPluginActivate(pluginId);
2198
+ const failed = results.find((r) => !r.success);
2199
+ if (failed) throw new Error(`Plugin activation failed: ${failed.error?.message ?? "Unknown error"}`);
2200
+ entry.state = "active";
2201
+ await setCronTasksEnabled(this.options.db, pluginId, true);
2202
+ this.reinitialize();
2203
+ await this.resolveExclusiveHooks();
2204
+ return results;
2205
+ }
2206
+ /**
2207
+ * Deactivate a plugin (run deactivate hooks, disable hooks/routes)
2208
+ */
2209
+ async deactivate(pluginId) {
2210
+ const entry = this.plugins.get(pluginId);
2211
+ if (!entry) throw new Error(`Plugin "${pluginId}" not found`);
2212
+ if (entry.state !== "active") return [];
2213
+ this.ensureInitialized();
2214
+ const results = await this.hookPipeline.runPluginDeactivate(pluginId);
2215
+ await setCronTasksEnabled(this.options.db, pluginId, false);
2216
+ entry.state = "inactive";
2217
+ this.reinitialize();
2218
+ await this.resolveExclusiveHooks();
2219
+ return results;
2220
+ }
2221
+ /**
2222
+ * Uninstall a plugin (run uninstall hooks, optionally delete data)
2223
+ */
2224
+ async uninstall(pluginId, deleteData = false) {
2225
+ const entry = this.plugins.get(pluginId);
2226
+ if (!entry) throw new Error(`Plugin "${pluginId}" not found`);
2227
+ if (entry.state === "active") await this.deactivate(pluginId);
2228
+ this.ensureInitialized();
2229
+ const results = await this.hookPipeline.runPluginUninstall(pluginId, deleteData);
2230
+ await this.deleteCronTasks(pluginId);
2231
+ this.plugins.delete(pluginId);
2232
+ this.initialized = false;
2233
+ await this.resolveExclusiveHooks();
2234
+ return results;
2235
+ }
2236
+ /**
2237
+ * Run content:beforeSave hooks across all active plugins
2238
+ */
2239
+ async runContentBeforeSave(content, collection, isNew) {
2240
+ this.ensureInitialized();
2241
+ return this.hookPipeline.runContentBeforeSave(content, collection, isNew);
2242
+ }
2243
+ /**
2244
+ * Run content:afterSave hooks across all active plugins
2245
+ */
2246
+ async runContentAfterSave(content, collection, isNew) {
2247
+ this.ensureInitialized();
2248
+ return this.hookPipeline.runContentAfterSave(content, collection, isNew);
2249
+ }
2250
+ /**
2251
+ * Run content:beforeDelete hooks across all active plugins
2252
+ */
2253
+ async runContentBeforeDelete(id, collection) {
2254
+ this.ensureInitialized();
2255
+ return this.hookPipeline.runContentBeforeDelete(id, collection);
2256
+ }
2257
+ /**
2258
+ * Run content:afterDelete hooks across all active plugins
2259
+ */
2260
+ async runContentAfterDelete(id, collection, permanent) {
2261
+ this.ensureInitialized();
2262
+ return this.hookPipeline.runContentAfterDelete(id, collection, permanent);
2263
+ }
2264
+ /**
2265
+ * Run content:afterPublish hooks across all active plugins
2266
+ */
2267
+ async runContentAfterPublish(content, collection) {
2268
+ this.ensureInitialized();
2269
+ return this.hookPipeline.runContentAfterPublish(content, collection);
2270
+ }
2271
+ /**
2272
+ * Run content:afterUnpublish hooks across all active plugins
2273
+ */
2274
+ async runContentAfterUnpublish(content, collection) {
2275
+ this.ensureInitialized();
2276
+ return this.hookPipeline.runContentAfterUnpublish(content, collection);
2277
+ }
2278
+ /**
2279
+ * Run media:beforeUpload hooks across all active plugins
2280
+ */
2281
+ async runMediaBeforeUpload(file) {
2282
+ this.ensureInitialized();
2283
+ return this.hookPipeline.runMediaBeforeUpload(file);
2284
+ }
2285
+ /**
2286
+ * Run media:afterUpload hooks across all active plugins
2287
+ */
2288
+ async runMediaAfterUpload(media) {
2289
+ this.ensureInitialized();
2290
+ return this.hookPipeline.runMediaAfterUpload(media);
2291
+ }
2292
+ /**
2293
+ * Invoke the cron hook for a specific plugin (per-plugin dispatch).
2294
+ * Used as the InvokeCronHookFn callback for CronExecutor.
2295
+ */
2296
+ async invokeCronHook(pluginId, event) {
2297
+ this.ensureInitialized();
2298
+ const result = await this.hookPipeline.invokeCronHook(pluginId, event);
2299
+ if (!result.success && result.error) throw result.error;
2300
+ }
2301
+ /**
2302
+ * Invoke a plugin route
2303
+ */
2304
+ async invokeRoute(pluginId, routeName, options) {
2305
+ this.ensureInitialized();
2306
+ return this.routeRegistry.invoke(pluginId, routeName, options);
2307
+ }
2308
+ /**
2309
+ * Get all routes for a plugin
2310
+ */
2311
+ getPluginRoutes(pluginId) {
2312
+ this.ensureInitialized();
2313
+ return this.routeRegistry.getRoutes(pluginId);
2314
+ }
2315
+ /**
2316
+ * Get a plugin by ID
2317
+ */
2318
+ getPlugin(pluginId) {
2319
+ return this.plugins.get(pluginId)?.plugin;
2320
+ }
2321
+ /**
2322
+ * Get plugin state
2323
+ */
2324
+ getPluginState(pluginId) {
2325
+ return this.plugins.get(pluginId)?.state;
2326
+ }
2327
+ /**
2328
+ * Get all registered plugins
2329
+ */
2330
+ getAllPlugins() {
2331
+ return Array.from(this.plugins.values(), (entry) => ({
2332
+ plugin: entry.plugin,
2333
+ state: entry.state
2334
+ }));
2335
+ }
2336
+ /**
2337
+ * Get all active plugins
2338
+ */
2339
+ getActivePlugins() {
2340
+ return [...this.plugins.values()].filter((entry) => entry.state === "active").map((entry) => entry.plugin);
2341
+ }
2342
+ /**
2343
+ * Check if a plugin exists
2344
+ */
2345
+ hasPlugin(pluginId) {
2346
+ return this.plugins.has(pluginId);
2347
+ }
2348
+ /**
2349
+ * Check if a plugin is active
2350
+ */
2351
+ isActive(pluginId) {
2352
+ return this.plugins.get(pluginId)?.state === "active";
2353
+ }
2354
+ /**
2355
+ * Get all plugins that registered a handler for an exclusive hook.
2356
+ */
2357
+ getExclusiveHookProviders(hookName) {
2358
+ this.ensureInitialized();
2359
+ return this.hookPipeline.getExclusiveHookProviders(hookName).map((p) => {
2360
+ const plugin = this.plugins.get(p.pluginId);
2361
+ return {
2362
+ pluginId: p.pluginId,
2363
+ pluginName: plugin?.plugin.id ?? p.pluginId
2364
+ };
2365
+ });
2366
+ }
2367
+ /**
2368
+ * Read the selected provider for an exclusive hook from the options table.
2369
+ */
2370
+ async getExclusiveHookSelection(hookName) {
2371
+ return new OptionsRepository(this.options.db).get(`${EXCLUSIVE_HOOK_KEY_PREFIX}${hookName}`);
2372
+ }
2373
+ /**
2374
+ * Set the selected provider for an exclusive hook in the options table.
2375
+ * Pass null to clear the selection.
2376
+ */
2377
+ async setExclusiveHookSelection(hookName, pluginId) {
2378
+ const optionsRepo = new OptionsRepository(this.options.db);
2379
+ const key = `${EXCLUSIVE_HOOK_KEY_PREFIX}${hookName}`;
2380
+ if (pluginId === null) {
2381
+ await optionsRepo.delete(key);
2382
+ this.hookPipeline?.clearExclusiveSelection(hookName);
2383
+ return;
2384
+ }
2385
+ const entry = this.plugins.get(pluginId);
2386
+ if (!entry) throw new Error(`Plugin "${pluginId}" not found`);
2387
+ if (entry.state !== "active") throw new Error(`Plugin "${pluginId}" is not active`);
2388
+ await optionsRepo.set(key, pluginId);
2389
+ this.hookPipeline?.setExclusiveSelection(hookName, pluginId);
2390
+ }
2391
+ /**
2392
+ * Resolution algorithm for exclusive hooks.
2393
+ *
2394
+ * Delegates to the shared resolveExclusiveHooks() function.
2395
+ * See hooks.ts for the full algorithm description.
2396
+ */
2397
+ async resolveExclusiveHooks(preferredHints) {
2398
+ this.ensureInitialized();
2399
+ const optionsRepo = new OptionsRepository(this.options.db);
2400
+ await resolveExclusiveHooks({
2401
+ pipeline: this.hookPipeline,
2402
+ isActive: (pluginId) => this.isActive(pluginId),
2403
+ getOption: (key) => optionsRepo.get(key),
2404
+ setOption: (key, value) => optionsRepo.set(key, value),
2405
+ deleteOption: async (key) => {
2406
+ await optionsRepo.delete(key);
2407
+ },
2408
+ preferredHints
2409
+ });
2410
+ }
2411
+ /**
2412
+ * Get all exclusive hooks with their providers and current selections.
2413
+ * Used by the admin API.
2414
+ */
2415
+ async getExclusiveHooksInfo() {
2416
+ this.ensureInitialized();
2417
+ const exclusiveHookNames = this.hookPipeline.getRegisteredExclusiveHooks();
2418
+ const result = [];
2419
+ for (const hookName of exclusiveHookNames) {
2420
+ const providers = this.hookPipeline.getExclusiveHookProviders(hookName);
2421
+ const selection = await this.getExclusiveHookSelection(hookName);
2422
+ result.push({
2423
+ hookName,
2424
+ providers,
2425
+ selectedPluginId: selection
2426
+ });
2427
+ }
2428
+ return result;
2429
+ }
2430
+ /**
2431
+ * Initialize or reinitialize the hook pipeline and route registry
2432
+ */
2433
+ ensureInitialized() {
2434
+ if (this.initialized) return;
2435
+ const activePlugins = this.getActivePlugins();
2436
+ this.hookPipeline = new HookPipeline(activePlugins, this.factoryOptions);
2437
+ this.routeRegistry = new PluginRouteRegistry(this.factoryOptions);
2438
+ for (const plugin of activePlugins) this.routeRegistry.register(plugin);
2439
+ this.initialized = true;
2440
+ }
2441
+ /**
2442
+ * Force reinitialization (useful after plugin state changes)
2443
+ */
2444
+ reinitialize() {
2445
+ this.initialized = false;
2446
+ this.ensureInitialized();
2447
+ }
2448
+ /**
2449
+ * Delete all cron tasks for a plugin.
2450
+ * Used during uninstall.
2451
+ */
2452
+ async deleteCronTasks(pluginId) {
2453
+ try {
2454
+ await sql`
2455
+ DELETE FROM _emdash_cron_tasks
2456
+ WHERE plugin_id = ${pluginId}
2457
+ `.execute(this.options.db);
2458
+ } catch {}
2459
+ }
2460
+ };
2461
+ /**
2462
+ * Create a plugin manager
2463
+ */
2464
+ function createPluginManager(options) {
2465
+ return new PluginManager(options);
2466
+ }
2467
+
2468
+ //#endregion
2469
+ //#region src/plugins/sandbox/noop.ts
2470
+ /**
2471
+ * Error thrown when attempting to use sandboxing on an unsupported platform.
2472
+ */
2473
+ var SandboxNotAvailableError = class extends Error {
2474
+ constructor() {
2475
+ super("Plugin sandboxing is not available on this platform. Sandboxed plugins require Cloudflare Workers with Worker Loader. Use trusted plugins (from config) instead, or deploy to Cloudflare.");
2476
+ this.name = "SandboxNotAvailableError";
2477
+ }
2478
+ };
2479
+ /**
2480
+ * No-op sandbox runner for platforms without isolation support.
2481
+ *
2482
+ * - `isAvailable()` returns false
2483
+ * - `load()` throws SandboxNotAvailableError
2484
+ * - `terminateAll()` is a no-op
2485
+ *
2486
+ * This is the default runner when no platform adapter is configured.
2487
+ */
2488
+ var NoopSandboxRunner = class {
2489
+ /**
2490
+ * Always returns false - sandboxing is not available.
2491
+ */
2492
+ isAvailable() {
2493
+ return false;
2494
+ }
2495
+ /**
2496
+ * Always throws - can't load sandboxed plugins without isolation.
2497
+ */
2498
+ async load(_manifest, _code) {
2499
+ throw new SandboxNotAvailableError();
2500
+ }
2501
+ /**
2502
+ * No-op - sandboxing not available, email callback is irrelevant.
2503
+ */
2504
+ setEmailSend() {}
2505
+ /**
2506
+ * No-op - nothing to terminate.
2507
+ */
2508
+ async terminateAll() {}
2509
+ };
2510
+ /**
2511
+ * Create a no-op sandbox runner.
2512
+ * This is used as the default when no platform adapter is configured.
2513
+ */
2514
+ function createNoopSandboxRunner(_options) {
2515
+ return new NoopSandboxRunner();
2516
+ }
2517
+
2518
+ //#endregion
2519
+ //#region src/comments/query.ts
2520
+ /**
2521
+ * Get approved comments for a content item.
2522
+ *
2523
+ * @example
2524
+ * ```ts
2525
+ * import { getComments } from "emdash";
2526
+ *
2527
+ * const { items, total } = await getComments({
2528
+ * collection: "posts",
2529
+ * contentId: post.id,
2530
+ * threaded: true,
2531
+ * });
2532
+ * ```
2533
+ */
2534
+ async function getComments(options) {
2535
+ return getCommentsWithDb(await getDb(), options);
2536
+ }
2537
+ /**
2538
+ * Get approved comments with an explicit db handle.
2539
+ *
2540
+ * @internal Use `getComments()` in templates. This variant is for routes
2541
+ * that already have a database handle.
2542
+ */
2543
+ async function getCommentsWithDb(db, options) {
2544
+ const repo = new CommentRepository(db);
2545
+ const total = await repo.countByContent(options.collection, options.contentId, "approved");
2546
+ const result = await repo.findByContent(options.collection, options.contentId, {
2547
+ status: "approved",
2548
+ limit: 500
2549
+ });
2550
+ if (options.threaded) return {
2551
+ items: CommentRepository.assembleThreads(result.items).map((c) => CommentRepository.toPublicComment(c)),
2552
+ total
2553
+ };
2554
+ return {
2555
+ items: result.items.map((c) => CommentRepository.toPublicComment(c)),
2556
+ total
2557
+ };
2558
+ }
2559
+ /**
2560
+ * Get the count of approved comments for a content item.
2561
+ *
2562
+ * @example
2563
+ * ```ts
2564
+ * import { getCommentCount } from "emdash";
2565
+ *
2566
+ * const count = await getCommentCount("posts", post.id);
2567
+ * ```
2568
+ */
2569
+ async function getCommentCount(collection, contentId) {
2570
+ return getCommentCountWithDb(await getDb(), collection, contentId);
2571
+ }
2572
+ /**
2573
+ * Get comment count with an explicit db handle.
2574
+ *
2575
+ * @internal Use `getCommentCount()` in templates.
2576
+ */
2577
+ async function getCommentCountWithDb(db, collection, contentId) {
2578
+ return new CommentRepository(db).countByContent(collection, contentId, "approved");
2579
+ }
2580
+
2581
+ //#endregion
2582
+ //#region src/menus/index.ts
2583
+ /**
2584
+ * Get a menu by name with resolved URLs.
2585
+ *
2586
+ * @example
2587
+ * ```ts
2588
+ * const menu = await getMenu("primary");
2589
+ * const menuEs = await getMenu("primary", { locale: "es" });
2590
+ * ```
2591
+ */
2592
+ function getMenu(name, options = {}) {
2593
+ const locale = resolveLocale(options.locale);
2594
+ return requestCached(`menu:${name}:${locale ?? "*"}`, async () => {
2595
+ return getMenuWithDb(name, await getDb(), { locale });
2596
+ });
2597
+ }
2598
+ /**
2599
+ * Get menu by name with resolved URLs (with explicit db). Internal helper for
2600
+ * admin routes that already have a database handle.
2601
+ */
2602
+ async function getMenuWithDb(name, db, options = {}) {
2603
+ const chain = resolveLocaleChain(options.locale);
2604
+ const selectMenu = () => db.selectFrom("_emdash_menus").selectAll().where("name", "=", name);
2605
+ let menuRow;
2606
+ if (chain.length === 0) menuRow = await selectMenu().orderBy("locale", "asc").executeTakeFirst();
2607
+ else {
2608
+ menuRow = void 0;
2609
+ for (const locale of chain) {
2610
+ menuRow = await selectMenu().where("locale", "=", locale).executeTakeFirst();
2611
+ if (menuRow) break;
2612
+ }
2613
+ }
2614
+ if (!menuRow) return null;
2615
+ const items = await buildMenuTree(await db.selectFrom("_emdash_menu_items").selectAll().$castTo().where("menu_id", "=", menuRow.id).orderBy("sort_order", "asc").execute(), db, menuRow.locale);
2616
+ return {
2617
+ id: menuRow.id,
2618
+ name: menuRow.name,
2619
+ label: menuRow.label,
2620
+ items,
2621
+ locale: menuRow.locale,
2622
+ translationGroup: menuRow.translation_group
2623
+ };
2624
+ }
2625
+ /**
2626
+ * Get all menus (without items, locale-filtered — for admin list / site nav
2627
+ * summaries). When no locale is configured, returns menus across all locales.
2628
+ */
2629
+ async function getMenus(options = {}) {
2630
+ return getMenusWithDb(await getDb(), options);
2631
+ }
2632
+ /**
2633
+ * Get all menus (with explicit db)
2634
+ *
2635
+ * @internal Use `getMenus()` in templates. This variant is for admin routes
2636
+ * that already have a database handle.
2637
+ */
2638
+ async function getMenusWithDb(db, options = {}) {
2639
+ const locale = resolveLocale(options.locale);
2640
+ let query = db.selectFrom("_emdash_menus").select([
2641
+ "id",
2642
+ "name",
2643
+ "label",
2644
+ "locale"
2645
+ ]).orderBy("name", "asc");
2646
+ if (locale !== void 0) query = query.where("locale", "=", locale);
2647
+ return query.execute();
2648
+ }
2649
+ /**
2650
+ * Build a hierarchical menu tree from a flat list of items. Items are
2651
+ * resolved against the given `locale` so references land on the right
2652
+ * per-locale content rows.
2653
+ */
2654
+ async function buildMenuTree(items, db, locale) {
2655
+ const collectionSlugs = /* @__PURE__ */ new Set();
2656
+ for (const item of items) {
2657
+ if (item.reference_collection) collectionSlugs.add(item.reference_collection);
2658
+ if (item.type === "page" || item.type === "post") collectionSlugs.add(item.reference_collection || `${item.type}s`);
2659
+ }
2660
+ const urlPatterns = /* @__PURE__ */ new Map();
2661
+ if (collectionSlugs.size > 0) {
2662
+ const rows = await db.selectFrom("_emdash_collections").select(["slug", "url_pattern"]).where("slug", "in", [...collectionSlugs]).execute();
2663
+ for (const row of rows) urlPatterns.set(row.slug, row.url_pattern);
2664
+ }
2665
+ const validItems = (await Promise.all(items.map((item) => resolveMenuItem(item, db, urlPatterns, locale)))).filter((item) => item !== null);
2666
+ const itemMap = /* @__PURE__ */ new Map();
2667
+ const rootItems = [];
2668
+ for (const item of validItems) itemMap.set(item.id, {
2669
+ ...item,
2670
+ children: []
2671
+ });
2672
+ for (const item of items) {
2673
+ const menuItem = itemMap.get(item.id);
2674
+ if (!menuItem) continue;
2675
+ if (item.parent_id) {
2676
+ const parent = itemMap.get(item.parent_id);
2677
+ if (parent) parent.children.push(menuItem);
2678
+ else rootItems.push(menuItem);
2679
+ } else rootItems.push(menuItem);
2680
+ }
2681
+ return rootItems;
2682
+ }
2683
+ /**
2684
+ * Resolve a single menu item's URL. `reference_id` is a translation_group
2685
+ * (migration 036 remapped all existing references); we join it against
2686
+ * the per-locale ec_* row or per-locale taxonomy row.
2687
+ */
2688
+ async function resolveMenuItem(item, db, urlPatterns, locale) {
2689
+ let url;
2690
+ try {
2691
+ switch (item.type) {
2692
+ case "custom":
2693
+ url = item.custom_url || "#";
2694
+ break;
2695
+ case "page":
2696
+ case "post":
2697
+ url = await resolveContentUrl(item.reference_collection || `${item.type}s`, item.reference_id, db, urlPatterns, locale);
2698
+ if (url === null) return null;
2699
+ break;
2700
+ case "taxonomy":
2701
+ url = await resolveTaxonomyUrl(item.reference_id, db, locale);
2702
+ if (url === null) return null;
2703
+ break;
2704
+ case "collection":
2705
+ url = `/${item.reference_collection}/`;
2706
+ break;
2707
+ default: if (item.reference_collection && item.reference_id) {
2708
+ url = await resolveContentUrl(item.reference_collection, item.reference_id, db, urlPatterns, locale);
2709
+ if (url === null) return null;
2710
+ } else url = "#";
2711
+ }
2712
+ } catch (error) {
2713
+ console.error(`Failed to resolve menu item ${item.id}:`, error);
2714
+ return null;
2715
+ }
2716
+ return {
2717
+ id: item.id,
2718
+ label: item.label,
2719
+ url: sanitizeHref(url),
2720
+ target: item.target || void 0,
2721
+ titleAttr: item.title_attr || void 0,
2722
+ cssClasses: item.css_classes || void 0,
2723
+ children: []
2724
+ };
2725
+ }
2726
+ const SLUG_PLACEHOLDER = /\{slug\}/g;
2727
+ const ID_PLACEHOLDER = /\{id\}/g;
2728
+ /**
2729
+ * Interpolate a URL pattern with entry data
2730
+ *
2731
+ * Replaces `{slug}` and `{id}` placeholders.
2732
+ */
2733
+ function interpolateUrlPattern(pattern, slug, id) {
2734
+ return pattern.replace(SLUG_PLACEHOLDER, slug).replace(ID_PLACEHOLDER, id);
2735
+ }
2736
+ /**
2737
+ * Resolve the URL for a content reference. `referenceGroup` is the content
2738
+ * row's translation_group; we look up the row in the requested locale
2739
+ * (falling back to the source if no translation exists so the menu link is
2740
+ * still clickable).
2741
+ */
2742
+ async function resolveContentUrl(collection, referenceGroup, db, urlPatterns, locale) {
2743
+ if (!referenceGroup) return null;
2744
+ try {
2745
+ validateIdentifier(collection, "menu item collection");
2746
+ let result = await sql`
2747
+ SELECT id, slug FROM ${sql.ref(`ec_${collection}`)}
2748
+ WHERE translation_group = ${referenceGroup} AND locale = ${locale}
2749
+ LIMIT 1
2750
+ `.execute(db);
2751
+ let row = result.rows[0];
2752
+ if (!row) {
2753
+ result = await sql`
2754
+ SELECT id, slug FROM ${sql.ref(`ec_${collection}`)}
2755
+ WHERE translation_group = ${referenceGroup}
2756
+ ORDER BY locale ASC LIMIT 1
2757
+ `.execute(db);
2758
+ row = result.rows[0];
2759
+ }
2760
+ if (!row) row = (await sql`
2761
+ SELECT id, slug FROM ${sql.ref(`ec_${collection}`)}
2762
+ WHERE id = ${referenceGroup} LIMIT 1
2763
+ `.execute(db)).rows[0];
2764
+ if (!row) return null;
2765
+ const pattern = urlPatterns.get(collection);
2766
+ if (pattern) return interpolateUrlPattern(pattern, row.slug, row.id);
2767
+ return `/${collection}/${row.slug}`;
2768
+ } catch (error) {
2769
+ console.error(`Failed to resolve content URL for ${collection}/${referenceGroup}:`, error);
2770
+ return null;
2771
+ }
2772
+ }
2773
+ /**
2774
+ * Resolve URL for a taxonomy term reference. `referenceGroup` is the term's
2775
+ * translation_group; we pick the row in the active locale (or fall back).
2776
+ */
2777
+ async function resolveTaxonomyUrl(referenceGroup, db, locale) {
2778
+ if (!referenceGroup) return null;
2779
+ let taxonomy = await db.selectFrom("taxonomies").select(["name", "slug"]).where("translation_group", "=", referenceGroup).where("locale", "=", locale).executeTakeFirst();
2780
+ if (!taxonomy) taxonomy = await db.selectFrom("taxonomies").select(["name", "slug"]).where("translation_group", "=", referenceGroup).orderBy("locale", "asc").executeTakeFirst();
2781
+ if (!taxonomy) taxonomy = await db.selectFrom("taxonomies").select(["name", "slug"]).where("id", "=", referenceGroup).executeTakeFirst();
2782
+ if (!taxonomy) return null;
2783
+ return `/${taxonomy.name}/${taxonomy.slug}`;
2784
+ }
2785
+
2786
+ //#endregion
2787
+ export { image as C, file as S, after as _, NoopSandboxRunner as a, portableText as b, PluginManager as c, PluginRouteRegistry as d, EmailPipeline as f, definePlugin as g, resolveExclusiveHooks as h, getComments as i, createPluginManager as l, createHookPipeline as m, getMenus as n, SandboxNotAvailableError as o, HookPipeline as p, getCommentCount as r, createNoopSandboxRunner as s, getMenu as t, PluginRouteError as u, portableTextToProsemirror as v, reference as x, prosemirrorToPortableText as y };
2788
+ //# sourceMappingURL=menus-X4Z-eBA1.mjs.map