emdash 0.24.1 → 0.26.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 (422) hide show
  1. package/dist/api/route-utils.d.mts +3 -3
  2. package/dist/api/route-utils.mjs +12 -11
  3. package/dist/api/route-utils.mjs.map +1 -1
  4. package/dist/api/schemas/index.d.mts +1 -1
  5. package/dist/api/schemas/index.mjs +2 -2
  6. package/dist/{api-d_0wi9fW.mjs → api-BMfveMoB.mjs} +24 -20
  7. package/dist/api-BMfveMoB.mjs.map +1 -0
  8. package/dist/{apply-BE9UaWX0.mjs → apply--IVNSdXn.mjs} +19 -16
  9. package/dist/apply--IVNSdXn.mjs.map +1 -0
  10. package/dist/astro/index.d.mts +9 -9
  11. package/dist/astro/index.mjs +3 -2
  12. package/dist/astro/index.mjs.map +1 -1
  13. package/dist/astro/middleware/auth.d.mts +8 -8
  14. package/dist/astro/middleware/auth.mjs +2 -2
  15. package/dist/astro/middleware/redirect.mjs +4 -4
  16. package/dist/astro/middleware.d.mts +1 -1
  17. package/dist/astro/middleware.d.mts.map +1 -1
  18. package/dist/astro/middleware.mjs +99 -70
  19. package/dist/astro/middleware.mjs.map +1 -1
  20. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  21. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  22. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
  23. package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
  24. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
  25. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +6 -6
  26. package/dist/astro/routes/api/admin/byline-fields/index.mjs +6 -6
  27. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +6 -6
  28. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +12 -12
  29. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +12 -12
  30. package/dist/astro/routes/api/admin/bylines/index.mjs +12 -12
  31. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
  32. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  33. package/dist/astro/routes/api/admin/comments/bulk.mjs +9 -9
  34. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  35. package/dist/astro/routes/api/admin/comments/index.mjs +9 -9
  36. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  37. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  38. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  39. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  40. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +31 -31
  41. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +31 -31
  42. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +31 -31
  43. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +31 -31
  44. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +31 -31
  45. package/dist/astro/routes/api/admin/plugins/index.mjs +31 -31
  46. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  47. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +31 -31
  48. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +31 -31
  49. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +31 -31
  50. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +31 -31
  51. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +32 -32
  52. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +31 -31
  53. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +32 -32
  54. package/dist/astro/routes/api/admin/plugins/updates.mjs +31 -31
  55. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +31 -31
  56. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  57. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +31 -31
  58. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  59. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  60. package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
  61. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  62. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  63. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  64. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  65. package/dist/astro/routes/api/auth/invite/complete.mjs +5 -5
  66. package/dist/astro/routes/api/auth/invite/index.mjs +5 -5
  67. package/dist/astro/routes/api/auth/invite/register-options.mjs +5 -5
  68. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  69. package/dist/astro/routes/api/auth/magic-link/send.mjs +6 -6
  70. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  71. package/dist/astro/routes/api/auth/me.mjs +6 -6
  72. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  73. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  74. package/dist/astro/routes/api/auth/passkey/options.mjs +6 -6
  75. package/dist/astro/routes/api/auth/passkey/register/options.mjs +5 -5
  76. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +5 -5
  77. package/dist/astro/routes/api/auth/passkey/verify.mjs +5 -5
  78. package/dist/astro/routes/api/auth/signup/complete.mjs +5 -5
  79. package/dist/astro/routes/api/auth/signup/request.mjs +6 -6
  80. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  81. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +9 -9
  82. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +9 -9
  83. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  84. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  85. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  86. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  87. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +6 -6
  88. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
  89. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  90. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  91. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
  92. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +11 -11
  93. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  94. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  95. package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -6
  96. package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
  97. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  98. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  99. package/dist/astro/routes/api/dashboard.mjs +8 -8
  100. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  101. package/dist/astro/routes/api/import/probe.d.mts +2 -2
  102. package/dist/astro/routes/api/import/probe.mjs +6 -6
  103. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  104. package/dist/astro/routes/api/import/wordpress/execute.d.mts +8 -8
  105. package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -9
  106. package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -1
  107. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  108. package/dist/astro/routes/api/import/wordpress/media.mjs +13 -9
  109. package/dist/astro/routes/api/import/wordpress/media.mjs.map +1 -1
  110. package/dist/astro/routes/api/import/wordpress/prepare.mjs +8 -8
  111. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
  112. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +6 -6
  113. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +9 -9
  114. package/dist/astro/routes/api/manifest.mjs +3 -3
  115. package/dist/astro/routes/api/mcp.mjs +36 -36
  116. package/dist/astro/routes/api/media/_id_/confirm.d.mts.map +1 -1
  117. package/dist/astro/routes/api/media/_id_/confirm.mjs +44 -8
  118. package/dist/astro/routes/api/media/_id_/confirm.mjs.map +1 -1
  119. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  120. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  121. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  122. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  123. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  124. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  125. package/dist/astro/routes/api/media.mjs +22 -21
  126. package/dist/astro/routes/api/media.mjs.map +1 -1
  127. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +8 -8
  128. package/dist/astro/routes/api/menus/_name_/items.mjs +8 -8
  129. package/dist/astro/routes/api/menus/_name_/reorder.mjs +8 -8
  130. package/dist/astro/routes/api/menus/_name_/translations.mjs +8 -8
  131. package/dist/astro/routes/api/menus/_name_.mjs +8 -8
  132. package/dist/astro/routes/api/menus/index.mjs +8 -8
  133. package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
  134. package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
  135. package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
  136. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  137. package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
  138. package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
  139. package/dist/astro/routes/api/oauth/token.mjs +2 -2
  140. package/dist/astro/routes/api/openapi.json.mjs +3 -3
  141. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
  142. package/dist/astro/routes/api/redirects/404s/index.mjs +8 -8
  143. package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
  144. package/dist/astro/routes/api/redirects/_id_.mjs +9 -9
  145. package/dist/astro/routes/api/redirects/index.mjs +9 -9
  146. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  147. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  148. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +31 -31
  149. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +31 -31
  150. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +31 -31
  151. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +31 -31
  152. package/dist/astro/routes/api/schema/collections/index.mjs +31 -31
  153. package/dist/astro/routes/api/schema/index.mjs +6 -6
  154. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +31 -31
  155. package/dist/astro/routes/api/schema/orphans/index.mjs +31 -31
  156. package/dist/astro/routes/api/search/enable.mjs +9 -9
  157. package/dist/astro/routes/api/search/index.mjs +8 -8
  158. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  159. package/dist/astro/routes/api/search/stats.mjs +6 -6
  160. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  161. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  162. package/dist/astro/routes/api/sections/index.mjs +8 -8
  163. package/dist/astro/routes/api/settings/email.mjs +4 -4
  164. package/dist/astro/routes/api/settings.mjs +11 -11
  165. package/dist/astro/routes/api/setup/admin-verify.mjs +5 -5
  166. package/dist/astro/routes/api/setup/admin.mjs +5 -5
  167. package/dist/astro/routes/api/setup/dev-bypass.mjs +17 -17
  168. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  169. package/dist/astro/routes/api/setup/index.mjs +20 -20
  170. package/dist/astro/routes/api/setup/status.mjs +3 -3
  171. package/dist/astro/routes/api/snapshot.mjs +3 -3
  172. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -11
  173. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -11
  174. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -11
  175. package/dist/astro/routes/api/taxonomies/index.mjs +11 -11
  176. package/dist/astro/routes/api/themes/preview.mjs +3 -3
  177. package/dist/astro/routes/api/typegen.mjs +5 -5
  178. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  179. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
  180. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
  181. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  182. package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
  183. package/dist/astro/routes/api/widget-components.mjs +2 -2
  184. package/dist/astro/routes/robots.txt.mjs +5 -5
  185. package/dist/astro/routes/sitemap-_collection_.xml.mjs +11 -10
  186. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  187. package/dist/astro/routes/sitemap.xml.mjs +6 -6
  188. package/dist/astro/types.d.mts +10 -10
  189. package/dist/{authorize-B__u-iZJ.mjs → authorize-BZnOGJFo.mjs} +2 -2
  190. package/dist/{authorize-B__u-iZJ.mjs.map → authorize-BZnOGJFo.mjs.map} +1 -1
  191. package/dist/{byline-C-YajfV7.mjs → byline-LL8lyqdb.mjs} +6 -6
  192. package/dist/{byline-C-YajfV7.mjs.map → byline-LL8lyqdb.mjs.map} +1 -1
  193. package/dist/{byline-fields-Ca56gaT6.d.mts → byline-fields-KD3JFRuH.d.mts} +24 -6
  194. package/dist/byline-fields-KD3JFRuH.d.mts.map +1 -0
  195. package/dist/{byline-fields-B-KXkg5R.mjs → byline-fields-eyJMblSr.mjs} +2 -2
  196. package/dist/{byline-fields-B-KXkg5R.mjs.map → byline-fields-eyJMblSr.mjs.map} +1 -1
  197. package/dist/{bylines-D4KADDAi.mjs → bylines-BmJ7Vg7J.mjs} +4 -4
  198. package/dist/{bylines-D4KADDAi.mjs.map → bylines-BmJ7Vg7J.mjs.map} +1 -1
  199. package/dist/{bylines-BMtJnPnG.mjs → bylines-DE47vP8d.mjs} +6 -6
  200. package/dist/{bylines-BMtJnPnG.mjs.map → bylines-DE47vP8d.mjs.map} +1 -1
  201. package/dist/{cache-BUJe2w6Z.mjs → cache-D9jF5bYw.mjs} +2 -2
  202. package/dist/{cache-BUJe2w6Z.mjs.map → cache-D9jF5bYw.mjs.map} +1 -1
  203. package/dist/{chunks-BHgcHh2C.mjs → chunks-OCG163rN.mjs} +2 -2
  204. package/dist/{chunks-BHgcHh2C.mjs.map → chunks-OCG163rN.mjs.map} +1 -1
  205. package/dist/cli/index.mjs +17 -17
  206. package/dist/{comment-BDx50EX5.mjs → comment-D9BLDpZI.mjs} +3 -3
  207. package/dist/{comment-BDx50EX5.mjs.map → comment-D9BLDpZI.mjs.map} +1 -1
  208. package/dist/{comment-reaction-Gv_pgfI3.mjs → comment-reaction-Drl9SkNu.mjs} +2 -2
  209. package/dist/{comment-reaction-Gv_pgfI3.mjs.map → comment-reaction-Drl9SkNu.mjs.map} +1 -1
  210. package/dist/{comments-CXHuQ6jI.mjs → comments-BjJ9SKGU.mjs} +3 -3
  211. package/dist/{comments-CXHuQ6jI.mjs.map → comments-BjJ9SKGU.mjs.map} +1 -1
  212. package/dist/{content-PoVGKjp0.mjs → content-ncUWWjna.mjs} +10 -8
  213. package/dist/content-ncUWWjna.mjs.map +1 -0
  214. package/dist/{context-Dvws41_A.mjs → context-C_g-iJVA.mjs} +14 -8
  215. package/dist/context-C_g-iJVA.mjs.map +1 -0
  216. package/dist/{dashboard-DsYU8JKS.mjs → dashboard-CotyqQrW.mjs} +4 -4
  217. package/dist/{dashboard-DsYU8JKS.mjs.map → dashboard-CotyqQrW.mjs.map} +1 -1
  218. package/dist/db/index.d.mts +2 -2
  219. package/dist/db/index.mjs +1 -1
  220. package/dist/{db-errors-UXB1CK42.mjs → db-errors-CK46D-ly.mjs} +1 -1
  221. package/dist/{db-errors-UXB1CK42.mjs.map → db-errors-CK46D-ly.mjs.map} +1 -1
  222. package/dist/{placeholder-B0s2mWu5.mjs → enrich-BQ0mxJRs.mjs} +61 -10
  223. package/dist/enrich-BQ0mxJRs.mjs.map +1 -0
  224. package/dist/{error-lq_fL-RS.mjs → error-rVGiqWDt.mjs} +3 -2
  225. package/dist/error-rVGiqWDt.mjs.map +1 -0
  226. package/dist/{field-defs-cache-CYYx8xlG.mjs → field-defs-cache-ljXzJCfc.mjs} +2 -2
  227. package/dist/{field-defs-cache-CYYx8xlG.mjs.map → field-defs-cache-ljXzJCfc.mjs.map} +1 -1
  228. package/dist/{fts-manager-DW_NR-Fs.mjs → fts-manager-BbCCbEKA.mjs} +2 -2
  229. package/dist/{fts-manager-DW_NR-Fs.mjs.map → fts-manager-BbCCbEKA.mjs.map} +1 -1
  230. package/dist/{index-BroXT-vD.d.mts → index-BRNabKrx.d.mts} +53 -15
  231. package/dist/index-BRNabKrx.d.mts.map +1 -0
  232. package/dist/{index-qbL02uhs.d.mts → index-Dt0OKJB4.d.mts} +2 -2
  233. package/dist/{index-qbL02uhs.d.mts.map → index-Dt0OKJB4.d.mts.map} +1 -1
  234. package/dist/index.d.mts +12 -12
  235. package/dist/index.mjs +43 -43
  236. package/dist/{load-DMFi4n1p.mjs → load-DMjXghbZ.mjs} +2 -2
  237. package/dist/{load-DMFi4n1p.mjs.map → load-DMjXghbZ.mjs.map} +1 -1
  238. package/dist/{loader-BR2SgfEc.mjs → loader-BA_zhkS_.mjs} +82 -19
  239. package/dist/loader-BA_zhkS_.mjs.map +1 -0
  240. package/dist/{manifest-schema-BWKnQYQF.mjs → manifest-schema-kPGX7VS-.mjs} +4 -1
  241. package/dist/manifest-schema-kPGX7VS-.mjs.map +1 -0
  242. package/dist/media/image-endpoint.mjs +1 -1
  243. package/dist/media/index.d.mts +45 -2
  244. package/dist/media/index.d.mts.map +1 -1
  245. package/dist/media/index.mjs +5 -3
  246. package/dist/media/index.mjs.map +1 -1
  247. package/dist/media/local-runtime.d.mts +9 -9
  248. package/dist/media/local-runtime.d.mts.map +1 -1
  249. package/dist/media/local-runtime.mjs +17 -5
  250. package/dist/media/local-runtime.mjs.map +1 -1
  251. package/dist/{media-CTjJoJTh.mjs → media-C5t_eCnk.mjs} +4 -2
  252. package/dist/media-C5t_eCnk.mjs.map +1 -0
  253. package/dist/{media-allowlist-B77I5_bw.mjs → media-allowlist-Du8t1u6a.mjs} +2 -2
  254. package/dist/{media-allowlist-B77I5_bw.mjs.map → media-allowlist-Du8t1u6a.mjs.map} +1 -1
  255. package/dist/{menus-8O6xNcYW.mjs → menus-CBb6UrMU.mjs} +3 -3
  256. package/dist/{menus-8O6xNcYW.mjs.map → menus-CBb6UrMU.mjs.map} +1 -1
  257. package/dist/{menus-GvRSpgIA.mjs → menus-CYH09a41.mjs} +65 -41
  258. package/dist/menus-CYH09a41.mjs.map +1 -0
  259. package/dist/{mime-BTzvzJ8M.mjs → mime-CCEzze7W.mjs} +1 -1
  260. package/dist/{mime-BTzvzJ8M.mjs.map → mime-CCEzze7W.mjs.map} +1 -1
  261. package/dist/{normalize-ClbNIenm.mjs → normalize-CeglrBT9.mjs} +11 -2
  262. package/dist/normalize-CeglrBT9.mjs.map +1 -0
  263. package/dist/{object-cache-SEb2IM4Z.mjs → object-cache-CHbHv83-.mjs} +8 -4
  264. package/dist/object-cache-CHbHv83-.mjs.map +1 -0
  265. package/dist/{options-CqECG0gM.d.mts → options-41nCWqi9.d.mts} +3 -3
  266. package/dist/{options-CqECG0gM.d.mts.map → options-41nCWqi9.d.mts.map} +1 -1
  267. package/dist/page/index.d.mts +5 -2
  268. package/dist/page/index.d.mts.map +1 -1
  269. package/dist/page/index.mjs +3 -2
  270. package/dist/page/index.mjs.map +1 -1
  271. package/dist/{parse-DHI873qU.mjs → parse-BwAdS7FZ.mjs} +2 -2
  272. package/dist/{parse-DHI873qU.mjs.map → parse-BwAdS7FZ.mjs.map} +1 -1
  273. package/dist/{placeholder-QoI4gEzP.d.mts → placeholder-Cuce9U-m.d.mts} +20 -5
  274. package/dist/placeholder-Cuce9U-m.d.mts.map +1 -0
  275. package/dist/plugin-types.d.mts +5 -2
  276. package/dist/plugin-types.d.mts.map +1 -1
  277. package/dist/plugin-utils.d.mts +8 -8
  278. package/dist/plugins/adapt-sandbox-entry.d.mts +8 -8
  279. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  280. package/dist/{query-DZdlS6Cu.mjs → query-BpQb-blG.mjs} +15 -15
  281. package/dist/{query-DZdlS6Cu.mjs.map → query-BpQb-blG.mjs.map} +1 -1
  282. package/dist/{rate-limit-D1Y6VFVP.mjs → rate-limit-Dap6HMNM.mjs} +2 -2
  283. package/dist/{rate-limit-D1Y6VFVP.mjs.map → rate-limit-Dap6HMNM.mjs.map} +1 -1
  284. package/dist/{redirect-C1KVGYWe.mjs → redirect-_M0trWoo.mjs} +2 -2
  285. package/dist/{redirect-C1KVGYWe.mjs.map → redirect-_M0trWoo.mjs.map} +1 -1
  286. package/dist/{redirects-x9eFPeyi.mjs → redirects-Dcbuisoj.mjs} +2 -1
  287. package/dist/redirects-Dcbuisoj.mjs.map +1 -0
  288. package/dist/{redirects-DgnypVir.mjs → redirects-w0V9vj_j.mjs} +3 -3
  289. package/dist/{redirects-DgnypVir.mjs.map → redirects-w0V9vj_j.mjs.map} +1 -1
  290. package/dist/{registry-CJkCubOJ.mjs → registry-g8yYt4cC.mjs} +14 -4
  291. package/dist/registry-g8yYt4cC.mjs.map +1 -0
  292. package/dist/{runner-CEtq-6Sm.d.mts → runner-BbR3DfrL.d.mts} +2 -2
  293. package/dist/{runner-CEtq-6Sm.d.mts.map → runner-BbR3DfrL.d.mts.map} +1 -1
  294. package/dist/{runner-BsquExlK.mjs → runner-DPdt_Wpa.mjs} +250 -178
  295. package/dist/runner-DPdt_Wpa.mjs.map +1 -0
  296. package/dist/runtime.d.mts +9 -9
  297. package/dist/runtime.mjs +2 -2
  298. package/dist/{schema-DMjXuvNU.mjs → schema-DoLd3j2e.mjs} +5 -5
  299. package/dist/{schema-DMjXuvNU.mjs.map → schema-DoLd3j2e.mjs.map} +1 -1
  300. package/dist/{search-D1wKk3lc.mjs → search-BR0ZeZmh.mjs} +4 -4
  301. package/dist/{search-D1wKk3lc.mjs.map → search-BR0ZeZmh.mjs.map} +1 -1
  302. package/dist/{sections-CCMic8dB.mjs → sections-5J2YJPqJ.mjs} +3 -3
  303. package/dist/{sections-CCMic8dB.mjs.map → sections-5J2YJPqJ.mjs.map} +1 -1
  304. package/dist/seed/index.d.mts +2 -2
  305. package/dist/seed/index.mjs +15 -15
  306. package/dist/seo/index.d.mts +1 -1
  307. package/dist/{seo-DCEF-AVr.mjs → seo-BkhuuaaE.mjs} +25 -3
  308. package/dist/seo-BkhuuaaE.mjs.map +1 -0
  309. package/dist/{seo-3QrZ1EPT.mjs → seo-DKeXHkzE.mjs} +3 -3
  310. package/dist/{seo-3QrZ1EPT.mjs.map → seo-DKeXHkzE.mjs.map} +1 -1
  311. package/dist/{service-CQHK_10l.mjs → service-BbO2s8gT.mjs} +2 -2
  312. package/dist/{service-CQHK_10l.mjs.map → service-BbO2s8gT.mjs.map} +1 -1
  313. package/dist/{settings-C3Yi5Co3.mjs → settings-BMNr9Dmi.mjs} +3 -3
  314. package/dist/{settings-C3Yi5Co3.mjs.map → settings-BMNr9Dmi.mjs.map} +1 -1
  315. package/dist/{settings-D9rvaLuY.mjs → settings-DJeki-97.mjs} +4 -4
  316. package/dist/{settings-D9rvaLuY.mjs.map → settings-DJeki-97.mjs.map} +1 -1
  317. package/dist/{taxonomies-DhLaNJji.mjs → taxonomies-CM_fUqLU.mjs} +5 -4
  318. package/dist/taxonomies-CM_fUqLU.mjs.map +1 -0
  319. package/dist/{taxonomies-CurpLtNC.mjs → taxonomies-D13i2ctt.mjs} +76 -21
  320. package/dist/taxonomies-D13i2ctt.mjs.map +1 -0
  321. package/dist/{taxonomy-BBUlGug5.mjs → taxonomy-BU0LjdVb.mjs} +4 -4
  322. package/dist/{taxonomy-BBUlGug5.mjs.map → taxonomy-BU0LjdVb.mjs.map} +1 -1
  323. package/dist/{types-TTx8uP7V.d.mts → types-BYnDBVwe.d.mts} +27 -5
  324. package/dist/{types-TTx8uP7V.d.mts.map → types-BYnDBVwe.d.mts.map} +1 -1
  325. package/dist/{types-CTLJYMhN.d.mts → types-CNlaBFzx.d.mts} +11 -1
  326. package/dist/{types-CTLJYMhN.d.mts.map → types-CNlaBFzx.d.mts.map} +1 -1
  327. package/dist/{types-CmI1OyQg.mjs → types-CZgK3EMW.mjs} +2 -2
  328. package/dist/{types-CmI1OyQg.mjs.map → types-CZgK3EMW.mjs.map} +1 -1
  329. package/dist/{types-BWh2MjmA.d.mts → types-ETmO_jQr.d.mts} +2 -2
  330. package/dist/{types-BWh2MjmA.d.mts.map → types-ETmO_jQr.d.mts.map} +1 -1
  331. package/dist/types-tM44hEcf.mjs.map +1 -1
  332. package/dist/{types-B-gIxFCE.d.mts → types-xIfVRNLp.d.mts} +38 -1
  333. package/dist/types-xIfVRNLp.d.mts.map +1 -0
  334. package/dist/{user-JAuc8VUf.mjs → user-DkG2jKCp.mjs} +3 -3
  335. package/dist/{user-JAuc8VUf.mjs.map → user-DkG2jKCp.mjs.map} +1 -1
  336. package/dist/{validate-DOFrIb-c.d.mts → validate-CG0V0wNR.d.mts} +3 -3
  337. package/dist/{validate-DOFrIb-c.d.mts.map → validate-CG0V0wNR.d.mts.map} +1 -1
  338. package/dist/{validate-BzXHWnkV.mjs → validate-CuJ1Ps9j.mjs} +2 -2
  339. package/dist/{validate-BzXHWnkV.mjs.map → validate-CuJ1Ps9j.mjs.map} +1 -1
  340. package/dist/{validation-CY1gk4Ar.mjs → validation-CwUfTdGF.mjs} +6 -6
  341. package/dist/{validation-CY1gk4Ar.mjs.map → validation-CwUfTdGF.mjs.map} +1 -1
  342. package/dist/version-BoNBItP_.mjs +7 -0
  343. package/dist/{version-C0JPFUG8.mjs.map → version-BoNBItP_.mjs.map} +1 -1
  344. package/dist/{widgets-Dri0spI4.mjs → widgets-BfOZ-ajY.mjs} +2 -2
  345. package/dist/{widgets-Dri0spI4.mjs.map → widgets-BfOZ-ajY.mjs.map} +1 -1
  346. package/dist/{zod-generator-xEHODMJf.mjs → zod-generator-gFsRuNNy.mjs} +6 -3
  347. package/dist/zod-generator-gFsRuNNy.mjs.map +1 -0
  348. package/package.json +6 -6
  349. package/src/api/errors.ts +1 -0
  350. package/src/api/handlers/content.ts +4 -4
  351. package/src/api/handlers/seo.ts +30 -2
  352. package/src/api/handlers/taxonomies.ts +5 -1
  353. package/src/api/schemas/schema.ts +1 -0
  354. package/src/astro/integration/virtual-modules.ts +15 -0
  355. package/src/astro/middleware.ts +14 -1
  356. package/src/astro/routes/api/import/wordpress/media.ts +9 -3
  357. package/src/astro/routes/api/media/[id]/confirm.ts +62 -2
  358. package/src/astro/routes/api/media.ts +17 -19
  359. package/src/astro/routes/sitemap-[collection].xml.ts +5 -4
  360. package/src/components/EmDashHead.astro +23 -3
  361. package/src/components/EmDashImage.astro +4 -7
  362. package/src/components/Image.astro +14 -4
  363. package/src/components/InlinePortableTextEditor.tsx +48 -1
  364. package/src/components/JsonLdScript.astro +9 -0
  365. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +16 -0
  366. package/src/database/migrations/046_media_usage_index.ts +115 -0
  367. package/src/database/migrations/047_restore_taxonomy_parent_index.ts +29 -0
  368. package/src/database/migrations/runner.ts +4 -0
  369. package/src/database/repositories/content.ts +8 -5
  370. package/src/database/repositories/media-usage.ts +444 -0
  371. package/src/database/repositories/media.ts +9 -1
  372. package/src/database/types.ts +39 -0
  373. package/src/emdash-runtime.ts +72 -25
  374. package/src/index.ts +3 -0
  375. package/src/loader.ts +110 -31
  376. package/src/media/enrich.ts +78 -0
  377. package/src/media/index.ts +1 -0
  378. package/src/media/local-runtime.ts +19 -0
  379. package/src/media/normalize.ts +20 -1
  380. package/src/media/placeholder.ts +29 -9
  381. package/src/media/types.ts +14 -0
  382. package/src/media/usage/extractor.ts +302 -0
  383. package/src/media/usage/types.ts +46 -0
  384. package/src/object-cache/index.ts +8 -2
  385. package/src/page/metadata.ts +23 -3
  386. package/src/plugin-types.ts +12 -0
  387. package/src/plugins/context.ts +8 -0
  388. package/src/plugins/define-plugin.ts +14 -5
  389. package/src/plugins/hooks.ts +66 -33
  390. package/src/plugins/index.ts +6 -0
  391. package/src/plugins/manager.ts +33 -0
  392. package/src/plugins/manifest-schema.ts +3 -0
  393. package/src/plugins/types.ts +41 -2
  394. package/src/schema/registry.ts +25 -0
  395. package/src/schema/types.ts +10 -0
  396. package/src/schema/zod-generator.ts +9 -1
  397. package/src/seed/apply.ts +7 -0
  398. package/src/taxonomies/index.ts +121 -18
  399. package/dist/api-d_0wi9fW.mjs.map +0 -1
  400. package/dist/apply-BE9UaWX0.mjs.map +0 -1
  401. package/dist/byline-fields-Ca56gaT6.d.mts.map +0 -1
  402. package/dist/content-PoVGKjp0.mjs.map +0 -1
  403. package/dist/context-Dvws41_A.mjs.map +0 -1
  404. package/dist/error-lq_fL-RS.mjs.map +0 -1
  405. package/dist/index-BroXT-vD.d.mts.map +0 -1
  406. package/dist/loader-BR2SgfEc.mjs.map +0 -1
  407. package/dist/manifest-schema-BWKnQYQF.mjs.map +0 -1
  408. package/dist/media-CTjJoJTh.mjs.map +0 -1
  409. package/dist/menus-GvRSpgIA.mjs.map +0 -1
  410. package/dist/normalize-ClbNIenm.mjs.map +0 -1
  411. package/dist/object-cache-SEb2IM4Z.mjs.map +0 -1
  412. package/dist/placeholder-B0s2mWu5.mjs.map +0 -1
  413. package/dist/placeholder-QoI4gEzP.d.mts.map +0 -1
  414. package/dist/redirects-x9eFPeyi.mjs.map +0 -1
  415. package/dist/registry-CJkCubOJ.mjs.map +0 -1
  416. package/dist/runner-BsquExlK.mjs.map +0 -1
  417. package/dist/seo-DCEF-AVr.mjs.map +0 -1
  418. package/dist/taxonomies-CurpLtNC.mjs.map +0 -1
  419. package/dist/taxonomies-DhLaNJji.mjs.map +0 -1
  420. package/dist/types-B-gIxFCE.d.mts.map +0 -1
  421. package/dist/version-C0JPFUG8.mjs +0 -7
  422. package/dist/zod-generator-xEHODMJf.mjs.map +0 -1
@@ -17,7 +17,7 @@ import type {
17
17
  PluginContext,
18
18
  ContentHookEvent,
19
19
  ContentDeleteEvent,
20
- ContentPublishStateChangeEvent,
20
+ ContentStateChangeEvent,
21
21
  MediaUploadEvent,
22
22
  MediaAfterUploadEvent,
23
23
  LifecycleEvent,
@@ -32,7 +32,10 @@ import type {
32
32
  ContentBeforeDeleteHandler,
33
33
  ContentAfterDeleteHandler,
34
34
  ContentAfterPublishHandler,
35
+ ContentAfterRestoreHandler,
36
+ ContentAfterScheduleHandler,
35
37
  ContentAfterUnpublishHandler,
38
+ ContentAfterUnscheduleHandler,
36
39
  MediaBeforeUploadHandler,
37
40
  MediaAfterUploadHandler,
38
41
  LifecycleHandler,
@@ -66,6 +69,9 @@ type HookNameV2 =
66
69
  | "content:afterDelete"
67
70
  | "content:afterPublish"
68
71
  | "content:afterUnpublish"
72
+ | "content:afterRestore"
73
+ | "content:afterSchedule"
74
+ | "content:afterUnschedule"
69
75
  | "media:beforeUpload"
70
76
  | "media:afterUpload"
71
77
  | "cron"
@@ -82,6 +88,13 @@ type HookNameV2 =
82
88
  /**
83
89
  * Map from hook name to handler type — used for type-safe hook retrieval
84
90
  */
91
+ type ContentStateChangeHookName =
92
+ | "content:afterPublish"
93
+ | "content:afterUnpublish"
94
+ | "content:afterRestore"
95
+ | "content:afterSchedule"
96
+ | "content:afterUnschedule";
97
+
85
98
  interface HookHandlerMap {
86
99
  "plugin:install": LifecycleHandler;
87
100
  "plugin:activate": LifecycleHandler;
@@ -93,6 +106,9 @@ interface HookHandlerMap {
93
106
  "content:afterDelete": ContentAfterDeleteHandler;
94
107
  "content:afterPublish": ContentAfterPublishHandler;
95
108
  "content:afterUnpublish": ContentAfterUnpublishHandler;
109
+ "content:afterRestore": ContentAfterRestoreHandler;
110
+ "content:afterSchedule": ContentAfterScheduleHandler;
111
+ "content:afterUnschedule": ContentAfterUnscheduleHandler;
96
112
  "media:beforeUpload": MediaBeforeUploadHandler;
97
113
  "media:afterUpload": MediaAfterUploadHandler;
98
114
  cron: CronHandler;
@@ -220,6 +236,9 @@ export class HookPipeline {
220
236
  this.registerPluginHook(plugin, "content:afterDelete");
221
237
  this.registerPluginHook(plugin, "content:afterPublish");
222
238
  this.registerPluginHook(plugin, "content:afterUnpublish");
239
+ this.registerPluginHook(plugin, "content:afterRestore");
240
+ this.registerPluginHook(plugin, "content:afterSchedule");
241
+ this.registerPluginHook(plugin, "content:afterUnschedule");
223
242
  this.registerPluginHook(plugin, "media:beforeUpload");
224
243
  this.registerPluginHook(plugin, "media:afterUpload");
225
244
  this.registerPluginHook(plugin, "cron");
@@ -264,6 +283,9 @@ export class HookPipeline {
264
283
  ["content:afterDelete", "content:read"],
265
284
  ["content:afterPublish", "content:read"],
266
285
  ["content:afterUnpublish", "content:read"],
286
+ ["content:afterRestore", "content:read"],
287
+ ["content:afterSchedule", "content:read"],
288
+ ["content:afterUnschedule", "content:read"],
267
289
  // Media
268
290
  ["media:beforeUpload", "media:write"],
269
291
  ["media:afterUpload", "media:read"],
@@ -648,18 +670,19 @@ export class HookPipeline {
648
670
  }
649
671
 
650
672
  /**
651
- * Run content:afterPublish hooks (fire-and-forget).
673
+ * Run content state-change hooks that all share the same event shape.
652
674
  */
653
- async runContentAfterPublish(
675
+ private async runContentStateChangeHook(
676
+ name: ContentStateChangeHookName,
654
677
  content: Record<string, unknown>,
655
678
  collection: string,
656
679
  ): Promise<HookResult<void>[]> {
657
- const hooks = this.getTypedHooks("content:afterPublish");
680
+ const hooks = this.getTypedHooks(name);
658
681
  const results: HookResult<void>[] = [];
659
682
 
660
683
  for (const hook of hooks) {
661
684
  const { handler } = hook;
662
- const event: ContentPublishStateChangeEvent = { content, collection };
685
+ const event: ContentStateChangeEvent = { content, collection };
663
686
  const ctx = this.getContext(hook.pluginId);
664
687
  const start = Date.now();
665
688
 
@@ -687,6 +710,16 @@ export class HookPipeline {
687
710
  return results;
688
711
  }
689
712
 
713
+ /**
714
+ * Run content:afterPublish hooks (fire-and-forget).
715
+ */
716
+ async runContentAfterPublish(
717
+ content: Record<string, unknown>,
718
+ collection: string,
719
+ ): Promise<HookResult<void>[]> {
720
+ return this.runContentStateChangeHook("content:afterPublish", content, collection);
721
+ }
722
+
690
723
  /**
691
724
  * Run content:afterUnpublish hooks (fire-and-forget).
692
725
  */
@@ -694,37 +727,37 @@ export class HookPipeline {
694
727
  content: Record<string, unknown>,
695
728
  collection: string,
696
729
  ): Promise<HookResult<void>[]> {
697
- const hooks = this.getTypedHooks("content:afterUnpublish");
698
- const results: HookResult<void>[] = [];
699
-
700
- for (const hook of hooks) {
701
- const { handler } = hook;
702
- const event: ContentPublishStateChangeEvent = { content, collection };
703
- const ctx = this.getContext(hook.pluginId);
704
- const start = Date.now();
730
+ return this.runContentStateChangeHook("content:afterUnpublish", content, collection);
731
+ }
705
732
 
706
- try {
707
- await this.executeWithTimeout(() => handler(event, ctx), hook.timeout);
708
- results.push({
709
- success: true,
710
- pluginId: hook.pluginId,
711
- duration: Date.now() - start,
712
- });
713
- } catch (error) {
714
- results.push({
715
- success: false,
716
- error: error instanceof Error ? error : new Error(String(error)),
717
- pluginId: hook.pluginId,
718
- duration: Date.now() - start,
719
- });
733
+ /**
734
+ * Run content:afterRestore hooks (fire-and-forget).
735
+ */
736
+ async runContentAfterRestore(
737
+ content: Record<string, unknown>,
738
+ collection: string,
739
+ ): Promise<HookResult<void>[]> {
740
+ return this.runContentStateChangeHook("content:afterRestore", content, collection);
741
+ }
720
742
 
721
- if (hook.errorPolicy === "abort") {
722
- throw error;
723
- }
724
- }
725
- }
743
+ /**
744
+ * Run content:afterSchedule hooks (fire-and-forget).
745
+ */
746
+ async runContentAfterSchedule(
747
+ content: Record<string, unknown>,
748
+ collection: string,
749
+ ): Promise<HookResult<void>[]> {
750
+ return this.runContentStateChangeHook("content:afterSchedule", content, collection);
751
+ }
726
752
 
727
- return results;
753
+ /**
754
+ * Run content:afterUnschedule hooks (fire-and-forget).
755
+ */
756
+ async runContentAfterUnschedule(
757
+ content: Record<string, unknown>,
758
+ collection: string,
759
+ ): Promise<HookResult<void>[]> {
760
+ return this.runContentStateChangeHook("content:afterUnschedule", content, collection);
728
761
  }
729
762
 
730
763
  // =========================================================================
@@ -128,6 +128,9 @@ export type {
128
128
  ContentHookEvent,
129
129
  ContentDeleteEvent,
130
130
  ContentPublishStateChangeEvent,
131
+ ContentRestoreStateChangeEvent,
132
+ ContentScheduleStateChangeEvent,
133
+ ContentStateChangeEvent,
131
134
  MediaUploadEvent,
132
135
  MediaAfterUploadEvent,
133
136
  LifecycleEvent,
@@ -148,6 +151,9 @@ export type {
148
151
  ContentAfterSaveHandler,
149
152
  ContentBeforeDeleteHandler,
150
153
  ContentAfterDeleteHandler,
154
+ ContentAfterRestoreHandler,
155
+ ContentAfterScheduleHandler,
156
+ ContentAfterUnscheduleHandler,
151
157
  MediaBeforeUploadHandler,
152
158
  MediaAfterUploadHandler,
153
159
  LifecycleHandler,
@@ -370,6 +370,39 @@ export class PluginManager {
370
370
  return this.hookPipeline!.runContentAfterUnpublish(content, collection);
371
371
  }
372
372
 
373
+ /**
374
+ * Run content:afterRestore hooks across all active plugins
375
+ */
376
+ async runContentAfterRestore(
377
+ content: Record<string, unknown>,
378
+ collection: string,
379
+ ): Promise<HookResult<void>[]> {
380
+ this.ensureInitialized();
381
+ return this.hookPipeline!.runContentAfterRestore(content, collection);
382
+ }
383
+
384
+ /**
385
+ * Run content:afterSchedule hooks across all active plugins
386
+ */
387
+ async runContentAfterSchedule(
388
+ content: Record<string, unknown>,
389
+ collection: string,
390
+ ): Promise<HookResult<void>[]> {
391
+ this.ensureInitialized();
392
+ return this.hookPipeline!.runContentAfterSchedule(content, collection);
393
+ }
394
+
395
+ /**
396
+ * Run content:afterUnschedule hooks across all active plugins
397
+ */
398
+ async runContentAfterUnschedule(
399
+ content: Record<string, unknown>,
400
+ collection: string,
401
+ ): Promise<HookResult<void>[]> {
402
+ this.ensureInitialized();
403
+ return this.hookPipeline!.runContentAfterUnschedule(content, collection);
404
+ }
405
+
373
406
  /**
374
407
  * Run media:beforeUpload hooks across all active plugins
375
408
  */
@@ -97,6 +97,9 @@ export const HOOK_NAMES = [
97
97
  "content:afterDelete",
98
98
  "content:afterPublish",
99
99
  "content:afterUnpublish",
100
+ "content:afterRestore",
101
+ "content:afterSchedule",
102
+ "content:afterUnschedule",
100
103
  "media:beforeUpload",
101
104
  "media:afterUpload",
102
105
  "cron",
@@ -725,13 +725,29 @@ export interface ContentDeleteEvent {
725
725
  }
726
726
 
727
727
  /**
728
- * Content publish state change hook event (fired after publish or unpublish)
728
+ * Content state-change hook event (fired after publish, unpublish, restore,
729
+ * schedule, or unschedule).
729
730
  */
730
- export interface ContentPublishStateChangeEvent {
731
+ export interface ContentStateChangeEvent {
731
732
  content: Record<string, unknown>;
732
733
  collection: string;
733
734
  }
734
735
 
736
+ /**
737
+ * Content publish/unpublish hook event.
738
+ */
739
+ export type ContentPublishStateChangeEvent = ContentStateChangeEvent;
740
+
741
+ /**
742
+ * Content restore hook event.
743
+ */
744
+ export type ContentRestoreStateChangeEvent = ContentStateChangeEvent;
745
+
746
+ /**
747
+ * Content schedule/unschedule hook event.
748
+ */
749
+ export type ContentScheduleStateChangeEvent = ContentStateChangeEvent;
750
+
735
751
  /**
736
752
  * Media hook event
737
753
  */
@@ -791,6 +807,21 @@ export type ContentAfterUnpublishHandler = (
791
807
  ctx: PluginContext,
792
808
  ) => Promise<void>;
793
809
 
810
+ export type ContentAfterRestoreHandler = (
811
+ event: ContentRestoreStateChangeEvent,
812
+ ctx: PluginContext,
813
+ ) => Promise<void>;
814
+
815
+ export type ContentAfterScheduleHandler = (
816
+ event: ContentScheduleStateChangeEvent,
817
+ ctx: PluginContext,
818
+ ) => Promise<void>;
819
+
820
+ export type ContentAfterUnscheduleHandler = (
821
+ event: ContentScheduleStateChangeEvent,
822
+ ctx: PluginContext,
823
+ ) => Promise<void>;
824
+
794
825
  export type MediaBeforeUploadHandler = (
795
826
  event: MediaUploadEvent,
796
827
  ctx: PluginContext,
@@ -976,6 +1007,11 @@ export interface PluginHooks {
976
1007
  "content:afterUnpublish"?:
977
1008
  | HookConfig<ContentAfterUnpublishHandler>
978
1009
  | ContentAfterUnpublishHandler;
1010
+ "content:afterRestore"?: HookConfig<ContentAfterRestoreHandler> | ContentAfterRestoreHandler;
1011
+ "content:afterSchedule"?: HookConfig<ContentAfterScheduleHandler> | ContentAfterScheduleHandler;
1012
+ "content:afterUnschedule"?:
1013
+ | HookConfig<ContentAfterUnscheduleHandler>
1014
+ | ContentAfterUnscheduleHandler;
979
1015
 
980
1016
  // Media hooks
981
1017
  "media:beforeUpload"?: HookConfig<MediaBeforeUploadHandler> | MediaBeforeUploadHandler;
@@ -1295,6 +1331,9 @@ export interface ResolvedPluginHooks {
1295
1331
  "content:afterDelete"?: ResolvedHook<ContentAfterDeleteHandler>;
1296
1332
  "content:afterPublish"?: ResolvedHook<ContentAfterPublishHandler>;
1297
1333
  "content:afterUnpublish"?: ResolvedHook<ContentAfterUnpublishHandler>;
1334
+ "content:afterRestore"?: ResolvedHook<ContentAfterRestoreHandler>;
1335
+ "content:afterSchedule"?: ResolvedHook<ContentAfterScheduleHandler>;
1336
+ "content:afterUnschedule"?: ResolvedHook<ContentAfterUnscheduleHandler>;
1298
1337
  "media:beforeUpload"?: ResolvedHook<MediaBeforeUploadHandler>;
1299
1338
  "media:afterUpload"?: ResolvedHook<MediaAfterUploadHandler>;
1300
1339
  cron?: ResolvedHook<CronHandler>;
@@ -530,10 +530,35 @@ export class SchemaRegistry {
530
530
  // an explicit `null` clears the column.
531
531
  const nextValidation = input.validation === undefined ? field.validation : input.validation;
532
532
 
533
+ // A field-type change is only safe when the underlying column type stays
534
+ // the same. There is no in-place column migration (only addColumn/
535
+ // dropColumn), so a change that would alter the SQLite column affinity
536
+ // (e.g. `text` TEXT -> `portableText` JSON) is rejected rather than
537
+ // silently rewriting only the metadata — which would leave `column_type`
538
+ // pointing at a column type the real `ec_*` column doesn't have (#1397).
539
+ let nextType = field.type;
540
+ let nextColumnType = field.columnType;
541
+ if (input.type !== undefined && input.type !== field.type) {
542
+ const newColumnType = FIELD_TYPE_TO_COLUMN[input.type];
543
+ if (newColumnType !== field.columnType) {
544
+ throw new SchemaError(
545
+ `Cannot change field "${fieldSlug}" in collection "${collectionSlug}" from type ` +
546
+ `"${field.type}" to "${input.type}": the underlying column type would change from ` +
547
+ `${field.columnType} to ${newColumnType}, which requires a manual content migration. ` +
548
+ `Drop and re-create the field, or migrate the column data, before changing its type.`,
549
+ "FIELD_TYPE_COLUMN_CHANGE",
550
+ );
551
+ }
552
+ nextType = input.type;
553
+ nextColumnType = newColumnType;
554
+ }
555
+
533
556
  return withTransaction(this.db, async (trx) => {
534
557
  await trx
535
558
  .updateTable("_emdash_fields")
536
559
  .set({
560
+ type: nextType,
561
+ column_type: nextColumnType,
537
562
  label: input.label ?? field.label,
538
563
  required:
539
564
  input.required !== undefined ? (input.required ? 1 : 0) : field.required ? 1 : 0,
@@ -264,6 +264,16 @@ export interface CreateFieldInput {
264
264
  */
265
265
  export interface UpdateFieldInput {
266
266
  label?: string;
267
+ /**
268
+ * Change the field's type. Only type changes that keep the same underlying
269
+ * column type (per `FIELD_TYPE_TO_COLUMN`) are allowed — e.g. `string` to
270
+ * `slug` (both TEXT). A change that would alter the column affinity (e.g.
271
+ * `text` TEXT to `portableText` JSON) is rejected, because there is no
272
+ * in-place column migration and silently rewriting the metadata would
273
+ * desync `column_type` from the real `ec_*` column. Omit to keep the
274
+ * current type.
275
+ */
276
+ type?: FieldType;
267
277
  required?: boolean;
268
278
  unique?: boolean;
269
279
  defaultValue?: unknown;
@@ -86,7 +86,15 @@ function getBaseSchema(type: FieldType, field: Field): ZodTypeAny {
86
86
  return z.preprocess((v) => (v === 0 || v === 1 ? Boolean(v) : v), z.boolean());
87
87
 
88
88
  case "datetime":
89
- return z.string().datetime().or(z.string().date());
89
+ // Accept every value that legitimately round-trips through the admin
90
+ // and seeds: ISO with `Z`, ISO with a timezone offset, a naive
91
+ // datetime (`YYYY-MM-DDTHH:mm[:ss]` -- what `<input type="datetime-local">`
92
+ // and many seeds produce), and a date-only value. The admin re-sends
93
+ // every loaded field on autosave, so a stored naive datetime must
94
+ // validate or the entry becomes unsavable through its own editor
95
+ // (#1368; same class as #867). `z.iso.*` retains semantic validation,
96
+ // so impossible dates are still rejected.
97
+ return z.iso.datetime({ offset: true, local: true }).or(z.iso.date());
90
98
 
91
99
  case "select": {
92
100
  const options = field.validation?.options;
package/src/seed/apply.ts CHANGED
@@ -159,6 +159,7 @@ export async function applySeed(
159
159
  if (existingField) {
160
160
  await registry.updateField(collection.slug, field.slug, {
161
161
  label: field.label,
162
+ type: field.type,
162
163
  required: field.required || false,
163
164
  unique: field.unique || false,
164
165
  searchable: field.searchable || false,
@@ -345,6 +346,12 @@ export async function applySeed(
345
346
  }
346
347
  }
347
348
  }
349
+
350
+ // Seeded/updated defs change which taxonomies exist — clear the
351
+ // isolate-wide defs + names caches so later reads in this isolate
352
+ // (e.g. an auto-seed triggered mid-request) reflect them immediately.
353
+ const { invalidateTaxonomyDefsCache } = await import("../taxonomies/index.js");
354
+ invalidateTaxonomyDefsCache();
348
355
  }
349
356
 
350
357
  // 6. Bylines
@@ -12,14 +12,16 @@
12
12
  */
13
13
 
14
14
  import { resolveLocale, resolveLocaleChain } from "../i18n/resolve.js";
15
- import { getDb } from "../loader.js";
15
+ import { getDb, resetTaxonomyNamesCache } from "../loader.js";
16
16
  import {
17
17
  cachedQuery,
18
18
  CacheNamespace,
19
19
  contentNamespace,
20
20
  invalidateTaxonomyObjectCache,
21
+ isObjectCacheActive,
21
22
  } from "../object-cache/index.js";
22
23
  import { peekRequestCache, requestCached, setRequestCacheEntry } from "../request-cache.js";
24
+ import { getRequestContext } from "../request-context.js";
23
25
  import { chunks, SQL_BATCH_SIZE } from "../utils/chunks.js";
24
26
  import { isMissingTableError } from "../utils/db-errors.js";
25
27
  import type { TaxonomyDef, TaxonomyTerm, TaxonomyTermRow } from "./types.js";
@@ -28,35 +30,136 @@ export interface TaxonomyQueryOptions {
28
30
  locale?: string;
29
31
  }
30
32
 
33
+ /** Invalidate cached taxonomy term data and any content that hydrates terms. */
34
+ export function invalidateTermCache(): void {
35
+ invalidateTaxonomyObjectCache();
36
+ }
37
+
31
38
  /**
32
- * Invalidate cached taxonomy data in the distributed object cache (and any
33
- * content that hydrates taxonomy terms). The legacy in-isolate term cache was
34
- * removed, so this used to be a no-op; it now drives object-cache invalidation.
39
+ * Worker-isolate cache for taxonomy definitions, keyed by resolved locale.
40
+ *
41
+ * Taxonomy *definitions* (the "category"/"tag" taxonomies themselves, not
42
+ * their terms) are read on every public render that hydrates entry terms —
43
+ * `getAllTermsForEntries` → `getCollectionTaxonomyNames` → `getTaxonomyDefs` —
44
+ * but change extremely rarely: they're created via the admin API or applied
45
+ * from a seed, and there is no edit/delete-def path. Caching them across the
46
+ * isolate lifetime drops the per-render `SELECT * FROM _emdash_taxonomy_defs`
47
+ * to once-per-isolate.
48
+ *
49
+ * Stored on globalThis behind a Symbol key (same pattern as
50
+ * `settings/index.ts`) so the bundler duplicating this module across SSR
51
+ * chunks can't produce two independent caches.
52
+ *
53
+ * When the distributed object cache is configured, it is authoritative and this
54
+ * fallback is bypassed so cross-isolate epoch invalidation cannot be undercut
55
+ * by stale per-isolate data on an object-cache miss.
56
+ *
57
+ * **Isolated databases bypass the cache.** Playground / DO preview requests
58
+ * set `requestContext.dbIsIsolated`; they point at a divergent schema, so we
59
+ * skip both reading and writing the global holder and fall back to the
60
+ * per-request cache (same precedent as `getTaxonomyNames` / byline field defs).
35
61
  */
36
- export function invalidateTermCache(): void {
62
+ interface TaxonomyDefsHolder {
63
+ version: number;
64
+ /** locale key ("*" for "all locales") → { version it was fetched at, promise }. */
65
+ cache: Map<string, { version: number; promise: Promise<TaxonomyDef[]> }>;
66
+ }
67
+
68
+ const TAXONOMY_DEFS_CACHE_KEY = Symbol.for("emdash:taxonomy-defs");
69
+ const taxonomyDefsStore = globalThis as Record<symbol, unknown>;
70
+ const defsHolder: TaxonomyDefsHolder =
71
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see settings/index.ts)
72
+ (taxonomyDefsStore[TAXONOMY_DEFS_CACHE_KEY] as TaxonomyDefsHolder | undefined) ??
73
+ (() => {
74
+ const h: TaxonomyDefsHolder = { version: 0, cache: new Map() };
75
+ taxonomyDefsStore[TAXONOMY_DEFS_CACHE_KEY] = h;
76
+ return h;
77
+ })();
78
+
79
+ /**
80
+ * Invalidate the isolate-wide taxonomy-definitions cache (and the related
81
+ * loader taxonomy-names cache). Called from every taxonomy-def write path
82
+ * (`handleTaxonomyCreate`, seed application). Other isolates refresh on their
83
+ * next recycle — staleness bounded by isolate lifetime.
84
+ */
85
+ export function invalidateTaxonomyDefsCache(): void {
86
+ defsHolder.version++;
87
+ defsHolder.cache.clear();
88
+ resetTaxonomyNamesCache();
37
89
  invalidateTaxonomyObjectCache();
38
90
  }
39
91
 
92
+ /**
93
+ * Test/internal helper: clear the per-isolate taxonomy-defs cache. Useful for
94
+ * unit tests that insert defs directly and need to force a refetch without
95
+ * going through a write path. Production code should rely on
96
+ * `invalidateTaxonomyDefsCache()`.
97
+ */
98
+ export function resetTaxonomyDefsCacheForTests(): void {
99
+ defsHolder.version++;
100
+ defsHolder.cache.clear();
101
+ }
102
+
103
+ /**
104
+ * Fetch taxonomy definitions straight from the database (no caching).
105
+ */
106
+ async function fetchTaxonomyDefs(locale: string | undefined): Promise<TaxonomyDef[]> {
107
+ const db = await getDb();
108
+ let query = db.selectFrom("_emdash_taxonomy_defs").selectAll();
109
+ if (locale !== undefined) query = query.where("locale", "=", locale);
110
+ const rows = await query.execute();
111
+ return rows.map(rowToTaxonomyDef);
112
+ }
113
+
114
+ /**
115
+ * Resolve taxonomy defs through the isolate fallback cache, bypassing it for
116
+ * isolated databases. The returned promise is cached (not the resolved value)
117
+ * so concurrent cold-isolate readers share one in-flight query; a rejection
118
+ * evicts the entry so the next caller retries.
119
+ */
120
+ function loadTaxonomyDefs(localeKey: string, locale: string | undefined): Promise<TaxonomyDef[]> {
121
+ if (getRequestContext()?.dbIsIsolated === true) {
122
+ return fetchTaxonomyDefs(locale);
123
+ }
124
+ const existing = defsHolder.cache.get(localeKey);
125
+ if (existing && existing.version === defsHolder.version) {
126
+ return existing.promise;
127
+ }
128
+ const version = defsHolder.version;
129
+ const promise = fetchTaxonomyDefs(locale).catch((error: unknown) => {
130
+ const current = defsHolder.cache.get(localeKey);
131
+ if (current && current.promise === promise) {
132
+ defsHolder.cache.delete(localeKey);
133
+ }
134
+ throw error;
135
+ });
136
+ defsHolder.cache.set(localeKey, { version, promise });
137
+ return promise;
138
+ }
139
+
40
140
  /**
41
141
  * Get every taxonomy definition. Definitions are per-locale (one row per
42
142
  * locale inside the same translation_group) — by default we resolve to the
43
143
  * active locale.
144
+ *
145
+ * Two-tier cache: per-request via `requestCached` (so a single render that
146
+ * hydrates terms for several collections pays at most one call), then
147
+ * per-isolate via the global holder (so warm renders issue zero queries).
148
+ * The `requestCached` key is unchanged so `getTaxonomyDef`'s peek still hits.
44
149
  */
45
150
  export async function getTaxonomyDefs(options: TaxonomyQueryOptions = {}): Promise<TaxonomyDef[]> {
46
151
  const locale = resolveLocale(options.locale);
47
- return requestCached(`taxonomy-defs:${locale ?? "*"}`, () =>
48
- cachedQuery({
49
- namespace: CacheNamespace.TAXONOMIES,
50
- key: `defs:${locale ?? "*"}`,
51
- load: async () => {
52
- const db = await getDb();
53
- let query = db.selectFrom("_emdash_taxonomy_defs").selectAll();
54
- if (locale !== undefined) query = query.where("locale", "=", locale);
55
- const rows = await query.execute();
56
- return rows.map(rowToTaxonomyDef);
57
- },
58
- }),
59
- );
152
+ const localeKey = locale ?? "*";
153
+ return requestCached(`taxonomy-defs:${localeKey}`, async () => {
154
+ if (await isObjectCacheActive()) {
155
+ return cachedQuery({
156
+ namespace: CacheNamespace.TAXONOMIES,
157
+ key: `defs:${localeKey}`,
158
+ load: () => fetchTaxonomyDefs(locale),
159
+ });
160
+ }
161
+ return loadTaxonomyDefs(localeKey, locale);
162
+ });
60
163
  }
61
164
 
62
165
  /**