emdash 0.12.0 → 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 (1003) 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-C1ZORgcy.mjs → apply-v4DBgjPw.mjs} +19 -346
  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 +140 -69
  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 -8
  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-Dlkzhb4C.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-Bp6d4d4n.mjs → manifest-schema-HCtSh4Jq.mjs} +1 -1
  749. package/dist/{manifest-schema-Bp6d4d4n.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 +7 -6
  756. package/dist/media/local-runtime.mjs.map +1 -1
  757. package/dist/media-Dg7he9uK.mjs +209 -0
  758. package/dist/media-Dg7he9uK.mjs.map +1 -0
  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 +2 -2
  784. package/dist/parse-BFTPon-J.mjs +89 -0
  785. package/dist/parse-BFTPon-J.mjs.map +1 -0
  786. package/dist/passkey-config-Cg86_ISa.mjs +46 -0
  787. package/dist/passkey-config-Cg86_ISa.mjs.map +1 -0
  788. package/dist/{patterns-DsUZ4uxI.mjs → patterns-CqG5Ya3i.mjs} +54 -2
  789. package/dist/{patterns-DsUZ4uxI.mjs.map → patterns-CqG5Ya3i.mjs.map} +1 -1
  790. package/dist/{placeholder-CDPtkelt.d.mts → placeholder-D3cFCU9y.d.mts} +2 -1
  791. package/dist/{placeholder-CDPtkelt.d.mts.map → placeholder-D3cFCU9y.d.mts.map} +1 -1
  792. package/dist/placeholder-LqmHqvBw.mjs +143 -0
  793. package/dist/placeholder-LqmHqvBw.mjs.map +1 -0
  794. package/dist/plugin-types.d.mts +122 -0
  795. package/dist/plugin-types.d.mts.map +1 -0
  796. package/dist/plugin-types.mjs +1 -0
  797. package/dist/plugins/adapt-sandbox-entry.d.mts +20 -12
  798. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  799. package/dist/plugins/adapt-sandbox-entry.mjs +46 -23
  800. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  801. package/dist/preview-C1LOEbWZ.mjs +107 -0
  802. package/dist/preview-C1LOEbWZ.mjs.map +1 -0
  803. package/dist/{public-url-B1AxbbbQ.mjs → public-url-CseXl9Fv.mjs} +39 -2
  804. package/dist/{public-url-B1AxbbbQ.mjs.map → public-url-CseXl9Fv.mjs.map} +1 -1
  805. package/dist/{query-yA3-rFji.mjs → query-axZmO6Tn.mjs} +12 -12
  806. package/dist/{query-yA3-rFji.mjs.map → query-axZmO6Tn.mjs.map} +1 -1
  807. package/dist/rate-limit-t5CVjCO6.mjs +120 -0
  808. package/dist/rate-limit-t5CVjCO6.mjs.map +1 -0
  809. package/dist/redirect-DGRsLO2I.mjs +17 -0
  810. package/dist/redirect-DGRsLO2I.mjs.map +1 -0
  811. package/dist/{redirect-C5H7VGIX.mjs → redirect-DkaDxq8e.mjs} +3 -3
  812. package/dist/{redirect-C5H7VGIX.mjs.map → redirect-DkaDxq8e.mjs.map} +1 -1
  813. package/dist/redirects-D1fdd68T.mjs +573 -0
  814. package/dist/redirects-D1fdd68T.mjs.map +1 -0
  815. package/dist/redirects-Dmj6KRU3.mjs +1141 -0
  816. package/dist/redirects-Dmj6KRU3.mjs.map +1 -0
  817. package/dist/{registry-Do34mz_P.mjs → registry-BnCeHYsf.mjs} +8 -300
  818. package/dist/registry-BnCeHYsf.mjs.map +1 -0
  819. package/dist/{request-cache-D4I69LeL.mjs → request-cache-dzCt8TZB.mjs} +1 -1
  820. package/dist/{request-cache-D4I69LeL.mjs.map → request-cache-dzCt8TZB.mjs.map} +1 -1
  821. package/dist/request-meta-CLCwSQOS.mjs +140 -0
  822. package/dist/request-meta-CLCwSQOS.mjs.map +1 -0
  823. package/dist/{runner-Iu3IZSDM.d.mts → runner-DcfZewkO.d.mts} +2 -2
  824. package/dist/{runner-Iu3IZSDM.d.mts.map → runner-DcfZewkO.d.mts.map} +1 -1
  825. package/dist/{runner-DIcU2UCC.mjs → runner-DdnQIwz_.mjs} +436 -187
  826. package/dist/runner-DdnQIwz_.mjs.map +1 -0
  827. package/dist/runtime.d.mts +10 -6
  828. package/dist/runtime.d.mts.map +1 -1
  829. package/dist/runtime.mjs +3 -3
  830. package/dist/schema-BmqagCwG.mjs +41 -0
  831. package/dist/schema-BmqagCwG.mjs.map +1 -0
  832. package/dist/search-CPrvO5u8.mjs +376 -0
  833. package/dist/search-CPrvO5u8.mjs.map +1 -0
  834. package/dist/{secrets-CZ8rxLX3.mjs → secrets-6pgZyq0K.mjs} +3 -3
  835. package/dist/{secrets-CZ8rxLX3.mjs.map → secrets-6pgZyq0K.mjs.map} +1 -1
  836. package/dist/sections-Cm-zb-gZ.mjs +346 -0
  837. package/dist/sections-Cm-zb-gZ.mjs.map +1 -0
  838. package/dist/seed/index.d.mts +2 -2
  839. package/dist/seed/index.mjs +19 -15
  840. package/dist/seo/index.d.mts +1 -1
  841. package/dist/seo-BoR4wCUh.mjs +86 -0
  842. package/dist/seo-BoR4wCUh.mjs.map +1 -0
  843. package/dist/seo-DRq9-EPP.mjs +130 -0
  844. package/dist/seo-DRq9-EPP.mjs.map +1 -0
  845. package/dist/service-vByySp-2.mjs +195 -0
  846. package/dist/service-vByySp-2.mjs.map +1 -0
  847. package/dist/settings-CBBj7HUd.mjs +51 -0
  848. package/dist/settings-CBBj7HUd.mjs.map +1 -0
  849. package/dist/settings-xQKsWnzQ.mjs +235 -0
  850. package/dist/settings-xQKsWnzQ.mjs.map +1 -0
  851. package/dist/setup-BGAJ2uXs.mjs +137 -0
  852. package/dist/setup-BGAJ2uXs.mjs.map +1 -0
  853. package/dist/setup-complete-C6ZCLhKo.mjs +26 -0
  854. package/dist/setup-complete-C6ZCLhKo.mjs.map +1 -0
  855. package/dist/setup-nonce-CY1gQiAU.mjs +25 -0
  856. package/dist/setup-nonce-CY1gQiAU.mjs.map +1 -0
  857. package/dist/site-url-D-M4Fd8O.mjs +13 -0
  858. package/dist/site-url-D-M4Fd8O.mjs.map +1 -0
  859. package/dist/slugify-Cjh1ssOZ.mjs +30 -0
  860. package/dist/slugify-Cjh1ssOZ.mjs.map +1 -0
  861. package/dist/ssrf-CTul4uQi.mjs +1 -0
  862. package/dist/ssrf-DzFN_qV-.mjs +332 -0
  863. package/dist/ssrf-DzFN_qV-.mjs.map +1 -0
  864. package/dist/storage/local.d.mts +1 -1
  865. package/dist/storage/local.mjs +1 -1
  866. package/dist/storage/s3.d.mts +1 -1
  867. package/dist/storage/s3.mjs +1 -1
  868. package/dist/{taxonomies-JmQQZiG1.mjs → taxonomies-Cn9UpaR2.mjs} +7 -7
  869. package/dist/{taxonomies-JmQQZiG1.mjs.map → taxonomies-Cn9UpaR2.mjs.map} +1 -1
  870. package/dist/taxonomies-Dc0mzlms.mjs +508 -0
  871. package/dist/taxonomies-Dc0mzlms.mjs.map +1 -0
  872. package/dist/{taxonomy-D6NvlKo8.mjs → taxonomy-wPfusMK9.mjs} +3 -3
  873. package/dist/{taxonomy-D6NvlKo8.mjs.map → taxonomy-wPfusMK9.mjs.map} +1 -1
  874. package/dist/{tokens-CyRDPVW2.mjs → tokens-DILYNZMi.mjs} +2 -2
  875. package/dist/{tokens-CyRDPVW2.mjs.map → tokens-DILYNZMi.mjs.map} +1 -1
  876. package/dist/{transaction-D44LBXvU.mjs → transaction-NQj4VJ7Z.mjs} +1 -1
  877. package/dist/{transaction-D44LBXvU.mjs.map → transaction-NQj4VJ7Z.mjs.map} +1 -1
  878. package/dist/{transport-DX_5rpsq.d.mts → transport-GeXlLscf.d.mts} +1 -1
  879. package/dist/{transport-DX_5rpsq.d.mts.map → transport-GeXlLscf.d.mts.map} +1 -1
  880. package/dist/{transport-xpzIjCIB.mjs → transport-fw-mKJzT.mjs} +1 -1
  881. package/dist/{transport-xpzIjCIB.mjs.map → transport-fw-mKJzT.mjs.map} +1 -1
  882. package/dist/trusted-proxy-CJhQIk65.mjs +51 -0
  883. package/dist/trusted-proxy-CJhQIk65.mjs.map +1 -0
  884. package/dist/{types-DgSc9Rpc.d.mts → types-B05e2naf.d.mts} +5 -59
  885. package/dist/types-B05e2naf.d.mts.map +1 -0
  886. package/dist/{types-B1gLSAH2.d.mts → types-BWhaSS7U.d.mts} +2 -75
  887. package/dist/types-BWhaSS7U.d.mts.map +1 -0
  888. package/dist/{types-BQx6ZXpR.d.mts → types-C1KKK4VP.d.mts} +3 -1
  889. package/dist/{types-BQx6ZXpR.d.mts.map → types-C1KKK4VP.d.mts.map} +1 -1
  890. package/dist/types-Cb2UCDJg.d.mts +345 -0
  891. package/dist/types-Cb2UCDJg.d.mts.map +1 -0
  892. package/dist/{types-BIgulNsW.mjs → types-CwXMEPRr.mjs} +10 -3
  893. package/dist/types-CwXMEPRr.mjs.map +1 -0
  894. package/dist/{types-B_CXXnzh.d.mts → types-CzvJd1ND.d.mts} +7 -1
  895. package/dist/{types-B_CXXnzh.d.mts.map → types-CzvJd1ND.d.mts.map} +1 -1
  896. package/dist/types-DFowNO60.d.mts +198 -0
  897. package/dist/types-DFowNO60.d.mts.map +1 -0
  898. package/dist/{types-56BKbld_.mjs → types-DSZl1Dsv.mjs} +1 -1
  899. package/dist/{types-56BKbld_.mjs.map → types-DSZl1Dsv.mjs.map} +1 -1
  900. package/dist/types-DW1l0gCv.d.mts +75 -0
  901. package/dist/types-DW1l0gCv.d.mts.map +1 -0
  902. package/dist/types-Db67HHlU.mjs +3 -0
  903. package/dist/{types-C-aFbqmA.d.mts → types-DmxPPXGf.d.mts} +1 -1
  904. package/dist/{types-C-aFbqmA.d.mts.map → types-DmxPPXGf.d.mts.map} +1 -1
  905. package/dist/{types-PafqtQuM.mjs → types-Dz9CGX_d.mjs} +1 -1
  906. package/dist/{types-PafqtQuM.mjs.map → types-Dz9CGX_d.mjs.map} +1 -1
  907. package/dist/user-Dr1bOCqS.mjs +155 -0
  908. package/dist/user-Dr1bOCqS.mjs.map +1 -0
  909. package/dist/utils-_F-rWBTN.mjs +286 -0
  910. package/dist/utils-_F-rWBTN.mjs.map +1 -0
  911. package/dist/{validate-BcC3m2O7.d.mts → validate-BpQGsmd7.d.mts} +5 -4
  912. package/dist/validate-BpQGsmd7.d.mts.map +1 -0
  913. package/dist/{validate-UK4Ja1uo.mjs → validate-DlFxcVVK.mjs} +3 -3
  914. package/dist/{validate-UK4Ja1uo.mjs.map → validate-DlFxcVVK.mjs.map} +1 -1
  915. package/dist/{validation-Vc5DQkJa.mjs → validation-BiFJqUp5.mjs} +6 -5
  916. package/dist/{validation-Vc5DQkJa.mjs.map → validation-BiFJqUp5.mjs.map} +1 -1
  917. package/dist/version-Dw7Z5PVU.mjs +7 -0
  918. package/dist/{version-BdP--J1g.mjs.map → version-Dw7Z5PVU.mjs.map} +1 -1
  919. package/dist/widgets-B9j_yzlk.mjs +106 -0
  920. package/dist/widgets-B9j_yzlk.mjs.map +1 -0
  921. package/dist/zod-generator-DSyz01KE.mjs +234 -0
  922. package/dist/zod-generator-DSyz01KE.mjs.map +1 -0
  923. package/locals.d.ts +1 -1
  924. package/package.json +37 -14
  925. package/src/api/handlers/content.ts +1 -0
  926. package/src/api/handlers/index.ts +7 -0
  927. package/src/api/handlers/marketplace.ts +27 -6
  928. package/src/api/handlers/menus.ts +157 -580
  929. package/src/api/handlers/plugins.ts +77 -31
  930. package/src/api/handlers/registry.ts +1086 -0
  931. package/src/api/openapi/document.ts +10 -4
  932. package/src/api/schemas/content.ts +1 -0
  933. package/src/api/schemas/menus.ts +27 -23
  934. package/src/api/types.ts +6 -0
  935. package/src/astro/integration/index.ts +1 -0
  936. package/src/astro/integration/route-naming.ts +19 -0
  937. package/src/astro/integration/routes.ts +25 -3
  938. package/src/astro/integration/runtime.ts +35 -8
  939. package/src/astro/middleware/auth.ts +8 -2
  940. package/src/astro/middleware/csp.ts +25 -3
  941. package/src/astro/middleware.ts +3 -0
  942. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +10 -0
  943. package/src/astro/routes/api/admin/plugins/registry/install.ts +107 -0
  944. package/src/astro/routes/api/auth/invite/register-options.ts +8 -1
  945. package/src/astro/routes/api/import/wordpress/execute.ts +185 -6
  946. package/src/astro/routes/api/menus/[name]/items/[id].ts +69 -0
  947. package/src/astro/routes/api/menus/[name]/items.ts +4 -65
  948. package/src/astro/types.ts +38 -0
  949. package/src/cli/wxr/parser.ts +263 -0
  950. package/src/client/index.ts +2 -1
  951. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +166 -49
  952. package/src/database/migrations/038_registry_plugin_state.ts +130 -0
  953. package/src/database/migrations/039_fix_fts5_triggers.ts +264 -0
  954. package/src/database/migrations/runner.ts +4 -0
  955. package/src/database/repositories/content.ts +5 -1
  956. package/src/database/repositories/index.ts +14 -0
  957. package/src/database/repositories/menu.ts +644 -0
  958. package/src/database/repositories/types.ts +6 -0
  959. package/src/database/types.ts +5 -1
  960. package/src/emdash-runtime.ts +122 -34
  961. package/src/import/sources/wordpress-plugin.ts +9 -2
  962. package/src/import/sources/wxr.ts +16 -2
  963. package/src/import/ssrf.ts +20 -500
  964. package/src/import/wxr-taxonomies.ts +730 -0
  965. package/src/index.ts +3 -10
  966. package/src/media/normalize.ts +37 -4
  967. package/src/plugin-types.ts +240 -0
  968. package/src/plugins/adapt-sandbox-entry.ts +115 -39
  969. package/src/plugins/define-plugin.ts +34 -56
  970. package/src/plugins/index.ts +1 -9
  971. package/src/plugins/marketplace.ts +63 -4
  972. package/src/plugins/sandbox/index.ts +1 -1
  973. package/src/plugins/sandbox/noop.ts +2 -2
  974. package/src/plugins/sandbox/types.ts +7 -4
  975. package/src/plugins/state.ts +84 -38
  976. package/src/plugins/types.ts +2 -79
  977. package/src/registry/config.ts +311 -0
  978. package/src/registry/plugin-id.ts +116 -0
  979. package/src/registry/types.ts +206 -0
  980. package/src/search/fts-manager.ts +77 -15
  981. package/src/security/ssrf.ts +501 -0
  982. package/dist/apply-C1ZORgcy.mjs.map +0 -1
  983. package/dist/content-CERxPUN0.mjs.map +0 -1
  984. package/dist/error-D6LuHLw9.mjs +0 -27
  985. package/dist/error-D6LuHLw9.mjs.map +0 -1
  986. package/dist/index-Dlkzhb4C.d.mts.map +0 -1
  987. package/dist/placeholder-Ci0RLeCk.mjs +0 -268
  988. package/dist/placeholder-Ci0RLeCk.mjs.map +0 -1
  989. package/dist/registry-Do34mz_P.mjs.map +0 -1
  990. package/dist/runner-DIcU2UCC.mjs.map +0 -1
  991. package/dist/search-n-ZCMfr3.mjs +0 -9914
  992. package/dist/search-n-ZCMfr3.mjs.map +0 -1
  993. package/dist/settings-nTXPRi3D.mjs +0 -440
  994. package/dist/settings-nTXPRi3D.mjs.map +0 -1
  995. package/dist/types-B1gLSAH2.d.mts.map +0 -1
  996. package/dist/types-BIgulNsW.mjs.map +0 -1
  997. package/dist/types-Cug_RO3W.mjs +0 -16
  998. package/dist/types-Cug_RO3W.mjs.map +0 -1
  999. package/dist/types-DgSc9Rpc.d.mts.map +0 -1
  1000. package/dist/validate-BcC3m2O7.d.mts.map +0 -1
  1001. package/dist/version-BdP--J1g.mjs +0 -7
  1002. package/dist/zod-generator-CHnJUP2l.mjs +0 -137
  1003. package/dist/zod-generator-CHnJUP2l.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.mjs","names":[],"sources":["../../../../src/mcp/server.ts","../../../../src/astro/routes/api/mcp.ts"],"sourcesContent":["/**\n * EmDash MCP Server\n *\n * Exposes content, schema, media, search, taxonomy, and menu operations\n * as MCP tools over the Streamable HTTP transport.\n *\n * Tools use the EmDashHandlers interface (same as locals.emdash) so\n * they work with the pre-bound handlers that the middleware provides.\n * The handlers instance is passed per-request via authInfo on the transport.\n */\n\nimport type { Permission, RoleLevel } from \"@emdash-cms/auth\";\nimport { canActOnOwn, hasPermission, Role } from \"@emdash-cms/auth\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nimport { contentBylineInputSchema, contentSeoInput } from \"#api/schemas.js\";\n\nimport type { EmDashHandlers } from \"../astro/types.js\";\nimport { hasScope } from \"../auth/api-tokens.js\";\n\nconst COLLECTION_SLUG_PATTERN = /^[a-z][a-z0-9_]*$/;\n/** http(s) scheme matcher used by `settings_update` URL validation. */\nconst HTTP_SCHEME_PATTERN = /^https?:\\/\\//i;\n\n// ---------------------------------------------------------------------------\n// Shared schemas — kept in sync with `api/schemas/settings.ts` (which the\n// REST handler validates against). Defined inline to match the rest of the\n// MCP tool registrations rather than reaching across into the REST layer.\n// ---------------------------------------------------------------------------\n\nconst settingsMediaReferenceSchema = z.object({\n\tmediaId: z.string().describe(\"Media item ID (use media_create or media_list)\"),\n\talt: z.string().optional().describe(\"Alt text for the media reference\"),\n});\n\nconst settingsSocialSchema = z.object({\n\ttwitter: z.string().optional(),\n\tgithub: z.string().optional(),\n\tfacebook: z.string().optional(),\n\tinstagram: z.string().optional(),\n\tlinkedin: z.string().optional(),\n\tyoutube: z.string().optional(),\n});\n\nconst settingsSeoSchema = z.object({\n\ttitleSeparator: z\n\t\t.string()\n\t\t.max(10)\n\t\t.optional()\n\t\t.describe(\"Separator between page title and site title (e.g. ' | ')\"),\n\tdefaultOgImage: settingsMediaReferenceSchema\n\t\t.optional()\n\t\t.describe(\"Default Open Graph image when content has none\"),\n\trobotsTxt: z\n\t\t.string()\n\t\t.max(5000)\n\t\t.optional()\n\t\t.describe(\"Custom robots.txt body. Leave unset for the EmDash default.\"),\n\tgoogleVerification: z\n\t\t.string()\n\t\t.max(100)\n\t\t.optional()\n\t\t.describe(\"Google Search Console verification token\"),\n\tbingVerification: z\n\t\t.string()\n\t\t.max(100)\n\t\t.optional()\n\t\t.describe(\"Bing Webmaster Tools verification token\"),\n});\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\ntype HandlerResult = {\n\tsuccess: boolean;\n\tdata?: unknown;\n\terror?: unknown;\n};\n\ntype SuccessEnvelope = {\n\tcontent: Array<{ type: \"text\"; text: string }>;\n\t_meta?: Record<string, unknown>;\n};\n\ntype ErrorEnvelope = {\n\tcontent: Array<{ type: \"text\"; text: string }>;\n\tisError: true;\n\t_meta: { code: string; details?: Record<string, unknown> };\n};\n\n/**\n * Return a successful tool response with the data as pretty-printed JSON.\n */\nfunction respondData(data: unknown): SuccessEnvelope {\n\treturn {\n\t\tcontent: [{ type: \"text\", text: JSON.stringify(data, null, 2) }],\n\t};\n}\n\n/**\n * Return a structured error tool response.\n *\n * The error code is emitted both in the human-readable message (as a stable\n * `[CODE]` prefix that callers can match on) and in `_meta.code` so MCP-aware\n * clients can read it programmatically once the SDK supports forwarding meta.\n */\nfunction respondError(\n\tcode: string,\n\tmessage: string,\n\tdetails?: Record<string, unknown>,\n): ErrorEnvelope {\n\tconst text = `[${code}] ${message}`;\n\tconst meta: { code: string; details?: Record<string, unknown> } = { code };\n\tif (details !== undefined) meta.details = details;\n\treturn {\n\t\tcontent: [{ type: \"text\", text }],\n\t\tisError: true,\n\t\t_meta: meta,\n\t};\n}\n\n/**\n * Auth/permission errors thrown from `requireScope` / `requireRole` /\n * `requireOwnership` / `requireDraftAccess`. Carries a stable string `code`\n * field so `respondHandlerError` can surface it through `_meta.code` and\n * the message prefix.\n *\n * Distinct from `McpError` (which the SDK catches at JSON-RPC level — the\n * code there is numeric, not a stable EmDash error code).\n */\nclass EmDashAuthError extends Error {\n\toverride readonly name = \"EmDashAuthError\";\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly code: string,\n\t) {\n\t\tsuper(message);\n\t}\n}\n\n/**\n * Map an unknown thrown error to a structured error envelope.\n *\n * Recognises (in priority order):\n * - `EmDashAuthError` — `code` is a stable EmDash auth code\n * (`UNAUTHORIZED`, `INSUFFICIENT_SCOPE`, `INSUFFICIENT_PERMISSIONS`).\n * - `Error` objects with an `apiError: { code, details? }` annotation\n * (handlers throw these for NOT_FOUND / CONFLICT inside transactions;\n * see `api/handlers/content.ts:538`).\n * - `SchemaError` (and any error with a string `code` field) — the code\n * is forwarded verbatim. `details` is forwarded too if present.\n * - Plain `Error` instances — message preserved, code falls back to\n * `fallbackCode` (or `INTERNAL_ERROR`).\n * - Strings — used directly as the message.\n * - Anything else — coerced via `String()`.\n *\n * The original message is always preserved so tests and humans can see the\n * specific failure cause. Numeric `code` values (e.g. on `McpError`) are\n * ignored — the field is reserved for stable string codes.\n */\nfunction respondHandlerError(error: unknown, fallbackCode = \"INTERNAL_ERROR\"): ErrorEnvelope {\n\tlet code = fallbackCode;\n\tlet message: string;\n\tlet details: Record<string, unknown> | undefined;\n\n\tif (error instanceof EmDashAuthError) {\n\t\tmessage = error.message || fallbackCode;\n\t\tcode = error.code;\n\t} else if (error instanceof Error) {\n\t\tmessage = error.message || fallbackCode;\n\t\tconst apiError = (error as { apiError?: { code?: string; details?: unknown } }).apiError;\n\t\tif (apiError && typeof apiError.code === \"string\" && apiError.code) {\n\t\t\tcode = apiError.code;\n\t\t\tif (apiError.details && typeof apiError.details === \"object\") {\n\t\t\t\tdetails = apiError.details as Record<string, unknown>;\n\t\t\t}\n\t\t} else {\n\t\t\t// Errors that carry their own `code` (SchemaError, custom errors).\n\t\t\t// Skip numeric codes (McpError, Node fs errors) — `_meta.code` is\n\t\t\t// reserved for stable string codes.\n\t\t\tconst rawCode = (error as { code?: unknown }).code;\n\t\t\tif (typeof rawCode === \"string\" && rawCode) {\n\t\t\t\tcode = rawCode;\n\t\t\t}\n\t\t\tconst rawDetails = (error as { details?: unknown }).details;\n\t\t\tif (rawDetails && typeof rawDetails === \"object\") {\n\t\t\t\tdetails = rawDetails as Record<string, unknown>;\n\t\t\t}\n\t\t}\n\t} else if (typeof error === \"string\") {\n\t\tmessage = error;\n\t} else {\n\t\tmessage = String(error);\n\t}\n\n\treturn respondError(code, message, details);\n}\n\n/**\n * Unwrap an ApiResult<T> into MCP tool result format.\n *\n * On success returns the data as JSON. On failure propagates the structured\n * `{ code, message, details }` from the handler so the caller sees both a\n * machine-readable code (in `_meta.code` and as a `[CODE]` message prefix)\n * and the original human-readable message.\n */\nfunction unwrap(result: HandlerResult): SuccessEnvelope | ErrorEnvelope {\n\tif (result.success && result.data !== undefined) {\n\t\treturn respondData(result.data);\n\t}\n\tconst err =\n\t\tresult.error && typeof result.error === \"object\"\n\t\t\t? (result.error as { code?: unknown; message?: unknown; details?: unknown })\n\t\t\t: undefined;\n\tif (!err) return respondError(\"INTERNAL_ERROR\", \"Unknown error\");\n\tconst code = typeof err.code === \"string\" && err.code ? err.code : \"INTERNAL_ERROR\";\n\tconst message = typeof err.message === \"string\" && err.message ? err.message : \"Unknown error\";\n\tconst details =\n\t\terr.details && typeof err.details === \"object\"\n\t\t\t? (err.details as Record<string, unknown>)\n\t\t\t: undefined;\n\treturn respondError(code, message, details);\n}\n\n/**\n * Return a JSON text block (success path for tools that don't go through\n * the ApiResult-returning handler layer, e.g. schema/menu/taxonomy).\n */\nfunction jsonResult(data: unknown): SuccessEnvelope {\n\treturn respondData(data);\n}\n\n// ---------------------------------------------------------------------------\n// Context extraction\n//\n// The route handler passes emdash + userId in authInfo.extra.\n// ---------------------------------------------------------------------------\n\ninterface EmDashExtra {\n\temdash: EmDashHandlers;\n\tuserId: string;\n\t/** The authenticated user's RBAC role level. */\n\tuserRole: RoleLevel;\n\t/** Token scopes — undefined for session auth (all access allowed). */\n\ttokenScopes?: string[];\n}\n\nfunction isPublished(t: unknown): boolean {\n\treturn (\n\t\ttypeof t === \"object\" &&\n\t\tt !== null &&\n\t\t\"status\" in t &&\n\t\t(t as Record<string, unknown>).status === \"published\"\n\t);\n}\n\nfunction getExtra(extra: { authInfo?: { extra?: Record<string, unknown> } }): EmDashExtra {\n\tconst payload = extra.authInfo?.extra as EmDashExtra | undefined;\n\tif (!payload?.emdash) {\n\t\tthrow new Error(\"EmDash not available — server misconfigured\");\n\t}\n\treturn payload;\n}\n\nfunction getEmDash(extra: { authInfo?: { extra?: Record<string, unknown> } }): EmDashHandlers {\n\treturn getExtra(extra).emdash;\n}\n\n/**\n * Enforce a scope requirement on the current request.\n *\n * When tokenScopes is undefined (session auth), all operations are allowed\n * since session users have full access based on their role. When scopes are\n * present (token auth), the required scope must be included.\n */\nfunction requireScope(\n\textra: { authInfo?: { extra?: Record<string, unknown> } },\n\tscope: string,\n): void {\n\tconst payload = getExtra(extra);\n\tif (payload.tokenScopes && !hasScope(payload.tokenScopes, scope)) {\n\t\tthrow new EmDashAuthError(`Insufficient scope: requires ${scope}`, \"INSUFFICIENT_SCOPE\");\n\t}\n}\n\n/**\n * Defense-in-depth: enforce a minimum RBAC role on the current request.\n *\n * This is checked in addition to scope requirements. Even if a token has\n * the right scopes (e.g. due to a bug in scope clamping), the user's\n * actual role must still meet the minimum.\n */\nfunction requireRole(\n\textra: { authInfo?: { extra?: Record<string, unknown> } },\n\tminRole: RoleLevel,\n): void {\n\tconst payload = getExtra(extra);\n\tif (payload.userRole < minRole) {\n\t\tthrow new EmDashAuthError(\n\t\t\t\"Insufficient permissions for this operation\",\n\t\t\t\"INSUFFICIENT_PERMISSIONS\",\n\t\t);\n\t}\n}\n\n/**\n * Whether the current user may read non-published content (drafts, scheduled,\n * trashed, revisions, compare). SUBSCRIBER may hold content:read for\n * member-only published content but must not see drafts.\n */\nfunction canReadDrafts(extra: { authInfo?: { extra?: Record<string, unknown> } }): boolean {\n\tconst payload = getExtra(extra);\n\treturn hasPermission({ role: payload.userRole }, \"content:read_drafts\");\n}\n\n/**\n * Throw if the current user cannot read non-published content. Used by\n * editor-only views (revisions, compare, trash, preview-url).\n */\nfunction requireDraftAccess(extra: { authInfo?: { extra?: Record<string, unknown> } }): void {\n\tif (!canReadDrafts(extra)) {\n\t\tthrow new EmDashAuthError(\n\t\t\t\"Insufficient permissions for this operation\",\n\t\t\t\"INSUFFICIENT_PERMISSIONS\",\n\t\t);\n\t}\n}\n\n/**\n * Enforce ownership-based permission checks, mirroring the REST API's\n * requireOwnerPerm() pattern.\n *\n * If the user is the owner, checks ownPermission. Otherwise checks\n * anyPermission (which requires EDITOR+ role).\n */\nfunction requireOwnership(\n\textra: { authInfo?: { extra?: Record<string, unknown> } },\n\townerId: string,\n\townPermission: Permission,\n\tanyPermission: Permission,\n): void {\n\tconst payload = getExtra(extra);\n\tconst user = { id: payload.userId, role: payload.userRole };\n\tif (!canActOnOwn(user, ownerId, ownPermission, anyPermission)) {\n\t\tthrow new EmDashAuthError(\n\t\t\t\"Insufficient permissions for this operation\",\n\t\t\t\"INSUFFICIENT_PERMISSIONS\",\n\t\t);\n\t}\n}\n\n/**\n * Extract the author ID from a content handler response.\n *\n * Content handlers return `{ item: { id, authorId, ... }, _rev? }`.\n * This helper navigates that shape safely. Returns \"\" when authorId is\n * missing or non-string (e.g. seed-imported content with no author);\n * `canActOnOwn` then decides based on the caller's permissions —\n * an actor with `*:edit_any` succeeds, an actor with only `*:edit_own`\n * is denied with a clean permission error.\n */\nfunction extractContentAuthorId(data: unknown): string {\n\tif (!data || typeof data !== \"object\") return \"\";\n\tconst obj = data as Record<string, unknown>;\n\tconst item =\n\t\tobj.item && typeof obj.item === \"object\" ? (obj.item as Record<string, unknown>) : obj;\n\treturn typeof item?.authorId === \"string\" ? item.authorId : \"\";\n}\n\n/**\n * Extract the resolved ID from a content handler response.\n * Handles slug -> ID resolution performed by the handler.\n */\nfunction extractContentId(data: unknown): string | undefined {\n\tif (!data || typeof data !== \"object\") return undefined;\n\tconst obj = data as Record<string, unknown>;\n\tconst item =\n\t\tobj.item && typeof obj.item === \"object\" ? (obj.item as Record<string, unknown>) : obj;\n\treturn typeof item?.id === \"string\" ? item.id : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Server factory\n// ---------------------------------------------------------------------------\n\nexport function createMcpServer(): McpServer {\n\tconst server = new McpServer(\n\t\t{ name: \"emdash\", version: \"0.1.0\" },\n\t\t{ capabilities: { logging: {} } },\n\t);\n\n\t// Wrap every tool registration's callback so EmDashAuthError throws\n\t// (from requireScope / requireRole / requireOwnership / requireDraftAccess)\n\t// surface as structured `_meta.code`-bearing tool error envelopes\n\t// instead of the SDK's text-only fallback in createToolError().\n\t//\n\t// Type-erased on purpose — the SDK's overloads are too narrow for a\n\t// generic wrapper, but the runtime contract (callback returns the tool\n\t// result envelope) holds for every registered tool.\n\tconst originalRegisterTool = server.registerTool.bind(server);\n\t(server as { registerTool: typeof server.registerTool }).registerTool = ((\n\t\tname: string,\n\t\tconfig: unknown,\n\t\tcallback: (...callbackArgs: unknown[]) => Promise<SuccessEnvelope | ErrorEnvelope>,\n\t) => {\n\t\tconst wrapped = async (\n\t\t\t...callbackArgs: unknown[]\n\t\t): Promise<SuccessEnvelope | ErrorEnvelope> => {\n\t\t\ttry {\n\t\t\t\treturn await callback(...callbackArgs);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"INTERNAL_ERROR\");\n\t\t\t}\n\t\t};\n\t\treturn (\n\t\t\toriginalRegisterTool as unknown as (n: string, c: unknown, cb: typeof wrapped) => unknown\n\t\t)(name, config, wrapped);\n\t}) as typeof server.registerTool;\n\n\t// =====================================================================\n\t// Content tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"content_list\",\n\t\t{\n\t\t\ttitle: \"List Content\",\n\t\t\tdescription:\n\t\t\t\t\"List content items in a collection with optional filtering and pagination. \" +\n\t\t\t\t\"Returns items sorted by the specified field. Use the nextCursor value from \" +\n\t\t\t\t\"the response to fetch the next page. Status can be 'draft', 'published', \" +\n\t\t\t\t\"or 'scheduled'. If no status is given, all non-trashed items are returned.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug (e.g. 'posts', 'pages')\"),\n\t\t\t\tstatus: z\n\t\t\t\t\t.enum([\"draft\", \"published\", \"scheduled\"])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Filter by content status\"),\n\t\t\t\tlimit: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.int()\n\t\t\t\t\t.min(1)\n\t\t\t\t\t.max(100)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Max items to return (default 50, max 100)\"),\n\t\t\t\tcursor: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.min(1)\n\t\t\t\t\t.max(2048)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Pagination cursor from a previous response\"),\n\t\t\t\torderBy: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Field to sort by (e.g. 'created_at', 'updated_at')\"),\n\t\t\t\torder: z.enum([\"asc\", \"desc\"]).optional().describe(\"Sort direction (default 'desc')\"),\n\t\t\t\tlocale: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Filter by locale (e.g. 'en', 'fr'). Only relevant when i18n is enabled.\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\t// Subscribers must only see published content; force the status\n\t\t\t// filter regardless of caller-supplied value.\n\t\t\tconst status = canReadDrafts(extra) ? args.status : \"published\";\n\t\t\treturn unwrap(\n\t\t\t\tawait ec.handleContentList(args.collection, {\n\t\t\t\t\tstatus,\n\t\t\t\t\tlimit: args.limit,\n\t\t\t\t\tcursor: args.cursor,\n\t\t\t\t\torderBy: args.orderBy,\n\t\t\t\t\torder: args.order,\n\t\t\t\t\tlocale: args.locale,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_get\",\n\t\t{\n\t\t\ttitle: \"Get Content\",\n\t\t\tdescription:\n\t\t\t\t\"Get a single content item by its ID or slug. Returns the full content data \" +\n\t\t\t\t\"including all field values, metadata, and a _rev token for optimistic \" +\n\t\t\t\t\"concurrency (pass _rev back when updating to detect conflicts).\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug (e.g. 'posts', 'pages')\"),\n\t\t\t\tid: z.string().describe(\"Content item ID (ULID) or slug\"),\n\t\t\t\tlocale: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Locale to scope slug lookup (e.g. 'fr'). Only affects slug resolution; IDs are globally unique.\",\n\t\t\t\t\t),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\tconst result = await ec.handleContentGet(args.collection, args.id, args.locale);\n\t\t\t// Hide non-published items from users without draft access. Return a\n\t\t\t// not-found error so subscribers can't enumerate draft IDs by status.\n\t\t\tif (result.success && !canReadDrafts(extra)) {\n\t\t\t\tconst data =\n\t\t\t\t\tresult.data && typeof result.data === \"object\"\n\t\t\t\t\t\t? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check\n\t\t\t\t\t\t\t(result.data as Record<string, unknown>)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst item =\n\t\t\t\t\tdata?.item && typeof data.item === \"object\"\n\t\t\t\t\t\t? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- narrowed by typeof check\n\t\t\t\t\t\t\t(data.item as Record<string, unknown>)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst status = typeof item?.status === \"string\" ? item.status : null;\n\t\t\t\tif (status !== \"published\") {\n\t\t\t\t\treturn unwrap({\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\terror: { code: \"NOT_FOUND\", message: `Content item not found: ${args.id}` },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn unwrap(result);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_create\",\n\t\t{\n\t\t\ttitle: \"Create Content\",\n\t\t\tdescription:\n\t\t\t\t\"Create a new content item in a collection. The 'data' object should \" +\n\t\t\t\t\"contain field values matching the collection's schema (use \" +\n\t\t\t\t\"schema_get_collection to check). Rich text fields accept Portable Text \" +\n\t\t\t\t\"JSON arrays. A slug is auto-generated if not provided. Items are created \" +\n\t\t\t\t\"as 'draft' by default — use content_publish to make them live.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug (e.g. 'posts', 'pages')\"),\n\t\t\t\tdata: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.describe(\"Field values as key-value pairs matching the collection schema\"),\n\t\t\t\tslug: z.string().optional().describe(\"URL slug (auto-generated from title if omitted)\"),\n\t\t\t\tstatus: z\n\t\t\t\t\t.enum([\"draft\", \"published\"])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Initial status (default 'draft'). Requires publish permission.\"),\n\t\t\t\tlocale: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Locale for this content (e.g. 'fr'). Defaults to default locale.\"),\n\t\t\t\ttranslationOf: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"ID of the content item this is a translation of. Links items in the same translation group.\",\n\t\t\t\t\t),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: false },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.CONTRIBUTOR);\n\t\t\tconst { emdash, userId } = getExtra(extra);\n\n\t\t\t// Creating a translation requires edit permission on the source item\n\t\t\tif (args.translationOf) {\n\t\t\t\tconst source = await emdash.handleContentGet(args.collection, args.translationOf);\n\t\t\t\tif (!source.success) return unwrap(source);\n\t\t\t\trequireOwnership(\n\t\t\t\t\textra,\n\t\t\t\t\textractContentAuthorId(source.data),\n\t\t\t\t\t\"content:edit_own\",\n\t\t\t\t\t\"content:edit_any\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Publishing requires publish permission — create as draft then publish\n\t\t\tif (args.status === \"published\") {\n\t\t\t\tconst user = { id: userId, role: getExtra(extra).userRole };\n\t\t\t\tif (!hasPermission(user, \"content:publish_own\" as Permission)) {\n\t\t\t\t\tthrow new EmDashAuthError(\n\t\t\t\t\t\t\"Insufficient permissions: publishing requires content:publish_own\",\n\t\t\t\t\t\t\"INSUFFICIENT_PERMISSIONS\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst result = await emdash.handleContentCreate(args.collection, {\n\t\t\t\t\tdata: args.data,\n\t\t\t\t\tslug: args.slug,\n\t\t\t\t\tauthorId: userId,\n\t\t\t\t\tlocale: args.locale,\n\t\t\t\t\ttranslationOf: args.translationOf,\n\t\t\t\t});\n\t\t\t\tif (!result.success) return unwrap(result);\n\t\t\t\tconst itemId = extractContentId(result.data);\n\t\t\t\tif (itemId) {\n\t\t\t\t\treturn unwrap(await emdash.handleContentPublish(args.collection, itemId));\n\t\t\t\t}\n\t\t\t\treturn unwrap(result);\n\t\t\t}\n\n\t\t\treturn unwrap(\n\t\t\t\tawait emdash.handleContentCreate(args.collection, {\n\t\t\t\t\tdata: args.data,\n\t\t\t\t\tslug: args.slug,\n\t\t\t\t\tauthorId: userId,\n\t\t\t\t\tlocale: args.locale,\n\t\t\t\t\ttranslationOf: args.translationOf,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_update\",\n\t\t{\n\t\t\ttitle: \"Update Content\",\n\t\t\tdescription:\n\t\t\t\t\"Update an existing content item. Only include fields you want to change \" +\n\t\t\t\t\"in the 'data' object — unspecified fields are left unchanged. Pass the \" +\n\t\t\t\t\"_rev token from content_get to enable optimistic concurrency checking \" +\n\t\t\t\t\"(the update fails if the item was modified since you read it). \" +\n\t\t\t\t\"`seo` and `bylines` are persisted alongside the field updates in a \" +\n\t\t\t\t\"single transaction. `publishedAt` requires the content:publish_any \" +\n\t\t\t\t\"permission and is useful for migrations or correcting historical dates.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t\tdata: z\n\t\t\t\t\t.record(z.string(), z.unknown())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Field values to update (only include changed fields)\"),\n\t\t\t\tslug: z.string().optional().describe(\"New URL slug\"),\n\t\t\t\tstatus: z\n\t\t\t\t\t.enum([\"draft\", \"published\"])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"New status. Setting to 'published' requires publish permission. Setting to 'draft' unpublishes the item and also requires publish permission.\",\n\t\t\t\t\t),\n\t\t\t\t// Reuse the REST schema rather than redefining inline. The REST schema's\n\t\t\t\t// `canonical` field is gated through `httpUrl` (validates the URL parses\n\t\t\t\t// AND has an http(s) scheme) which rejects javascript:/data: URIs that\n\t\t\t\t// would otherwise become stored XSS in the rendered <link rel=\"canonical\">.\n\t\t\t\t// Inlining a looser shape here would let MCP callers bypass that.\n\t\t\t\tseo: contentSeoInput\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Per-content SEO metadata. Only valid for collections with SEO enabled (see schema_get_collection.hasSeo). Fields not included are left unchanged; pass null to clear.\",\n\t\t\t\t\t),\n\t\t\t\tbylines: z\n\t\t\t\t\t.array(contentBylineInputSchema)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Replace the byline list for this item. The first entry becomes the primary byline. Pass an empty array to clear all bylines.\",\n\t\t\t\t\t),\n\t\t\t\tpublishedAt: z.iso\n\t\t\t\t\t.datetime({ offset: true, message: \"must be an ISO 8601 datetime\" })\n\t\t\t\t\t.nullish()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Override the publication timestamp (ISO 8601). Requires content:publish_any permission. Pass null to clear. Useful for content migrations.\",\n\t\t\t\t\t),\n\t\t\t\t_rev: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Revision token from content_get for conflict detection\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst { emdash, userId, userRole } = getExtra(extra);\n\n\t\t\t// Fetch item to check ownership\n\t\t\tconst existing = await emdash.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\tconst ownerId = extractContentAuthorId(existing.data);\n\t\t\trequireOwnership(extra, ownerId, \"content:edit_own\", \"content:edit_any\");\n\n\t\t\t// Writing publishedAt directly (incl. clearing to null) overwrites\n\t\t\t// historical record — gate behind publish_any, mirroring the REST PUT\n\t\t\t// route. Status-driven publishes are gated separately below.\n\t\t\tif (args.publishedAt !== undefined) {\n\t\t\t\tconst user = { id: userId, role: userRole };\n\t\t\t\tif (!hasPermission(user, \"content:publish_any\" as Permission)) {\n\t\t\t\t\tthrow new EmDashAuthError(\n\t\t\t\t\t\t\"Setting publishedAt requires content:publish_any permission\",\n\t\t\t\t\t\t\"INSUFFICIENT_PERMISSIONS\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\n\t\t\t// Status transitions route through dedicated handlers for proper revision management\n\t\t\tif (args.status === \"published\") {\n\t\t\t\trequireOwnership(extra, ownerId, \"content:publish_own\", \"content:publish_any\");\n\t\t\t\tif (\n\t\t\t\t\targs.data ||\n\t\t\t\t\targs.slug ||\n\t\t\t\t\targs.seo !== undefined ||\n\t\t\t\t\targs.bylines !== undefined ||\n\t\t\t\t\targs.publishedAt !== undefined\n\t\t\t\t) {\n\t\t\t\t\tconst updateResult = await emdash.handleContentUpdate(args.collection, resolvedId, {\n\t\t\t\t\t\tdata: args.data,\n\t\t\t\t\t\tslug: args.slug,\n\t\t\t\t\t\tauthorId: userId,\n\t\t\t\t\t\tseo: args.seo,\n\t\t\t\t\t\tbylines: args.bylines,\n\t\t\t\t\t\tpublishedAt: args.publishedAt,\n\t\t\t\t\t\t_rev: args._rev,\n\t\t\t\t\t});\n\t\t\t\t\tif (!updateResult.success) return unwrap(updateResult);\n\t\t\t\t}\n\t\t\t\treturn unwrap(await emdash.handleContentPublish(args.collection, resolvedId));\n\t\t\t}\n\n\t\t\tif (args.status === \"draft\") {\n\t\t\t\trequireOwnership(extra, ownerId, \"content:publish_own\", \"content:publish_any\");\n\t\t\t\tif (\n\t\t\t\t\targs.data ||\n\t\t\t\t\targs.slug ||\n\t\t\t\t\targs.seo !== undefined ||\n\t\t\t\t\targs.bylines !== undefined ||\n\t\t\t\t\targs.publishedAt !== undefined\n\t\t\t\t) {\n\t\t\t\t\tconst updateResult = await emdash.handleContentUpdate(args.collection, resolvedId, {\n\t\t\t\t\t\tdata: args.data,\n\t\t\t\t\t\tslug: args.slug,\n\t\t\t\t\t\tauthorId: userId,\n\t\t\t\t\t\tseo: args.seo,\n\t\t\t\t\t\tbylines: args.bylines,\n\t\t\t\t\t\tpublishedAt: args.publishedAt,\n\t\t\t\t\t\t_rev: args._rev,\n\t\t\t\t\t});\n\t\t\t\t\tif (!updateResult.success) return unwrap(updateResult);\n\t\t\t\t}\n\t\t\t\treturn unwrap(await emdash.handleContentUnpublish(args.collection, resolvedId));\n\t\t\t}\n\n\t\t\treturn unwrap(\n\t\t\t\tawait emdash.handleContentUpdate(args.collection, resolvedId, {\n\t\t\t\t\tdata: args.data,\n\t\t\t\t\tslug: args.slug,\n\t\t\t\t\tauthorId: userId,\n\t\t\t\t\tseo: args.seo,\n\t\t\t\t\tbylines: args.bylines,\n\t\t\t\t\tpublishedAt: args.publishedAt,\n\t\t\t\t\t_rev: args._rev,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_delete\",\n\t\t{\n\t\t\ttitle: \"Delete Content (Trash)\",\n\t\t\tdescription:\n\t\t\t\t\"Soft-delete a content item by moving it to the trash. The item can be \" +\n\t\t\t\t\"restored later with content_restore, or permanently deleted with \" +\n\t\t\t\t\"content_permanent_delete.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch item to check ownership\n\t\t\tconst existing = await ec.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:delete_own\",\n\t\t\t\t\"content:delete_any\",\n\t\t\t);\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(await ec.handleContentDelete(args.collection, resolvedId));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_restore\",\n\t\t{\n\t\t\ttitle: \"Restore Content\",\n\t\t\tdescription: \"Restore a soft-deleted content item from the trash back to its previous state.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch trashed item to check ownership\n\t\t\tconst existing = await ec.handleContentGetIncludingTrashed(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:edit_own\",\n\t\t\t\t\"content:edit_any\",\n\t\t\t);\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(await ec.handleContentRestore(args.collection, resolvedId));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_permanent_delete\",\n\t\t{\n\t\t\ttitle: \"Permanently Delete Content\",\n\t\t\tdescription:\n\t\t\t\t\"Permanently and irreversibly delete a trashed content item. The item \" +\n\t\t\t\t\"must be in the trash first (use content_delete). This cannot be undone.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.ADMIN);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(await ec.handleContentPermanentDelete(args.collection, args.id));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_publish\",\n\t\t{\n\t\t\ttitle: \"Publish Content\",\n\t\t\tdescription:\n\t\t\t\t\"Publish a content item, making it live on the site. Creates a published \" +\n\t\t\t\t\"revision from the current draft. Further edits create a new draft without \" +\n\t\t\t\t\"affecting the live version until re-published. Pass `publishedAt` to \" +\n\t\t\t\t\"backdate (e.g. when migrating content from another CMS) — this requires \" +\n\t\t\t\t\"the content:publish_any permission. Without `publishedAt`, the existing \" +\n\t\t\t\t\"`published_at` is preserved on re-publish (idempotent) and falls back to \" +\n\t\t\t\t\"the current time on first publish.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t\tpublishedAt: z.iso\n\t\t\t\t\t.datetime({ offset: true, message: \"must be an ISO 8601 datetime\" })\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Override publication timestamp (ISO 8601). Requires content:publish_any permission. Useful when importing content with original publish dates.\",\n\t\t\t\t\t),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst { emdash, userId, userRole } = getExtra(extra);\n\n\t\t\t// Fetch item to check ownership\n\t\t\tconst existing = await emdash.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\tconst ownerId = extractContentAuthorId(existing.data);\n\t\t\trequireOwnership(extra, ownerId, \"content:publish_own\", \"content:publish_any\");\n\n\t\t\t// Backdating overwrites historical record — gate behind publish_any\n\t\t\t// regardless of ownership (mirrors the REST PUT route's publishedAt gate).\n\t\t\tif (args.publishedAt !== undefined) {\n\t\t\t\tconst user = { id: userId, role: userRole };\n\t\t\t\tif (!hasPermission(user, \"content:publish_any\" as Permission)) {\n\t\t\t\t\tthrow new EmDashAuthError(\n\t\t\t\t\t\t\"Setting publishedAt requires content:publish_any permission\",\n\t\t\t\t\t\t\"INSUFFICIENT_PERMISSIONS\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(\n\t\t\t\tawait emdash.handleContentPublish(args.collection, resolvedId, {\n\t\t\t\t\tpublishedAt: args.publishedAt,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_unpublish\",\n\t\t{\n\t\t\ttitle: \"Unpublish Content\",\n\t\t\tdescription:\n\t\t\t\t\"Unpublish a content item, reverting it to draft status. It will no \" +\n\t\t\t\t\"longer be visible on the live site but its content is preserved.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch item to check ownership\n\t\t\tconst existing = await ec.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:publish_own\",\n\t\t\t\t\"content:publish_any\",\n\t\t\t);\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(await ec.handleContentUnpublish(args.collection, resolvedId));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_schedule\",\n\t\t{\n\t\t\ttitle: \"Schedule Content\",\n\t\t\tdescription:\n\t\t\t\t\"Schedule a content item for future publication. It will be automatically \" +\n\t\t\t\t\"published at the specified date/time. The scheduledAt value must be an \" +\n\t\t\t\t\"ISO 8601 datetime string in the future (e.g. '2025-06-01T09:00:00Z').\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t\tscheduledAt: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\"ISO 8601 datetime for publication (e.g. '2025-06-01T09:00:00Z')\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch item to check ownership\n\t\t\tconst existing = await ec.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:publish_own\",\n\t\t\t\t\"content:publish_any\",\n\t\t\t);\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(await ec.handleContentSchedule(args.collection, resolvedId, args.scheduledAt));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_unschedule\",\n\t\t{\n\t\t\ttitle: \"Cancel Scheduled Publication\",\n\t\t\tdescription:\n\t\t\t\t\"Cancel a previously scheduled publication. The item remains in its current \" +\n\t\t\t\t\"status (typically 'draft' or 'scheduled'); only the scheduledAt timestamp is \" +\n\t\t\t\t\"cleared. Idempotent — calling on an item that isn't scheduled is a no-op.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\tconst existing = await ec.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:publish_own\",\n\t\t\t\t\"content:publish_any\",\n\t\t\t);\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(await ec.handleContentUnschedule(args.collection, resolvedId));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_compare\",\n\t\t{\n\t\t\ttitle: \"Compare Live vs Draft\",\n\t\t\tdescription:\n\t\t\t\t\"Compare the published (live) version of a content item with its current \" +\n\t\t\t\t\"draft. Returns both versions and a flag indicating whether there are \" +\n\t\t\t\t\"changes. Useful for reviewing unpublished edits before publishing.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\trequireDraftAccess(extra);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(await ec.handleContentCompare(args.collection, args.id));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_discard_draft\",\n\t\t{\n\t\t\ttitle: \"Discard Draft\",\n\t\t\tdescription:\n\t\t\t\t\"Discard the current draft changes and revert to the last published \" +\n\t\t\t\t\"version. Only works on items that have been published at least once.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch item to check ownership\n\t\t\tconst existing = await ec.handleContentGet(args.collection, args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:edit_own\",\n\t\t\t\t\"content:edit_any\",\n\t\t\t);\n\n\t\t\tconst resolvedId = extractContentId(existing.data) ?? args.id;\n\t\t\treturn unwrap(await ec.handleContentDiscardDraft(args.collection, resolvedId));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_list_trashed\",\n\t\t{\n\t\t\ttitle: \"List Trashed Content\",\n\t\t\tdescription:\n\t\t\t\t\"List soft-deleted content items in a collection's trash. These items \" +\n\t\t\t\t\"can be restored with content_restore or permanently deleted with \" +\n\t\t\t\t\"content_permanent_delete.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tlimit: z.number().int().min(1).max(100).optional().describe(\"Max items (default 50)\"),\n\t\t\t\tcursor: z.string().min(1).max(2048).optional().describe(\"Pagination cursor\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\trequireDraftAccess(extra);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(\n\t\t\t\tawait ec.handleContentListTrashed(args.collection, {\n\t\t\t\t\tlimit: args.limit,\n\t\t\t\t\tcursor: args.cursor,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_duplicate\",\n\t\t{\n\t\t\ttitle: \"Duplicate Content\",\n\t\t\tdescription:\n\t\t\t\t\"Create a copy of an existing content item. The duplicate is created \" +\n\t\t\t\t\"as a draft with '(Copy)' appended to the title and an auto-generated slug.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug to duplicate\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.CONTRIBUTOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(await ec.handleContentDuplicate(args.collection, args.id));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"content_translations\",\n\t\t{\n\t\t\ttitle: \"Get Content Translations\",\n\t\t\tdescription:\n\t\t\t\t\"Get all locale variants of a content item. Returns the translation group \" +\n\t\t\t\t\"and a summary of each locale version (id, locale, slug, status). Only \" +\n\t\t\t\t\"relevant when i18n is enabled on the site.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\tconst result = await ec.handleContentTranslations(args.collection, args.id);\n\t\t\t// Filter out non-published translations for users without draft\n\t\t\t// access so a subscriber can't enumerate locales that aren't yet live.\n\t\t\tif (result.success && !canReadDrafts(extra)) {\n\t\t\t\tconst data =\n\t\t\t\t\tresult.data && typeof result.data === \"object\"\n\t\t\t\t\t\t? // eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- handler returns unknown data; narrowed by typeof check\n\t\t\t\t\t\t\t(result.data as Record<string, unknown>)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst translations = Array.isArray(data?.translations) ? data.translations : [];\n\t\t\t\tconst filtered = translations.filter(isPublished);\n\t\t\t\treturn unwrap({\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: { ...data, translations: filtered },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn unwrap(result);\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Schema tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"schema_list_collections\",\n\t\t{\n\t\t\ttitle: \"List Collections\",\n\t\t\tdescription:\n\t\t\t\t\"List all content collections defined in the CMS. Each collection \" +\n\t\t\t\t\"represents a content type (e.g. posts, pages, products) with its own \" +\n\t\t\t\t\"schema and database table. Returns slug, label, supported features, \" +\n\t\t\t\t\"and timestamps.\",\n\t\t\tinputSchema: z.object({}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (_args, extra) => {\n\t\t\trequireScope(extra, \"schema:read\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { SchemaRegistry } = await import(\"../schema/index.js\");\n\t\t\t\tconst registry = new SchemaRegistry(ec.db);\n\t\t\t\tconst items = await registry.listCollections();\n\t\t\t\treturn jsonResult({ items });\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SCHEMA_LIST_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"schema_get_collection\",\n\t\t{\n\t\t\ttitle: \"Get Collection Schema\",\n\t\t\tdescription:\n\t\t\t\t\"Get detailed info about a collection including all field definitions. \" +\n\t\t\t\t\"Fields describe the data model: name, type (string, text, number, \" +\n\t\t\t\t\"boolean, datetime, portableText, image, reference, json, select, \" +\n\t\t\t\t\"multiSelect, slug), constraints, and validation rules. Use this to \" +\n\t\t\t\t\"understand what data content_create and content_update expect.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Collection slug (e.g. 'posts'). Use schema_list_collections to see available slugs.\",\n\t\t\t\t\t),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"schema:read\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { SchemaRegistry } = await import(\"../schema/index.js\");\n\t\t\t\tconst registry = new SchemaRegistry(ec.db);\n\t\t\t\tconst collection = await registry.getCollectionWithFields(args.slug);\n\t\t\t\tif (!collection) {\n\t\t\t\t\treturn respondError(\"NOT_FOUND\", `Collection '${args.slug}' not found`);\n\t\t\t\t}\n\t\t\t\treturn jsonResult(collection);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SCHEMA_GET_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"schema_create_collection\",\n\t\t{\n\t\t\ttitle: \"Create Collection\",\n\t\t\tdescription:\n\t\t\t\t\"Create a new content collection (content type). This creates a database \" +\n\t\t\t\t\"table and schema definition. The slug must be lowercase alphanumeric \" +\n\t\t\t\t\"with underscores, starting with a letter. Supports: 'drafts' (draft/\" +\n\t\t\t\t\"publish workflow), 'revisions' (version history), 'preview' (live \" +\n\t\t\t\t\"preview), 'scheduling' (timed publish), 'search' (full-text indexing).\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.regex(COLLECTION_SLUG_PATTERN)\n\t\t\t\t\t.describe(\"Unique identifier (lowercase letters, numbers, underscores)\"),\n\t\t\t\tlabel: z.string().describe(\"Display name (plural, e.g. 'Blog Posts')\"),\n\t\t\t\tlabelSingular: z.string().optional().describe(\"Singular display name (e.g. 'Blog Post')\"),\n\t\t\t\tdescription: z.string().optional().describe(\"Description of this collection\"),\n\t\t\t\ticon: z.string().optional().describe(\"Icon name for the admin UI\"),\n\t\t\t\tsupports: z\n\t\t\t\t\t.array(z.enum([\"drafts\", \"revisions\", \"preview\", \"scheduling\", \"search\"]))\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Features to enable (default: ['drafts', 'revisions'])\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"schema:write\");\n\t\t\trequireRole(extra, Role.ADMIN);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { SchemaRegistry } = await import(\"../schema/index.js\");\n\t\t\t\tconst registry = new SchemaRegistry(ec.db);\n\t\t\t\tconst collection = await registry.createCollection({\n\t\t\t\t\tslug: args.slug,\n\t\t\t\t\tlabel: args.label,\n\t\t\t\t\tlabelSingular: args.labelSingular,\n\t\t\t\t\tdescription: args.description,\n\t\t\t\t\ticon: args.icon,\n\t\t\t\t\t// SchemaRegistry.createCollection now defaults `supports` to\n\t\t\t\t\t// ['drafts', 'revisions'] when undefined; pass through verbatim.\n\t\t\t\t\tsupports: args.supports,\n\t\t\t\t});\n\t\t\t\tec.invalidateUrlPatternCache();\n\t\t\t\treturn jsonResult(collection);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SCHEMA_CREATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"schema_delete_collection\",\n\t\t{\n\t\t\ttitle: \"Delete Collection\",\n\t\t\tdescription:\n\t\t\t\t\"Delete a collection and its database table. This is irreversible and \" +\n\t\t\t\t\"deletes all content in the collection. Use with extreme caution.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tslug: z.string().describe(\"Collection slug to delete\"),\n\t\t\t\tforce: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Force deletion even if the collection has content (default false)\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"schema:write\");\n\t\t\trequireRole(extra, Role.ADMIN);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { SchemaRegistry } = await import(\"../schema/index.js\");\n\t\t\t\tconst registry = new SchemaRegistry(ec.db);\n\t\t\t\tawait registry.deleteCollection(args.slug, { force: args.force });\n\t\t\t\tec.invalidateUrlPatternCache();\n\t\t\t\treturn jsonResult({ deleted: args.slug });\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SCHEMA_DELETE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"schema_create_field\",\n\t\t{\n\t\t\ttitle: \"Add Field to Collection\",\n\t\t\tdescription:\n\t\t\t\t\"Add a new field to a collection's schema. This adds a column to the \" +\n\t\t\t\t\"database table. Field types: string (short text), text (long text), \" +\n\t\t\t\t\"number (decimal), integer, boolean, datetime, select (single choice), \" +\n\t\t\t\t\"multiSelect (multiple), portableText (rich text), image, file, \" +\n\t\t\t\t\"reference (link to another collection), json, slug (URL-safe id). \" +\n\t\t\t\t\"For select/multiSelect, provide choices in validation.options array.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug to add the field to\"),\n\t\t\t\tslug: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.regex(COLLECTION_SLUG_PATTERN)\n\t\t\t\t\t.describe(\"Field identifier (lowercase letters, numbers, underscores)\"),\n\t\t\t\tlabel: z.string().describe(\"Display name for the field\"),\n\t\t\t\ttype: z\n\t\t\t\t\t.enum([\n\t\t\t\t\t\t\"string\",\n\t\t\t\t\t\t\"text\",\n\t\t\t\t\t\t\"number\",\n\t\t\t\t\t\t\"integer\",\n\t\t\t\t\t\t\"boolean\",\n\t\t\t\t\t\t\"datetime\",\n\t\t\t\t\t\t\"select\",\n\t\t\t\t\t\t\"multiSelect\",\n\t\t\t\t\t\t\"portableText\",\n\t\t\t\t\t\t\"image\",\n\t\t\t\t\t\t\"file\",\n\t\t\t\t\t\t\"reference\",\n\t\t\t\t\t\t\"json\",\n\t\t\t\t\t\t\"slug\",\n\t\t\t\t\t])\n\t\t\t\t\t.describe(\"Data type for this field\"),\n\t\t\t\trequired: z.boolean().optional().describe(\"Whether the field is required (default false)\"),\n\t\t\t\tunique: z.boolean().optional().describe(\"Whether values must be unique (default false)\"),\n\t\t\t\tdefaultValue: z.unknown().optional().describe(\"Default value for new items\"),\n\t\t\t\tvalidation: z\n\t\t\t\t\t.object({\n\t\t\t\t\t\tmin: z.number().optional(),\n\t\t\t\t\t\tmax: z.number().optional(),\n\t\t\t\t\t\tminLength: z.number().optional(),\n\t\t\t\t\t\tmaxLength: z.number().optional(),\n\t\t\t\t\t\tpattern: z.string().optional(),\n\t\t\t\t\t\toptions: z\n\t\t\t\t\t\t\t.array(z.string())\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.describe(\"Allowed values for select/multiSelect\"),\n\t\t\t\t\t})\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Validation constraints\"),\n\t\t\t\toptions: z\n\t\t\t\t\t.object({\n\t\t\t\t\t\tcollection: z\n\t\t\t\t\t\t\t.string()\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.describe(\"Target collection slug for reference fields\"),\n\t\t\t\t\t\trows: z.number().optional().describe(\"Number of rows for textarea\"),\n\t\t\t\t\t})\n\t\t\t\t\t.passthrough()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Widget configuration\"),\n\t\t\t\tsearchable: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Include in full-text search index (default false)\"),\n\t\t\t\ttranslatable: z\n\t\t\t\t\t.boolean()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"Whether this field is translatable (default true). \" +\n\t\t\t\t\t\t\t\"Non-translatable fields are synced across all locales in a translation group.\",\n\t\t\t\t\t),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"schema:write\");\n\t\t\trequireRole(extra, Role.ADMIN);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { SchemaRegistry } = await import(\"../schema/index.js\");\n\t\t\t\tconst registry = new SchemaRegistry(ec.db);\n\t\t\t\tconst field = await registry.createField(args.collection, {\n\t\t\t\t\tslug: args.slug,\n\t\t\t\t\tlabel: args.label,\n\t\t\t\t\ttype: args.type,\n\t\t\t\t\trequired: args.required,\n\t\t\t\t\tunique: args.unique,\n\t\t\t\t\tdefaultValue: args.defaultValue,\n\t\t\t\t\tvalidation: args.validation,\n\t\t\t\t\toptions: args.options,\n\t\t\t\t\tsearchable: args.searchable,\n\t\t\t\t\ttranslatable: args.translatable,\n\t\t\t\t});\n\t\t\t\treturn jsonResult(field);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"FIELD_CREATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"schema_delete_field\",\n\t\t{\n\t\t\ttitle: \"Remove Field from Collection\",\n\t\t\tdescription:\n\t\t\t\t\"Remove a field from a collection. This drops the column from the \" +\n\t\t\t\t\"database table and deletes all data in that field. Irreversible.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tfieldSlug: z.string().describe(\"Field slug to remove\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"schema:write\");\n\t\t\trequireRole(extra, Role.ADMIN);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { SchemaRegistry } = await import(\"../schema/index.js\");\n\t\t\t\tconst registry = new SchemaRegistry(ec.db);\n\t\t\t\tawait registry.deleteField(args.collection, args.fieldSlug);\n\t\t\t\treturn jsonResult({ deleted: args.fieldSlug, collection: args.collection });\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"FIELD_DELETE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Media tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"media_list\",\n\t\t{\n\t\t\ttitle: \"List Media\",\n\t\t\tdescription:\n\t\t\t\t\"List uploaded media files (images, documents, etc.) with optional MIME \" +\n\t\t\t\t\"type filtering and pagination. Returns file metadata including filename, \" +\n\t\t\t\t\"URL, dimensions, and alt text.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tmimeType: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Filter by MIME type prefix (e.g. 'image/', 'application/pdf')\"),\n\t\t\t\tlimit: z.number().int().min(1).max(100).optional().describe(\"Max items (default 50)\"),\n\t\t\t\tcursor: z.string().min(1).max(2048).optional().describe(\"Pagination cursor\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"media:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(\n\t\t\t\tawait ec.handleMediaList({\n\t\t\t\t\tmimeType: args.mimeType,\n\t\t\t\t\tlimit: args.limit,\n\t\t\t\t\tcursor: args.cursor,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"media_create\",\n\t\t{\n\t\t\ttitle: \"Register Uploaded Media\",\n\t\t\tdescription:\n\t\t\t\t\"Register a media file that has already been uploaded to storage. The \" +\n\t\t\t\t\"caller is responsible for placing the file at `storageKey` (typically \" +\n\t\t\t\t\"using a signed upload URL obtained from the admin UI or a separate API). \" +\n\t\t\t\t\"This tool persists the metadata record so the file is discoverable via \" +\n\t\t\t\t\"media_list / media_get and can be referenced by content. For binary \" +\n\t\t\t\t\"uploads the MCP transport is not appropriate — use the signed-upload \" +\n\t\t\t\t\"flow instead.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tfilename: z.string().describe(\"Original filename (e.g. 'logo.png')\"),\n\t\t\t\tmimeType: z.string().describe(\"MIME type (e.g. 'image/png')\"),\n\t\t\t\tstorageKey: z.string().describe(\"Storage path/key the file was uploaded to\"),\n\t\t\t\tsize: z.number().int().nonnegative().optional().describe(\"File size in bytes\"),\n\t\t\t\twidth: z.number().int().positive().optional().describe(\"Image width in pixels\"),\n\t\t\t\theight: z.number().int().positive().optional().describe(\"Image height in pixels\"),\n\t\t\t\tcontentHash: z.string().optional().describe(\"Hash of the file contents (for dedupe)\"),\n\t\t\t\tblurhash: z.string().optional().describe(\"Blurhash for image placeholders\"),\n\t\t\t\tdominantColor: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Hex color string for the image's dominant color\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"media:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst { emdash, userId } = getExtra(extra);\n\t\t\treturn unwrap(\n\t\t\t\tawait emdash.handleMediaCreate({\n\t\t\t\t\tfilename: args.filename,\n\t\t\t\t\tmimeType: args.mimeType,\n\t\t\t\t\tstorageKey: args.storageKey,\n\t\t\t\t\tsize: args.size,\n\t\t\t\t\twidth: args.width,\n\t\t\t\t\theight: args.height,\n\t\t\t\t\tcontentHash: args.contentHash,\n\t\t\t\t\tblurhash: args.blurhash,\n\t\t\t\t\tdominantColor: args.dominantColor,\n\t\t\t\t\tauthorId: userId,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"media_get\",\n\t\t{\n\t\t\ttitle: \"Get Media Item\",\n\t\t\tdescription:\n\t\t\t\t\"Get details of a single media file by its ID. Returns metadata \" +\n\t\t\t\t\"including filename, MIME type, size, dimensions, alt text, and URL.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tid: z.string().describe(\"Media item ID\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"media:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(await ec.handleMediaGet(args.id));\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"media_update\",\n\t\t{\n\t\t\ttitle: \"Update Media Metadata\",\n\t\t\tdescription:\n\t\t\t\t\"Update the metadata of an uploaded media file. You can change the \" +\n\t\t\t\t\"alt text, caption, and dimensions. The file itself cannot be changed.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tid: z.string().describe(\"Media item ID\"),\n\t\t\t\talt: z.string().optional().describe(\"Alt text for accessibility\"),\n\t\t\t\tcaption: z.string().optional().describe(\"Caption text\"),\n\t\t\t\twidth: z.number().int().optional().describe(\"Image width in pixels\"),\n\t\t\t\theight: z.number().int().optional().describe(\"Image height in pixels\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"media:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch media item for ownership check\n\t\t\tconst existing = await ec.handleMediaGet(args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\tconst media = (existing.data as Record<string, unknown> | undefined)?.item as\n\t\t\t\t| Record<string, unknown>\n\t\t\t\t| undefined;\n\t\t\tconst authorId = typeof media?.authorId === \"string\" ? media.authorId : \"\";\n\t\t\trequireOwnership(extra, authorId, \"media:edit_own\", \"media:edit_any\");\n\n\t\t\treturn unwrap(\n\t\t\t\tawait ec.handleMediaUpdate(args.id, {\n\t\t\t\t\talt: args.alt,\n\t\t\t\t\tcaption: args.caption,\n\t\t\t\t\twidth: args.width,\n\t\t\t\t\theight: args.height,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"media_delete\",\n\t\t{\n\t\t\ttitle: \"Delete Media\",\n\t\t\tdescription:\n\t\t\t\t\"Permanently delete an uploaded media file. Removes the database record \" +\n\t\t\t\t\"and the file from storage. Content referencing this media will have \" +\n\t\t\t\t\"broken references. Cannot be undone.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tid: z.string().describe(\"Media item ID\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"media:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst ec = getEmDash(extra);\n\n\t\t\t// Fetch media item for ownership check\n\t\t\tconst existing = await ec.handleMediaGet(args.id);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\tconst media = (existing.data as Record<string, unknown> | undefined)?.item as\n\t\t\t\t| Record<string, unknown>\n\t\t\t\t| undefined;\n\t\t\tconst authorId = typeof media?.authorId === \"string\" ? media.authorId : \"\";\n\t\t\trequireOwnership(extra, authorId, \"media:delete_own\", \"media:delete_any\");\n\n\t\t\treturn unwrap(await ec.handleMediaDelete(args.id));\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Search tool\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"search\",\n\t\t{\n\t\t\ttitle: \"Search Content\",\n\t\t\tdescription:\n\t\t\t\t\"Full-text search across content collections. Searches indexed fields \" +\n\t\t\t\t\"for matching content. Collections must have 'search' in their supports \" +\n\t\t\t\t\"list and fields must be marked as searchable. Returns collection, item \" +\n\t\t\t\t\"ID, title, excerpt, and relevance score.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tquery: z.string().describe(\"Search query text\"),\n\t\t\t\tcollections: z\n\t\t\t\t\t.array(z.string())\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Limit search to specific collection slugs (all if omitted)\"),\n\t\t\t\tlocale: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Filter results by locale (omit to search all locales)\"),\n\t\t\t\tlimit: z.number().int().min(1).max(50).optional().describe(\"Max results (default 20)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { searchWithDb } = await import(\"../search/index.js\");\n\t\t\t\tconst results = await searchWithDb(ec.db, args.query, {\n\t\t\t\t\tcollections: args.collections,\n\t\t\t\t\tlocale: args.locale,\n\t\t\t\t\tlimit: args.limit,\n\t\t\t\t});\n\t\t\t\treturn jsonResult(results);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SEARCH_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Taxonomy tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"taxonomy_list\",\n\t\t{\n\t\t\ttitle: \"List Taxonomies\",\n\t\t\tdescription:\n\t\t\t\t\"List all taxonomy definitions (e.g. categories, tags). Taxonomies are \" +\n\t\t\t\t\"classification systems applied to content. Each has a name, label, and \" +\n\t\t\t\t\"can be hierarchical (categories) or flat (tags). Optionally filter by \" +\n\t\t\t\t\"locale.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tlocale: z.string().optional().describe(\"Filter by locale (omit for all)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleTaxonomyList } = await import(\"../api/handlers/taxonomies.js\");\n\t\t\t\treturn unwrap(await handleTaxonomyList(ec.db, { locale: args.locale }));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"TAXONOMY_LIST_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"taxonomy_list_terms\",\n\t\t{\n\t\t\ttitle: \"List Taxonomy Terms\",\n\t\t\tdescription:\n\t\t\t\t\"List terms in a taxonomy with pagination. Terms are individual entries \" +\n\t\t\t\t\"(e.g. specific categories or tags). Hierarchical taxonomies can have \" +\n\t\t\t\t\"parent-child relationships.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\ttaxonomy: z.string().describe(\"Taxonomy name (e.g. 'categories', 'tags')\"),\n\t\t\t\tlimit: z.number().int().min(1).max(100).optional().describe(\"Max items (default 50)\"),\n\t\t\t\tcursor: z.string().min(1).max(2048).optional().describe(\"Pagination cursor\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Filter by locale (omit for all)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleTaxonomyList } = await import(\"../api/handlers/taxonomies.js\");\n\t\t\t\tconst listResult = await handleTaxonomyList(ec.db, { locale: args.locale });\n\t\t\t\tif (!listResult.success) return unwrap(listResult);\n\n\t\t\t\tconst taxonomies = (listResult.data as { taxonomies: Array<{ name: string; id?: string }> })\n\t\t\t\t\t.taxonomies;\n\t\t\t\tconst taxonomy = taxonomies.find((t: { name: string }) => t.name === args.taxonomy);\n\t\t\t\tif (!taxonomy) return respondError(\"NOT_FOUND\", `Taxonomy '${args.taxonomy}' not found`);\n\n\t\t\t\tconst { TaxonomyRepository } = await import(\"../database/repositories/taxonomy.js\");\n\t\t\t\tconst { decodeCursor, encodeCursor, InvalidCursorError } =\n\t\t\t\t\tawait import(\"../database/repositories/types.js\");\n\t\t\t\tconst repo = new TaxonomyRepository(ec.db);\n\t\t\t\tconst limit = Math.min(args.limit ?? 50, 100);\n\t\t\t\tconst terms = await repo.findByName(args.taxonomy, { locale: args.locale });\n\n\t\t\t\t// Manual keyset pagination over the sorted-by-label results.\n\t\t\t\t// Using a base64-encoded `(label, id)` cursor matches the\n\t\t\t\t// scheme other list endpoints use and tolerates concurrent\n\t\t\t\t// deletion of the cursor-term — the cursor is a position,\n\t\t\t\t// not a row reference, so a missing row just means we skip\n\t\t\t\t// past it rather than erroring.\n\t\t\t\tlet startIdx = 0;\n\t\t\t\tif (args.cursor) {\n\t\t\t\t\tlet decoded: { orderValue: string; id: string };\n\t\t\t\t\ttry {\n\t\t\t\t\t\tdecoded = decodeCursor(args.cursor);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (error instanceof InvalidCursorError) {\n\t\t\t\t\t\t\treturn respondError(\"INVALID_CURSOR\", error.message);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\t// Find the first term that sorts strictly after the cursor\n\t\t\t\t\t// position. Stable order is `(label asc, id asc)` so a\n\t\t\t\t\t// `(label, id)` tuple comparison is the keyset.\n\t\t\t\t\tstartIdx = terms.findIndex(\n\t\t\t\t\t\t(t) =>\n\t\t\t\t\t\t\tt.label > decoded.orderValue || (t.label === decoded.orderValue && t.id > decoded.id),\n\t\t\t\t\t);\n\t\t\t\t\tif (startIdx < 0) startIdx = terms.length;\n\t\t\t\t}\n\n\t\t\t\tconst page = terms.slice(startIdx, startIdx + limit);\n\t\t\t\tconst hasMore = startIdx + limit < terms.length;\n\t\t\t\tconst last = page.at(-1);\n\t\t\t\tconst nextCursor = hasMore && last ? encodeCursor(last.label, last.id) : undefined;\n\n\t\t\t\treturn jsonResult({\n\t\t\t\t\titems: page.map((t) => ({\n\t\t\t\t\t\tid: t.id,\n\t\t\t\t\t\tname: t.name,\n\t\t\t\t\t\tslug: t.slug,\n\t\t\t\t\t\tlabel: t.label,\n\t\t\t\t\t\tparentId: t.parentId,\n\t\t\t\t\t\tdescription: typeof t.data?.description === \"string\" ? t.data.description : undefined,\n\t\t\t\t\t\tlocale: t.locale,\n\t\t\t\t\t\ttranslationGroup: t.translationGroup,\n\t\t\t\t\t})),\n\t\t\t\t\tnextCursor,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"TAXONOMY_LIST_TERMS_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"taxonomy_create_term\",\n\t\t{\n\t\t\ttitle: \"Create Taxonomy Term\",\n\t\t\tdescription:\n\t\t\t\t\"Create a new term in a taxonomy. For hierarchical taxonomies like \" +\n\t\t\t\t\"categories, you can specify a parentId to create a child term. The \" +\n\t\t\t\t\"parent must exist and belong to the same taxonomy. The parent's \" +\n\t\t\t\t\"ancestor chain must not exceed 100 levels — attempts to attach a \" +\n\t\t\t\t\"new term beneath a chain of 100+ existing ancestors are rejected.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\ttaxonomy: z.string().describe(\"Taxonomy name (e.g. 'categories', 'tags')\"),\n\t\t\t\tslug: z.string().describe(\"URL-safe identifier for the term\"),\n\t\t\t\tlabel: z.string().describe(\"Display name\"),\n\t\t\t\tparentId: z.string().optional().describe(\"Parent term ID for hierarchical taxonomies\"),\n\t\t\t\tdescription: z.string().optional().describe(\"Description of the term\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Locale for the new term (e.g. 'es')\"),\n\t\t\t\ttranslationOf: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Term id to join as a translation (same translation_group)\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"taxonomies:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleTermCreate } = await import(\"../api/handlers/taxonomies.js\");\n\t\t\t\treturn unwrap(\n\t\t\t\t\tawait handleTermCreate(ec.db, args.taxonomy, {\n\t\t\t\t\t\tslug: args.slug,\n\t\t\t\t\t\tlabel: args.label,\n\t\t\t\t\t\tparentId: args.parentId,\n\t\t\t\t\t\tdescription: args.description,\n\t\t\t\t\t\tlocale: args.locale,\n\t\t\t\t\t\ttranslationOf: args.translationOf,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"TAXONOMY_TERM_CREATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"taxonomy_update_term\",\n\t\t{\n\t\t\ttitle: \"Update Taxonomy Term\",\n\t\t\tdescription:\n\t\t\t\t\"Update an existing term in a taxonomy. Any field can be omitted to leave \" +\n\t\t\t\t\"it unchanged. Renaming a term's slug must not collide with another term in \" +\n\t\t\t\t\"the same taxonomy. Set parentId to null to detach from a parent. The new \" +\n\t\t\t\t\"parent must exist, belong to the same taxonomy, and not introduce a cycle \" +\n\t\t\t\t\"(a term cannot be its own ancestor). The new parent's ancestor chain must \" +\n\t\t\t\t\"not exceed 100 levels — reparenting under a chain of 100+ ancestors is \" +\n\t\t\t\t\"rejected.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\ttaxonomy: z.string().describe(\"Taxonomy name (e.g. 'categories', 'tags')\"),\n\t\t\t\ttermSlug: z.string().describe(\"Current slug of the term to update\"),\n\t\t\t\tslug: z.string().optional().describe(\"New slug (must be unique in the taxonomy)\"),\n\t\t\t\tlabel: z.string().optional().describe(\"New display name\"),\n\t\t\t\tparentId: z.string().nullable().optional().describe(\"New parent term ID; null to detach\"),\n\t\t\t\tdescription: z.string().optional().describe(\"New description\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"taxonomies:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleTermUpdate } = await import(\"../api/handlers/taxonomies.js\");\n\t\t\t\treturn unwrap(\n\t\t\t\t\tawait handleTermUpdate(ec.db, args.taxonomy, args.termSlug, {\n\t\t\t\t\t\tslug: args.slug,\n\t\t\t\t\t\tlabel: args.label,\n\t\t\t\t\t\tparentId: args.parentId,\n\t\t\t\t\t\tdescription: args.description,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"TAXONOMY_TERM_UPDATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"taxonomy_delete_term\",\n\t\t{\n\t\t\ttitle: \"Delete Taxonomy Term\",\n\t\t\tdescription:\n\t\t\t\t\"Permanently delete a term from a taxonomy. Any content tagged with this \" +\n\t\t\t\t\"term loses the association. Cannot delete a term that has children — \" +\n\t\t\t\t\"delete children first.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\ttaxonomy: z.string().describe(\"Taxonomy name\"),\n\t\t\t\ttermSlug: z.string().describe(\"Slug of the term to delete\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"taxonomies:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleTermDelete } = await import(\"../api/handlers/taxonomies.js\");\n\t\t\t\treturn unwrap(await handleTermDelete(ec.db, args.taxonomy, args.termSlug));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"TAXONOMY_TERM_DELETE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"taxonomy_term_translations\",\n\t\t{\n\t\t\ttitle: \"List Term Translations\",\n\t\t\tdescription:\n\t\t\t\t\"Return every locale variant of a taxonomy term, identified via its shared translation_group.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tid: z.string().describe(\"Term id (or translation_group)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleTermTranslations } = await import(\"../api/handlers/taxonomies.js\");\n\t\t\t\treturn unwrap(await handleTermTranslations(ec.db, args.id));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"TERM_TRANSLATIONS_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Menu tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"menu_list\",\n\t\t{\n\t\t\ttitle: \"List Menus\",\n\t\t\tdescription:\n\t\t\t\t\"List navigation menus. Menus are per-locale: filter by `locale` to \" +\n\t\t\t\t\"get just one locale's worth, or omit to list every row (one per \" +\n\t\t\t\t\"locale per menu name).\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tlocale: z.string().optional().describe(\"Filter by locale (omit for all)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuList } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(await handleMenuList(ec.db, { locale: args.locale }));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_LIST_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"menu_get\",\n\t\t{\n\t\t\ttitle: \"Get Menu with Items\",\n\t\t\tdescription:\n\t\t\t\t\"Get a menu by name, including its items. When multiple locales exist, \" +\n\t\t\t\t\"pass `locale` to pick the right one.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tname: z.string().describe(\"Menu name (e.g. 'main', 'footer')\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Locale to resolve the menu for\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuGet } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(await handleMenuGet(ec.db, args.name, { locale: args.locale }));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_GET_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"menu_translations\",\n\t\t{\n\t\t\ttitle: \"List Menu Translations\",\n\t\t\tdescription:\n\t\t\t\t\"Return every locale variant of a menu, identified via the shared translation_group.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tid: z.string().describe(\"Menu id (or translation_group)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuTranslations } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(await handleMenuTranslations(ec.db, args.id));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_TRANSLATIONS_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"menu_create\",\n\t\t{\n\t\t\ttitle: \"Create Menu\",\n\t\t\tdescription:\n\t\t\t\t\"Create a new navigation menu. The `name` is the stable identifier used \" +\n\t\t\t\t\"by site templates (e.g. 'main', 'footer'); `label` is the human-readable \" +\n\t\t\t\t\"name shown in the admin. Menus are per-locale, so pass `locale` when \" +\n\t\t\t\t\"the same menu name exists in multiple translations. Add items afterwards \" +\n\t\t\t\t\"with menu_set_items. If `translationOf` is set, `locale` must also be set.\",\n\t\t\t// `locale`-when-`translationOf` is enforced inside handleMenuCreate\n\t\t\t// so REST/SDK callers get the same guard. The description above\n\t\t\t// documents the rule; the handler returns VALIDATION_ERROR.\n\t\t\tinputSchema: z.object({\n\t\t\t\tname: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.regex(COLLECTION_SLUG_PATTERN)\n\t\t\t\t\t.describe(\"Stable identifier (lowercase letters, numbers, underscores)\"),\n\t\t\t\tlabel: z.string().describe(\"Display name for the admin\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Locale for this menu (e.g. 'fr-fr')\"),\n\t\t\t\ttranslationOf: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Existing menu id to create this locale variant from\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"menus:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuCreate } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(\n\t\t\t\t\tawait handleMenuCreate(ec.db, {\n\t\t\t\t\t\tname: args.name,\n\t\t\t\t\t\tlabel: args.label,\n\t\t\t\t\t\tlocale: args.locale,\n\t\t\t\t\t\ttranslationOf: args.translationOf,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_CREATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"menu_update\",\n\t\t{\n\t\t\ttitle: \"Update Menu\",\n\t\t\tdescription:\n\t\t\t\t\"Update a menu's label. The `name` (stable identifier) cannot be changed. \" +\n\t\t\t\t\"On multi-locale installs, pass `locale` so the correct translation is updated.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tname: z.string().describe(\"Menu name to update\"),\n\t\t\t\tlabel: z.string().describe(\"New display label\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Locale of the menu to update\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"menus:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuUpdate } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(\n\t\t\t\t\tawait handleMenuUpdate(ec.db, args.name, { label: args.label, locale: args.locale }),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_UPDATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"menu_delete\",\n\t\t{\n\t\t\ttitle: \"Delete Menu\",\n\t\t\tdescription:\n\t\t\t\t\"Delete a menu. Items are also removed. Cannot be undone. On multi-locale \" +\n\t\t\t\t\"installs, pass `locale` so only the intended translation is removed.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tname: z.string().describe(\"Menu name to delete\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Locale of the menu to delete\"),\n\t\t\t}),\n\t\t\tannotations: { destructiveHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"menus:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuDelete } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(await handleMenuDelete(ec.db, args.name, { locale: args.locale }));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_DELETE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"menu_set_items\",\n\t\t{\n\t\t\ttitle: \"Set Menu Items\",\n\t\t\tdescription:\n\t\t\t\t\"Replace the entire item list of a menu in one call. This is atomic: the \" +\n\t\t\t\t\"existing items are deleted and the new list is inserted in the order \" +\n\t\t\t\t\"provided. Use this rather than per-item add/remove tools so the resulting \" +\n\t\t\t\t\"order and parent links are unambiguous. On multi-locale installs, pass \" +\n\t\t\t\t\"`locale` so only the intended translation is rewritten.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tname: z.string().describe(\"Menu name to update\"),\n\t\t\t\tlocale: z.string().optional().describe(\"Locale of the menu to rewrite\"),\n\t\t\t\titems: z\n\t\t\t\t\t.array(\n\t\t\t\t\t\tz.object({\n\t\t\t\t\t\t\tlabel: z.string().describe(\"Item display text\"),\n\t\t\t\t\t\t\ttype: z\n\t\t\t\t\t\t\t\t.enum([\"custom\", \"page\", \"post\", \"taxonomy\", \"collection\"])\n\t\t\t\t\t\t\t\t.describe(\"Item kind\"),\n\t\t\t\t\t\t\tcustomUrl: z\n\t\t\t\t\t\t\t\t.string()\n\t\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t\t.describe(\"URL for type='custom' items (ignored otherwise)\"),\n\t\t\t\t\t\t\treferenceCollection: z\n\t\t\t\t\t\t\t\t.string()\n\t\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t\t.describe(\"Target collection slug for content references\"),\n\t\t\t\t\t\t\treferenceId: z.string().optional().describe(\"Target content/term ID for references\"),\n\t\t\t\t\t\t\ttitleAttr: z.string().optional().describe(\"HTML title attribute\"),\n\t\t\t\t\t\t\ttarget: z.string().optional().describe(\"HTML target attribute, e.g. '_blank'\"),\n\t\t\t\t\t\t\tcssClasses: z.string().optional().describe(\"Space-separated CSS classes\"),\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * Items are positioned by array index, but parents may be referenced\n\t\t\t\t\t\t\t * by their array index — items with `parentIndex` set are nested under\n\t\t\t\t\t\t\t * the item at that position. Items without `parentIndex` are top-level.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tparentIndex: z\n\t\t\t\t\t\t\t\t.number()\n\t\t\t\t\t\t\t\t.int()\n\t\t\t\t\t\t\t\t.nonnegative()\n\t\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t\t.describe(\n\t\t\t\t\t\t\t\t\t\"Array index of the parent item (must be earlier in the list). Omit for top-level items.\",\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.describe(\"Ordered list of menu items\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"menus:manage\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleMenuSetItems } = await import(\"../api/handlers/menus.js\");\n\t\t\t\treturn unwrap(\n\t\t\t\t\tawait handleMenuSetItems(ec.db, args.name, args.items, { locale: args.locale }),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"MENU_SET_ITEMS_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Revision tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"revision_list\",\n\t\t{\n\t\t\ttitle: \"List Revisions\",\n\t\t\tdescription:\n\t\t\t\t\"List revision history for a content item. Revisions are snapshots \" +\n\t\t\t\t\"created on publish or update. Returns newest-first. Requires the \" +\n\t\t\t\t\"collection to support 'revisions'.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\tcollection: z.string().describe(\"Collection slug\"),\n\t\t\t\tid: z.string().describe(\"Content item ID or slug\"),\n\t\t\t\tlimit: z.number().int().min(1).max(50).optional().describe(\"Max revisions (default 20)\"),\n\t\t\t}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:read\");\n\t\t\trequireDraftAccess(extra);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\treturn unwrap(\n\t\t\t\tawait ec.handleRevisionList(args.collection, args.id, {\n\t\t\t\t\tlimit: args.limit,\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"revision_restore\",\n\t\t{\n\t\t\ttitle: \"Restore Revision\",\n\t\t\tdescription:\n\t\t\t\t\"Restore a content item to a previous revision. Replaces the current \" +\n\t\t\t\t\"draft with the specified revision's data. Not automatically published — \" +\n\t\t\t\t\"use content_publish afterward if needed.\",\n\t\t\tinputSchema: z.object({\n\t\t\t\trevisionId: z.string().describe(\"Revision ID to restore\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"content:write\");\n\t\t\trequireRole(extra, Role.AUTHOR);\n\t\t\tconst { emdash, userId } = getExtra(extra);\n\n\t\t\t// Fetch the revision to discover the parent content entry\n\t\t\tconst revision = await emdash.handleRevisionGet(args.revisionId);\n\t\t\tif (!revision.success) {\n\t\t\t\treturn unwrap(revision);\n\t\t\t}\n\t\t\tconst revItem = revision.data?.item;\n\t\t\tif (!revItem?.collection || !revItem?.entryId) {\n\t\t\t\treturn respondError(\n\t\t\t\t\t\"VALIDATION_ERROR\",\n\t\t\t\t\t\"Revision is missing collection or entry reference\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Fetch the content entry to check ownership\n\t\t\tconst existing = await emdash.handleContentGet(revItem.collection, revItem.entryId);\n\t\t\tif (!existing.success) {\n\t\t\t\treturn unwrap(existing);\n\t\t\t}\n\t\t\trequireOwnership(\n\t\t\t\textra,\n\t\t\t\textractContentAuthorId(existing.data),\n\t\t\t\t\"content:edit_own\",\n\t\t\t\t\"content:edit_any\",\n\t\t\t);\n\n\t\t\treturn unwrap(await emdash.handleRevisionRestore(args.revisionId, userId));\n\t\t},\n\t);\n\n\t// =====================================================================\n\t// Settings tools\n\t// =====================================================================\n\n\tserver.registerTool(\n\t\t\"settings_get\",\n\t\t{\n\t\t\ttitle: \"Get Site Settings\",\n\t\t\tdescription:\n\t\t\t\t\"Get all site-wide settings (title, tagline, logo, favicon, URL, \" +\n\t\t\t\t\"date/time formatting, social links, SEO defaults). Media references \" +\n\t\t\t\t\"(logo, favicon, defaultOgImage) include resolved URLs. Unset values \" +\n\t\t\t\t\"are omitted from the response.\",\n\t\t\tinputSchema: z.object({}),\n\t\t\tannotations: { readOnlyHint: true },\n\t\t},\n\t\tasync (_args, extra) => {\n\t\t\trequireScope(extra, \"settings:read\");\n\t\t\trequireRole(extra, Role.EDITOR);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleSettingsGet } = await import(\"../api/handlers/settings.js\");\n\t\t\t\treturn unwrap(await handleSettingsGet(ec.db, ec.storage));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SETTINGS_READ_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\tserver.registerTool(\n\t\t\"settings_update\",\n\t\t{\n\t\t\ttitle: \"Update Site Settings\",\n\t\t\tdescription:\n\t\t\t\t\"Update one or more site-wide settings. This is a partial update: only \" +\n\t\t\t\t\"the fields provided are changed; omitted fields are left as-is. Returns \" +\n\t\t\t\t\"the full settings object after the update. To set a media reference \" +\n\t\t\t\t\"(logo, favicon, seo.defaultOgImage), pass an object with `mediaId` \" +\n\t\t\t\t\"(and optional `alt`) — the media item must already exist (use \" +\n\t\t\t\t\"media_create first).\",\n\t\t\tinputSchema: z.object({\n\t\t\t\ttitle: z.string().optional().describe(\"Site title\"),\n\t\t\t\ttagline: z.string().optional().describe(\"Site tagline / short description\"),\n\t\t\t\tlogo: settingsMediaReferenceSchema\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Logo media reference ({ mediaId, alt? })\"),\n\t\t\t\tfavicon: settingsMediaReferenceSchema\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Favicon media reference ({ mediaId, alt? })\"),\n\t\t\t\turl: z\n\t\t\t\t\t.union([\n\t\t\t\t\t\tz\n\t\t\t\t\t\t\t.string()\n\t\t\t\t\t\t\t.url()\n\t\t\t\t\t\t\t.refine((u) => HTTP_SCHEME_PATTERN.test(u), \"URL must use http or https\"),\n\t\t\t\t\t\tz.literal(\"\"),\n\t\t\t\t\t])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Canonical site URL (http or https). Empty string clears it.\"),\n\t\t\t\tpostsPerPage: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.int()\n\t\t\t\t\t.min(1)\n\t\t\t\t\t.max(100)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Default page size for content listings\"),\n\t\t\t\tdateFormat: z.string().optional().describe(\"Date format token string\"),\n\t\t\t\ttimezone: z.string().optional().describe(\"IANA timezone identifier\"),\n\t\t\t\tsocial: settingsSocialSchema.optional().describe(\"Social handles / URLs\"),\n\t\t\t\tseo: settingsSeoSchema.optional().describe(\"Site-wide SEO defaults\"),\n\t\t\t}),\n\t\t},\n\t\tasync (args, extra) => {\n\t\t\trequireScope(extra, \"settings:manage\");\n\t\t\trequireRole(extra, Role.ADMIN);\n\t\t\tconst ec = getEmDash(extra);\n\t\t\ttry {\n\t\t\t\tconst { handleSettingsUpdate } = await import(\"../api/handlers/settings.js\");\n\t\t\t\treturn unwrap(await handleSettingsUpdate(ec.db, ec.storage, args));\n\t\t\t} catch (error) {\n\t\t\t\treturn respondHandlerError(error, \"SETTINGS_UPDATE_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n\treturn server;\n}\n","/**\n * MCP Streamable HTTP endpoint\n *\n * Exposes an MCP server at /_emdash/api/mcp using the Streamable HTTP\n * transport (Web Standard variant). The server runs stateless — each\n * request creates a fresh transport, so no session tracking is needed.\n * Authentication is handled by the existing EmDash auth middleware.\n *\n * POST /_emdash/api/mcp — JSON-RPC tool calls\n * GET /_emdash/api/mcp — SSE stream (not used in stateless mode)\n * DELETE /_emdash/api/mcp — Session close (not used in stateless mode)\n */\n\nimport { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\";\nimport type { APIRoute } from \"astro\";\n\nimport { apiError } from \"#api/error.js\";\nimport { createMcpServer } from \"#mcp/server.js\";\n\nexport const prerender = false;\n\nexport const POST: APIRoute = async ({ request, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tif (!emdash) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tif (!user) {\n\t\treturn apiError(\"UNAUTHORIZED\", \"Authentication required\", 401);\n\t}\n\n\tconst server = createMcpServer();\n\n\ttry {\n\t\tconst transport = new WebStandardStreamableHTTPServerTransport({\n\t\t\t// Stateless: no session management\n\t\t\tsessionIdGenerator: undefined,\n\t\t});\n\n\t\tawait server.connect(transport);\n\n\t\treturn await transport.handleRequest(request, {\n\t\t\tauthInfo: {\n\t\t\t\ttoken: \"\",\n\t\t\t\tclientId: \"emdash-admin\",\n\t\t\t\tscopes: [],\n\t\t\t\textra: {\n\t\t\t\t\temdash,\n\t\t\t\t\tuserId: user.id,\n\t\t\t\t\tuserRole: user.role,\n\t\t\t\t\ttokenScopes: locals.tokenScopes,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\t\tconsole.error(\"[MCP]\", error);\n\t\tawait server.close().catch(() => {});\n\n\t\treturn new Response(\n\t\t\tJSON.stringify({\n\t\t\t\tjsonrpc: \"2.0\",\n\t\t\t\terror: {\n\t\t\t\t\tcode: -32603,\n\t\t\t\t\tmessage: \"Internal server error\",\n\t\t\t\t},\n\t\t\t\tid: null,\n\t\t\t}),\n\t\t\t{\n\t\t\t\tstatus: 500,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"Cache-Control\": \"private, no-store\",\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n};\n\n/**\n * GET — SSE stream. Not used in stateless mode.\n */\nexport const GET: APIRoute = async () => {\n\treturn new Response(\n\t\tJSON.stringify({\n\t\t\tjsonrpc: \"2.0\",\n\t\t\terror: {\n\t\t\t\tcode: -32000,\n\t\t\t\tmessage: \"Method not allowed. This is a stateless MCP endpoint — use POST.\",\n\t\t\t},\n\t\t\tid: null,\n\t\t}),\n\t\t{\n\t\t\tstatus: 405,\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\"Cache-Control\": \"private, no-store\",\n\t\t\t},\n\t\t},\n\t);\n};\n\n/**\n * DELETE — Session close. Not used in stateless mode.\n */\nexport const DELETE: APIRoute = async () => {\n\treturn new Response(\n\t\tJSON.stringify({\n\t\t\tjsonrpc: \"2.0\",\n\t\t\terror: {\n\t\t\t\tcode: -32000,\n\t\t\t\tmessage: \"Method not allowed. This is a stateless MCP endpoint.\",\n\t\t\t},\n\t\t\tid: null,\n\t\t}),\n\t\t{\n\t\t\tstatus: 405,\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\"Cache-Control\": \"private, no-store\",\n\t\t\t},\n\t\t},\n\t);\n};\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { APIRoute } from "astro";
2
+
3
+ //#region src/astro/routes/api/media/[id]/confirm.d.ts
4
+ declare const prerender = false;
5
+ /**
6
+ * Confirm upload completion
7
+ */
8
+ declare const POST: APIRoute;
9
+ //#endregion
10
+ export { POST, prerender };
11
+ //# sourceMappingURL=confirm.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.d.mts","names":[],"sources":["../../../../../../src/astro/routes/api/media/[id]/confirm.ts"],"mappings":";;;cAkBa,SAAA;;;;cAeA,IAAA,EAAM,QAAA"}
@@ -0,0 +1,61 @@
1
+ import "../../../../../base64-CqR-7kqF.mjs";
2
+ import "../../../../../types-CwXMEPRr.mjs";
3
+ import { n as apiSuccess, r as handleError, t as apiError } from "../../../../../error-tSQWIl5U.mjs";
4
+ import { r as parseOptionalBody, t as isParseError } from "../../../../../parse-BFTPon-J.mjs";
5
+ import { Vt as mediaConfirmBody } from "../../../../../redirects-Dmj6KRU3.mjs";
6
+ import "../../../../../setup-BGAJ2uXs.mjs";
7
+ import "../../../../../api/schemas/index.mjs";
8
+ import { n as requirePerm, t as requireOwnerPerm } from "../../../../../authorize-BlyCH-96.mjs";
9
+ import { MediaRepository } from "emdash";
10
+
11
+ //#region src/astro/routes/api/media/[id]/confirm.ts
12
+ const prerender = false;
13
+ /**
14
+ * Add URL to media item (relative URL for portability)
15
+ */
16
+ function addUrlToMedia(item) {
17
+ return {
18
+ ...item,
19
+ url: `/_emdash/api/media/file/${item.storageKey}`
20
+ };
21
+ }
22
+ /**
23
+ * Confirm upload completion
24
+ */
25
+ const POST = async ({ params, request, locals }) => {
26
+ const { emdash, user } = locals;
27
+ const { id } = params;
28
+ const denied = requirePerm(user, "media:upload");
29
+ if (denied) return denied;
30
+ if (!id) return apiError("INVALID_REQUEST", "Media ID is required", 400);
31
+ if (!emdash?.db) return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
32
+ try {
33
+ const body = await parseOptionalBody(request, mediaConfirmBody, {});
34
+ if (isParseError(body)) return body;
35
+ const repo = new MediaRepository(emdash.db);
36
+ const existing = await repo.findById(id);
37
+ if (!existing) return apiError("NOT_FOUND", `Media item not found: ${id}`, 404);
38
+ if (existing.status !== "pending") return apiError("INVALID_STATE", `Media item is not pending: ${existing.status}`, 400);
39
+ const ownerDenied = requireOwnerPerm(user, existing.authorId ?? "", "media:edit_own", "media:edit_any");
40
+ if (ownerDenied) return ownerDenied;
41
+ if (emdash.storage) {
42
+ if (!await emdash.storage.exists(existing.storageKey)) {
43
+ await repo.markFailed(id);
44
+ return apiError("FILE_NOT_FOUND", "File was not uploaded to storage", 400);
45
+ }
46
+ }
47
+ const item = await repo.confirmUpload(id, {
48
+ size: body.size,
49
+ width: body.width,
50
+ height: body.height
51
+ });
52
+ if (!item) return apiError("CONFIRM_FAILED", "Failed to confirm upload", 500);
53
+ return apiSuccess({ item: addUrlToMedia(item) });
54
+ } catch (error) {
55
+ return handleError(error, "Failed to confirm upload", "CONFIRM_ERROR");
56
+ }
57
+ };
58
+
59
+ //#endregion
60
+ export { POST, prerender };
61
+ //# sourceMappingURL=confirm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/media/[id]/confirm.ts"],"sourcesContent":["/**\n * Confirm media upload endpoint\n *\n * POST /_emdash/api/media/{id}/confirm\n *\n * Confirms that the client has successfully uploaded the file to storage.\n * Marks the media record as ready and optionally updates metadata.\n */\n\nimport type { APIRoute } from \"astro\";\nimport { MediaRepository } from \"emdash\";\n\nimport { requireOwnerPerm, requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { isParseError, parseOptionalBody } from \"#api/parse.js\";\nimport { mediaConfirmBody } from \"#api/schemas.js\";\nimport type { MediaItem } from \"#types\";\n\nexport const prerender = false;\n\n/**\n * Add URL to media item (relative URL for portability)\n */\nfunction addUrlToMedia(item: MediaItem): MediaItem & { url: string } {\n\treturn {\n\t\t...item,\n\t\turl: `/_emdash/api/media/file/${item.storageKey}`,\n\t};\n}\n\n/**\n * Confirm upload completion\n */\nexport const POST: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\tconst denied = requirePerm(user, \"media:upload\");\n\tif (denied) return denied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID is required\", 400);\n\t}\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\tconst body = await parseOptionalBody(request, mediaConfirmBody, {});\n\t\tif (isParseError(body)) return body;\n\n\t\tconst repo = new MediaRepository(emdash.db);\n\n\t\t// Get the media item first to check status\n\t\tconst existing = await repo.findById(id);\n\t\tif (!existing) {\n\t\t\treturn apiError(\"NOT_FOUND\", `Media item not found: ${id}`, 404);\n\t\t}\n\n\t\tif (existing.status !== \"pending\") {\n\t\t\treturn apiError(\"INVALID_STATE\", `Media item is not pending: ${existing.status}`, 400);\n\t\t}\n\n\t\t// Only the uploader or a user with media:edit_any can confirm/fail a pending upload\n\t\tconst ownerDenied = requireOwnerPerm(\n\t\t\tuser,\n\t\t\texisting.authorId ?? \"\",\n\t\t\t\"media:edit_own\",\n\t\t\t\"media:edit_any\",\n\t\t);\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\t// Optionally verify the file exists in storage\n\t\tif (emdash.storage) {\n\t\t\tconst exists = await emdash.storage.exists(existing.storageKey);\n\t\t\tif (!exists) {\n\t\t\t\t// Mark as failed\n\t\t\t\tawait repo.markFailed(id);\n\t\t\t\treturn apiError(\"FILE_NOT_FOUND\", \"File was not uploaded to storage\", 400);\n\t\t\t}\n\t\t}\n\n\t\t// Confirm the upload\n\t\tconst item = await repo.confirmUpload(id, {\n\t\t\tsize: body.size,\n\t\t\twidth: body.width,\n\t\t\theight: body.height,\n\t\t});\n\n\t\tif (!item) {\n\t\t\treturn apiError(\"CONFIRM_FAILED\", \"Failed to confirm upload\", 500);\n\t\t}\n\n\t\t// Add URL to the response (relative URL for portability)\n\t\tconst itemWithUrl = addUrlToMedia(item);\n\n\t\treturn apiSuccess({ item: itemWithUrl });\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to confirm upload\", \"CONFIRM_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;AAkBA,MAAa,YAAY;;;;AAKzB,SAAS,cAAc,MAA8C;AACpE,QAAO;EACN,GAAG;EACH,KAAK,2BAA2B,KAAK;EACrC;;;;;AAMF,MAAa,OAAiB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACpE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAEf,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,wBAAwB,IAAI;AAGhE,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EACH,MAAM,OAAO,MAAM,kBAAkB,SAAS,kBAAkB,EAAE,CAAC;AACnE,MAAI,aAAa,KAAK,CAAE,QAAO;EAE/B,MAAM,OAAO,IAAI,gBAAgB,OAAO,GAAG;EAG3C,MAAM,WAAW,MAAM,KAAK,SAAS,GAAG;AACxC,MAAI,CAAC,SACJ,QAAO,SAAS,aAAa,yBAAyB,MAAM,IAAI;AAGjE,MAAI,SAAS,WAAW,UACvB,QAAO,SAAS,iBAAiB,8BAA8B,SAAS,UAAU,IAAI;EAIvF,MAAM,cAAc,iBACnB,MACA,SAAS,YAAY,IACrB,kBACA,iBACA;AACD,MAAI,YAAa,QAAO;AAGxB,MAAI,OAAO,SAEV;OAAI,CADW,MAAM,OAAO,QAAQ,OAAO,SAAS,WAAW,EAClD;AAEZ,UAAM,KAAK,WAAW,GAAG;AACzB,WAAO,SAAS,kBAAkB,oCAAoC,IAAI;;;EAK5E,MAAM,OAAO,MAAM,KAAK,cAAc,IAAI;GACzC,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,CAAC;AAEF,MAAI,CAAC,KACJ,QAAO,SAAS,kBAAkB,4BAA4B,IAAI;AAMnE,SAAO,WAAW,EAAE,MAFA,cAAc,KAAK,EAEA,CAAC;UAChC,OAAO;AACf,SAAO,YAAY,OAAO,4BAA4B,gBAAgB"}
@@ -0,0 +1,23 @@
1
+ import { APIRoute } from "astro";
2
+
3
+ //#region src/astro/routes/api/media/[id].d.ts
4
+ declare const prerender = false;
5
+ /**
6
+ * Get media item
7
+ */
8
+ declare const GET: APIRoute;
9
+ /**
10
+ * Update media metadata
11
+ *
12
+ * Authors can edit their own media; editors+ can edit any.
13
+ */
14
+ declare const PUT: APIRoute;
15
+ /**
16
+ * Delete media item
17
+ *
18
+ * Authors can delete their own media; editors+ can delete any.
19
+ */
20
+ declare const DELETE: APIRoute;
21
+ //#endregion
22
+ export { DELETE, GET, PUT, prerender };
23
+ //# sourceMappingURL=_id_.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_id_.d.mts","names":[],"sources":["../../../../../src/astro/routes/api/media/[id].ts"],"mappings":";;;cAea,SAAA;;;;cAKA,GAAA,EAAK,QAAA;AAwBlB;;;;;AAAA,cAAa,GAAA,EAAK,QAAA;;;;;;cAkDL,MAAA,EAAQ,QAAA"}
@@ -0,0 +1,83 @@
1
+ import "../../../../base64-CqR-7kqF.mjs";
2
+ import "../../../../types-CwXMEPRr.mjs";
3
+ import { a as unwrapResult, r as handleError, t as apiError } from "../../../../error-tSQWIl5U.mjs";
4
+ import { n as parseBody, t as isParseError } from "../../../../parse-BFTPon-J.mjs";
5
+ import { Yt as mediaUpdateBody } from "../../../../redirects-Dmj6KRU3.mjs";
6
+ import "../../../../setup-BGAJ2uXs.mjs";
7
+ import "../../../../api/schemas/index.mjs";
8
+ import { n as requirePerm, t as requireOwnerPerm } from "../../../../authorize-BlyCH-96.mjs";
9
+
10
+ //#region src/astro/routes/api/media/[id].ts
11
+ const prerender = false;
12
+ /**
13
+ * Get media item
14
+ */
15
+ const GET = async ({ params, locals }) => {
16
+ const { emdash, user } = locals;
17
+ const { id } = params;
18
+ const readDenied = requirePerm(user, "media:read");
19
+ if (readDenied) return readDenied;
20
+ if (!id) return apiError("INVALID_REQUEST", "Media ID required", 400);
21
+ if (!emdash?.handleMediaGet) return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
22
+ return unwrapResult(await emdash.handleMediaGet(id));
23
+ };
24
+ /**
25
+ * Update media metadata
26
+ *
27
+ * Authors can edit their own media; editors+ can edit any.
28
+ */
29
+ const PUT = async ({ params, request, locals }) => {
30
+ const { emdash, user } = locals;
31
+ const { id } = params;
32
+ const editDenied = requirePerm(user, "media:edit_own");
33
+ if (editDenied) return editDenied;
34
+ if (!id) return apiError("INVALID_REQUEST", "Media ID required", 400);
35
+ if (!emdash?.handleMediaGet || !emdash?.handleMediaUpdate) return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
36
+ try {
37
+ const getResult = await emdash.handleMediaGet(id);
38
+ if (!getResult.success || !getResult.data?.item) return apiError("NOT_FOUND", "Media item not found", 404);
39
+ const media = getResult.data.item;
40
+ const ownerDenied = requireOwnerPerm(user, media.authorId, "media:edit_own", "media:edit_any");
41
+ if (ownerDenied) return ownerDenied;
42
+ const body = await parseBody(request, mediaUpdateBody);
43
+ if (isParseError(body)) return body;
44
+ return unwrapResult(await emdash.handleMediaUpdate(id, {
45
+ alt: body.alt,
46
+ caption: body.caption,
47
+ width: body.width,
48
+ height: body.height
49
+ }));
50
+ } catch (error) {
51
+ return handleError(error, "Failed to update media", "MEDIA_UPDATE_ERROR");
52
+ }
53
+ };
54
+ /**
55
+ * Delete media item
56
+ *
57
+ * Authors can delete their own media; editors+ can delete any.
58
+ */
59
+ const DELETE = async ({ params, locals }) => {
60
+ const { emdash, user } = locals;
61
+ const { id } = params;
62
+ const deleteDenied = requirePerm(user, "media:delete_own");
63
+ if (deleteDenied) return deleteDenied;
64
+ if (!id) return apiError("INVALID_REQUEST", "Media ID required", 400);
65
+ if (!emdash?.handleMediaGet || !emdash?.handleMediaDelete) return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
66
+ try {
67
+ const getResult = await emdash.handleMediaGet(id);
68
+ if (!getResult.success || !getResult.data?.item) return apiError("NOT_FOUND", "Media item not found", 404);
69
+ const media = getResult.data.item;
70
+ const ownerDenied = requireOwnerPerm(user, media.authorId, "media:delete_own", "media:delete_any");
71
+ if (ownerDenied) return ownerDenied;
72
+ if (emdash.storage) try {
73
+ await emdash.storage.delete(media.storageKey);
74
+ } catch {}
75
+ return unwrapResult(await emdash.handleMediaDelete(id));
76
+ } catch (error) {
77
+ return handleError(error, "Failed to delete media", "MEDIA_DELETE_ERROR");
78
+ }
79
+ };
80
+
81
+ //#endregion
82
+ export { DELETE, GET, PUT, prerender };
83
+ //# sourceMappingURL=_id_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_id_.mjs","names":[],"sources":["../../../../../src/astro/routes/api/media/[id].ts"],"sourcesContent":["/**\n * Single media item endpoint\n *\n * GET /_emdash/api/media/:id - Get media item\n * PUT /_emdash/api/media/:id - Update media metadata\n * DELETE /_emdash/api/media/:id - Delete media item\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requireOwnerPerm, requirePerm } from \"#api/authorize.js\";\nimport { apiError, handleError, unwrapResult } from \"#api/error.js\";\nimport { isParseError, parseBody } from \"#api/parse.js\";\nimport { mediaUpdateBody } from \"#api/schemas.js\";\n\nexport const prerender = false;\n\n/**\n * Get media item\n */\nexport const GET: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\tconst readDenied = requirePerm(user, \"media:read\");\n\tif (readDenied) return readDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst result = await emdash.handleMediaGet(id);\n\treturn unwrapResult(result);\n};\n\n/**\n * Update media metadata\n *\n * Authors can edit their own media; editors+ can edit any.\n */\nexport const PUT: APIRoute = async ({ params, request, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\t// Minimum permission gate — ownership checked below\n\tconst editDenied = requirePerm(user, \"media:edit_own\");\n\tif (editDenied) return editDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet || !emdash?.handleMediaUpdate) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\t// Fetch media item for ownership check\n\t\tconst getResult = await emdash.handleMediaGet(id);\n\t\tif (!getResult.success || !getResult.data?.item) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Media item not found\", 404);\n\t\t}\n\n\t\tconst media = getResult.data.item;\n\n\t\t// Ownership check: authors can edit own, editors+ can edit any\n\t\tconst ownerDenied = requireOwnerPerm(user, media.authorId, \"media:edit_own\", \"media:edit_any\");\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\tconst body = await parseBody(request, mediaUpdateBody);\n\t\tif (isParseError(body)) return body;\n\n\t\tconst result = await emdash.handleMediaUpdate(id, {\n\t\t\talt: body.alt,\n\t\t\tcaption: body.caption,\n\t\t\twidth: body.width,\n\t\t\theight: body.height,\n\t\t});\n\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to update media\", \"MEDIA_UPDATE_ERROR\");\n\t}\n};\n\n/**\n * Delete media item\n *\n * Authors can delete their own media; editors+ can delete any.\n */\nexport const DELETE: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst { id } = params;\n\n\t// Minimum permission gate — ownership checked below\n\tconst deleteDenied = requirePerm(user, \"media:delete_own\");\n\tif (deleteDenied) return deleteDenied;\n\n\tif (!id) {\n\t\treturn apiError(\"INVALID_REQUEST\", \"Media ID required\", 400);\n\t}\n\n\tif (!emdash?.handleMediaGet || !emdash?.handleMediaDelete) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\ttry {\n\t\t// Fetch media item for ownership check and storage key\n\t\tconst getResult = await emdash.handleMediaGet(id);\n\t\tif (!getResult.success || !getResult.data?.item) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Media item not found\", 404);\n\t\t}\n\n\t\tconst media = getResult.data.item;\n\n\t\t// Ownership check: authors can delete own, editors+ can delete any\n\t\tconst ownerDenied = requireOwnerPerm(\n\t\t\tuser,\n\t\t\tmedia.authorId,\n\t\t\t\"media:delete_own\",\n\t\t\t\"media:delete_any\",\n\t\t);\n\t\tif (ownerDenied) return ownerDenied;\n\n\t\t// Delete file from storage via the storage adapter\n\t\tif (emdash.storage) {\n\t\t\ttry {\n\t\t\t\tawait emdash.storage.delete(media.storageKey);\n\t\t\t} catch {\n\t\t\t\t// Best-effort — continue with database deletion\n\t\t\t}\n\t\t}\n\n\t\t// Delete from database — site-settings cache invalidation happens\n\t\t// in `EmDashRuntime.handleMediaDelete` so MCP/plugin paths inherit it.\n\t\tconst result = await emdash.handleMediaDelete(id);\n\n\t\treturn unwrapResult(result);\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to delete media\", \"MEDIA_DELETE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;AAeA,MAAa,YAAY;;;;AAKzB,MAAa,MAAgB,OAAO,EAAE,QAAQ,aAAa;CAC1D,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAEf,MAAM,aAAa,YAAY,MAAM,aAAa;AAClD,KAAI,WAAY,QAAO;AAEvB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,qBAAqB,IAAI;AAG7D,KAAI,CAAC,QAAQ,eACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAIpE,QAAO,aADQ,MAAM,OAAO,eAAe,GAAG,CACnB;;;;;;;AAQ5B,MAAa,MAAgB,OAAO,EAAE,QAAQ,SAAS,aAAa;CACnE,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAGf,MAAM,aAAa,YAAY,MAAM,iBAAiB;AACtD,KAAI,WAAY,QAAO;AAEvB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,qBAAqB,IAAI;AAG7D,KAAI,CAAC,QAAQ,kBAAkB,CAAC,QAAQ,kBACvC,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EAEH,MAAM,YAAY,MAAM,OAAO,eAAe,GAAG;AACjD,MAAI,CAAC,UAAU,WAAW,CAAC,UAAU,MAAM,KAC1C,QAAO,SAAS,aAAa,wBAAwB,IAAI;EAG1D,MAAM,QAAQ,UAAU,KAAK;EAG7B,MAAM,cAAc,iBAAiB,MAAM,MAAM,UAAU,kBAAkB,iBAAiB;AAC9F,MAAI,YAAa,QAAO;EAExB,MAAM,OAAO,MAAM,UAAU,SAAS,gBAAgB;AACtD,MAAI,aAAa,KAAK,CAAE,QAAO;AAS/B,SAAO,aAPQ,MAAM,OAAO,kBAAkB,IAAI;GACjD,KAAK,KAAK;GACV,SAAS,KAAK;GACd,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,CAAC,CAEyB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,qBAAqB;;;;;;;;AAS3E,MAAa,SAAmB,OAAO,EAAE,QAAQ,aAAa;CAC7D,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,EAAE,OAAO;CAGf,MAAM,eAAe,YAAY,MAAM,mBAAmB;AAC1D,KAAI,aAAc,QAAO;AAEzB,KAAI,CAAC,GACJ,QAAO,SAAS,mBAAmB,qBAAqB,IAAI;AAG7D,KAAI,CAAC,QAAQ,kBAAkB,CAAC,QAAQ,kBACvC,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;AAGpE,KAAI;EAEH,MAAM,YAAY,MAAM,OAAO,eAAe,GAAG;AACjD,MAAI,CAAC,UAAU,WAAW,CAAC,UAAU,MAAM,KAC1C,QAAO,SAAS,aAAa,wBAAwB,IAAI;EAG1D,MAAM,QAAQ,UAAU,KAAK;EAG7B,MAAM,cAAc,iBACnB,MACA,MAAM,UACN,oBACA,mBACA;AACD,MAAI,YAAa,QAAO;AAGxB,MAAI,OAAO,QACV,KAAI;AACH,SAAM,OAAO,QAAQ,OAAO,MAAM,WAAW;UACtC;AAST,SAAO,aAFQ,MAAM,OAAO,kBAAkB,GAAG,CAEtB;UACnB,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,qBAAqB"}
@@ -0,0 +1,8 @@
1
+ import { APIRoute } from "astro";
2
+
3
+ //#region src/astro/routes/api/media/file/[...key].d.ts
4
+ declare const prerender = false;
5
+ declare const GET: APIRoute;
6
+ //#endregion
7
+ export { GET, prerender };
8
+ //# sourceMappingURL=_...key_.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_...key_.d.mts","names":[],"sources":["../../../../../../src/astro/routes/api/media/file/[...key].ts"],"mappings":";;;cAUa,SAAA;AAAA,cAoBA,GAAA,EAAK,QAAA"}
@@ -0,0 +1,52 @@
1
+ import "../../../../../base64-CqR-7kqF.mjs";
2
+ import "../../../../../types-CwXMEPRr.mjs";
3
+ import { r as handleError, t as apiError } from "../../../../../error-tSQWIl5U.mjs";
4
+
5
+ //#region src/astro/routes/api/media/file/[...key].ts
6
+ const prerender = false;
7
+ /**
8
+ * Content types that are safe to display inline (simple raster/vector images, video, audio).
9
+ * Everything else gets Content-Disposition: attachment to prevent script execution.
10
+ */
11
+ const SAFE_INLINE_TYPES = new Set([
12
+ "image/jpeg",
13
+ "image/png",
14
+ "image/gif",
15
+ "image/webp",
16
+ "image/avif",
17
+ "image/x-icon",
18
+ "video/mp4",
19
+ "video/webm",
20
+ "audio/mpeg",
21
+ "audio/wav",
22
+ "audio/ogg"
23
+ ]);
24
+ const GET = async ({ params, locals }) => {
25
+ const { key } = params;
26
+ const { emdash } = locals;
27
+ if (!key) return apiError("NOT_FOUND", "File not found", 404);
28
+ if (!emdash?.storage) return apiError("NOT_CONFIGURED", "Storage not configured", 500);
29
+ try {
30
+ const result = await emdash.storage.download(key);
31
+ const headers = {
32
+ "Content-Type": result.contentType,
33
+ "Cache-Control": "public, max-age=31536000, immutable",
34
+ "X-Content-Type-Options": "nosniff",
35
+ "Content-Security-Policy": "sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'"
36
+ };
37
+ if (result.size) headers["Content-Length"] = String(result.size);
38
+ if (SAFE_INLINE_TYPES.has(result.contentType)) headers["Content-Disposition"] = "inline";
39
+ else headers["Content-Disposition"] = "attachment";
40
+ return new Response(result.body, {
41
+ status: 200,
42
+ headers
43
+ });
44
+ } catch (error) {
45
+ if (error instanceof Error && (error.message.includes("not found") || error.message.includes("NOT_FOUND"))) return apiError("NOT_FOUND", "File not found", 404);
46
+ return handleError(error, "Failed to serve file", "FILE_SERVE_ERROR");
47
+ }
48
+ };
49
+
50
+ //#endregion
51
+ export { GET, prerender };
52
+ //# sourceMappingURL=_...key_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_...key_.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/media/file/[...key].ts"],"sourcesContent":["/**\n * Serve uploaded media files\n *\n * GET /_emdash/api/media/file/:key - Serve file from storage\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { apiError, handleError } from \"#api/error.js\";\n\nexport const prerender = false;\n\n/**\n * Content types that are safe to display inline (simple raster/vector images, video, audio).\n * Everything else gets Content-Disposition: attachment to prevent script execution.\n */\nconst SAFE_INLINE_TYPES = new Set([\n\t\"image/jpeg\",\n\t\"image/png\",\n\t\"image/gif\",\n\t\"image/webp\",\n\t\"image/avif\",\n\t\"image/x-icon\",\n\t\"video/mp4\",\n\t\"video/webm\",\n\t\"audio/mpeg\",\n\t\"audio/wav\",\n\t\"audio/ogg\",\n]);\n\nexport const GET: APIRoute = async ({ params, locals }) => {\n\tconst { key } = params;\n\tconst { emdash } = locals;\n\n\tif (!key) {\n\t\treturn apiError(\"NOT_FOUND\", \"File not found\", 404);\n\t}\n\n\tif (!emdash?.storage) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"Storage not configured\", 500);\n\t}\n\n\ttry {\n\t\tconst result = await emdash.storage.download(key);\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Content-Type\": result.contentType,\n\t\t\t\"Cache-Control\": \"public, max-age=31536000, immutable\",\n\t\t\t\"X-Content-Type-Options\": \"nosniff\",\n\t\t\t// Sandbox CSP on all user-uploaded content — prevents script execution\n\t\t\t// even for SVGs navigated to directly or content types that support scripting.\n\t\t\t\"Content-Security-Policy\":\n\t\t\t\t\"sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'\",\n\t\t};\n\n\t\tif (result.size) {\n\t\t\theaders[\"Content-Length\"] = String(result.size);\n\t\t}\n\n\t\t// Safe image/media types can render inline; everything else (SVG, PDF,\n\t\t// HTML, JS, etc.) must be downloaded to prevent stored XSS.\n\t\tif (SAFE_INLINE_TYPES.has(result.contentType)) {\n\t\t\theaders[\"Content-Disposition\"] = \"inline\";\n\t\t} else {\n\t\t\theaders[\"Content-Disposition\"] = \"attachment\";\n\t\t}\n\n\t\treturn new Response(result.body, { status: 200, headers });\n\t} catch (error) {\n\t\t// Check if it's a \"not found\" error\n\t\tif (\n\t\t\terror instanceof Error &&\n\t\t\t(error.message.includes(\"not found\") || error.message.includes(\"NOT_FOUND\"))\n\t\t) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"File not found\", 404);\n\t\t}\n\t\treturn handleError(error, \"Failed to serve file\", \"FILE_SERVE_ERROR\");\n\t}\n};\n"],"mappings":";;;;;AAUA,MAAa,YAAY;;;;;AAMzB,MAAM,oBAAoB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;AAEF,MAAa,MAAgB,OAAO,EAAE,QAAQ,aAAa;CAC1D,MAAM,EAAE,QAAQ;CAChB,MAAM,EAAE,WAAW;AAEnB,KAAI,CAAC,IACJ,QAAO,SAAS,aAAa,kBAAkB,IAAI;AAGpD,KAAI,CAAC,QAAQ,QACZ,QAAO,SAAS,kBAAkB,0BAA0B,IAAI;AAGjE,KAAI;EACH,MAAM,SAAS,MAAM,OAAO,QAAQ,SAAS,IAAI;EAEjD,MAAM,UAAkC;GACvC,gBAAgB,OAAO;GACvB,iBAAiB;GACjB,0BAA0B;GAG1B,2BACC;GACD;AAED,MAAI,OAAO,KACV,SAAQ,oBAAoB,OAAO,OAAO,KAAK;AAKhD,MAAI,kBAAkB,IAAI,OAAO,YAAY,CAC5C,SAAQ,yBAAyB;MAEjC,SAAQ,yBAAyB;AAGlC,SAAO,IAAI,SAAS,OAAO,MAAM;GAAE,QAAQ;GAAK;GAAS,CAAC;UAClD,OAAO;AAEf,MACC,iBAAiB,UAChB,MAAM,QAAQ,SAAS,YAAY,IAAI,MAAM,QAAQ,SAAS,YAAY,EAE3E,QAAO,SAAS,aAAa,kBAAkB,IAAI;AAEpD,SAAO,YAAY,OAAO,wBAAwB,mBAAmB"}