emdash 0.21.0 → 0.23.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 (655) hide show
  1. package/dist/{adapters-BxSmgtbF.d.mts → adapters-DAAjOID4.d.mts} +1 -1
  2. package/dist/{adapters-BxSmgtbF.d.mts.map → adapters-DAAjOID4.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-D5FxMUo8.mjs} +2 -2
  6. package/dist/{allowed-origins-BqC8cul8.mjs.map → allowed-origins-D5FxMUo8.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-BQ_yKRdG.mjs} +31 -25
  13. package/dist/api-BQ_yKRdG.mjs.map +1 -0
  14. package/dist/{api-tokens-BFFkB0jB.mjs → api-tokens-D6ppjIVi.mjs} +13 -3
  15. package/dist/api-tokens-D6ppjIVi.mjs.map +1 -0
  16. package/dist/{apply-CLjxheyb.mjs → apply-CWRyxIoO.mjs} +18 -18
  17. package/dist/{apply-CLjxheyb.mjs.map → apply-CWRyxIoO.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 +122 -26
  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.d.mts.map +1 -1
  32. package/dist/astro/middleware/request-context.mjs +8 -6
  33. package/dist/astro/middleware/request-context.mjs.map +1 -1
  34. package/dist/astro/middleware/setup.mjs +1 -1
  35. package/dist/astro/middleware.d.mts +1 -1
  36. package/dist/astro/middleware.d.mts.map +1 -1
  37. package/dist/astro/middleware.mjs +444 -149
  38. package/dist/astro/middleware.mjs.map +1 -1
  39. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -7
  40. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -7
  41. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +5 -5
  42. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  43. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
  44. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +10 -10
  45. package/dist/astro/routes/api/admin/byline-fields/index.mjs +10 -10
  46. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +10 -10
  47. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +18 -16
  48. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  49. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +18 -16
  50. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
  51. package/dist/astro/routes/api/admin/bylines/index.mjs +18 -16
  52. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +15 -13
  54. package/dist/astro/routes/api/admin/comments/_id_/status.mjs.map +1 -1
  55. package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -6
  56. package/dist/astro/routes/api/admin/comments/_id_.mjs.map +1 -1
  57. package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -10
  58. package/dist/astro/routes/api/admin/comments/bulk.mjs.map +1 -1
  59. package/dist/astro/routes/api/admin/comments/counts.mjs +8 -6
  60. package/dist/astro/routes/api/admin/comments/counts.mjs.map +1 -1
  61. package/dist/astro/routes/api/admin/comments/index.mjs +12 -10
  62. package/dist/astro/routes/api/admin/comments/index.mjs.map +1 -1
  63. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +6 -6
  64. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +5 -5
  65. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +5 -5
  66. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +5 -5
  67. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +41 -39
  68. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +41 -39
  70. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +40 -38
  72. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +40 -38
  74. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  75. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +40 -38
  76. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  77. package/dist/astro/routes/api/admin/plugins/index.mjs +40 -38
  78. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  79. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  80. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +40 -38
  81. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +40 -38
  83. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +40 -38
  85. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +40 -38
  87. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +41 -39
  89. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +40 -38
  91. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +41 -39
  93. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/plugins/updates.mjs +40 -38
  95. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  96. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +40 -38
  97. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  98. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  99. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +40 -38
  100. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  101. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  102. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
  103. package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -8
  104. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +5 -5
  105. package/dist/astro/routes/api/admin/users/index.mjs +7 -7
  106. package/dist/astro/routes/api/auth/dev-bypass.mjs +6 -6
  107. package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
  108. package/dist/astro/routes/api/auth/invite/complete.mjs +12 -12
  109. package/dist/astro/routes/api/auth/invite/index.mjs +9 -9
  110. package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -11
  111. package/dist/astro/routes/api/auth/logout.mjs +4 -4
  112. package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -11
  113. package/dist/astro/routes/api/auth/magic-link/verify.mjs +4 -4
  114. package/dist/astro/routes/api/auth/me.mjs +8 -8
  115. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  116. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  117. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  118. package/dist/astro/routes/api/auth/passkey/_id_.mjs +7 -7
  119. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  120. package/dist/astro/routes/api/auth/passkey/options.mjs +13 -13
  121. package/dist/astro/routes/api/auth/passkey/register/options.mjs +11 -11
  122. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +12 -12
  123. package/dist/astro/routes/api/auth/passkey/verify.mjs +12 -12
  124. package/dist/astro/routes/api/auth/signup/complete.mjs +12 -12
  125. package/dist/astro/routes/api/auth/signup/request.mjs +11 -11
  126. package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
  127. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +16 -15
  128. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs.map +1 -1
  129. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts +9 -0
  130. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts.map +1 -0
  131. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +179 -0
  132. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs.map +1 -0
  133. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
  134. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +4 -4
  135. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
  136. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  137. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +13 -13
  138. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +8 -8
  139. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
  140. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
  141. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +8 -8
  142. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +17 -15
  143. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  144. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +4 -4
  145. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +4 -4
  146. package/dist/astro/routes/api/content/_collection_/_id_.mjs +8 -8
  147. package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
  148. package/dist/astro/routes/api/content/_collection_/index.mjs +8 -8
  149. package/dist/astro/routes/api/content/_collection_/trash.mjs +8 -8
  150. package/dist/astro/routes/api/dashboard.mjs +10 -8
  151. package/dist/astro/routes/api/dashboard.mjs.map +1 -1
  152. package/dist/astro/routes/api/dev/emails.mjs +4 -4
  153. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  154. package/dist/astro/routes/api/import/probe.mjs +12 -12
  155. package/dist/astro/routes/api/import/wordpress/analyze.mjs +5 -5
  156. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  157. package/dist/astro/routes/api/import/wordpress/execute.mjs +17 -15
  158. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  159. package/dist/astro/routes/api/import/wordpress/media.mjs +10 -10
  160. package/dist/astro/routes/api/import/wordpress/prepare.mjs +11 -11
  161. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +10 -10
  162. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  163. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +12 -12
  164. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  165. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  166. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +19 -17
  167. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  168. package/dist/astro/routes/api/manifest.mjs +5 -5
  169. package/dist/astro/routes/api/mcp.mjs +213 -46
  170. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  171. package/dist/astro/routes/api/media/_id_/confirm.mjs +8 -8
  172. package/dist/astro/routes/api/media/_id_.mjs +8 -8
  173. package/dist/astro/routes/api/media/file/_...key_.mjs +3 -3
  174. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  175. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  176. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  177. package/dist/astro/routes/api/media/upload-url.mjs +10 -10
  178. package/dist/astro/routes/api/media.mjs +13 -13
  179. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +11 -9
  180. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
  181. package/dist/astro/routes/api/menus/_name_/items.mjs +11 -9
  182. package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
  183. package/dist/astro/routes/api/menus/_name_/reorder.mjs +11 -9
  184. package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
  185. package/dist/astro/routes/api/menus/_name_/translations.mjs +11 -9
  186. package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
  187. package/dist/astro/routes/api/menus/_name_.mjs +11 -9
  188. package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
  189. package/dist/astro/routes/api/menus/index.mjs +11 -9
  190. package/dist/astro/routes/api/menus/index.mjs.map +1 -1
  191. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  192. package/dist/astro/routes/api/oauth/device/authorize.mjs +7 -7
  193. package/dist/astro/routes/api/oauth/device/code.mjs +10 -10
  194. package/dist/astro/routes/api/oauth/device/token.mjs +9 -9
  195. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  196. package/dist/astro/routes/api/oauth/token/refresh.mjs +7 -7
  197. package/dist/astro/routes/api/oauth/token/revoke.mjs +7 -7
  198. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  199. package/dist/astro/routes/api/openapi.json.mjs +5 -5
  200. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +5 -5
  201. package/dist/astro/routes/api/redirects/404s/index.mjs +11 -11
  202. package/dist/astro/routes/api/redirects/404s/summary.mjs +11 -11
  203. package/dist/astro/routes/api/redirects/_id_.mjs +12 -12
  204. package/dist/astro/routes/api/redirects/index.mjs +12 -12
  205. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  206. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +4 -4
  207. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +40 -38
  208. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  209. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +40 -38
  210. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  211. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +40 -38
  212. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  213. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +40 -38
  214. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  215. package/dist/astro/routes/api/schema/collections/index.mjs +40 -38
  216. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  217. package/dist/astro/routes/api/schema/index.mjs +9 -8
  218. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  219. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +40 -38
  220. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  221. package/dist/astro/routes/api/schema/orphans/index.mjs +40 -38
  222. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  223. package/dist/astro/routes/api/search/enable.mjs +11 -11
  224. package/dist/astro/routes/api/search/index.mjs +10 -10
  225. package/dist/astro/routes/api/search/rebuild.mjs +11 -11
  226. package/dist/astro/routes/api/search/stats.mjs +7 -7
  227. package/dist/astro/routes/api/search/suggest.mjs +10 -10
  228. package/dist/astro/routes/api/sections/_slug_.mjs +10 -10
  229. package/dist/astro/routes/api/sections/index.mjs +10 -10
  230. package/dist/astro/routes/api/settings/email.mjs +6 -6
  231. package/dist/astro/routes/api/settings.mjs +16 -15
  232. package/dist/astro/routes/api/settings.mjs.map +1 -1
  233. package/dist/astro/routes/api/setup/admin-verify.mjs +13 -13
  234. package/dist/astro/routes/api/setup/admin.mjs +12 -12
  235. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
  236. package/dist/astro/routes/api/setup/dev-bypass.mjs +30 -27
  237. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  238. package/dist/astro/routes/api/setup/dev-reset.mjs +4 -4
  239. package/dist/astro/routes/api/setup/index.mjs +30 -28
  240. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  241. package/dist/astro/routes/api/setup/status.mjs +5 -5
  242. package/dist/astro/routes/api/snapshot.d.mts.map +1 -1
  243. package/dist/astro/routes/api/snapshot.mjs +10 -9
  244. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  245. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +16 -14
  246. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  247. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +16 -14
  248. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  249. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +16 -14
  250. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  251. package/dist/astro/routes/api/taxonomies/index.mjs +16 -14
  252. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  253. package/dist/astro/routes/api/themes/preview.mjs +8 -8
  254. package/dist/astro/routes/api/typegen.mjs +6 -6
  255. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  256. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  257. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  258. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +8 -8
  259. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +11 -11
  260. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +11 -11
  261. package/dist/astro/routes/api/widget-areas/_name_.mjs +7 -7
  262. package/dist/astro/routes/api/widget-areas/index.mjs +11 -11
  263. package/dist/astro/routes/api/widget-components.mjs +4 -4
  264. package/dist/astro/routes/robots.txt.mjs +10 -9
  265. package/dist/astro/routes/robots.txt.mjs.map +1 -1
  266. package/dist/astro/routes/sitemap-_collection_.xml.mjs +13 -12
  267. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  268. package/dist/astro/routes/sitemap.xml.mjs +11 -10
  269. package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
  270. package/dist/astro/types.d.mts +16 -12
  271. package/dist/astro/types.d.mts.map +1 -1
  272. package/dist/auth/providers/github.d.mts +1 -1
  273. package/dist/auth/providers/google.d.mts +1 -1
  274. package/dist/{authorize-D5gfBVU5.mjs → authorize-Cse0k7B0.mjs} +2 -2
  275. package/dist/{authorize-D5gfBVU5.mjs.map → authorize-Cse0k7B0.mjs.map} +1 -1
  276. package/dist/{base64-CqR-7kqF.mjs → base64-CmWvODNW.mjs} +1 -1
  277. package/dist/{base64-CqR-7kqF.mjs.map → base64-CmWvODNW.mjs.map} +1 -1
  278. package/dist/{byline-V_Qp1Ziw.mjs → byline-DVo-liaP.mjs} +27 -76
  279. package/dist/byline-DVo-liaP.mjs.map +1 -0
  280. package/dist/{byline-fields-B0NO1yUB.mjs → byline-fields-B-KXkg5R.mjs} +3 -3
  281. package/dist/{byline-fields-B0NO1yUB.mjs.map → byline-fields-B-KXkg5R.mjs.map} +1 -1
  282. package/dist/{byline-fields-nBVqK_Ff.mjs → byline-fields-DaMKzkhO.mjs} +2 -2
  283. package/dist/{byline-fields-nBVqK_Ff.mjs.map → byline-fields-DaMKzkhO.mjs.map} +1 -1
  284. package/dist/{byline-fields-CQJRIQkn.d.mts → byline-fields-RFPkDLRw.d.mts} +56 -31
  285. package/dist/byline-fields-RFPkDLRw.d.mts.map +1 -0
  286. package/dist/{byline-registry-DedidtqC.mjs → byline-registry-BOjqDOim.mjs} +3 -3
  287. package/dist/{byline-registry-DedidtqC.mjs.map → byline-registry-BOjqDOim.mjs.map} +1 -1
  288. package/dist/{bylines-DfGDnred.mjs → bylines-f5ppBpD5.mjs} +8 -8
  289. package/dist/{bylines-DfGDnred.mjs.map → bylines-f5ppBpD5.mjs.map} +1 -1
  290. package/dist/{bylines-B2NWnIwS.mjs → bylines-pIKgc_TL.mjs} +10 -4
  291. package/dist/{bylines-B2NWnIwS.mjs.map → bylines-pIKgc_TL.mjs.map} +1 -1
  292. package/dist/{cache-DTTHWD8n.mjs → cache-Q6V4U-Xz.mjs} +3 -3
  293. package/dist/{cache-DTTHWD8n.mjs.map → cache-Q6V4U-Xz.mjs.map} +1 -1
  294. package/dist/{challenge-store-woE0bbCf.mjs → challenge-store-LhiqMccz.mjs} +1 -1
  295. package/dist/{challenge-store-woE0bbCf.mjs.map → challenge-store-LhiqMccz.mjs.map} +1 -1
  296. package/dist/{chunks-BerYVuve.mjs → chunks-SyjZaYwV.mjs} +2 -2
  297. package/dist/{chunks-BerYVuve.mjs.map → chunks-SyjZaYwV.mjs.map} +1 -1
  298. package/dist/cli/index.mjs +29 -27
  299. package/dist/cli/index.mjs.map +1 -1
  300. package/dist/client/cf-access.d.mts +1 -1
  301. package/dist/client/index.d.mts +1 -1
  302. package/dist/client/index.mjs +2 -1
  303. package/dist/client/index.mjs.map +1 -1
  304. package/dist/{comment-sqQxNpN3.mjs → comment-80UyJJUR.mjs} +11 -3
  305. package/dist/comment-80UyJJUR.mjs.map +1 -0
  306. package/dist/comment-reaction-Dyb-AutY.mjs +85 -0
  307. package/dist/comment-reaction-Dyb-AutY.mjs.map +1 -0
  308. package/dist/{comments-D2hNuxNa.mjs → comments-Cczx7AvD.mjs} +3 -3
  309. package/dist/{comments-D2hNuxNa.mjs.map → comments-Cczx7AvD.mjs.map} +1 -1
  310. package/dist/{components-DYKp2gmo.mjs → components-CYt4uVK9.mjs} +1 -1
  311. package/dist/{components-DYKp2gmo.mjs.map → components-CYt4uVK9.mjs.map} +1 -1
  312. package/dist/{content-BIlVx-RX.mjs → content-2PTDNnoh.mjs} +22 -7
  313. package/dist/content-2PTDNnoh.mjs.map +1 -0
  314. package/dist/{context-Cm4pt1Ws.mjs → context-B1W8soLv.mjs} +64 -26
  315. package/dist/context-B1W8soLv.mjs.map +1 -0
  316. package/dist/{cron-DdEVrQ2Y.mjs → cron-C5LVoNmP.mjs} +14 -2
  317. package/dist/cron-C5LVoNmP.mjs.map +1 -0
  318. package/dist/{dashboard-C-UYpps0.mjs → dashboard-CYjpQZ6-.mjs} +4 -4
  319. package/dist/{dashboard-C-UYpps0.mjs.map → dashboard-CYjpQZ6-.mjs.map} +1 -1
  320. package/dist/database/instrumentation.d.mts +19 -0
  321. package/dist/database/instrumentation.d.mts.map +1 -1
  322. package/dist/database/instrumentation.mjs +8 -1
  323. package/dist/database/instrumentation.mjs.map +1 -1
  324. package/dist/db/index.d.mts +3 -3
  325. package/dist/db/index.mjs +1 -1
  326. package/dist/db/libsql.d.mts +1 -1
  327. package/dist/db/postgres.d.mts +1 -1
  328. package/dist/db/sqlite.d.mts +1 -1
  329. package/dist/{db-errors-BluWkwGI.mjs → db-errors-UXB1CK42.mjs} +1 -1
  330. package/dist/{db-errors-BluWkwGI.mjs.map → db-errors-UXB1CK42.mjs.map} +1 -1
  331. package/dist/{default-NHGuJzQ3.mjs → default-CeRG-Ot4.mjs} +1 -1
  332. package/dist/{default-NHGuJzQ3.mjs.map → default-CeRG-Ot4.mjs.map} +1 -1
  333. package/dist/{device-flow-BQApWgnW.mjs → device-flow-DENDCQ9F.mjs} +5 -5
  334. package/dist/{device-flow-BQApWgnW.mjs.map → device-flow-DENDCQ9F.mjs.map} +1 -1
  335. package/dist/{email-console-BbU3RbWv.mjs → email-console-DJP32ucW.mjs} +1 -1
  336. package/dist/{email-console-BbU3RbWv.mjs.map → email-console-DJP32ucW.mjs.map} +1 -1
  337. package/dist/{error-CNn_w7jf.mjs → error-Bl6kZgtt.mjs} +2 -2
  338. package/dist/{error-CNn_w7jf.mjs.map → error-Bl6kZgtt.mjs.map} +1 -1
  339. package/dist/{escape-DPgcxcpL.mjs → escape-Bjio4ZsM.mjs} +1 -1
  340. package/dist/{escape-DPgcxcpL.mjs.map → escape-Bjio4ZsM.mjs.map} +1 -1
  341. package/dist/field-defs-cache-ztrdzUGb.mjs +77 -0
  342. package/dist/field-defs-cache-ztrdzUGb.mjs.map +1 -0
  343. package/dist/{fts-manager-Cx5z8jdA.mjs → fts-manager-CQuHt-vS.mjs} +2 -2
  344. package/dist/{fts-manager-Cx5z8jdA.mjs.map → fts-manager-CQuHt-vS.mjs.map} +1 -1
  345. package/dist/{hash-DlvIFn0b.mjs → hash-DrvzIXcz.mjs} +1 -1
  346. package/dist/{hash-DlvIFn0b.mjs.map → hash-DrvzIXcz.mjs.map} +1 -1
  347. package/dist/{import-KyxT1Mbs.mjs → import-Bb1T9WJS.mjs} +4 -4
  348. package/dist/{import-KyxT1Mbs.mjs.map → import-Bb1T9WJS.mjs.map} +1 -1
  349. package/dist/{index-D2VAiumu.d.mts → index-BaIj5hIq.d.mts} +198 -21
  350. package/dist/index-BaIj5hIq.d.mts.map +1 -0
  351. package/dist/{index-uT2yR66F.d.mts → index-qbL02uhs.d.mts} +3 -3
  352. package/dist/{index-uT2yR66F.d.mts.map → index-qbL02uhs.d.mts.map} +1 -1
  353. package/dist/index.d.mts +18 -17
  354. package/dist/index.mjs +64 -61
  355. package/dist/{init-lock-DlBHjf9-.mjs → init-lock-6b309ZrF.mjs} +2 -29
  356. package/dist/init-lock-6b309ZrF.mjs.map +1 -0
  357. package/dist/{load-Dq91b_DK.mjs → load-BNo-ER8C.mjs} +2 -2
  358. package/dist/{load-Dq91b_DK.mjs.map → load-BNo-ER8C.mjs.map} +1 -1
  359. package/dist/{loader-BqWjcH3h.mjs → loader-Dn74CG1b.mjs} +70 -11
  360. package/dist/loader-Dn74CG1b.mjs.map +1 -0
  361. package/dist/{manifest-schema-DFPeqMAn.mjs → manifest-schema-BWKnQYQF.mjs} +1 -1
  362. package/dist/{manifest-schema-DFPeqMAn.mjs.map → manifest-schema-BWKnQYQF.mjs.map} +1 -1
  363. package/dist/media/image-endpoint.d.mts +74 -0
  364. package/dist/media/image-endpoint.d.mts.map +1 -0
  365. package/dist/media/image-endpoint.mjs +162 -0
  366. package/dist/media/image-endpoint.mjs.map +1 -0
  367. package/dist/media/index.d.mts +1 -1
  368. package/dist/media/index.mjs +2 -2
  369. package/dist/media/local-runtime.d.mts +19 -11
  370. package/dist/media/local-runtime.d.mts.map +1 -1
  371. package/dist/media/local-runtime.mjs +16 -13
  372. package/dist/media/local-runtime.mjs.map +1 -1
  373. package/dist/{media-JOf3pNkw.mjs → media-Bw0sA6rb.mjs} +2 -2
  374. package/dist/{media-JOf3pNkw.mjs.map → media-Bw0sA6rb.mjs.map} +1 -1
  375. package/dist/{media-allowlist-_A0SuDn4.mjs → media-allowlist-B77I5_bw.mjs} +2 -2
  376. package/dist/{media-allowlist-_A0SuDn4.mjs.map → media-allowlist-B77I5_bw.mjs.map} +1 -1
  377. package/dist/{media-url-CqLd69IO.mjs → media-url-O4rm9-SQ.mjs} +1 -1
  378. package/dist/{media-url-CqLd69IO.mjs.map → media-url-O4rm9-SQ.mjs.map} +1 -1
  379. package/dist/{menus-DX4_E01q.mjs → menus-CYs0WZoL.mjs} +20 -6
  380. package/dist/menus-CYs0WZoL.mjs.map +1 -0
  381. package/dist/{menus-Ryk9L7fT.mjs → menus-DS8VTZgo.mjs} +167 -24
  382. package/dist/menus-DS8VTZgo.mjs.map +1 -0
  383. package/dist/{mime-YbtlEtvS.mjs → mime-BTzvzJ8M.mjs} +1 -1
  384. package/dist/{mime-YbtlEtvS.mjs.map → mime-BTzvzJ8M.mjs.map} +1 -1
  385. package/dist/{mode-CGXzIbD8.mjs → mode-BB0F8xTC.mjs} +1 -1
  386. package/dist/{mode-CGXzIbD8.mjs.map → mode-BB0F8xTC.mjs.map} +1 -1
  387. package/dist/{normalize-DKsg36ty.mjs → normalize-ClbNIenm.mjs} +1 -1
  388. package/dist/{normalize-DKsg36ty.mjs.map → normalize-ClbNIenm.mjs.map} +1 -1
  389. package/dist/{oauth-authorization-C2kVyjXI.mjs → oauth-authorization-CsvzIp_F.mjs} +5 -5
  390. package/dist/{oauth-authorization-C2kVyjXI.mjs.map → oauth-authorization-CsvzIp_F.mjs.map} +1 -1
  391. package/dist/{oauth-clients-BC873NCV.mjs → oauth-clients-C9SYwEbZ.mjs} +1 -1
  392. package/dist/{oauth-clients-BC873NCV.mjs.map → oauth-clients-C9SYwEbZ.mjs.map} +1 -1
  393. package/dist/{oauth-state-store-Cd--TUaq.mjs → oauth-state-store---zrApfB.mjs} +1 -1
  394. package/dist/{oauth-state-store-Cd--TUaq.mjs.map → oauth-state-store---zrApfB.mjs.map} +1 -1
  395. package/dist/{oauth-user-lookup-e4wOvDud.mjs → oauth-user-lookup-SHsWRlG9.mjs} +1 -1
  396. package/dist/{oauth-user-lookup-e4wOvDud.mjs.map → oauth-user-lookup-SHsWRlG9.mjs.map} +1 -1
  397. package/dist/object-cache/memory.d.mts +15 -0
  398. package/dist/object-cache/memory.d.mts.map +1 -0
  399. package/dist/object-cache/memory.mjs +56 -0
  400. package/dist/object-cache/memory.mjs.map +1 -0
  401. package/dist/object-cache-SEb2IM4Z.mjs +373 -0
  402. package/dist/object-cache-SEb2IM4Z.mjs.map +1 -0
  403. package/dist/{options-9kLgkE8m.d.mts → options-CqECG0gM.d.mts} +3 -3
  404. package/dist/{options-9kLgkE8m.d.mts.map → options-CqECG0gM.d.mts.map} +1 -1
  405. package/dist/{options-BPCVnesz.mjs → options-DTTML-Tx.mjs} +1 -1
  406. package/dist/{options-BPCVnesz.mjs.map → options-DTTML-Tx.mjs.map} +1 -1
  407. package/dist/page/index.d.mts +2 -2
  408. package/dist/{parse-DzSrk1t8.mjs → parse-C9hpjUyY.mjs} +2 -2
  409. package/dist/{parse-DzSrk1t8.mjs.map → parse-C9hpjUyY.mjs.map} +1 -1
  410. package/dist/{passkey-config-BpjbE_Uv.mjs → passkey-config-C0YfSBko.mjs} +1 -1
  411. package/dist/{passkey-config-BpjbE_Uv.mjs.map → passkey-config-C0YfSBko.mjs.map} +1 -1
  412. package/dist/{patterns-p-RBdTbM.mjs → patterns-BKmjvM7K.mjs} +1 -1
  413. package/dist/{patterns-p-RBdTbM.mjs.map → patterns-BKmjvM7K.mjs.map} +1 -1
  414. package/dist/{placeholder-2xumZh4g.mjs → placeholder-B0s2mWu5.mjs} +1 -1
  415. package/dist/{placeholder-2xumZh4g.mjs.map → placeholder-B0s2mWu5.mjs.map} +1 -1
  416. package/dist/{placeholder-BevVKfay.d.mts → placeholder-QoI4gEzP.d.mts} +1 -1
  417. package/dist/{placeholder-BevVKfay.d.mts.map → placeholder-QoI4gEzP.d.mts.map} +1 -1
  418. package/dist/plugin-types.d.mts +1 -1
  419. package/dist/plugin-utils.d.mts +9 -9
  420. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  421. package/dist/plugins/adapt-sandbox-entry.mjs +4 -2
  422. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  423. package/dist/{transport-1cIrOb1Y.mjs → portable-text-BICg8bTk.mjs} +2 -135
  424. package/dist/portable-text-BICg8bTk.mjs.map +1 -0
  425. package/dist/{preview-Dqv2hwXr.mjs → preview-DKGCt2_p.mjs} +2 -2
  426. package/dist/{preview-Dqv2hwXr.mjs.map → preview-DKGCt2_p.mjs.map} +1 -1
  427. package/dist/{public-url-D_zARuvZ.mjs → public-url-CTVqgMmg.mjs} +1 -1
  428. package/dist/{public-url-D_zARuvZ.mjs.map → public-url-CTVqgMmg.mjs.map} +1 -1
  429. package/dist/{query-Crm038Mc.mjs → query-DgUHZLWB.mjs} +230 -31
  430. package/dist/query-DgUHZLWB.mjs.map +1 -0
  431. package/dist/{rate-limit-hRTBqmw1.mjs → rate-limit-BuQ5d4X_.mjs} +2 -2
  432. package/dist/{rate-limit-hRTBqmw1.mjs.map → rate-limit-BuQ5d4X_.mjs.map} +1 -1
  433. package/dist/{redirect-CRWIt8Zj.mjs → redirect-Bifv_yHv.mjs} +3 -3
  434. package/dist/{redirect-CRWIt8Zj.mjs.map → redirect-Bifv_yHv.mjs.map} +1 -1
  435. package/dist/{redirect-C-OOkyku.mjs → redirect-CS-PHtNh.mjs} +1 -1
  436. package/dist/{redirect-C-OOkyku.mjs.map → redirect-CS-PHtNh.mjs.map} +1 -1
  437. package/dist/{redirects-CP3TnTLO.mjs → redirects-BZ8Mxn8H.mjs} +6 -6
  438. package/dist/{redirects-CP3TnTLO.mjs.map → redirects-BZ8Mxn8H.mjs.map} +1 -1
  439. package/dist/{redirects-6Zg2SoYo.mjs → redirects-x9eFPeyi.mjs} +10 -3
  440. package/dist/redirects-x9eFPeyi.mjs.map +1 -0
  441. package/dist/{registry-diMzD1Wf.mjs → registry-CK1SS6pi.mjs} +6 -6
  442. package/dist/{registry-diMzD1Wf.mjs.map → registry-CK1SS6pi.mjs.map} +1 -1
  443. package/dist/{request-cache-UwmBAiUK.mjs → request-cache-KCNHp_RJ.mjs} +1 -1
  444. package/dist/{request-cache-UwmBAiUK.mjs.map → request-cache-KCNHp_RJ.mjs.map} +1 -1
  445. package/dist/{request-meta-DPechd0W.mjs → request-meta-CmS1tDFf.mjs} +2 -2
  446. package/dist/{request-meta-DPechd0W.mjs.map → request-meta-CmS1tDFf.mjs.map} +1 -1
  447. package/dist/{resolve-B3NUUtVY.mjs → resolve-C7I0qiR0.mjs} +1 -1
  448. package/dist/{resolve-B3NUUtVY.mjs.map → resolve-C7I0qiR0.mjs.map} +1 -1
  449. package/dist/{runner-C8vcbvCe.d.mts → runner-CEtq-6Sm.d.mts} +2 -2
  450. package/dist/{runner-C8vcbvCe.d.mts.map → runner-CEtq-6Sm.d.mts.map} +1 -1
  451. package/dist/{runner--4wMWwKM.mjs → runner-DYYnW530.mjs} +201 -170
  452. package/dist/runner-DYYnW530.mjs.map +1 -0
  453. package/dist/runtime.d.mts +10 -10
  454. package/dist/runtime.mjs +3 -3
  455. package/dist/{schema-BDOkd3OU.mjs → schema-CbFRFoM7.mjs} +13 -8
  456. package/dist/schema-CbFRFoM7.mjs.map +1 -0
  457. package/dist/{search-Bs_J_EW-.mjs → search-C-waE_YW.mjs} +4 -4
  458. package/dist/{search-Bs_J_EW-.mjs.map → search-C-waE_YW.mjs.map} +1 -1
  459. package/dist/{secrets-C8xmE6mR.mjs → secrets-BSf9pRRY.mjs} +5 -5
  460. package/dist/{secrets-C8xmE6mR.mjs.map → secrets-BSf9pRRY.mjs.map} +1 -1
  461. package/dist/{sections-P0zuBlyz.mjs → sections-osX9U-YJ.mjs} +3 -3
  462. package/dist/{sections-P0zuBlyz.mjs.map → sections-osX9U-YJ.mjs.map} +1 -1
  463. package/dist/seed/index.d.mts +2 -2
  464. package/dist/seed/index.mjs +23 -21
  465. package/dist/seo/index.d.mts +1 -1
  466. package/dist/seo/index.mjs +1 -1
  467. package/dist/{seo-DpNgGQjF.mjs → seo-4FovMwNS.mjs} +5 -2
  468. package/dist/seo-4FovMwNS.mjs.map +1 -0
  469. package/dist/{seo-CLhm-Fmb.mjs → seo-DCEF-AVr.mjs} +1 -1
  470. package/dist/{seo-CLhm-Fmb.mjs.map → seo-DCEF-AVr.mjs.map} +1 -1
  471. package/dist/{service-CDQQnT8W.mjs → service-jby1RRmU.mjs} +3 -3
  472. package/dist/{service-CDQQnT8W.mjs.map → service-jby1RRmU.mjs.map} +1 -1
  473. package/dist/session-user-B8aLtKAH.mjs +51 -0
  474. package/dist/session-user-B8aLtKAH.mjs.map +1 -0
  475. package/dist/{settings-sO0Fif4p.mjs → settings-4bRT2NIf.mjs} +3 -3
  476. package/dist/{settings-sO0Fif4p.mjs.map → settings-4bRT2NIf.mjs.map} +1 -1
  477. package/dist/{settings-BjBsmVAo.mjs → settings-t-H2jPuJ.mjs} +18 -10
  478. package/dist/settings-t-H2jPuJ.mjs.map +1 -0
  479. package/dist/{setup-complete-CMMr-oZU.mjs → setup-complete-gEiySUc-.mjs} +2 -2
  480. package/dist/{setup-complete-CMMr-oZU.mjs.map → setup-complete-gEiySUc-.mjs.map} +1 -1
  481. package/dist/{setup-nonce-169xl4fV.mjs → setup-nonce-DzS50zme.mjs} +1 -1
  482. package/dist/{setup-nonce-169xl4fV.mjs.map → setup-nonce-DzS50zme.mjs.map} +1 -1
  483. package/dist/{single-flight-cache-C0UV1Npg.mjs → single-flight-cache-Cdfkic3t.mjs} +2 -2
  484. package/dist/{single-flight-cache-C0UV1Npg.mjs.map → single-flight-cache-Cdfkic3t.mjs.map} +1 -1
  485. package/dist/{site-url-vtsuOvSD.mjs → site-url-BLebyON8.mjs} +2 -2
  486. package/dist/{site-url-vtsuOvSD.mjs.map → site-url-BLebyON8.mjs.map} +1 -1
  487. package/dist/{slugify-Cjh1ssOZ.mjs → slugify-Cce3dTdg.mjs} +1 -1
  488. package/dist/{slugify-Cjh1ssOZ.mjs.map → slugify-Cce3dTdg.mjs.map} +1 -1
  489. package/dist/{ssrf-XO05Voq6.mjs → ssrf-BRKb343l.mjs} +1 -1
  490. package/dist/{ssrf-XO05Voq6.mjs.map → ssrf-BRKb343l.mjs.map} +1 -1
  491. package/dist/{status-2gZklYuj.mjs → status-vUK0SA17.mjs} +1 -1
  492. package/dist/{status-2gZklYuj.mjs.map → status-vUK0SA17.mjs.map} +1 -1
  493. package/dist/storage/local.d.mts +1 -1
  494. package/dist/storage/local.mjs +1 -1
  495. package/dist/storage/s3.d.mts +1 -1
  496. package/dist/storage/s3.mjs +1 -1
  497. package/dist/{taxonomies-DuESHWKI.mjs → taxonomies-BBB8O-CU.mjs} +7 -7
  498. package/dist/{taxonomies-DuESHWKI.mjs.map → taxonomies-BBB8O-CU.mjs.map} +1 -1
  499. package/dist/{taxonomies-BBxYA38v.mjs → taxonomies-Dxrc_szG.mjs} +177 -123
  500. package/dist/taxonomies-Dxrc_szG.mjs.map +1 -0
  501. package/dist/{taxonomy-CdllE4oq.mjs → taxonomy-B2HQuVf5.mjs} +19 -6
  502. package/dist/taxonomy-B2HQuVf5.mjs.map +1 -0
  503. package/dist/{tokens-DMkVjxrx.mjs → tokens-LeuXF9gG.mjs} +2 -2
  504. package/dist/{tokens-DMkVjxrx.mjs.map → tokens-LeuXF9gG.mjs.map} +1 -1
  505. package/dist/{transaction-x2tJQ-A1.mjs → transaction-qfqpPVpu.mjs} +1 -1
  506. package/dist/{transaction-x2tJQ-A1.mjs.map → transaction-qfqpPVpu.mjs.map} +1 -1
  507. package/dist/{transport-jdvsZEIt.d.mts → transport-BZ-03aFT.d.mts} +1 -1
  508. package/dist/{transport-jdvsZEIt.d.mts.map → transport-BZ-03aFT.d.mts.map} +1 -1
  509. package/dist/transport-_2nBz7e9.mjs +135 -0
  510. package/dist/transport-_2nBz7e9.mjs.map +1 -0
  511. package/dist/{trusted-proxy-CHp41Fjj.mjs → trusted-proxy-DZY5WCn2.mjs} +1 -1
  512. package/dist/{trusted-proxy-CHp41Fjj.mjs.map → trusted-proxy-DZY5WCn2.mjs.map} +1 -1
  513. package/dist/{types-Del0VMij.d.mts → types-B-gIxFCE.d.mts} +9 -1
  514. package/dist/{types-Del0VMij.d.mts.map → types-B-gIxFCE.d.mts.map} +1 -1
  515. package/dist/{types-DdkL6fyv.d.mts → types-BG8_XTLj.d.mts} +1 -1
  516. package/dist/{types-DdkL6fyv.d.mts.map → types-BG8_XTLj.d.mts.map} +1 -1
  517. package/dist/{types-BTnnBYVX.d.mts → types-BWh2MjmA.d.mts} +15 -2
  518. package/dist/types-BWh2MjmA.d.mts.map +1 -0
  519. package/dist/{types-CkEuk-Zr.d.mts → types-BWqGVhFn.d.mts} +1 -1
  520. package/dist/{types-CkEuk-Zr.d.mts.map → types-BWqGVhFn.d.mts.map} +1 -1
  521. package/dist/{types-DejCHqWT.mjs → types-CQAugunJ.mjs} +1 -1
  522. package/dist/{types-DejCHqWT.mjs.map → types-CQAugunJ.mjs.map} +1 -1
  523. package/dist/{types-Bzfk2yC8.d.mts → types-CTLJYMhN.d.mts} +1 -1
  524. package/dist/{types-Bzfk2yC8.d.mts.map → types-CTLJYMhN.d.mts.map} +1 -1
  525. package/dist/{types-BFgYtuKd.d.mts → types-CUsXGRVj.d.mts} +1 -1
  526. package/dist/{types-BFgYtuKd.d.mts.map → types-CUsXGRVj.d.mts.map} +1 -1
  527. package/dist/{types-BXSUSAjt.mjs → types-DXOIbece.mjs} +3 -3
  528. package/dist/types-DXOIbece.mjs.map +1 -0
  529. package/dist/{types-u_XxjbS8.d.mts → types-DrYMm9s5.d.mts} +1 -1
  530. package/dist/{types-u_XxjbS8.d.mts.map → types-DrYMm9s5.d.mts.map} +1 -1
  531. package/dist/{types-DO7whVYU.d.mts → types-TTx8uP7V.d.mts} +2 -2
  532. package/dist/{types-DO7whVYU.d.mts.map → types-TTx8uP7V.d.mts.map} +1 -1
  533. package/dist/types-fS7-VTdR.d.mts +124 -0
  534. package/dist/types-fS7-VTdR.d.mts.map +1 -0
  535. package/dist/{types-BIduXPJk.mjs → types-tM44hEcf.mjs} +1 -1
  536. package/dist/{types-BIduXPJk.mjs.map → types-tM44hEcf.mjs.map} +1 -1
  537. package/dist/{user-C0um7wrg.mjs → user-Db-Rti_z.mjs} +3 -3
  538. package/dist/{user-C0um7wrg.mjs.map → user-Db-Rti_z.mjs.map} +1 -1
  539. package/dist/{utils-C4M981Br.mjs → utils-B7A57fm9.mjs} +2 -2
  540. package/dist/{utils-C4M981Br.mjs.map → utils-B7A57fm9.mjs.map} +1 -1
  541. package/dist/{validate-DGhQPXzI.mjs → validate-0Utjspbs.mjs} +3 -3
  542. package/dist/{validate-DGhQPXzI.mjs.map → validate-0Utjspbs.mjs.map} +1 -1
  543. package/dist/{validate-cJOiOvT2.d.mts → validate-DOFrIb-c.d.mts} +5 -5
  544. package/dist/{validate-cJOiOvT2.d.mts.map → validate-DOFrIb-c.d.mts.map} +1 -1
  545. package/dist/{validation-DVHjPM1M.mjs → validation-D9EnzH1T.mjs} +6 -6
  546. package/dist/{validation-DVHjPM1M.mjs.map → validation-D9EnzH1T.mjs.map} +1 -1
  547. package/dist/version-BgVM_1MU.mjs +7 -0
  548. package/dist/{version-BOjj_cfz.mjs.map → version-BgVM_1MU.mjs.map} +1 -1
  549. package/dist/{widgets-Ci6hLwfO.mjs → widgets-BSTzPUYa.mjs} +4 -4
  550. package/dist/{widgets-Ci6hLwfO.mjs.map → widgets-BSTzPUYa.mjs.map} +1 -1
  551. package/dist/{zod-generator-CarzgPAu.mjs → zod-generator-ElVQOav7.mjs} +51 -15
  552. package/dist/zod-generator-ElVQOav7.mjs.map +1 -0
  553. package/package.json +19 -6
  554. package/src/api/handlers/api-tokens.ts +19 -0
  555. package/src/api/handlers/comment-reactions.ts +165 -0
  556. package/src/api/handlers/schema.ts +8 -0
  557. package/src/api/schemas/bylines.ts +8 -0
  558. package/src/api/schemas/comments.ts +10 -0
  559. package/src/astro/image-endpoint.ts +84 -0
  560. package/src/astro/index.ts +6 -0
  561. package/src/astro/integration/index.ts +83 -22
  562. package/src/astro/integration/routes.ts +5 -0
  563. package/src/astro/integration/runtime.ts +65 -1
  564. package/src/astro/integration/virtual-modules.ts +40 -0
  565. package/src/astro/integration/vite-config.ts +25 -1
  566. package/src/astro/middleware/auth.ts +4 -3
  567. package/src/astro/middleware/request-context.ts +6 -1
  568. package/src/astro/middleware/scoped-db.ts +131 -0
  569. package/src/astro/middleware/stream-end-metrics.ts +15 -9
  570. package/src/astro/middleware.ts +131 -31
  571. package/src/astro/object-cache/adapters.ts +50 -0
  572. package/src/astro/prefetch.ts +77 -0
  573. package/src/astro/routes/admin.astro +5 -1
  574. package/src/astro/routes/api/comments/[collection]/[contentId]/reactions.ts +97 -0
  575. package/src/astro/routes/api/schema/index.ts +9 -3
  576. package/src/astro/routes/api/setup/dev-bypass.ts +5 -1
  577. package/src/astro/routes/api/snapshot.ts +3 -1
  578. package/src/astro/session-user.ts +57 -0
  579. package/src/astro/types.ts +1 -0
  580. package/src/cli/commands/export-seed.ts +10 -7
  581. package/src/comments/query.ts +78 -7
  582. package/src/comments/ranking.ts +58 -0
  583. package/src/components/Block.astro +71 -0
  584. package/src/components/Comments.astro +136 -1
  585. package/src/components/EmDashMedia.astro +1 -2
  586. package/src/components/Image.astro +36 -2
  587. package/src/components/InlinePortableTextEditor.tsx +10 -2
  588. package/src/components/index.ts +5 -0
  589. package/src/components/portable-text-text-align.ts +38 -0
  590. package/src/content/converters/portable-text-to-prosemirror.ts +5 -1
  591. package/src/content/converters/prosemirror-to-portable-text.ts +8 -0
  592. package/src/content/converters/types.ts +1 -0
  593. package/src/database/instrumentation.ts +21 -1
  594. package/src/database/migrations/044_comment_reactions.ts +56 -0
  595. package/src/database/migrations/runner.ts +2 -0
  596. package/src/database/repositories/byline.ts +27 -0
  597. package/src/database/repositories/comment-reaction.ts +132 -0
  598. package/src/database/repositories/comment.ts +10 -0
  599. package/src/database/repositories/content.ts +25 -3
  600. package/src/database/repositories/menu.ts +13 -1
  601. package/src/database/repositories/seo.ts +3 -0
  602. package/src/database/repositories/taxonomy.ts +13 -1
  603. package/src/database/repositories/types.ts +13 -0
  604. package/src/database/types.ts +9 -0
  605. package/src/emdash-runtime.ts +244 -75
  606. package/src/index.ts +22 -0
  607. package/src/loader.ts +97 -5
  608. package/src/mcp/server.ts +307 -20
  609. package/src/media/image-endpoint.ts +167 -0
  610. package/src/media/local-runtime.ts +18 -5
  611. package/src/menus/index.ts +11 -4
  612. package/src/object-cache/codec.ts +73 -0
  613. package/src/object-cache/index.ts +495 -0
  614. package/src/object-cache/memory.ts +91 -0
  615. package/src/object-cache/types.ts +124 -0
  616. package/src/plugins/adapt-sandbox-entry.ts +11 -1
  617. package/src/plugins/context.ts +94 -22
  618. package/src/plugins/cron.ts +18 -2
  619. package/src/plugins/routes.ts +40 -1
  620. package/src/query.ts +304 -18
  621. package/src/schema/query.ts +11 -4
  622. package/src/schema/zod-generator.ts +53 -8
  623. package/src/settings/index.ts +18 -5
  624. package/src/taxonomies/index.ts +263 -165
  625. package/src/ui.ts +5 -0
  626. package/src/virtual-modules.d.ts +24 -0
  627. package/dist/api-DxjIV2o8.mjs.map +0 -1
  628. package/dist/api-tokens-BFFkB0jB.mjs.map +0 -1
  629. package/dist/byline-V_Qp1Ziw.mjs.map +0 -1
  630. package/dist/byline-fields-CQJRIQkn.d.mts.map +0 -1
  631. package/dist/comment-sqQxNpN3.mjs.map +0 -1
  632. package/dist/content-BIlVx-RX.mjs.map +0 -1
  633. package/dist/context-Cm4pt1Ws.mjs.map +0 -1
  634. package/dist/cron-DdEVrQ2Y.mjs.map +0 -1
  635. package/dist/index-D2VAiumu.d.mts.map +0 -1
  636. package/dist/init-lock-DlBHjf9-.mjs.map +0 -1
  637. package/dist/loader-BqWjcH3h.mjs.map +0 -1
  638. package/dist/menus-DX4_E01q.mjs.map +0 -1
  639. package/dist/menus-Ryk9L7fT.mjs.map +0 -1
  640. package/dist/query-Crm038Mc.mjs.map +0 -1
  641. package/dist/redirects-6Zg2SoYo.mjs.map +0 -1
  642. package/dist/runner--4wMWwKM.mjs.map +0 -1
  643. package/dist/schema-BDOkd3OU.mjs.map +0 -1
  644. package/dist/seo-DpNgGQjF.mjs.map +0 -1
  645. package/dist/settings-BjBsmVAo.mjs.map +0 -1
  646. package/dist/taxonomies-BBxYA38v.mjs.map +0 -1
  647. package/dist/taxonomy-CdllE4oq.mjs.map +0 -1
  648. package/dist/transport-1cIrOb1Y.mjs.map +0 -1
  649. package/dist/types-BTnnBYVX.d.mts.map +0 -1
  650. package/dist/types-BXSUSAjt.mjs.map +0 -1
  651. package/dist/version-BOjj_cfz.mjs +0 -7
  652. package/dist/zod-generator-CarzgPAu.mjs.map +0 -1
  653. /package/dist/{api-tokens-C7ywRx7l.mjs → api-tokens-B4BQybOp.mjs} +0 -0
  654. /package/dist/{ssrf-CRZGzjdL.mjs → ssrf-CcX9zvMK.mjs} +0 -0
  655. /package/dist/{types-BoRm8-pp.mjs → types-BvbeGEtr.mjs} +0 -0
@@ -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
  /**
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Object-cache serialization codec.
3
+ *
4
+ * Cached values are JSON, with one extension: `Date` instances are preserved
5
+ * across the round-trip. EmDash content entries carry `Date` objects for the
6
+ * system timestamp columns (`createdAt`, `updatedAt`, `publishedAt`,
7
+ * `scheduledAt`) and on `cacheHint.lastModified`; plain `JSON.stringify` would
8
+ * silently flatten those to ISO strings, so a value read from cache would no
9
+ * longer be `=== instanceof Date` and downstream `value instanceof Date`
10
+ * branches (cursor encoding, scheduled-visibility checks) would diverge from a
11
+ * fresh database read.
12
+ *
13
+ * Functions and symbol-keyed properties are NOT preserved — callers that cache
14
+ * values carrying either (e.g. content entries with their `.edit` proxy and
15
+ * the non-enumerable `CURSOR_RAW_VALUES` symbol) must reduce to a serializable
16
+ * snapshot before caching and rebuild the non-serializable parts on read. See
17
+ * `query.ts` content snapshot helpers.
18
+ */
19
+
20
+ /** Tag used to mark a serialized `Date`. Deliberately unlikely to collide. */
21
+ const DATE_TAG = "$$emdashDate";
22
+
23
+ interface TaggedDate {
24
+ [DATE_TAG]: string;
25
+ }
26
+
27
+ function isTaggedDate(value: unknown): value is TaggedDate {
28
+ if (typeof value !== "object" || value === null) return false;
29
+ // encode() always emits the tag as the object's *only* key, so requiring
30
+ // exactly one key keeps a user object that merely happens to carry a
31
+ // `$$emdashDate` string alongside other fields from being collapsed to a
32
+ // Date (which would silently drop those other fields).
33
+ const keys = Object.keys(value);
34
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- narrowing a JSON-parsed value to read the date tag
35
+ return keys.length === 1 && typeof (value as Record<string, unknown>)[DATE_TAG] === "string";
36
+ }
37
+
38
+ /**
39
+ * Serialize a value to a cache string, preserving `Date` instances.
40
+ *
41
+ * Uses the JSON replacer's `this` binding to inspect the *original* property
42
+ * value: `JSON.stringify` invokes `Date.prototype.toJSON` before the replacer
43
+ * sees it, so by the time `value` arrives it is already an ISO string. Reading
44
+ * `this[key]` recovers the live `Date` so we can tag it.
45
+ */
46
+ export function encode(value: unknown): string {
47
+ return JSON.stringify(value, function (this: Record<string, unknown>, key, val) {
48
+ const original = this[key];
49
+ if (original instanceof Date) {
50
+ return { [DATE_TAG]: original.toISOString() } satisfies TaggedDate;
51
+ }
52
+ return val;
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Parse a cache string produced by {@link encode}, rehydrating tagged `Date`s.
58
+ *
59
+ * Returns `undefined` if the input is not valid JSON (treated as a cache miss
60
+ * by the read-through layer rather than throwing).
61
+ */
62
+ export function decode(raw: string): unknown {
63
+ try {
64
+ return JSON.parse(raw, (_key, value) => {
65
+ if (isTaggedDate(value)) {
66
+ return new Date(value[DATE_TAG]);
67
+ }
68
+ return value;
69
+ });
70
+ } catch {
71
+ return undefined;
72
+ }
73
+ }
@@ -0,0 +1,495 @@
1
+ /**
2
+ * Object cache — distributed read-through query cache.
3
+ *
4
+ * Layering (per query):
5
+ *
6
+ * requestCached → in-request dedupe (per render, WeakMap on ALS context)
7
+ * cachedQuery → THIS layer: distributed L2 (KV / memory), epoch-keyed
8
+ * database → source of truth
9
+ *
10
+ * Optional and off by default: when no `objectCache` descriptor is configured,
11
+ * `virtual:emdash/object-cache` exports `createObjectCache = undefined`,
12
+ * {@link getBackend} resolves to `null`, and {@link cachedQuery} is a
13
+ * transparent passthrough to its `load` function. Configure with
14
+ * `memoryCache()` (Node) or `kvCache()` from `@emdash-cms/cloudflare`.
15
+ *
16
+ * Invalidation is epoch-based: each cache key embeds a per-namespace epoch
17
+ * ("last changed" marker) read from the backend. A write calls
18
+ * {@link invalidateObjectCache}, which stamps the namespace epoch to
19
+ * `Date.now()`; every previously-stored key for that namespace is instantly
20
+ * orphaned and reclaimed by its TTL. This is O(1) and needs no key
21
+ * enumeration (KV has no prefix delete).
22
+ *
23
+ * The singleton backend/config and the per-isolate epoch cache live on
24
+ * `globalThis` behind `Symbol.for` keys so Vite SSR chunk duplication can't
25
+ * fork them (same pattern as `request-context.ts`).
26
+ */
27
+
28
+ import { after } from "../after.js";
29
+ import { getRequestContext } from "../request-context.js";
30
+ import { decode, encode } from "./codec.js";
31
+ import type {
32
+ CreateObjectCacheBackendFn,
33
+ ObjectCacheBackend,
34
+ ObjectCacheRuntimeConfig,
35
+ } from "./types.js";
36
+
37
+ const DEFAULT_KEY_PREFIX = "em";
38
+ const DEFAULT_TTL_SECONDS = 3600;
39
+ const DEFAULT_REVALIDATE_MS = 1000;
40
+ const DEFAULT_TIMEOUT_MS = 2000;
41
+
42
+ interface BackendHolder {
43
+ /** Whether the virtual module has been loaded and the backend resolved. */
44
+ initialized: boolean;
45
+ /** Resolved backend, or `null` when no object cache is configured. */
46
+ backend: ObjectCacheBackend | null;
47
+ /** In-flight initialization promise (dedupes concurrent first calls). */
48
+ initPromise: Promise<ObjectCacheBackend | null> | null;
49
+ config: Required<Pick<ObjectCacheRuntimeConfig, "keyPrefix">> & {
50
+ defaultTtl: number;
51
+ revalidate: number;
52
+ timeout: number;
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Race a backend operation against a timeout so a stalled call (e.g. a KV read
58
+ * that never resolves *and* never rejects — a cold cross-region read, or one
59
+ * queued behind the Workers simultaneous-connection limit) degrades to a
60
+ * rejection instead of hanging the isolate. A rejection is benign: callers
61
+ * already treat a failed read as a cache miss / last-known epoch.
62
+ */
63
+ function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
64
+ if (!(ms > 0)) return promise;
65
+ let timer: ReturnType<typeof setTimeout>;
66
+ const timeout = new Promise<never>((_resolve, reject) => {
67
+ timer = setTimeout(() => {
68
+ reject(new Error(`object-cache ${label} timed out after ${ms}ms`));
69
+ }, ms);
70
+ });
71
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
72
+ }
73
+
74
+ interface EpochEntry {
75
+ value: number;
76
+ /** `Date.now()` at which this epoch was read from the backend. */
77
+ at: number;
78
+ /** In-flight read, so concurrent callers share one backend round-trip. */
79
+ promise?: Promise<number>;
80
+ }
81
+
82
+ const BACKEND_KEY = Symbol.for("emdash:object-cache:backend");
83
+ const EPOCH_KEY = Symbol.for("emdash:object-cache:epochs");
84
+ const PENDING_KEY = Symbol.for("emdash:object-cache:pending-bumps");
85
+ const g = globalThis as Record<symbol, unknown>;
86
+
87
+ const holder: BackendHolder =
88
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)
89
+ (g[BACKEND_KEY] as BackendHolder | undefined) ??
90
+ (() => {
91
+ const h: BackendHolder = {
92
+ initialized: false,
93
+ backend: null,
94
+ initPromise: null,
95
+ config: {
96
+ keyPrefix: DEFAULT_KEY_PREFIX,
97
+ defaultTtl: DEFAULT_TTL_SECONDS,
98
+ revalidate: DEFAULT_REVALIDATE_MS,
99
+ timeout: DEFAULT_TIMEOUT_MS,
100
+ },
101
+ };
102
+ g[BACKEND_KEY] = h;
103
+ return h;
104
+ })();
105
+
106
+ const epochCache: Map<string, EpochEntry> =
107
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)
108
+ (g[EPOCH_KEY] as Map<string, EpochEntry> | undefined) ??
109
+ (() => {
110
+ const m = new Map<string, EpochEntry>();
111
+ g[EPOCH_KEY] = m;
112
+ return m;
113
+ })();
114
+
115
+ /** Namespaces with a backend epoch write already scheduled this tick. */
116
+ const pendingBumps: Set<string> =
117
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)
118
+ (g[PENDING_KEY] as Set<string> | undefined) ??
119
+ (() => {
120
+ const s = new Set<string>();
121
+ g[PENDING_KEY] = s;
122
+ return s;
123
+ })();
124
+
125
+ /**
126
+ * Resolve (once per isolate) the configured object-cache backend.
127
+ *
128
+ * Loads `virtual:emdash/object-cache`, which exports `createObjectCache`
129
+ * (`undefined` when no cache is configured) and the serialized
130
+ * `objectCacheConfig`. Returns `null` when the cache is disabled.
131
+ */
132
+ async function getBackend(): Promise<ObjectCacheBackend | null> {
133
+ if (holder.initialized) return holder.backend;
134
+ if (holder.initPromise) return holder.initPromise;
135
+
136
+ holder.initPromise = (async () => {
137
+ try {
138
+ const mod: {
139
+ createObjectCache?: CreateObjectCacheBackendFn;
140
+ objectCacheConfig?: ObjectCacheRuntimeConfig;
141
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
142
+ // @ts-ignore - virtual module
143
+ } = await import("virtual:emdash/object-cache");
144
+
145
+ const config = mod.objectCacheConfig ?? {};
146
+ holder.config = {
147
+ keyPrefix:
148
+ typeof config.keyPrefix === "string" && config.keyPrefix.length > 0
149
+ ? config.keyPrefix
150
+ : DEFAULT_KEY_PREFIX,
151
+ defaultTtl:
152
+ typeof config.defaultTtl === "number" && config.defaultTtl > 0
153
+ ? config.defaultTtl
154
+ : DEFAULT_TTL_SECONDS,
155
+ revalidate:
156
+ typeof config.revalidate === "number" && config.revalidate >= 0
157
+ ? config.revalidate
158
+ : DEFAULT_REVALIDATE_MS,
159
+ timeout:
160
+ typeof config.timeout === "number" && config.timeout >= 0
161
+ ? config.timeout
162
+ : DEFAULT_TIMEOUT_MS,
163
+ };
164
+
165
+ holder.backend =
166
+ typeof mod.createObjectCache === "function" ? mod.createObjectCache(config) : null;
167
+ } catch (error) {
168
+ // Importing the virtual module fails outside an Astro/Vite context
169
+ // (e.g. unit tests, CLI). Treat as "no cache configured".
170
+ if (import.meta.env.DEV) {
171
+ console.warn("[object-cache] backend unavailable:", error);
172
+ }
173
+ holder.backend = null;
174
+ }
175
+ holder.initialized = true;
176
+ holder.initPromise = null;
177
+ return holder.backend;
178
+ })();
179
+
180
+ return holder.initPromise;
181
+ }
182
+
183
+ /**
184
+ * Test-only override of the backend, bypassing the virtual module.
185
+ *
186
+ * Lets unit tests inject an in-memory backend (and optional config) without a
187
+ * full Astro/Vite build. Pass `null` to simulate "no cache configured".
188
+ *
189
+ * @internal
190
+ */
191
+ export function __setObjectCacheBackendForTests(
192
+ backend: ObjectCacheBackend | null,
193
+ config?: Partial<BackendHolder["config"]>,
194
+ ): void {
195
+ holder.initialized = true;
196
+ holder.initPromise = null;
197
+ holder.backend = backend;
198
+ holder.config = { ...holder.config, ...config };
199
+ epochCache.clear();
200
+ }
201
+
202
+ /** Build the backend key for a namespace's epoch anchor. */
203
+ function epochKey(namespace: string): string {
204
+ return `${holder.config.keyPrefix}:epoch:${namespace}`;
205
+ }
206
+
207
+ /**
208
+ * Build the (epoch-independent) backend key for a cached value.
209
+ *
210
+ * The key is stable across invalidations — the namespace epochs are stored
211
+ * *inside* the value envelope and validated on read, not baked into the key.
212
+ * This lets the value and the epochs be fetched in one parallel round-trip
213
+ * (instead of "read epoch, then read value"), and means an invalidated value
214
+ * is overwritten in place rather than orphaned under a dead epoch-keyed name.
215
+ */
216
+ function valueKey(namespaces: readonly string[], key: string): string {
217
+ return `${holder.config.keyPrefix}:${namespaces.join(",")}:${key}`;
218
+ }
219
+
220
+ /**
221
+ * Stored cache envelope: the namespace epochs captured at write time alongside
222
+ * the cached value. A read is a HIT only when every stored epoch still matches
223
+ * the current epoch for its namespace.
224
+ */
225
+ interface CacheEnvelope<T> {
226
+ /** Epoch per namespace, in the query's namespace order. */
227
+ e: number[];
228
+ /** The cached value. */
229
+ v: T;
230
+ }
231
+
232
+ function epochsMatch(stored: readonly number[], current: readonly number[]): boolean {
233
+ if (stored.length !== current.length) return false;
234
+ for (let i = 0; i < stored.length; i++) {
235
+ if (stored[i] !== current[i]) return false;
236
+ }
237
+ return true;
238
+ }
239
+
240
+ /**
241
+ * Requests that must always read live data and never populate the cache:
242
+ * visual edit mode, preview tokens, and isolated databases (playground / DO
243
+ * preview, whose schema and content diverge from the configured site).
244
+ */
245
+ function shouldBypass(): boolean {
246
+ const ctx = getRequestContext();
247
+ if (!ctx) return false;
248
+ return ctx.editMode === true || ctx.preview !== undefined || ctx.dbIsIsolated === true;
249
+ }
250
+
251
+ /**
252
+ * Read the current epoch for `namespace`, reusing an isolate-cached value for
253
+ * up to `revalidate` ms. A missing epoch (never bumped) is treated as `0`.
254
+ *
255
+ * Backend errors and stalls are non-fatal: the read is bounded by a timeout,
256
+ * and on failure we fall back to the last known epoch (or `0`), so a flaky or
257
+ * hung cache degrades to "serve whatever's keyed" rather than throwing or
258
+ * hanging.
259
+ */
260
+ async function getEpoch(namespace: string, backend: ObjectCacheBackend): Promise<number> {
261
+ const now = Date.now();
262
+ const cached = epochCache.get(namespace);
263
+ if (cached && now - cached.at < holder.config.revalidate) {
264
+ return cached.value;
265
+ }
266
+ if (cached?.promise) return cached.promise;
267
+
268
+ const promise = (async () => {
269
+ let value: number;
270
+ try {
271
+ const raw = await withTimeout(
272
+ backend.get(epochKey(namespace)),
273
+ holder.config.timeout,
274
+ "epoch read",
275
+ );
276
+ const parsed = raw === null ? 0 : Number(raw);
277
+ value = Number.isFinite(parsed) ? parsed : 0;
278
+ } catch {
279
+ value = cached?.value ?? 0;
280
+ }
281
+ // A concurrent invalidateObjectCache may have bumped the epoch while this
282
+ // read was in flight. Epochs are monotonic, so never let a stale backend
283
+ // read lower a freshly-bumped local epoch — that would resurrect the very
284
+ // values the bump just invalidated.
285
+ const merged = Math.max(value, epochCache.get(namespace)?.value ?? 0);
286
+ epochCache.set(namespace, { value: merged, at: Date.now() });
287
+ return merged;
288
+ })();
289
+
290
+ // Concurrent callers share this in-flight read (dedup). The timeout above
291
+ // guarantees `promise` settles — its success/catch handler then replaces
292
+ // this entry with a fresh, promise-free one — so a stalled backend can no
293
+ // longer pin the namespace to a never-settling promise (the bug that
294
+ // poisoned an isolate until it was recycled).
295
+ epochCache.set(namespace, { value: cached?.value ?? 0, at: cached?.at ?? 0, promise });
296
+ return promise;
297
+ }
298
+
299
+ /** Options for {@link cachedQuery}. */
300
+ export interface CachedQueryOptions<T> {
301
+ /**
302
+ * Invalidation namespace(s). A single string for self-contained data
303
+ * (`settings`, `menus`), or several when the cached value depends on data
304
+ * owned by other namespaces — e.g. a content entry hydrates bylines and
305
+ * taxonomy terms, so it caches under
306
+ * `[content:posts, "bylines", "taxonomies"]` and is invalidated when *any*
307
+ * of them is bumped. Every namespace's epoch is folded into the key.
308
+ */
309
+ namespace: string | readonly string[];
310
+ /** Stable, fully-qualifying cache key *within* the namespace. */
311
+ key: string;
312
+ /** Loader run on a miss (or when caching is disabled/bypassed). */
313
+ load: () => Promise<T>;
314
+ /** TTL override in seconds. Falls back to the configured `defaultTtl`. */
315
+ ttl?: number;
316
+ /**
317
+ * Predicate gating whether a freshly-loaded value is stored. Defaults to
318
+ * always-cache. Use it to skip caching error/empty sentinels.
319
+ */
320
+ cacheable?: (value: T) => boolean;
321
+ }
322
+
323
+ /**
324
+ * Distributed read-through cache around `load`.
325
+ *
326
+ * `T` must be the value as it should be *stored* — i.e. JSON-serializable with
327
+ * the codec's `Date` support, carrying no functions or symbol-keyed props.
328
+ * Callers caching richer objects (content entries) reduce to a serializable
329
+ * snapshot here and rebuild on the way out; see `query.ts`.
330
+ *
331
+ * On a miss or when the cache is disabled/bypassed, this is equivalent to
332
+ * `await load()`. Backend errors never propagate: a failing `get` is a miss, a
333
+ * failing `set` is dropped.
334
+ */
335
+ export async function cachedQuery<T>(options: CachedQueryOptions<T>): Promise<T> {
336
+ const backend = await getBackend();
337
+ if (!backend || shouldBypass()) {
338
+ return options.load();
339
+ }
340
+
341
+ const namespaces =
342
+ typeof options.namespace === "string" ? [options.namespace] : options.namespace;
343
+ const fullKey = valueKey(namespaces, options.key);
344
+
345
+ // Kick off the value read and every namespace epoch read concurrently — one
346
+ // round-trip instead of "read epochs, then read value". getEpoch never
347
+ // rejects, so awaiting the epochs separately from the value read guarantees
348
+ // we hold the pre-load epochs even when the value read errors or times out.
349
+ // Storing a value under an epoch read *after* load() would mask a write that
350
+ // landed during load(): the stale value would match and be served as a HIT.
351
+ const epochsPromise = Promise.all(namespaces.map((ns) => getEpoch(ns, backend)));
352
+ const rawPromise = withTimeout(backend.get(fullKey), holder.config.timeout, "read").catch(
353
+ () => null,
354
+ );
355
+ const currentEpochs = await epochsPromise;
356
+ const raw = await rawPromise;
357
+ if (raw !== null) {
358
+ const decoded = decode(raw);
359
+ if (decoded !== undefined) {
360
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- value envelope written by this function
361
+ const envelope = decoded as CacheEnvelope<T>;
362
+ if (epochsMatch(envelope.e, currentEpochs)) {
363
+ return envelope.v;
364
+ }
365
+ }
366
+ }
367
+
368
+ const value = await options.load();
369
+
370
+ const cacheable = options.cacheable ? options.cacheable(value) : true;
371
+ if (cacheable) {
372
+ const ttl = options.ttl ?? holder.config.defaultTtl;
373
+ // Defer the write so it never adds to TTFB. The epochs were captured
374
+ // before load() ran, so a write that invalidated this namespace mid-load
375
+ // correctly orphans the value stored here.
376
+ after(async () => {
377
+ try {
378
+ const encoded = encode({ e: currentEpochs, v: value } satisfies CacheEnvelope<T>);
379
+ await backend.set(fullKey, encoded, ttl);
380
+ } catch (error) {
381
+ if (import.meta.env.DEV) {
382
+ console.warn("[object-cache] set failed:", error);
383
+ }
384
+ }
385
+ });
386
+ }
387
+
388
+ return value;
389
+ }
390
+
391
+ /**
392
+ * Invalidate every cached value in `namespace` by bumping its epoch.
393
+ *
394
+ * Sync and non-blocking: the local epoch is stamped immediately (so the
395
+ * writing isolate is instantly consistent) and the backend write is deferred
396
+ * via `after`. Other isolates pick up the new epoch within their `revalidate`
397
+ * window. No-ops when the cache is disabled.
398
+ */
399
+ export function invalidateObjectCache(namespace: string): void {
400
+ // Monotonic so two writes in the same millisecond still produce distinct
401
+ // epochs — otherwise the second write reuses the first's stamp and its
402
+ // stale entries survive.
403
+ const prev = epochCache.get(namespace)?.value ?? 0;
404
+ const stamp = Math.max(prev + 1, Date.now());
405
+ // Optimistic local bump: keep this isolate consistent without a round-trip.
406
+ epochCache.set(namespace, { value: stamp, at: stamp });
407
+
408
+ // Coalesce repeated bumps of the same namespace within a tick (e.g. a bulk
409
+ // publish loop) into a single backend write that persists the latest epoch.
410
+ if (pendingBumps.has(namespace)) return;
411
+ pendingBumps.add(namespace);
412
+ after(async () => {
413
+ pendingBumps.delete(namespace);
414
+ try {
415
+ const backend = await getBackend();
416
+ if (!backend) return;
417
+ const latest = epochCache.get(namespace)?.value ?? stamp;
418
+ // Epoch anchors are persistent (no TTL) — they must outlive the
419
+ // value keys they invalidate.
420
+ await backend.set(epochKey(namespace), String(latest));
421
+ } catch (error) {
422
+ console.error("[object-cache] epoch bump failed for", namespace, error);
423
+ }
424
+ });
425
+ }
426
+
427
+ /**
428
+ * Fixed namespaces for data shared across collections. Content reads fold the
429
+ * `BYLINES` and `TAXONOMIES` epochs into their keys (via {@link cachedQuery})
430
+ * because entries hydrate byline and taxonomy-term data — so renaming an
431
+ * author or a category correctly invalidates every cached entry that displays
432
+ * it, without tracking which collections reference it.
433
+ */
434
+ export const CacheNamespace = {
435
+ SETTINGS: "settings",
436
+ MENUS: "menus",
437
+ TAXONOMIES: "taxonomies",
438
+ BYLINES: "bylines",
439
+ /** Collection schema/metadata (label, supports, commentsEnabled, fields). */
440
+ SCHEMA: "schema",
441
+ /** Public (approved) comments. */
442
+ COMMENTS: "comments",
443
+ } as const;
444
+
445
+ /** Namespace for a content collection's cached queries. */
446
+ export function contentNamespace(collection: string): string {
447
+ return `content:${collection}`;
448
+ }
449
+
450
+ /**
451
+ * Namespaces a content read depends on: the collection itself plus the shared
452
+ * byline/taxonomy data folded into each entry.
453
+ */
454
+ export function contentNamespaces(collection: string): readonly string[] {
455
+ return [contentNamespace(collection), CacheNamespace.BYLINES, CacheNamespace.TAXONOMIES];
456
+ }
457
+
458
+ /**
459
+ * Invalidate all cached reads (list + entry) for a content collection.
460
+ * Call from every write path that mutates rows in `ec_<collection>`.
461
+ */
462
+ export function invalidateCollectionCache(collection: string): void {
463
+ invalidateObjectCache(contentNamespace(collection));
464
+ }
465
+
466
+ /** Invalidate cached taxonomy definitions/terms and all content that hydrates them. */
467
+ export function invalidateTaxonomyObjectCache(): void {
468
+ invalidateObjectCache(CacheNamespace.TAXONOMIES);
469
+ }
470
+
471
+ /** Invalidate cached bylines and all content that hydrates them. */
472
+ export function invalidateBylineObjectCache(): void {
473
+ invalidateObjectCache(CacheNamespace.BYLINES);
474
+ }
475
+
476
+ /** Invalidate cached navigation menus. */
477
+ export function invalidateMenuObjectCache(): void {
478
+ invalidateObjectCache(CacheNamespace.MENUS);
479
+ }
480
+
481
+ /** Invalidate cached collection schema/metadata reads (e.g. getCollectionInfo). */
482
+ export function invalidateSchemaObjectCache(): void {
483
+ invalidateObjectCache(CacheNamespace.SCHEMA);
484
+ }
485
+
486
+ /** Invalidate cached public comment reads. */
487
+ export function invalidateCommentObjectCache(): void {
488
+ invalidateObjectCache(CacheNamespace.COMMENTS);
489
+ }
490
+
491
+ export type {
492
+ ObjectCacheBackend,
493
+ ObjectCacheDescriptor,
494
+ ObjectCacheRuntimeConfig,
495
+ } from "./types.js";
@@ -0,0 +1,91 @@
1
+ /**
2
+ * In-isolate memory object-cache backend — RUNTIME ENTRY
3
+ *
4
+ * The default backend for the Node runtime and a sensible local-dev option.
5
+ * Caches across requests within a single isolate/process; it is NOT shared
6
+ * across isolates, so on a multi-isolate platform (Cloudflare) you want the KV
7
+ * backend instead. Still useful on Node, where one long-lived process serves
8
+ * every request.
9
+ *
10
+ * Wire it up with `memoryCache()` from `emdash`:
11
+ *
12
+ * ```ts
13
+ * import { memoryCache } from "emdash";
14
+ * emdash({ objectCache: memoryCache() });
15
+ * ```
16
+ *
17
+ * The store lives on `globalThis` behind a `Symbol.for` key so Vite SSR chunk
18
+ * duplication doesn't create two independent caches (same pattern as
19
+ * `request-context.ts`).
20
+ */
21
+
22
+ import type { CreateObjectCacheBackendFn, ObjectCacheBackend } from "./types.js";
23
+
24
+ interface Entry {
25
+ value: string;
26
+ /** Absolute expiry in ms (`Date.now()` epoch), or `null` for none. */
27
+ expiresAt: number | null;
28
+ }
29
+
30
+ interface MemoryStore {
31
+ map: Map<string, Entry>;
32
+ maxEntries: number;
33
+ }
34
+
35
+ const STORE_KEY = Symbol.for("emdash:object-cache:memory");
36
+ const g = globalThis as Record<symbol, unknown>;
37
+
38
+ function getStore(maxEntries: number): MemoryStore {
39
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-context.ts)
40
+ const existing = g[STORE_KEY] as MemoryStore | undefined;
41
+ if (existing) {
42
+ // First descriptor wins for sizing; later calls reuse the same map.
43
+ return existing;
44
+ }
45
+ const store: MemoryStore = { map: new Map(), maxEntries };
46
+ g[STORE_KEY] = store;
47
+ return store;
48
+ }
49
+
50
+ /**
51
+ * Create the in-isolate memory backend.
52
+ *
53
+ * Config keys (all optional):
54
+ * - `maxEntries` — soft cap on stored keys; oldest insertions are evicted
55
+ * first when exceeded (FIFO, cheap and good enough for a backstop). Default
56
+ * 1000.
57
+ */
58
+ export const createObjectCache: CreateObjectCacheBackendFn = (config): ObjectCacheBackend => {
59
+ const maxEntries = typeof config.maxEntries === "number" ? config.maxEntries : 1000;
60
+ const store = getStore(maxEntries);
61
+
62
+ return {
63
+ get(key: string): Promise<string | null> {
64
+ const entry = store.map.get(key);
65
+ if (!entry) return Promise.resolve(null);
66
+ if (entry.expiresAt !== null && entry.expiresAt <= Date.now()) {
67
+ store.map.delete(key);
68
+ return Promise.resolve(null);
69
+ }
70
+ return Promise.resolve(entry.value);
71
+ },
72
+ set(key: string, value: string, ttlSeconds?: number): Promise<void> {
73
+ // Refresh insertion order so recently-written keys survive eviction.
74
+ store.map.delete(key);
75
+ store.map.set(key, {
76
+ value,
77
+ expiresAt: ttlSeconds && ttlSeconds > 0 ? Date.now() + ttlSeconds * 1000 : null,
78
+ });
79
+ while (store.map.size > store.maxEntries) {
80
+ const oldest = store.map.keys().next().value;
81
+ if (oldest === undefined) break;
82
+ store.map.delete(oldest);
83
+ }
84
+ return Promise.resolve();
85
+ },
86
+ delete(key: string): Promise<void> {
87
+ store.map.delete(key);
88
+ return Promise.resolve();
89
+ },
90
+ };
91
+ };