emdash 0.21.0 → 0.22.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 (620) hide show
  1. package/dist/{adapters-BxSmgtbF.d.mts → adapters-hUy8vOB-.d.mts} +1 -1
  2. package/dist/{adapters-BxSmgtbF.d.mts.map → adapters-hUy8vOB-.d.mts.map} +1 -1
  3. package/dist/after-B1IIdH3Y.mjs +29 -0
  4. package/dist/after-B1IIdH3Y.mjs.map +1 -0
  5. package/dist/{allowed-origins-BqC8cul8.mjs → allowed-origins-DjlhyfNN.mjs} +2 -2
  6. package/dist/{allowed-origins-BqC8cul8.mjs.map → allowed-origins-DjlhyfNN.mjs.map} +1 -1
  7. package/dist/api/route-utils.d.mts +3 -3
  8. package/dist/api/route-utils.mjs +20 -19
  9. package/dist/api/route-utils.mjs.map +1 -1
  10. package/dist/api/schemas/index.d.mts +2 -2
  11. package/dist/api/schemas/index.mjs +4 -4
  12. package/dist/{api-DxjIV2o8.mjs → api-BDuM4bEy.mjs} +31 -25
  13. package/dist/api-BDuM4bEy.mjs.map +1 -0
  14. package/dist/{api-tokens-BFFkB0jB.mjs → api-tokens-ViYKeIp9.mjs} +13 -3
  15. package/dist/api-tokens-ViYKeIp9.mjs.map +1 -0
  16. package/dist/{apply-CLjxheyb.mjs → apply-wDqQoxX4.mjs} +18 -18
  17. package/dist/{apply-CLjxheyb.mjs.map → apply-wDqQoxX4.mjs.map} +1 -1
  18. package/dist/astro/image-endpoint.d.mts +8 -0
  19. package/dist/astro/image-endpoint.d.mts.map +1 -0
  20. package/dist/astro/image-endpoint.mjs +55 -0
  21. package/dist/astro/image-endpoint.mjs.map +1 -0
  22. package/dist/astro/index.d.mts +36 -11
  23. package/dist/astro/index.d.mts.map +1 -1
  24. package/dist/astro/index.mjs +114 -24
  25. package/dist/astro/index.mjs.map +1 -1
  26. package/dist/astro/middleware/auth.d.mts +9 -9
  27. package/dist/astro/middleware/auth.d.mts.map +1 -1
  28. package/dist/astro/middleware/auth.mjs +12 -10
  29. package/dist/astro/middleware/auth.mjs.map +1 -1
  30. package/dist/astro/middleware/redirect.mjs +6 -6
  31. package/dist/astro/middleware/request-context.mjs +5 -5
  32. package/dist/astro/middleware/setup.mjs +1 -1
  33. package/dist/astro/middleware.d.mts +1 -1
  34. package/dist/astro/middleware.d.mts.map +1 -1
  35. package/dist/astro/middleware.mjs +153 -79
  36. package/dist/astro/middleware.mjs.map +1 -1
  37. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -7
  38. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -7
  39. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
  40. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  41. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
  42. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +10 -10
  43. package/dist/astro/routes/api/admin/byline-fields/index.mjs +10 -10
  44. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +10 -10
  45. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +17 -16
  46. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  47. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -16
  48. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
  49. package/dist/astro/routes/api/admin/bylines/index.mjs +17 -16
  50. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  51. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +15 -13
  52. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -6
  54. package/dist/astro/routes/api/admin/comments/_id_.mjs.map +1 -1
  55. package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -10
  56. package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
  57. package/dist/astro/routes/api/admin/comments/counts.mjs +8 -6
  58. package/dist/astro/routes/api/admin/comments/counts.mjs.map +1 -1
  59. package/dist/astro/routes/api/admin/comments/index.mjs +12 -10
  60. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
  61. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
  62. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
  63. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
  64. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
  65. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +40 -39
  66. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +40 -39
  68. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +39 -38
  70. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +39 -38
  72. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +39 -38
  74. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  75. package/dist/astro/routes/api/admin/plugins/index.mjs +39 -38
  76. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  77. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  78. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +39 -38
  79. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +39 -38
  81. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +39 -38
  83. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +39 -38
  85. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +40 -39
  87. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +39 -38
  89. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +40 -39
  91. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/plugins/updates.mjs +39 -38
  93. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +39 -38
  95. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  97. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +39 -38
  98. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  99. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  100. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
  101. package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -8
  102. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
  103. package/dist/astro/routes/api/admin/users/index.mjs +7 -7
  104. package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
  105. package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
  106. package/dist/astro/routes/api/auth/invite/complete.mjs +12 -12
  107. package/dist/astro/routes/api/auth/invite/index.mjs +9 -9
  108. package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -11
  109. package/dist/astro/routes/api/auth/logout.mjs +4 -4
  110. package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -11
  111. package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
  112. package/dist/astro/routes/api/auth/me.mjs +8 -8
  113. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  114. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  115. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  116. package/dist/astro/routes/api/auth/passkey/_id_.mjs +7 -7
  117. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  118. package/dist/astro/routes/api/auth/passkey/options.mjs +13 -13
  119. package/dist/astro/routes/api/auth/passkey/register/options.mjs +11 -11
  120. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +12 -12
  121. package/dist/astro/routes/api/auth/passkey/verify.mjs +12 -12
  122. package/dist/astro/routes/api/auth/signup/complete.mjs +12 -12
  123. package/dist/astro/routes/api/auth/signup/request.mjs +11 -11
  124. package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
  125. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +16 -15
  126. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
  127. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts +9 -0
  128. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts.map +1 -0
  129. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +179 -0
  130. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -0
  131. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
  132. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +4 -4
  133. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
  134. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  135. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +13 -13
  136. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +8 -8
  137. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
  138. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
  139. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
  140. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +17 -15
  141. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  142. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
  143. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +4 -4
  144. package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
  145. package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
  146. package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
  147. package/dist/astro/routes/api/content/_collection_/trash.mjs +8 -8
  148. package/dist/astro/routes/api/dashboard.mjs +10 -8
  149. package/dist/astro/routes/api/dashboard.mjs.map +1 -1
  150. package/dist/astro/routes/api/dev/emails.mjs +4 -4
  151. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  152. package/dist/astro/routes/api/import/probe.mjs +12 -12
  153. package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
  154. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  155. package/dist/astro/routes/api/import/wordpress/execute.mjs +16 -15
  156. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  157. package/dist/astro/routes/api/import/wordpress/media.mjs +10 -10
  158. package/dist/astro/routes/api/import/wordpress/prepare.mjs +11 -11
  159. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +10 -10
  160. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  161. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +12 -12
  162. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  163. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  164. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +18 -17
  165. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  166. package/dist/astro/routes/api/manifest.mjs +5 -5
  167. package/dist/astro/routes/api/mcp.mjs +213 -46
  168. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  169. package/dist/astro/routes/api/media/_id_/confirm.mjs +8 -8
  170. package/dist/astro/routes/api/media/_id_.mjs +8 -8
  171. package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
  172. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  173. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  174. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  175. package/dist/astro/routes/api/media/upload-url.mjs +10 -10
  176. package/dist/astro/routes/api/media.mjs +13 -13
  177. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +11 -9
  178. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
  179. package/dist/astro/routes/api/menus/_name_/items.mjs +11 -9
  180. package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
  181. package/dist/astro/routes/api/menus/_name_/reorder.mjs +11 -9
  182. package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
  183. package/dist/astro/routes/api/menus/_name_/translations.mjs +11 -9
  184. package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
  185. package/dist/astro/routes/api/menus/_name_.mjs +11 -9
  186. package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
  187. package/dist/astro/routes/api/menus/index.mjs +11 -9
  188. package/dist/astro/routes/api/menus/index.mjs.map +1 -1
  189. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  190. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
  191. package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
  192. package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
  193. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  194. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
  195. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
  196. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  197. package/dist/astro/routes/api/openapi.json.mjs +5 -5
  198. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +5 -5
  199. package/dist/astro/routes/api/redirects/404s/index.mjs +11 -11
  200. package/dist/astro/routes/api/redirects/404s/summary.mjs +11 -11
  201. package/dist/astro/routes/api/redirects/_id_.mjs +12 -12
  202. package/dist/astro/routes/api/redirects/index.mjs +12 -12
  203. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  204. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +4 -4
  205. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +39 -38
  206. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  207. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +39 -38
  208. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  209. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +39 -38
  210. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  211. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +39 -38
  212. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  213. package/dist/astro/routes/api/schema/collections/index.mjs +39 -38
  214. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  215. package/dist/astro/routes/api/schema/index.mjs +7 -7
  216. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +39 -38
  217. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  218. package/dist/astro/routes/api/schema/orphans/index.mjs +39 -38
  219. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  220. package/dist/astro/routes/api/search/enable.mjs +11 -11
  221. package/dist/astro/routes/api/search/index.mjs +10 -10
  222. package/dist/astro/routes/api/search/rebuild.mjs +11 -11
  223. package/dist/astro/routes/api/search/stats.mjs +7 -7
  224. package/dist/astro/routes/api/search/suggest.mjs +10 -10
  225. package/dist/astro/routes/api/sections/_slug_.mjs +10 -10
  226. package/dist/astro/routes/api/sections/index.mjs +10 -10
  227. package/dist/astro/routes/api/settings/email.mjs +6 -6
  228. package/dist/astro/routes/api/settings.mjs +16 -15
  229. package/dist/astro/routes/api/settings.mjs.map +1 -1
  230. package/dist/astro/routes/api/setup/admin-verify.mjs +13 -13
  231. package/dist/astro/routes/api/setup/admin.mjs +12 -12
  232. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
  233. package/dist/astro/routes/api/setup/dev-bypass.mjs +29 -27
  234. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  235. package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
  236. package/dist/astro/routes/api/setup/index.mjs +29 -28
  237. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  238. package/dist/astro/routes/api/setup/status.mjs +5 -5
  239. package/dist/astro/routes/api/snapshot.d.mts.map +1 -1
  240. package/dist/astro/routes/api/snapshot.mjs +10 -9
  241. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  242. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +16 -14
  243. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  244. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +16 -14
  245. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  246. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +16 -14
  247. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  248. package/dist/astro/routes/api/taxonomies/index.mjs +16 -14
  249. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  250. package/dist/astro/routes/api/themes/preview.mjs +8 -8
  251. package/dist/astro/routes/api/typegen.mjs +6 -6
  252. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  253. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  254. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  255. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +8 -8
  256. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +11 -11
  257. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +11 -11
  258. package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -7
  259. package/dist/astro/routes/api/widget-areas/index.mjs +11 -11
  260. package/dist/astro/routes/api/widget-components.mjs +4 -4
  261. package/dist/astro/routes/robots.txt.mjs +10 -9
  262. package/dist/astro/routes/robots.txt.mjs.map +1 -1
  263. package/dist/astro/routes/sitemap-_collection_.xml.mjs +13 -12
  264. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  265. package/dist/astro/routes/sitemap.xml.mjs +11 -10
  266. package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
  267. package/dist/astro/types.d.mts +16 -12
  268. package/dist/astro/types.d.mts.map +1 -1
  269. package/dist/auth/providers/github.d.mts +1 -1
  270. package/dist/auth/providers/google.d.mts +1 -1
  271. package/dist/{authorize-D5gfBVU5.mjs → authorize-C0EYoUeV.mjs} +2 -2
  272. package/dist/{authorize-D5gfBVU5.mjs.map → authorize-C0EYoUeV.mjs.map} +1 -1
  273. package/dist/{base64-CqR-7kqF.mjs → base64-CmWvODNW.mjs} +1 -1
  274. package/dist/{base64-CqR-7kqF.mjs.map → base64-CmWvODNW.mjs.map} +1 -1
  275. package/dist/{byline-V_Qp1Ziw.mjs → byline-CC0WS4Gu.mjs} +17 -8
  276. package/dist/byline-CC0WS4Gu.mjs.map +1 -0
  277. package/dist/{byline-fields-B0NO1yUB.mjs → byline-fields-53i9Et0x.mjs} +3 -3
  278. package/dist/{byline-fields-B0NO1yUB.mjs.map → byline-fields-53i9Et0x.mjs.map} +1 -1
  279. package/dist/{byline-fields-nBVqK_Ff.mjs → byline-fields-DNp0HNKc.mjs} +2 -2
  280. package/dist/{byline-fields-nBVqK_Ff.mjs.map → byline-fields-DNp0HNKc.mjs.map} +1 -1
  281. package/dist/{byline-fields-CQJRIQkn.d.mts → byline-fields-jy07PZJM.d.mts} +36 -31
  282. package/dist/byline-fields-jy07PZJM.d.mts.map +1 -0
  283. package/dist/{byline-registry-DedidtqC.mjs → byline-registry-BOjqDOim.mjs} +3 -3
  284. package/dist/{byline-registry-DedidtqC.mjs.map → byline-registry-BOjqDOim.mjs.map} +1 -1
  285. package/dist/{bylines-DfGDnred.mjs → bylines-CCO1CYnH.mjs} +8 -8
  286. package/dist/{bylines-DfGDnred.mjs.map → bylines-CCO1CYnH.mjs.map} +1 -1
  287. package/dist/{bylines-B2NWnIwS.mjs → bylines-DGekMGGm.mjs} +10 -4
  288. package/dist/{bylines-B2NWnIwS.mjs.map → bylines-DGekMGGm.mjs.map} +1 -1
  289. package/dist/{cache-DTTHWD8n.mjs → cache-pXTpun6s.mjs} +3 -3
  290. package/dist/{cache-DTTHWD8n.mjs.map → cache-pXTpun6s.mjs.map} +1 -1
  291. package/dist/{challenge-store-woE0bbCf.mjs → challenge-store-C6E_kWTs.mjs} +1 -1
  292. package/dist/{challenge-store-woE0bbCf.mjs.map → challenge-store-C6E_kWTs.mjs.map} +1 -1
  293. package/dist/{chunks-BerYVuve.mjs → chunks-SyjZaYwV.mjs} +2 -2
  294. package/dist/{chunks-BerYVuve.mjs.map → chunks-SyjZaYwV.mjs.map} +1 -1
  295. package/dist/cli/index.mjs +27 -26
  296. package/dist/cli/index.mjs.map +1 -1
  297. package/dist/client/cf-access.d.mts +1 -1
  298. package/dist/client/index.d.mts +1 -1
  299. package/dist/client/index.mjs +2 -1
  300. package/dist/client/index.mjs.map +1 -1
  301. package/dist/{comment-sqQxNpN3.mjs → comment-80UyJJUR.mjs} +11 -3
  302. package/dist/comment-80UyJJUR.mjs.map +1 -0
  303. package/dist/comment-reaction-B6AdcpXw.mjs +85 -0
  304. package/dist/comment-reaction-B6AdcpXw.mjs.map +1 -0
  305. package/dist/{comments-D2hNuxNa.mjs → comments-CtPkT2tp.mjs} +3 -3
  306. package/dist/{comments-D2hNuxNa.mjs.map → comments-CtPkT2tp.mjs.map} +1 -1
  307. package/dist/{components-DYKp2gmo.mjs → components-D6ZnrzbB.mjs} +1 -1
  308. package/dist/{components-DYKp2gmo.mjs.map → components-D6ZnrzbB.mjs.map} +1 -1
  309. package/dist/{content-BIlVx-RX.mjs → content-2PTDNnoh.mjs} +22 -7
  310. package/dist/content-2PTDNnoh.mjs.map +1 -0
  311. package/dist/{context-Cm4pt1Ws.mjs → context-f1__jpzF.mjs} +11 -11
  312. package/dist/{context-Cm4pt1Ws.mjs.map → context-f1__jpzF.mjs.map} +1 -1
  313. package/dist/{cron-DdEVrQ2Y.mjs → cron-CQPxBjYs.mjs} +1 -1
  314. package/dist/{cron-DdEVrQ2Y.mjs.map → cron-CQPxBjYs.mjs.map} +1 -1
  315. package/dist/{dashboard-C-UYpps0.mjs → dashboard-BOESNcwE.mjs} +4 -4
  316. package/dist/{dashboard-C-UYpps0.mjs.map → dashboard-BOESNcwE.mjs.map} +1 -1
  317. package/dist/database/instrumentation.d.mts +19 -0
  318. package/dist/database/instrumentation.d.mts.map +1 -1
  319. package/dist/database/instrumentation.mjs +8 -1
  320. package/dist/database/instrumentation.mjs.map +1 -1
  321. package/dist/db/index.d.mts +3 -3
  322. package/dist/db/index.mjs +1 -1
  323. package/dist/db/libsql.d.mts +1 -1
  324. package/dist/db/postgres.d.mts +1 -1
  325. package/dist/db/sqlite.d.mts +1 -1
  326. package/dist/{db-errors-BluWkwGI.mjs → db-errors-CrC5w3Jz.mjs} +1 -1
  327. package/dist/{db-errors-BluWkwGI.mjs.map → db-errors-CrC5w3Jz.mjs.map} +1 -1
  328. package/dist/{default-NHGuJzQ3.mjs → default-CpBEPn6a.mjs} +1 -1
  329. package/dist/{default-NHGuJzQ3.mjs.map → default-CpBEPn6a.mjs.map} +1 -1
  330. package/dist/{device-flow-BQApWgnW.mjs → device-flow-Bn-qiDrw.mjs} +5 -5
  331. package/dist/{device-flow-BQApWgnW.mjs.map → device-flow-Bn-qiDrw.mjs.map} +1 -1
  332. package/dist/{email-console-BbU3RbWv.mjs → email-console-B9VS6eN4.mjs} +1 -1
  333. package/dist/{email-console-BbU3RbWv.mjs.map → email-console-B9VS6eN4.mjs.map} +1 -1
  334. package/dist/{error-CNn_w7jf.mjs → error-BQ1pxs0L.mjs} +2 -2
  335. package/dist/{error-CNn_w7jf.mjs.map → error-BQ1pxs0L.mjs.map} +1 -1
  336. package/dist/{escape-DPgcxcpL.mjs → escape-BtbJWyaW.mjs} +1 -1
  337. package/dist/{escape-DPgcxcpL.mjs.map → escape-BtbJWyaW.mjs.map} +1 -1
  338. package/dist/{fts-manager-Cx5z8jdA.mjs → fts-manager-DtiWqwNJ.mjs} +2 -2
  339. package/dist/{fts-manager-Cx5z8jdA.mjs.map → fts-manager-DtiWqwNJ.mjs.map} +1 -1
  340. package/dist/{hash-DlvIFn0b.mjs → hash-BowcuPwv.mjs} +1 -1
  341. package/dist/{hash-DlvIFn0b.mjs.map → hash-BowcuPwv.mjs.map} +1 -1
  342. package/dist/{import-KyxT1Mbs.mjs → import-DqSGOlmR.mjs} +4 -4
  343. package/dist/{import-KyxT1Mbs.mjs.map → import-DqSGOlmR.mjs.map} +1 -1
  344. package/dist/{index-D2VAiumu.d.mts → index-C2dLNT6S.d.mts} +172 -17
  345. package/dist/index-C2dLNT6S.d.mts.map +1 -0
  346. package/dist/{index-uT2yR66F.d.mts → index-ZDEwR7qW.d.mts} +3 -3
  347. package/dist/{index-uT2yR66F.d.mts.map → index-ZDEwR7qW.d.mts.map} +1 -1
  348. package/dist/index.d.mts +18 -17
  349. package/dist/index.mjs +63 -61
  350. package/dist/{init-lock-DlBHjf9-.mjs → init-lock-6b309ZrF.mjs} +2 -29
  351. package/dist/init-lock-6b309ZrF.mjs.map +1 -0
  352. package/dist/{load-Dq91b_DK.mjs → load-Dtoo7KcJ.mjs} +2 -2
  353. package/dist/{load-Dq91b_DK.mjs.map → load-Dtoo7KcJ.mjs.map} +1 -1
  354. package/dist/{loader-BqWjcH3h.mjs → loader-C8Z48Uof.mjs} +4 -4
  355. package/dist/{loader-BqWjcH3h.mjs.map → loader-C8Z48Uof.mjs.map} +1 -1
  356. package/dist/{manifest-schema-DFPeqMAn.mjs → manifest-schema-DDSbwkAL.mjs} +1 -1
  357. package/dist/{manifest-schema-DFPeqMAn.mjs.map → manifest-schema-DDSbwkAL.mjs.map} +1 -1
  358. package/dist/media/image-endpoint.d.mts +74 -0
  359. package/dist/media/image-endpoint.d.mts.map +1 -0
  360. package/dist/media/image-endpoint.mjs +162 -0
  361. package/dist/media/image-endpoint.mjs.map +1 -0
  362. package/dist/media/index.d.mts +1 -1
  363. package/dist/media/index.mjs +2 -2
  364. package/dist/media/local-runtime.d.mts +11 -11
  365. package/dist/media/local-runtime.mjs +9 -8
  366. package/dist/media/local-runtime.mjs.map +1 -1
  367. package/dist/{media-JOf3pNkw.mjs → media-Bw0sA6rb.mjs} +2 -2
  368. package/dist/{media-JOf3pNkw.mjs.map → media-Bw0sA6rb.mjs.map} +1 -1
  369. package/dist/{media-allowlist-_A0SuDn4.mjs → media-allowlist-DunzrKFM.mjs} +2 -2
  370. package/dist/{media-allowlist-_A0SuDn4.mjs.map → media-allowlist-DunzrKFM.mjs.map} +1 -1
  371. package/dist/{media-url-CqLd69IO.mjs → media-url-S22B6aPr.mjs} +1 -1
  372. package/dist/{media-url-CqLd69IO.mjs.map → media-url-S22B6aPr.mjs.map} +1 -1
  373. package/dist/{menus-DX4_E01q.mjs → menus-CYs0WZoL.mjs} +20 -6
  374. package/dist/menus-CYs0WZoL.mjs.map +1 -0
  375. package/dist/{menus-Ryk9L7fT.mjs → menus-DOs1MQJg.mjs} +120 -20
  376. package/dist/menus-DOs1MQJg.mjs.map +1 -0
  377. package/dist/{mime-YbtlEtvS.mjs → mime-DYpsOAny.mjs} +1 -1
  378. package/dist/{mime-YbtlEtvS.mjs.map → mime-DYpsOAny.mjs.map} +1 -1
  379. package/dist/{mode-CGXzIbD8.mjs → mode-CFh8Dw8G.mjs} +1 -1
  380. package/dist/{mode-CGXzIbD8.mjs.map → mode-CFh8Dw8G.mjs.map} +1 -1
  381. package/dist/{normalize-DKsg36ty.mjs → normalize-Uam4_Vkr.mjs} +1 -1
  382. package/dist/{normalize-DKsg36ty.mjs.map → normalize-Uam4_Vkr.mjs.map} +1 -1
  383. package/dist/{oauth-authorization-C2kVyjXI.mjs → oauth-authorization-BN-t83Uy.mjs} +5 -5
  384. package/dist/{oauth-authorization-C2kVyjXI.mjs.map → oauth-authorization-BN-t83Uy.mjs.map} +1 -1
  385. package/dist/{oauth-clients-BC873NCV.mjs → oauth-clients-R6I_V0qz.mjs} +1 -1
  386. package/dist/{oauth-clients-BC873NCV.mjs.map → oauth-clients-R6I_V0qz.mjs.map} +1 -1
  387. package/dist/{oauth-state-store-Cd--TUaq.mjs → oauth-state-store-Csoc6kkR.mjs} +1 -1
  388. package/dist/{oauth-state-store-Cd--TUaq.mjs.map → oauth-state-store-Csoc6kkR.mjs.map} +1 -1
  389. package/dist/{oauth-user-lookup-e4wOvDud.mjs → oauth-user-lookup-d7VYjTpx.mjs} +1 -1
  390. package/dist/{oauth-user-lookup-e4wOvDud.mjs.map → oauth-user-lookup-d7VYjTpx.mjs.map} +1 -1
  391. package/dist/object-cache/memory.d.mts +15 -0
  392. package/dist/object-cache/memory.d.mts.map +1 -0
  393. package/dist/object-cache/memory.mjs +56 -0
  394. package/dist/object-cache/memory.mjs.map +1 -0
  395. package/dist/object-cache-SEb2IM4Z.mjs +373 -0
  396. package/dist/object-cache-SEb2IM4Z.mjs.map +1 -0
  397. package/dist/{options-9kLgkE8m.d.mts → options-DFFpvNJU.d.mts} +3 -3
  398. package/dist/{options-9kLgkE8m.d.mts.map → options-DFFpvNJU.d.mts.map} +1 -1
  399. package/dist/{options-BPCVnesz.mjs → options-DTTML-Tx.mjs} +1 -1
  400. package/dist/{options-BPCVnesz.mjs.map → options-DTTML-Tx.mjs.map} +1 -1
  401. package/dist/page/index.d.mts +2 -2
  402. package/dist/{parse-DzSrk1t8.mjs → parse-qrHlnzTy.mjs} +2 -2
  403. package/dist/{parse-DzSrk1t8.mjs.map → parse-qrHlnzTy.mjs.map} +1 -1
  404. package/dist/{passkey-config-BpjbE_Uv.mjs → passkey-config-BJTbcnI5.mjs} +1 -1
  405. package/dist/{passkey-config-BpjbE_Uv.mjs.map → passkey-config-BJTbcnI5.mjs.map} +1 -1
  406. package/dist/{patterns-p-RBdTbM.mjs → patterns-BKmjvM7K.mjs} +1 -1
  407. package/dist/{patterns-p-RBdTbM.mjs.map → patterns-BKmjvM7K.mjs.map} +1 -1
  408. package/dist/{placeholder-2xumZh4g.mjs → placeholder-CIDCpyEY.mjs} +1 -1
  409. package/dist/{placeholder-2xumZh4g.mjs.map → placeholder-CIDCpyEY.mjs.map} +1 -1
  410. package/dist/{placeholder-BevVKfay.d.mts → placeholder-CirPauNG.d.mts} +1 -1
  411. package/dist/{placeholder-BevVKfay.d.mts.map → placeholder-CirPauNG.d.mts.map} +1 -1
  412. package/dist/plugin-types.d.mts +1 -1
  413. package/dist/plugin-utils.d.mts +9 -9
  414. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  415. package/dist/plugins/adapt-sandbox-entry.mjs +4 -2
  416. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  417. package/dist/{transport-1cIrOb1Y.mjs → portable-text-BIFhrU6T.mjs} +2 -135
  418. package/dist/portable-text-BIFhrU6T.mjs.map +1 -0
  419. package/dist/{preview-Dqv2hwXr.mjs → preview-IDye9SPQ.mjs} +2 -2
  420. package/dist/{preview-Dqv2hwXr.mjs.map → preview-IDye9SPQ.mjs.map} +1 -1
  421. package/dist/{public-url-D_zARuvZ.mjs → public-url-8lFyQ8ZF.mjs} +1 -1
  422. package/dist/{public-url-D_zARuvZ.mjs.map → public-url-8lFyQ8ZF.mjs.map} +1 -1
  423. package/dist/{query-Crm038Mc.mjs → query-B1RVFUNM.mjs} +159 -31
  424. package/dist/query-B1RVFUNM.mjs.map +1 -0
  425. package/dist/{rate-limit-hRTBqmw1.mjs → rate-limit-DfNAqIWW.mjs} +2 -2
  426. package/dist/{rate-limit-hRTBqmw1.mjs.map → rate-limit-DfNAqIWW.mjs.map} +1 -1
  427. package/dist/{redirect-C-OOkyku.mjs → redirect-B4wuX2A5.mjs} +1 -1
  428. package/dist/{redirect-C-OOkyku.mjs.map → redirect-B4wuX2A5.mjs.map} +1 -1
  429. package/dist/{redirect-CRWIt8Zj.mjs → redirect-Bifv_yHv.mjs} +3 -3
  430. package/dist/{redirect-CRWIt8Zj.mjs.map → redirect-Bifv_yHv.mjs.map} +1 -1
  431. package/dist/{redirects-CP3TnTLO.mjs → redirects-CT_vb3NV.mjs} +6 -6
  432. package/dist/{redirects-CP3TnTLO.mjs.map → redirects-CT_vb3NV.mjs.map} +1 -1
  433. package/dist/{redirects-6Zg2SoYo.mjs → redirects-DUvXgzCX.mjs} +8 -3
  434. package/dist/redirects-DUvXgzCX.mjs.map +1 -0
  435. package/dist/{registry-diMzD1Wf.mjs → registry-CjK96fHD.mjs} +6 -6
  436. package/dist/{registry-diMzD1Wf.mjs.map → registry-CjK96fHD.mjs.map} +1 -1
  437. package/dist/{request-cache-UwmBAiUK.mjs → request-cache-KCNHp_RJ.mjs} +1 -1
  438. package/dist/{request-cache-UwmBAiUK.mjs.map → request-cache-KCNHp_RJ.mjs.map} +1 -1
  439. package/dist/{request-meta-DPechd0W.mjs → request-meta-ei3ATilC.mjs} +2 -2
  440. package/dist/{request-meta-DPechd0W.mjs.map → request-meta-ei3ATilC.mjs.map} +1 -1
  441. package/dist/{resolve-B3NUUtVY.mjs → resolve-CpbBglV0.mjs} +1 -1
  442. package/dist/{resolve-B3NUUtVY.mjs.map → resolve-CpbBglV0.mjs.map} +1 -1
  443. package/dist/{runner--4wMWwKM.mjs → runner-DYYnW530.mjs} +201 -170
  444. package/dist/runner-DYYnW530.mjs.map +1 -0
  445. package/dist/{runner-C8vcbvCe.d.mts → runner-jdXtFEd3.d.mts} +2 -2
  446. package/dist/{runner-C8vcbvCe.d.mts.map → runner-jdXtFEd3.d.mts.map} +1 -1
  447. package/dist/runtime.d.mts +10 -10
  448. package/dist/runtime.mjs +3 -3
  449. package/dist/{schema-BDOkd3OU.mjs → schema-5z2Jfnbm.mjs} +13 -8
  450. package/dist/schema-5z2Jfnbm.mjs.map +1 -0
  451. package/dist/{search-Bs_J_EW-.mjs → search-D9FkoM-k.mjs} +4 -4
  452. package/dist/{search-Bs_J_EW-.mjs.map → search-D9FkoM-k.mjs.map} +1 -1
  453. package/dist/{secrets-C8xmE6mR.mjs → secrets-BUE5UQys.mjs} +5 -5
  454. package/dist/{secrets-C8xmE6mR.mjs.map → secrets-BUE5UQys.mjs.map} +1 -1
  455. package/dist/{sections-P0zuBlyz.mjs → sections-DWYZo6HK.mjs} +3 -3
  456. package/dist/{sections-P0zuBlyz.mjs.map → sections-DWYZo6HK.mjs.map} +1 -1
  457. package/dist/seed/index.d.mts +2 -2
  458. package/dist/seed/index.mjs +22 -21
  459. package/dist/seo/index.d.mts +1 -1
  460. package/dist/seo/index.mjs +1 -1
  461. package/dist/{seo-DpNgGQjF.mjs → seo-Cu47j3mJ.mjs} +5 -2
  462. package/dist/seo-Cu47j3mJ.mjs.map +1 -0
  463. package/dist/{seo-CLhm-Fmb.mjs → seo-DRnqnstF.mjs} +1 -1
  464. package/dist/{seo-CLhm-Fmb.mjs.map → seo-DRnqnstF.mjs.map} +1 -1
  465. package/dist/{service-CDQQnT8W.mjs → service-DTmtqCnw.mjs} +3 -3
  466. package/dist/{service-CDQQnT8W.mjs.map → service-DTmtqCnw.mjs.map} +1 -1
  467. package/dist/session-user-DmtPMNa1.mjs +51 -0
  468. package/dist/session-user-DmtPMNa1.mjs.map +1 -0
  469. package/dist/{settings-sO0Fif4p.mjs → settings-DUrVDN0c.mjs} +3 -3
  470. package/dist/{settings-sO0Fif4p.mjs.map → settings-DUrVDN0c.mjs.map} +1 -1
  471. package/dist/{settings-BjBsmVAo.mjs → settings-yaxu9mU-.mjs} +18 -10
  472. package/dist/settings-yaxu9mU-.mjs.map +1 -0
  473. package/dist/{setup-complete-CMMr-oZU.mjs → setup-complete-BWFHzgvZ.mjs} +2 -2
  474. package/dist/{setup-complete-CMMr-oZU.mjs.map → setup-complete-BWFHzgvZ.mjs.map} +1 -1
  475. package/dist/{setup-nonce-169xl4fV.mjs → setup-nonce-DFWG-J5c.mjs} +1 -1
  476. package/dist/{setup-nonce-169xl4fV.mjs.map → setup-nonce-DFWG-J5c.mjs.map} +1 -1
  477. package/dist/{single-flight-cache-C0UV1Npg.mjs → single-flight-cache-B5p5cNOL.mjs} +2 -2
  478. package/dist/{single-flight-cache-C0UV1Npg.mjs.map → single-flight-cache-B5p5cNOL.mjs.map} +1 -1
  479. package/dist/{site-url-vtsuOvSD.mjs → site-url-BOTPgmeM.mjs} +2 -2
  480. package/dist/{site-url-vtsuOvSD.mjs.map → site-url-BOTPgmeM.mjs.map} +1 -1
  481. package/dist/{slugify-Cjh1ssOZ.mjs → slugify-Cce3dTdg.mjs} +1 -1
  482. package/dist/{slugify-Cjh1ssOZ.mjs.map → slugify-Cce3dTdg.mjs.map} +1 -1
  483. package/dist/{ssrf-XO05Voq6.mjs → ssrf-B0VeRLrp.mjs} +1 -1
  484. package/dist/{ssrf-XO05Voq6.mjs.map → ssrf-B0VeRLrp.mjs.map} +1 -1
  485. package/dist/{status-2gZklYuj.mjs → status-CB2basWJ.mjs} +1 -1
  486. package/dist/{status-2gZklYuj.mjs.map → status-CB2basWJ.mjs.map} +1 -1
  487. package/dist/storage/local.d.mts +1 -1
  488. package/dist/storage/local.mjs +1 -1
  489. package/dist/storage/s3.d.mts +1 -1
  490. package/dist/storage/s3.mjs +1 -1
  491. package/dist/{taxonomies-BBxYA38v.mjs → taxonomies-Be9B1jEj.mjs} +156 -122
  492. package/dist/taxonomies-Be9B1jEj.mjs.map +1 -0
  493. package/dist/{taxonomies-DuESHWKI.mjs → taxonomies-CJmkEpdS.mjs} +7 -7
  494. package/dist/{taxonomies-DuESHWKI.mjs.map → taxonomies-CJmkEpdS.mjs.map} +1 -1
  495. package/dist/{taxonomy-CdllE4oq.mjs → taxonomy-B2HQuVf5.mjs} +19 -6
  496. package/dist/taxonomy-B2HQuVf5.mjs.map +1 -0
  497. package/dist/{tokens-DMkVjxrx.mjs → tokens-BvrJvIB6.mjs} +2 -2
  498. package/dist/{tokens-DMkVjxrx.mjs.map → tokens-BvrJvIB6.mjs.map} +1 -1
  499. package/dist/{transaction-x2tJQ-A1.mjs → transaction-qfqpPVpu.mjs} +1 -1
  500. package/dist/{transaction-x2tJQ-A1.mjs.map → transaction-qfqpPVpu.mjs.map} +1 -1
  501. package/dist/transport-B4rXnSTf.mjs +135 -0
  502. package/dist/transport-B4rXnSTf.mjs.map +1 -0
  503. package/dist/{transport-jdvsZEIt.d.mts → transport-k7YjfmEn.d.mts} +1 -1
  504. package/dist/{transport-jdvsZEIt.d.mts.map → transport-k7YjfmEn.d.mts.map} +1 -1
  505. package/dist/{trusted-proxy-CHp41Fjj.mjs → trusted-proxy-DY1_UqHr.mjs} +1 -1
  506. package/dist/{trusted-proxy-CHp41Fjj.mjs.map → trusted-proxy-DY1_UqHr.mjs.map} +1 -1
  507. package/dist/{types-DO7whVYU.d.mts → types-CIKX2HO5.d.mts} +2 -2
  508. package/dist/{types-DO7whVYU.d.mts.map → types-CIKX2HO5.d.mts.map} +1 -1
  509. package/dist/{types-u_XxjbS8.d.mts → types-CKNXt63n.d.mts} +1 -1
  510. package/dist/{types-u_XxjbS8.d.mts.map → types-CKNXt63n.d.mts.map} +1 -1
  511. package/dist/{types-BTnnBYVX.d.mts → types-CWGYDYqF.d.mts} +2 -2
  512. package/dist/{types-BTnnBYVX.d.mts.map → types-CWGYDYqF.d.mts.map} +1 -1
  513. package/dist/{types-CkEuk-Zr.d.mts → types-CgvhU-hF.d.mts} +1 -1
  514. package/dist/{types-CkEuk-Zr.d.mts.map → types-CgvhU-hF.d.mts.map} +1 -1
  515. package/dist/{types-BFgYtuKd.d.mts → types-CmivgZbp.d.mts} +1 -1
  516. package/dist/{types-BFgYtuKd.d.mts.map → types-CmivgZbp.d.mts.map} +1 -1
  517. package/dist/{types-Del0VMij.d.mts → types-Czg1S3gB.d.mts} +9 -1
  518. package/dist/{types-Del0VMij.d.mts.map → types-Czg1S3gB.d.mts.map} +1 -1
  519. package/dist/types-DCNNfeCv.d.mts +124 -0
  520. package/dist/types-DCNNfeCv.d.mts.map +1 -0
  521. package/dist/{types-Bzfk2yC8.d.mts → types-DPCpkzvS.d.mts} +1 -1
  522. package/dist/{types-Bzfk2yC8.d.mts.map → types-DPCpkzvS.d.mts.map} +1 -1
  523. package/dist/{types-DdkL6fyv.d.mts → types-DXLVzV2w.d.mts} +1 -1
  524. package/dist/{types-DdkL6fyv.d.mts.map → types-DXLVzV2w.d.mts.map} +1 -1
  525. package/dist/{types-BXSUSAjt.mjs → types-DXOIbece.mjs} +3 -3
  526. package/dist/{types-BXSUSAjt.mjs.map → types-DXOIbece.mjs.map} +1 -1
  527. package/dist/{types-DejCHqWT.mjs → types-DYF2_Vf4.mjs} +1 -1
  528. package/dist/{types-DejCHqWT.mjs.map → types-DYF2_Vf4.mjs.map} +1 -1
  529. package/dist/{types-BIduXPJk.mjs → types-tM44hEcf.mjs} +1 -1
  530. package/dist/{types-BIduXPJk.mjs.map → types-tM44hEcf.mjs.map} +1 -1
  531. package/dist/{user-C0um7wrg.mjs → user-Db-Rti_z.mjs} +3 -3
  532. package/dist/{user-C0um7wrg.mjs.map → user-Db-Rti_z.mjs.map} +1 -1
  533. package/dist/{utils-C4M981Br.mjs → utils-LbHcSRTj.mjs} +2 -2
  534. package/dist/{utils-C4M981Br.mjs.map → utils-LbHcSRTj.mjs.map} +1 -1
  535. package/dist/{validate-DGhQPXzI.mjs → validate-Bwl64sxv.mjs} +3 -3
  536. package/dist/{validate-DGhQPXzI.mjs.map → validate-Bwl64sxv.mjs.map} +1 -1
  537. package/dist/{validate-cJOiOvT2.d.mts → validate-CE2M0nvx.d.mts} +5 -5
  538. package/dist/{validate-cJOiOvT2.d.mts.map → validate-CE2M0nvx.d.mts.map} +1 -1
  539. package/dist/{validation-DVHjPM1M.mjs → validation-C_yOvFaO.mjs} +6 -6
  540. package/dist/{validation-DVHjPM1M.mjs.map → validation-C_yOvFaO.mjs.map} +1 -1
  541. package/dist/version-RnYXYjzD.mjs +7 -0
  542. package/dist/{version-BOjj_cfz.mjs.map → version-RnYXYjzD.mjs.map} +1 -1
  543. package/dist/{widgets-Ci6hLwfO.mjs → widgets-8GONuRHo.mjs} +4 -4
  544. package/dist/{widgets-Ci6hLwfO.mjs.map → widgets-8GONuRHo.mjs.map} +1 -1
  545. package/dist/{zod-generator-CarzgPAu.mjs → zod-generator-D481JjzD.mjs} +3 -3
  546. package/dist/{zod-generator-CarzgPAu.mjs.map → zod-generator-D481JjzD.mjs.map} +1 -1
  547. package/package.json +18 -6
  548. package/src/api/handlers/api-tokens.ts +19 -0
  549. package/src/api/handlers/comment-reactions.ts +165 -0
  550. package/src/api/handlers/schema.ts +8 -0
  551. package/src/api/schemas/comments.ts +10 -0
  552. package/src/astro/image-endpoint.ts +84 -0
  553. package/src/astro/index.ts +6 -0
  554. package/src/astro/integration/index.ts +83 -22
  555. package/src/astro/integration/routes.ts +5 -0
  556. package/src/astro/integration/runtime.ts +65 -1
  557. package/src/astro/integration/virtual-modules.ts +32 -0
  558. package/src/astro/integration/vite-config.ts +16 -0
  559. package/src/astro/middleware/auth.ts +4 -3
  560. package/src/astro/middleware/stream-end-metrics.ts +11 -1
  561. package/src/astro/middleware.ts +41 -3
  562. package/src/astro/object-cache/adapters.ts +50 -0
  563. package/src/astro/prefetch.ts +77 -0
  564. package/src/astro/routes/api/comments/[collection]/[contentId]/reactions.ts +97 -0
  565. package/src/astro/routes/api/setup/dev-bypass.ts +5 -1
  566. package/src/astro/routes/api/snapshot.ts +3 -1
  567. package/src/astro/session-user.ts +57 -0
  568. package/src/astro/types.ts +1 -0
  569. package/src/comments/query.ts +78 -7
  570. package/src/comments/ranking.ts +58 -0
  571. package/src/components/Comments.astro +136 -1
  572. package/src/database/instrumentation.ts +21 -1
  573. package/src/database/migrations/044_comment_reactions.ts +56 -0
  574. package/src/database/migrations/runner.ts +2 -0
  575. package/src/database/repositories/byline.ts +13 -0
  576. package/src/database/repositories/comment-reaction.ts +132 -0
  577. package/src/database/repositories/comment.ts +10 -0
  578. package/src/database/repositories/content.ts +25 -3
  579. package/src/database/repositories/menu.ts +13 -1
  580. package/src/database/repositories/seo.ts +3 -0
  581. package/src/database/repositories/taxonomy.ts +13 -1
  582. package/src/database/types.ts +9 -0
  583. package/src/emdash-runtime.ts +18 -4
  584. package/src/index.ts +22 -0
  585. package/src/mcp/server.ts +307 -20
  586. package/src/media/image-endpoint.ts +167 -0
  587. package/src/menus/index.ts +11 -4
  588. package/src/object-cache/codec.ts +73 -0
  589. package/src/object-cache/index.ts +495 -0
  590. package/src/object-cache/memory.ts +91 -0
  591. package/src/object-cache/types.ts +124 -0
  592. package/src/plugins/adapt-sandbox-entry.ts +11 -1
  593. package/src/query.ts +196 -17
  594. package/src/schema/query.ts +11 -4
  595. package/src/settings/index.ts +18 -5
  596. package/src/taxonomies/index.ts +237 -165
  597. package/src/virtual-modules.d.ts +11 -0
  598. package/dist/api-DxjIV2o8.mjs.map +0 -1
  599. package/dist/api-tokens-BFFkB0jB.mjs.map +0 -1
  600. package/dist/byline-V_Qp1Ziw.mjs.map +0 -1
  601. package/dist/byline-fields-CQJRIQkn.d.mts.map +0 -1
  602. package/dist/comment-sqQxNpN3.mjs.map +0 -1
  603. package/dist/content-BIlVx-RX.mjs.map +0 -1
  604. package/dist/index-D2VAiumu.d.mts.map +0 -1
  605. package/dist/init-lock-DlBHjf9-.mjs.map +0 -1
  606. package/dist/menus-DX4_E01q.mjs.map +0 -1
  607. package/dist/menus-Ryk9L7fT.mjs.map +0 -1
  608. package/dist/query-Crm038Mc.mjs.map +0 -1
  609. package/dist/redirects-6Zg2SoYo.mjs.map +0 -1
  610. package/dist/runner--4wMWwKM.mjs.map +0 -1
  611. package/dist/schema-BDOkd3OU.mjs.map +0 -1
  612. package/dist/seo-DpNgGQjF.mjs.map +0 -1
  613. package/dist/settings-BjBsmVAo.mjs.map +0 -1
  614. package/dist/taxonomies-BBxYA38v.mjs.map +0 -1
  615. package/dist/taxonomy-CdllE4oq.mjs.map +0 -1
  616. package/dist/transport-1cIrOb1Y.mjs.map +0 -1
  617. package/dist/version-BOjj_cfz.mjs +0 -7
  618. /package/dist/{api-tokens-C7ywRx7l.mjs → api-tokens-BVH-H8Z9.mjs} +0 -0
  619. /package/dist/{ssrf-CRZGzjdL.mjs → ssrf-Cz1e2QPn.mjs} +0 -0
  620. /package/dist/{types-BoRm8-pp.mjs → types-Bfr2Pj6z.mjs} +0 -0
package/src/mcp/server.ts CHANGED
@@ -14,10 +14,17 @@ import { canActOnOwn, hasPermission, Role } from "@emdash-cms/auth";
14
14
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
15
15
  import { z } from "zod";
16
16
 
17
- import { contentBylineInputSchema, contentSeoInput } from "#api/schemas.js";
17
+ import {
18
+ bylineCreateBody,
19
+ bylineUpdateBody,
20
+ contentBylineInputSchema,
21
+ contentSeoInput,
22
+ } from "#api/schemas.js";
18
23
 
19
24
  import type { EmDashHandlers } from "../astro/types.js";
20
25
  import { hasScope } from "../auth/api-tokens.js";
26
+ import { convertDataForRead, convertDataForWrite } from "../client/portable-text.js";
27
+ import type { FieldSchema } from "../client/portable-text.js";
21
28
 
22
29
  const COLLECTION_SLUG_PATTERN = /^[a-z][a-z0-9_]*$/;
23
30
  /** http(s) scheme matcher used by `settings_update` URL validation. */
@@ -268,6 +275,64 @@ function getEmDash(extra: { authInfo?: { extra?: Record<string, unknown> } }): E
268
275
  return getExtra(extra).emdash;
269
276
  }
270
277
 
278
+ async function getCollectionFields(
279
+ ec: EmDashHandlers,
280
+ collection: string,
281
+ ): Promise<FieldSchema[] | null> {
282
+ try {
283
+ const { SchemaRegistry } = await import("../schema/index.js");
284
+ const col = await new SchemaRegistry(ec.db).getCollectionWithFields(collection);
285
+ return col ? col.fields : null;
286
+ } catch {
287
+ return null;
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Convert markdown strings to Portable Text for `portableText` fields on write.
293
+ * Non-string values pass through, so callers may still send Portable Text. If
294
+ * the schema can't be loaded, data is returned unchanged for the handler to
295
+ * validate.
296
+ */
297
+ async function convertWriteData(
298
+ ec: EmDashHandlers,
299
+ collection: string,
300
+ data: Record<string, unknown>,
301
+ ): Promise<Record<string, unknown>> {
302
+ const fields = await getCollectionFields(ec, collection);
303
+ if (!fields) return data;
304
+ return convertDataForWrite(data, fields);
305
+ }
306
+
307
+ /**
308
+ * Convert `portableText` field values on each item's `data` to markdown,
309
+ * mutating in place. Inverse of {@link convertWriteData}, gated on the read
310
+ * tools' `markdown` argument.
311
+ */
312
+ async function applyReadMarkdown(
313
+ ec: EmDashHandlers,
314
+ collection: string,
315
+ items: Array<Record<string, unknown>>,
316
+ ): Promise<void> {
317
+ const fields = await getCollectionFields(ec, collection);
318
+ if (!fields) return;
319
+ for (const item of items) {
320
+ if (item.data && typeof item.data === "object") {
321
+ item.data = convertDataForRead(
322
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowed by typeof check above
323
+ item.data as Record<string, unknown>,
324
+ fields,
325
+ false,
326
+ );
327
+ }
328
+ }
329
+ }
330
+
331
+ async function invalidateBylines(): Promise<void> {
332
+ const { invalidateBylineCache } = await import("../bylines/index.js");
333
+ invalidateBylineCache();
334
+ }
335
+
271
336
  /**
272
337
  * Enforce a scope requirement on the current request.
273
338
  *
@@ -460,6 +525,12 @@ export function createMcpServer(): McpServer {
460
525
  .string()
461
526
  .optional()
462
527
  .describe("Filter by locale (e.g. 'en', 'fr'). Only relevant when i18n is enabled."),
528
+ markdown: z
529
+ .boolean()
530
+ .optional()
531
+ .describe(
532
+ "Return rich text (portableText) fields as Markdown strings instead of Portable Text arrays (default false).",
533
+ ),
463
534
  }),
464
535
  annotations: { readOnlyHint: true },
465
536
  },
@@ -469,16 +540,26 @@ export function createMcpServer(): McpServer {
469
540
  // Subscribers must only see published content; force the status
470
541
  // filter regardless of caller-supplied value.
471
542
  const status = canReadDrafts(extra) ? args.status : "published";
472
- return unwrap(
473
- await ec.handleContentList(args.collection, {
474
- status,
475
- limit: args.limit,
476
- cursor: args.cursor,
477
- orderBy: args.orderBy,
478
- order: args.order,
479
- locale: args.locale,
480
- }),
481
- );
543
+ const result = await ec.handleContentList(args.collection, {
544
+ status,
545
+ limit: args.limit,
546
+ cursor: args.cursor,
547
+ orderBy: args.orderBy,
548
+ order: args.order,
549
+ locale: args.locale,
550
+ });
551
+ if (result.success && args.markdown) {
552
+ const payload = result.data;
553
+ if (
554
+ payload &&
555
+ typeof payload === "object" &&
556
+ "items" in payload &&
557
+ Array.isArray(payload.items)
558
+ ) {
559
+ await applyReadMarkdown(ec, args.collection, payload.items);
560
+ }
561
+ }
562
+ return unwrap(result);
482
563
  },
483
564
  );
484
565
 
@@ -499,6 +580,12 @@ export function createMcpServer(): McpServer {
499
580
  .describe(
500
581
  "Locale to scope slug lookup (e.g. 'fr'). Only affects slug resolution; IDs are globally unique.",
501
582
  ),
583
+ markdown: z
584
+ .boolean()
585
+ .optional()
586
+ .describe(
587
+ "Return rich text (portableText) fields as Markdown strings instead of Portable Text arrays (default false).",
588
+ ),
502
589
  }),
503
590
  annotations: { readOnlyHint: true },
504
591
  },
@@ -527,6 +614,9 @@ export function createMcpServer(): McpServer {
527
614
  });
528
615
  }
529
616
  }
617
+ if (result.success && args.markdown && result.data?.item) {
618
+ await applyReadMarkdown(ec, args.collection, [result.data.item]);
619
+ }
530
620
  return unwrap(result);
531
621
  },
532
622
  );
@@ -538,9 +628,12 @@ export function createMcpServer(): McpServer {
538
628
  description:
539
629
  "Create a new content item in a collection. The 'data' object should " +
540
630
  "contain field values matching the collection's schema (use " +
541
- "schema_get_collection to check). Rich text fields accept Portable Text " +
542
- "JSON arrays. A slug is auto-generated if not provided. Items are created " +
543
- "as 'draft' by default use content_publish to make them live.",
631
+ "schema_get_collection to check). For rich text (portableText) fields, " +
632
+ "pass a Markdown string converted to Portable Text automatically; prefer " +
633
+ "this. Pass a Portable Text JSON array only for complex content Markdown " +
634
+ "can't express (custom blocks, embeds). A slug is auto-generated if not " +
635
+ "provided. Items are created as 'draft' by default — use content_publish " +
636
+ "to make them live.",
544
637
  inputSchema: z.object({
545
638
  collection: z.string().describe("Collection slug (e.g. 'posts', 'pages')"),
546
639
  data: z
@@ -561,6 +654,12 @@ export function createMcpServer(): McpServer {
561
654
  .describe(
562
655
  "ID of the content item this is a translation of. Links items in the same translation group.",
563
656
  ),
657
+ bylines: z
658
+ .array(contentBylineInputSchema)
659
+ .optional()
660
+ .describe(
661
+ "Bylines to credit. Each entry references an existing byline by id (see byline_list / byline_create) with an optional roleLabel. The first entry becomes the primary byline.",
662
+ ),
564
663
  }),
565
664
  annotations: { destructiveHint: false },
566
665
  },
@@ -581,6 +680,8 @@ export function createMcpServer(): McpServer {
581
680
  );
582
681
  }
583
682
 
683
+ const data = await convertWriteData(emdash, args.collection, args.data);
684
+
584
685
  // Publishing requires publish permission — create as draft then publish
585
686
  if (args.status === "published") {
586
687
  const user = { id: userId, role: getExtra(extra).userRole };
@@ -591,11 +692,12 @@ export function createMcpServer(): McpServer {
591
692
  );
592
693
  }
593
694
  const result = await emdash.handleContentCreate(args.collection, {
594
- data: args.data,
695
+ data,
595
696
  slug: args.slug,
596
697
  authorId: userId,
597
698
  locale: args.locale,
598
699
  translationOf: args.translationOf,
700
+ bylines: args.bylines,
599
701
  });
600
702
  if (!result.success) return unwrap(result);
601
703
  const itemId = extractContentId(result.data);
@@ -607,11 +709,12 @@ export function createMcpServer(): McpServer {
607
709
 
608
710
  return unwrap(
609
711
  await emdash.handleContentCreate(args.collection, {
610
- data: args.data,
712
+ data,
611
713
  slug: args.slug,
612
714
  authorId: userId,
613
715
  locale: args.locale,
614
716
  translationOf: args.translationOf,
717
+ bylines: args.bylines,
615
718
  }),
616
719
  );
617
720
  },
@@ -623,7 +726,10 @@ export function createMcpServer(): McpServer {
623
726
  title: "Update Content",
624
727
  description:
625
728
  "Update an existing content item. Only include fields you want to change " +
626
- "in the 'data' object — unspecified fields are left unchanged. Pass the " +
729
+ "in the 'data' object — unspecified fields are left unchanged. Rich text " +
730
+ "(portableText) fields accept a Markdown string (recommended, converted " +
731
+ "automatically); use a Portable Text JSON array only for complex content " +
732
+ "Markdown can't express (custom blocks, embeds). Pass the " +
627
733
  "_rev token from content_get to enable optimistic concurrency checking " +
628
734
  "(the update fails if the item was modified since you read it). " +
629
735
  "`seo` and `bylines` are persisted alongside the field updates in a " +
@@ -690,6 +796,10 @@ export function createMcpServer(): McpServer {
690
796
  const ownerId = extractContentAuthorId(existing.data);
691
797
  requireOwnership(extra, ownerId, "content:edit_own", "content:edit_any");
692
798
 
799
+ const data = args.data
800
+ ? await convertWriteData(emdash, args.collection, args.data)
801
+ : args.data;
802
+
693
803
  // Writing publishedAt directly (incl. clearing to null) overwrites
694
804
  // historical record — gate behind publish_any, mirroring the REST PUT
695
805
  // route. Status-driven publishes are gated separately below.
@@ -716,7 +826,7 @@ export function createMcpServer(): McpServer {
716
826
  args.publishedAt !== undefined
717
827
  ) {
718
828
  const updateResult = await emdash.handleContentUpdate(args.collection, resolvedId, {
719
- data: args.data,
829
+ data,
720
830
  slug: args.slug,
721
831
  authorId: userId,
722
832
  locale: args.locale,
@@ -740,7 +850,7 @@ export function createMcpServer(): McpServer {
740
850
  args.publishedAt !== undefined
741
851
  ) {
742
852
  const updateResult = await emdash.handleContentUpdate(args.collection, resolvedId, {
743
- data: args.data,
853
+ data,
744
854
  slug: args.slug,
745
855
  authorId: userId,
746
856
  locale: args.locale,
@@ -756,7 +866,7 @@ export function createMcpServer(): McpServer {
756
866
 
757
867
  return unwrap(
758
868
  await emdash.handleContentUpdate(args.collection, resolvedId, {
759
- data: args.data,
869
+ data,
760
870
  slug: args.slug,
761
871
  authorId: userId,
762
872
  locale: args.locale,
@@ -1163,6 +1273,183 @@ export function createMcpServer(): McpServer {
1163
1273
  },
1164
1274
  );
1165
1275
 
1276
+ // =====================================================================
1277
+ // Byline tools
1278
+ // =====================================================================
1279
+
1280
+ server.registerTool(
1281
+ "byline_list",
1282
+ {
1283
+ title: "List Bylines",
1284
+ description:
1285
+ "List bylines (author/contributor credits) with optional filtering and " +
1286
+ "pagination. Bylines are standalone records referenced by content items; " +
1287
+ "use the returned id with content_create/content_update or byline_get. Use " +
1288
+ "the nextCursor value from the response to fetch the next page.",
1289
+ inputSchema: z.object({
1290
+ search: z.string().optional().describe("Filter by display name or slug substring"),
1291
+ isGuest: z.boolean().optional().describe("Filter by guest (true) or linked-user (false)"),
1292
+ userId: z.string().optional().describe("Filter to the byline linked to a CMS user ID"),
1293
+ locale: z.string().optional().describe("Filter by locale (omit for all)"),
1294
+ limit: z.number().int().min(1).max(100).optional().describe("Max items (default 50)"),
1295
+ cursor: z.string().min(1).max(2048).optional().describe("Pagination cursor"),
1296
+ }),
1297
+ annotations: { readOnlyHint: true },
1298
+ },
1299
+ async (args, extra) => {
1300
+ requireScope(extra, "content:read");
1301
+ const ec = getEmDash(extra);
1302
+ try {
1303
+ const { BylineRepository } = await import("../database/repositories/byline.js");
1304
+ const repo = new BylineRepository(ec.db);
1305
+ return jsonResult(
1306
+ await repo.findMany({
1307
+ search: args.search,
1308
+ isGuest: args.isGuest,
1309
+ userId: args.userId,
1310
+ locale: args.locale,
1311
+ limit: args.limit,
1312
+ cursor: args.cursor,
1313
+ }),
1314
+ );
1315
+ } catch (error) {
1316
+ return respondHandlerError(error, "BYLINE_LIST_ERROR");
1317
+ }
1318
+ },
1319
+ );
1320
+
1321
+ server.registerTool(
1322
+ "byline_get",
1323
+ {
1324
+ title: "Get Byline",
1325
+ description:
1326
+ "Get a single byline by its ID, including bio, avatar, website, linked " +
1327
+ "user, and any custom fields.",
1328
+ inputSchema: z.object({
1329
+ id: z.string().describe("Byline ID"),
1330
+ }),
1331
+ annotations: { readOnlyHint: true },
1332
+ },
1333
+ async (args, extra) => {
1334
+ requireScope(extra, "content:read");
1335
+ const ec = getEmDash(extra);
1336
+ try {
1337
+ const { BylineRepository } = await import("../database/repositories/byline.js");
1338
+ const byline = await new BylineRepository(ec.db).findById(args.id);
1339
+ if (!byline) return respondError("NOT_FOUND", `Byline '${args.id}' not found`);
1340
+ return jsonResult(byline);
1341
+ } catch (error) {
1342
+ return respondHandlerError(error, "BYLINE_GET_ERROR");
1343
+ }
1344
+ },
1345
+ );
1346
+
1347
+ server.registerTool(
1348
+ "byline_create",
1349
+ {
1350
+ title: "Create Byline",
1351
+ description:
1352
+ "Create a new byline (author/contributor credit). The slug must be unique " +
1353
+ "and contain only lowercase letters, digits, and hyphens. Link the byline " +
1354
+ "to a CMS user via userId, or leave it as a standalone guest credit. The " +
1355
+ "returned id can then be passed to content_create/content_update bylines.",
1356
+ inputSchema: z.object({ ...bylineCreateBody.shape }),
1357
+ annotations: { destructiveHint: false },
1358
+ },
1359
+ async (args, extra) => {
1360
+ requireScope(extra, "content:write");
1361
+ requireRole(extra, Role.EDITOR);
1362
+ const ec = getEmDash(extra);
1363
+ try {
1364
+ const { handleBylineCreate } = await import("../api/handlers/bylines.js");
1365
+ const result = await handleBylineCreate(ec.db, args);
1366
+ if (result.success) await invalidateBylines();
1367
+ return unwrap(result);
1368
+ } catch (error) {
1369
+ return respondHandlerError(error, "BYLINE_CREATE_ERROR");
1370
+ }
1371
+ },
1372
+ );
1373
+
1374
+ server.registerTool(
1375
+ "byline_update",
1376
+ {
1377
+ title: "Update Byline",
1378
+ description:
1379
+ "Update an existing byline. Any field can be omitted to leave it " +
1380
+ "unchanged. Renaming the slug must not collide with another byline.",
1381
+ inputSchema: z.object({
1382
+ id: z.string().describe("Byline ID to update"),
1383
+ ...bylineUpdateBody.shape,
1384
+ }),
1385
+ },
1386
+ async (args, extra) => {
1387
+ requireScope(extra, "content:write");
1388
+ requireRole(extra, Role.EDITOR);
1389
+ const ec = getEmDash(extra);
1390
+ try {
1391
+ const { handleBylineUpdate } = await import("../api/handlers/bylines.js");
1392
+ const { id, ...input } = args;
1393
+ const result = await handleBylineUpdate(ec.db, id, input);
1394
+ if (result.success) await invalidateBylines();
1395
+ return unwrap(result);
1396
+ } catch (error) {
1397
+ return respondHandlerError(error, "BYLINE_UPDATE_ERROR");
1398
+ }
1399
+ },
1400
+ );
1401
+
1402
+ server.registerTool(
1403
+ "byline_delete",
1404
+ {
1405
+ title: "Delete Byline",
1406
+ description:
1407
+ "Permanently delete a byline. Any content crediting this byline loses the " +
1408
+ "association, and it is cleared as a primary byline where set.",
1409
+ inputSchema: z.object({
1410
+ id: z.string().describe("Byline ID to delete"),
1411
+ }),
1412
+ annotations: { destructiveHint: true },
1413
+ },
1414
+ async (args, extra) => {
1415
+ requireScope(extra, "content:write");
1416
+ requireRole(extra, Role.EDITOR);
1417
+ const ec = getEmDash(extra);
1418
+ try {
1419
+ const { BylineRepository } = await import("../database/repositories/byline.js");
1420
+ const deleted = await new BylineRepository(ec.db).delete(args.id);
1421
+ if (!deleted) return respondError("NOT_FOUND", `Byline '${args.id}' not found`);
1422
+ await invalidateBylines();
1423
+ return jsonResult({ deleted: args.id });
1424
+ } catch (error) {
1425
+ return respondHandlerError(error, "BYLINE_DELETE_ERROR");
1426
+ }
1427
+ },
1428
+ );
1429
+
1430
+ server.registerTool(
1431
+ "byline_translations",
1432
+ {
1433
+ title: "List Byline Translations",
1434
+ description:
1435
+ "Return every locale variant of a byline, identified via its shared translation_group.",
1436
+ inputSchema: z.object({
1437
+ id: z.string().describe("Byline id (or translation_group)"),
1438
+ }),
1439
+ annotations: { readOnlyHint: true },
1440
+ },
1441
+ async (args, extra) => {
1442
+ requireScope(extra, "content:read");
1443
+ const ec = getEmDash(extra);
1444
+ try {
1445
+ const { handleBylineTranslations } = await import("../api/handlers/bylines.js");
1446
+ return unwrap(await handleBylineTranslations(ec.db, args.id));
1447
+ } catch (error) {
1448
+ return respondHandlerError(error, "BYLINE_TRANSLATIONS_ERROR");
1449
+ }
1450
+ },
1451
+ );
1452
+
1166
1453
  // =====================================================================
1167
1454
  // Schema tools
1168
1455
  // =====================================================================
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Portable helpers shared by the platform image-endpoint modules.
3
+ *
4
+ * EmDash wraps Astro's image endpoint (`image.endpoint`) so that source bytes
5
+ * for EmDash media are read straight from the storage adapter instead of being
6
+ * fetched over HTTP. The platform endpoint modules (Node: sharp via
7
+ * `astro:assets`; Cloudflare: the `IMAGES` binding) do the actual transform;
8
+ * this module holds the platform-agnostic bits they share: recognizing an
9
+ * EmDash media URL and validating transform query params.
10
+ *
11
+ * Kept free of `astro:*` / `virtual:emdash/*` imports so it stays in the
12
+ * precompiled package and can be unit-tested directly.
13
+ */
14
+
15
+ import { INTERNAL_MEDIA_PREFIX } from "./normalize.js";
16
+
17
+ /** Output formats the wrapped endpoint can produce on Cloudflare. */
18
+ export const ALLOWED_TRANSFORM_FORMATS = ["webp", "avif", "jpeg", "png"] as const;
19
+
20
+ /** Default output format -- broad support, strong compression. */
21
+ export const DEFAULT_TRANSFORM_FORMAT: ImageTransformFormat = "webp";
22
+
23
+ /** Upper bound for a requested dimension; caps the work a single request asks for. */
24
+ export const MAX_TRANSFORM_DIMENSION = 4000;
25
+
26
+ /** A format string accepted by {@link ImageTransformOptions.format}. */
27
+ export type ImageTransformFormat = (typeof ALLOWED_TRANSFORM_FORMATS)[number];
28
+
29
+ /** Validated options for a single transform. */
30
+ export interface ImageTransformOptions {
31
+ width?: number;
32
+ height?: number;
33
+ format: ImageTransformFormat;
34
+ quality?: number;
35
+ }
36
+
37
+ /** Long-lived immutable cache -- transform output is deterministic per key+params. */
38
+ export const IMMUTABLE_IMAGE_CACHE = "public, max-age=31536000, immutable";
39
+
40
+ /**
41
+ * Raster types safe to render inline. Anything else (SVG, PDF, ...) is served
42
+ * as an attachment so it can't execute as an active document. Mirrors the
43
+ * `/_emdash/api/media/file/{key}` route's allowlist.
44
+ */
45
+ const SAFE_INLINE_IMAGE_TYPES = new Set([
46
+ "image/jpeg",
47
+ "image/png",
48
+ "image/gif",
49
+ "image/webp",
50
+ "image/avif",
51
+ "image/x-icon",
52
+ ]);
53
+
54
+ /**
55
+ * Headers for streaming **original** stored bytes (the no-transform fallback).
56
+ * Carries the same stored-XSS protections as the media file route: a sandbox
57
+ * CSP, `nosniff`, and `Content-Disposition: attachment` for anything not on the
58
+ * inline raster allowlist (so a stored SVG can't run scripts in the site
59
+ * origin). Transformed output is always generated raster and doesn't need this.
60
+ */
61
+ export function originalMediaHeaders(contentType: string): Record<string, string> {
62
+ return {
63
+ "Content-Type": contentType,
64
+ "Cache-Control": IMMUTABLE_IMAGE_CACHE,
65
+ "X-Content-Type-Options": "nosniff",
66
+ "Content-Security-Policy":
67
+ "sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'",
68
+ "Content-Disposition": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? "inline" : "attachment",
69
+ };
70
+ }
71
+
72
+ /** Storage keys safe to serve: the flat `{ulid}{ext}` shape, no slashes/traversal. */
73
+ const SAFE_STORAGE_KEY = /^[A-Za-z0-9._-]+$/;
74
+
75
+ /** Plain decimal digits only -- rejects "1e3", "0x10", "+5", whitespace. */
76
+ const DECIMAL_DIGITS = /^\d+$/;
77
+
78
+ /** Whether a storage key is safe to resolve against the storage backend. */
79
+ export function isSafeTransformKey(key: string): boolean {
80
+ return SAFE_STORAGE_KEY.test(key);
81
+ }
82
+
83
+ /**
84
+ * If `href` points at the internal EmDash media route
85
+ * (`/_emdash/api/media/file/{key}`) with a safe key, return the key; otherwise
86
+ * `null` (the endpoint then delegates to the stock image endpoint for bundled
87
+ * assets, allowed remote, and `publicUrl` media).
88
+ *
89
+ * The component absolutizes same-origin media (Astro only optimizes absolute,
90
+ * remote-allowed URLs), so `href` is typically `https://site/_emdash/...` but
91
+ * may be relative. We match on the **pathname** only and never fetch `href` —
92
+ * the key is read from our own storage — so the host is irrelevant and can't be
93
+ * an SSRF vector. A dummy base resolves both absolute and relative forms and
94
+ * strips any query/fragment.
95
+ */
96
+ export function matchInternalMediaKey(href: string | null | undefined): string | null {
97
+ if (!href) return null;
98
+ let pathname: string;
99
+ try {
100
+ pathname = new URL(href, "http://localhost").pathname;
101
+ } catch {
102
+ return null;
103
+ }
104
+ if (!pathname.startsWith(INTERNAL_MEDIA_PREFIX)) return null;
105
+ const key = pathname.slice(INTERNAL_MEDIA_PREFIX.length);
106
+ if (!key || !isSafeTransformKey(key)) return null;
107
+ return key;
108
+ }
109
+
110
+ /** Type guard for {@link ImageTransformFormat}. */
111
+ export function isTransformFormat(value: string): value is ImageTransformFormat {
112
+ return (ALLOWED_TRANSFORM_FORMATS as readonly string[]).includes(value);
113
+ }
114
+
115
+ /** Outcome of parsing transform query params: validated options or an error. */
116
+ export type ParsedTransformParams =
117
+ | { ok: true; options: ImageTransformOptions }
118
+ | { ok: false; message: string };
119
+
120
+ /**
121
+ * Parse and validate `?w=&h=&f=&q=` query params. Width is required (it sizes
122
+ * the rendition); dimensions are bounded so a request can't ask for an
123
+ * unbounded or nonsensical transform.
124
+ */
125
+ export function parseTransformParams(params: URLSearchParams): ParsedTransformParams {
126
+ const width = parseDimension(params.get("w"));
127
+ if (width === null) return { ok: false, message: "Invalid 'w' (width)" };
128
+ if (width === undefined) return { ok: false, message: "Missing 'w' (width)" };
129
+
130
+ const height = parseDimension(params.get("h"));
131
+ if (height === null) return { ok: false, message: "Invalid 'h' (height)" };
132
+
133
+ const formatRaw = params.get("f");
134
+ let format: ImageTransformFormat = DEFAULT_TRANSFORM_FORMAT;
135
+ if (formatRaw !== null) {
136
+ if (!isTransformFormat(formatRaw)) {
137
+ return { ok: false, message: `Unsupported 'f' (format): ${formatRaw}` };
138
+ }
139
+ format = formatRaw;
140
+ }
141
+
142
+ const qualityRaw = params.get("q");
143
+ let quality: number | undefined;
144
+ if (qualityRaw !== null) {
145
+ const q = Number(qualityRaw);
146
+ if (!Number.isInteger(q) || q < 1 || q > 100) {
147
+ return { ok: false, message: "Invalid 'q' (quality), expected 1-100" };
148
+ }
149
+ quality = q;
150
+ }
151
+
152
+ return { ok: true, options: { width, height, format, quality } };
153
+ }
154
+
155
+ /**
156
+ * Parse a dimension query value.
157
+ * - `undefined`: param absent
158
+ * - `null`: present but invalid (non-integer, out of range)
159
+ * - `number`: valid, within [1, MAX_TRANSFORM_DIMENSION]
160
+ */
161
+ function parseDimension(raw: string | null): number | undefined | null {
162
+ if (raw === null) return undefined;
163
+ if (!DECIMAL_DIGITS.test(raw)) return null;
164
+ const n = Number(raw);
165
+ if (n < 1 || n > MAX_TRANSFORM_DIMENSION) return null;
166
+ return n;
167
+ }
@@ -15,6 +15,7 @@ import type { Database } from "../database/types.js";
15
15
  import { validateIdentifier } from "../database/validate.js";
16
16
  import { resolveLocale, resolveLocaleChain } from "../i18n/resolve.js";
17
17
  import { getDb } from "../loader.js";
18
+ import { cachedQuery, CacheNamespace } from "../object-cache/index.js";
18
19
  import { requestCached } from "../request-cache.js";
19
20
  import { sanitizeHref } from "../utils/url.js";
20
21
  import type { Menu, MenuItem, MenuItemRow } from "./types.js";
@@ -36,10 +37,16 @@ export interface MenuQueryOptions {
36
37
  */
37
38
  export function getMenu(name: string, options: MenuQueryOptions = {}): Promise<Menu | null> {
38
39
  const locale = resolveLocale(options.locale);
39
- return requestCached(`menu:${name}:${locale ?? "*"}`, async () => {
40
- const db = await getDb();
41
- return getMenuWithDb(name, db, { locale });
42
- });
40
+ return requestCached(`menu:${name}:${locale ?? "*"}`, () =>
41
+ cachedQuery({
42
+ namespace: CacheNamespace.MENUS,
43
+ key: `${name}:${locale ?? "*"}`,
44
+ load: async () => {
45
+ const db = await getDb();
46
+ return getMenuWithDb(name, db, { locale });
47
+ },
48
+ }),
49
+ );
43
50
  }
44
51
 
45
52
  /**