emdash 0.25.1 → 0.27.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 (418) hide show
  1. package/dist/{adapters-DAAjOID4.d.mts → adapters-u037EnTR.d.mts} +1 -1
  2. package/dist/{adapters-DAAjOID4.d.mts.map → adapters-u037EnTR.d.mts.map} +1 -1
  3. package/dist/api/route-utils.d.mts +3 -3
  4. package/dist/api/route-utils.mjs +11 -11
  5. package/dist/api/schemas/index.d.mts +1 -1
  6. package/dist/{api-D2_sbavn.mjs → api-80kycR9o.mjs} +86 -30
  7. package/dist/api-80kycR9o.mjs.map +1 -0
  8. package/dist/{apply-Bk2mAuLn.mjs → apply-DSypk6Iu.mjs} +20 -18
  9. package/dist/apply-DSypk6Iu.mjs.map +1 -0
  10. package/dist/astro/index.d.mts +11 -10
  11. package/dist/astro/index.d.mts.map +1 -1
  12. package/dist/astro/index.mjs +12 -3
  13. package/dist/astro/index.mjs.map +1 -1
  14. package/dist/astro/middleware/auth.d.mts +10 -9
  15. package/dist/astro/middleware/auth.d.mts.map +1 -1
  16. package/dist/astro/middleware/auth.mjs +4 -3
  17. package/dist/astro/middleware/auth.mjs.map +1 -1
  18. package/dist/astro/middleware/redirect.mjs +4 -4
  19. package/dist/astro/middleware.d.mts +2 -9
  20. package/dist/astro/middleware.d.mts.map +1 -1
  21. package/dist/astro/middleware.mjs +86 -85
  22. package/dist/astro/middleware.mjs.map +1 -1
  23. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +3 -3
  24. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +3 -3
  25. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
  26. package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
  27. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
  28. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +4 -4
  29. package/dist/astro/routes/api/admin/byline-fields/index.mjs +4 -4
  30. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +4 -4
  31. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +10 -10
  32. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +10 -10
  33. package/dist/astro/routes/api/admin/bylines/index.mjs +10 -10
  34. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +8 -8
  35. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  36. package/dist/astro/routes/api/admin/comments/bulk.mjs +7 -7
  37. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  38. package/dist/astro/routes/api/admin/comments/index.mjs +7 -7
  39. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  40. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  41. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  42. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  43. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +29 -29
  44. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  45. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +29 -29
  46. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  47. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +29 -29
  48. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  49. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +28 -28
  50. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +28 -28
  51. package/dist/astro/routes/api/admin/plugins/index.mjs +29 -29
  52. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  54. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +28 -28
  55. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +28 -28
  56. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +28 -28
  57. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +28 -28
  58. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +29 -29
  59. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +28 -28
  60. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +29 -29
  61. package/dist/astro/routes/api/admin/plugins/updates.mjs +28 -28
  62. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +28 -28
  63. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  64. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +28 -28
  65. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  66. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  67. package/dist/astro/routes/api/admin/users/_id_/index.mjs +3 -3
  68. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  69. package/dist/astro/routes/api/admin/users/index.mjs +3 -3
  70. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  71. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  72. package/dist/astro/routes/api/auth/invite/complete.mjs +3 -3
  73. package/dist/astro/routes/api/auth/invite/index.mjs +3 -3
  74. package/dist/astro/routes/api/auth/invite/register-options.mjs +3 -3
  75. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  76. package/dist/astro/routes/api/auth/magic-link/send.mjs +4 -4
  77. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  78. package/dist/astro/routes/api/auth/me.mjs +4 -4
  79. package/dist/astro/routes/api/auth/passkey/_id_.mjs +3 -3
  80. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  81. package/dist/astro/routes/api/auth/passkey/options.mjs +4 -4
  82. package/dist/astro/routes/api/auth/passkey/register/options.mjs +3 -3
  83. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +3 -3
  84. package/dist/astro/routes/api/auth/passkey/verify.mjs +3 -3
  85. package/dist/astro/routes/api/auth/signup/complete.mjs +3 -3
  86. package/dist/astro/routes/api/auth/signup/request.mjs +4 -4
  87. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  88. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +7 -7
  89. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +7 -7
  90. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  91. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  92. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  93. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  94. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +4 -4
  95. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +4 -4
  96. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  97. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  98. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +4 -4
  99. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +9 -9
  100. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  101. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  102. package/dist/astro/routes/api/content/_collection_/_id_.mjs +4 -4
  103. package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
  104. package/dist/astro/routes/api/content/_collection_/index.mjs +4 -4
  105. package/dist/astro/routes/api/content/_collection_/trash.mjs +4 -4
  106. package/dist/astro/routes/api/dashboard.mjs +8 -8
  107. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  108. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  109. package/dist/astro/routes/api/import/probe.mjs +4 -4
  110. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  111. package/dist/astro/routes/api/import/wordpress/execute.d.mts +10 -9
  112. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  113. package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -9
  114. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -9
  115. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  116. package/dist/astro/routes/api/import/wordpress/media.mjs +4 -4
  117. package/dist/astro/routes/api/import/wordpress/prepare.mjs +6 -6
  118. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +5 -5
  119. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  120. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +4 -4
  121. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  122. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +7 -7
  123. package/dist/astro/routes/api/manifest.d.mts.map +1 -1
  124. package/dist/astro/routes/api/manifest.mjs +13 -4
  125. package/dist/astro/routes/api/manifest.mjs.map +1 -1
  126. package/dist/astro/routes/api/mcp.mjs +34 -34
  127. package/dist/astro/routes/api/media/_id_/confirm.mjs +4 -4
  128. package/dist/astro/routes/api/media/_id_.mjs +4 -4
  129. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  130. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  131. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  132. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  133. package/dist/astro/routes/api/media/upload-url.mjs +4 -4
  134. package/dist/astro/routes/api/media.mjs +5 -5
  135. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +6 -6
  136. package/dist/astro/routes/api/menus/_name_/items.mjs +6 -6
  137. package/dist/astro/routes/api/menus/_name_/reorder.mjs +6 -6
  138. package/dist/astro/routes/api/menus/_name_/translations.mjs +6 -6
  139. package/dist/astro/routes/api/menus/_name_.mjs +6 -6
  140. package/dist/astro/routes/api/menus/index.mjs +6 -6
  141. package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
  142. package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
  143. package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
  144. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  145. package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
  146. package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
  147. package/dist/astro/routes/api/oauth/token.mjs +2 -2
  148. package/dist/astro/routes/api/openapi.json.mjs +2 -2
  149. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
  150. package/dist/astro/routes/api/redirects/404s/index.mjs +6 -6
  151. package/dist/astro/routes/api/redirects/404s/summary.mjs +6 -6
  152. package/dist/astro/routes/api/redirects/_id_.mjs +7 -7
  153. package/dist/astro/routes/api/redirects/index.mjs +7 -7
  154. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  155. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  156. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +28 -28
  157. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +28 -28
  158. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +28 -28
  159. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +28 -28
  160. package/dist/astro/routes/api/schema/collections/index.mjs +28 -28
  161. package/dist/astro/routes/api/schema/index.mjs +6 -6
  162. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +28 -28
  163. package/dist/astro/routes/api/schema/orphans/index.mjs +28 -28
  164. package/dist/astro/routes/api/search/enable.mjs +7 -7
  165. package/dist/astro/routes/api/search/index.mjs +6 -6
  166. package/dist/astro/routes/api/search/rebuild.mjs +7 -7
  167. package/dist/astro/routes/api/search/stats.mjs +6 -6
  168. package/dist/astro/routes/api/search/suggest.mjs +6 -6
  169. package/dist/astro/routes/api/sections/_slug_.mjs +6 -6
  170. package/dist/astro/routes/api/sections/index.mjs +6 -6
  171. package/dist/astro/routes/api/settings/email.mjs +4 -4
  172. package/dist/astro/routes/api/settings.mjs +9 -9
  173. package/dist/astro/routes/api/setup/admin-verify.mjs +3 -3
  174. package/dist/astro/routes/api/setup/admin.mjs +3 -3
  175. package/dist/astro/routes/api/setup/dev-bypass.d.mts.map +1 -1
  176. package/dist/astro/routes/api/setup/dev-bypass.mjs +20 -18
  177. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  178. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  179. package/dist/astro/routes/api/setup/index.mjs +18 -18
  180. package/dist/astro/routes/api/setup/status.mjs +3 -3
  181. package/dist/astro/routes/api/snapshot.mjs +3 -3
  182. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +9 -9
  183. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +9 -9
  184. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +9 -9
  185. package/dist/astro/routes/api/taxonomies/index.mjs +9 -9
  186. package/dist/astro/routes/api/themes/preview.mjs +3 -3
  187. package/dist/astro/routes/api/typegen.mjs +5 -5
  188. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +4 -4
  189. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +6 -6
  190. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +6 -6
  191. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  192. package/dist/astro/routes/api/widget-areas/index.mjs +6 -6
  193. package/dist/astro/routes/api/widget-components.mjs +2 -2
  194. package/dist/astro/routes/robots.txt.mjs +5 -5
  195. package/dist/astro/routes/sitemap-_collection_.xml.mjs +10 -9
  196. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  197. package/dist/astro/routes/sitemap.xml.mjs +5 -5
  198. package/dist/astro/types.d.mts +12 -10
  199. package/dist/astro/types.d.mts.map +1 -1
  200. package/dist/auth/providers/github.d.mts +1 -1
  201. package/dist/auth/providers/google.d.mts +1 -1
  202. package/dist/{authorize-CuxZ0i2t.mjs → authorize-C3a_zGsM.mjs} +2 -2
  203. package/dist/{authorize-CuxZ0i2t.mjs.map → authorize-C3a_zGsM.mjs.map} +1 -1
  204. package/dist/{byline-C-YajfV7.mjs → byline-DEKSVPTy.mjs} +6 -6
  205. package/dist/{byline-C-YajfV7.mjs.map → byline-DEKSVPTy.mjs.map} +1 -1
  206. package/dist/{byline-fields-KD3JFRuH.d.mts → byline-fields-CtQ6blXd.d.mts} +32 -32
  207. package/dist/{byline-fields-KD3JFRuH.d.mts.map → byline-fields-CtQ6blXd.d.mts.map} +1 -1
  208. package/dist/{bylines-CPc_q2Vd.mjs → bylines-CiqgTHWF.mjs} +5 -5
  209. package/dist/{bylines-CPc_q2Vd.mjs.map → bylines-CiqgTHWF.mjs.map} +1 -1
  210. package/dist/{bylines-D4KADDAi.mjs → bylines-Ds4-otXl.mjs} +4 -4
  211. package/dist/{bylines-D4KADDAi.mjs.map → bylines-Ds4-otXl.mjs.map} +1 -1
  212. package/dist/{cache-C35VWD5D.mjs → cache-Ciu3e3AF.mjs} +2 -2
  213. package/dist/{cache-C35VWD5D.mjs.map → cache-Ciu3e3AF.mjs.map} +1 -1
  214. package/dist/{chunks-BHgcHh2C.mjs → chunks-CZFiauig.mjs} +2 -2
  215. package/dist/{chunks-BHgcHh2C.mjs.map → chunks-CZFiauig.mjs.map} +1 -1
  216. package/dist/cli/index.mjs +17 -17
  217. package/dist/cli/index.mjs.map +1 -1
  218. package/dist/client/cf-access.d.mts +1 -1
  219. package/dist/client/index.d.mts +1 -1
  220. package/dist/{comment-BDx50EX5.mjs → comment-CH1IrFFs.mjs} +3 -3
  221. package/dist/{comment-BDx50EX5.mjs.map → comment-CH1IrFFs.mjs.map} +1 -1
  222. package/dist/{comment-reaction-Gv_pgfI3.mjs → comment-reaction-kruNY-kP.mjs} +2 -2
  223. package/dist/{comment-reaction-Gv_pgfI3.mjs.map → comment-reaction-kruNY-kP.mjs.map} +1 -1
  224. package/dist/{comments-CXHuQ6jI.mjs → comments-BUJyXbgq.mjs} +3 -3
  225. package/dist/{comments-CXHuQ6jI.mjs.map → comments-BUJyXbgq.mjs.map} +1 -1
  226. package/dist/{content-B43-YrIq.mjs → content-RmfHoWqK.mjs} +4 -4
  227. package/dist/{content-B43-YrIq.mjs.map → content-RmfHoWqK.mjs.map} +1 -1
  228. package/dist/{context-BW3N7wyt.mjs → context-CzUU_WzL.mjs} +7 -7
  229. package/dist/{context-BW3N7wyt.mjs.map → context-CzUU_WzL.mjs.map} +1 -1
  230. package/dist/{dashboard-FIe0S512.mjs → dashboard-CVyGhift.mjs} +4 -4
  231. package/dist/{dashboard-FIe0S512.mjs.map → dashboard-CVyGhift.mjs.map} +1 -1
  232. package/dist/db/index.d.mts +3 -3
  233. package/dist/db/index.mjs +1 -1
  234. package/dist/db/libsql.d.mts +1 -1
  235. package/dist/db/postgres.d.mts +1 -1
  236. package/dist/db/sqlite.d.mts +1 -1
  237. package/dist/{error-DXnK2wF4.mjs → error-BHkLZk-w.mjs} +2 -2
  238. package/dist/{error-DXnK2wF4.mjs.map → error-BHkLZk-w.mjs.map} +1 -1
  239. package/dist/{field-defs-cache-CYYx8xlG.mjs → field-defs-cache-BA-8ZPiT.mjs} +2 -2
  240. package/dist/{field-defs-cache-CYYx8xlG.mjs.map → field-defs-cache-BA-8ZPiT.mjs.map} +1 -1
  241. package/dist/{fts-manager-DW_NR-Fs.mjs → fts-manager-Db9jGavf.mjs} +2 -2
  242. package/dist/{fts-manager-DW_NR-Fs.mjs.map → fts-manager-Db9jGavf.mjs.map} +1 -1
  243. package/dist/{index-Cz6_JBL3.d.mts → index-CDZZjrLT.d.mts} +2430 -2363
  244. package/dist/index-CDZZjrLT.d.mts.map +1 -0
  245. package/dist/{index-qbL02uhs.d.mts → index-DGIjmUXQ.d.mts} +3 -3
  246. package/dist/{index-qbL02uhs.d.mts.map → index-DGIjmUXQ.d.mts.map} +1 -1
  247. package/dist/index.d.mts +16 -15
  248. package/dist/index.mjs +38 -38
  249. package/dist/{load-DMFi4n1p.mjs → load-DpHICVPh.mjs} +2 -2
  250. package/dist/{load-DMFi4n1p.mjs.map → load-DpHICVPh.mjs.map} +1 -1
  251. package/dist/{loader-DrpofRon.mjs → loader-4K37qA-y.mjs} +81 -18
  252. package/dist/loader-4K37qA-y.mjs.map +1 -0
  253. package/dist/{manifest-schema-BOfPXse0.mjs → manifest-schema-kPGX7VS-.mjs} +3 -1
  254. package/dist/manifest-schema-kPGX7VS-.mjs.map +1 -0
  255. package/dist/media/local-runtime.d.mts +11 -10
  256. package/dist/media/local-runtime.d.mts.map +1 -1
  257. package/dist/media/local-runtime.mjs +5 -5
  258. package/dist/{media-BjKxjzk8.mjs → media-C0nRRfs1.mjs} +2 -2
  259. package/dist/{media-BjKxjzk8.mjs.map → media-C0nRRfs1.mjs.map} +1 -1
  260. package/dist/{menus-CxqJ-z-N.mjs → menus-DzRyC1ID.mjs} +50 -68
  261. package/dist/menus-DzRyC1ID.mjs.map +1 -0
  262. package/dist/{menus-8O6xNcYW.mjs → menus-SL2K0xq2.mjs} +3 -3
  263. package/dist/{menus-8O6xNcYW.mjs.map → menus-SL2K0xq2.mjs.map} +1 -1
  264. package/dist/object-cache/memory.d.mts +1 -1
  265. package/dist/{object-cache-SEb2IM4Z.mjs → object-cache-CHbHv83-.mjs} +8 -4
  266. package/dist/object-cache-CHbHv83-.mjs.map +1 -0
  267. package/dist/{options-BvClpP5Q.d.mts → options-41nCWqi9.d.mts} +2 -2
  268. package/dist/{options-BvClpP5Q.d.mts.map → options-41nCWqi9.d.mts.map} +1 -1
  269. package/dist/page/index.d.mts +6 -3
  270. package/dist/page/index.d.mts.map +1 -1
  271. package/dist/page/index.mjs +3 -2
  272. package/dist/page/index.mjs.map +1 -1
  273. package/dist/{parse-DqMWHQ8x.mjs → parse-CqyZj3Hp.mjs} +2 -2
  274. package/dist/{parse-DqMWHQ8x.mjs.map → parse-CqyZj3Hp.mjs.map} +1 -1
  275. package/dist/plugin-types.d.mts +4 -2
  276. package/dist/plugin-types.d.mts.map +1 -1
  277. package/dist/plugin-utils.d.mts +10 -9
  278. package/dist/plugin-utils.d.mts.map +1 -1
  279. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -9
  280. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  281. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  282. package/dist/{query-34pfm02Q.mjs → query-B0M-9LYR.mjs} +14 -14
  283. package/dist/{query-34pfm02Q.mjs.map → query-B0M-9LYR.mjs.map} +1 -1
  284. package/dist/{rate-limit-CBQK4ygJ.mjs → rate-limit-BwoUdIpC.mjs} +2 -2
  285. package/dist/{rate-limit-CBQK4ygJ.mjs.map → rate-limit-BwoUdIpC.mjs.map} +1 -1
  286. package/dist/{redirect-C1KVGYWe.mjs → redirect-lMOzG04S.mjs} +2 -2
  287. package/dist/{redirect-C1KVGYWe.mjs.map → redirect-lMOzG04S.mjs.map} +1 -1
  288. package/dist/{redirects-DgnypVir.mjs → redirects-9218MmYl.mjs} +3 -3
  289. package/dist/{redirects-DgnypVir.mjs.map → redirects-9218MmYl.mjs.map} +1 -1
  290. package/dist/{registry-3aOAS4My.mjs → registry-DP-iEtdR.mjs} +4 -4
  291. package/dist/{registry-3aOAS4My.mjs.map → registry-DP-iEtdR.mjs.map} +1 -1
  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-CFngB4WZ.mjs} +296 -191
  295. package/dist/runner-CFngB4WZ.mjs.map +1 -0
  296. package/dist/runtime.d.mts +10 -9
  297. package/dist/runtime.d.mts.map +1 -1
  298. package/dist/runtime.mjs +2 -2
  299. package/dist/scheduled-publish-BMljtY5G.d.mts +11 -0
  300. package/dist/scheduled-publish-BMljtY5G.d.mts.map +1 -0
  301. package/dist/{schema-BGwx8AQY.mjs → schema-BfJ7bIXH.mjs} +5 -5
  302. package/dist/{schema-BGwx8AQY.mjs.map → schema-BfJ7bIXH.mjs.map} +1 -1
  303. package/dist/{search-Gl747zMP.mjs → search-C7t3PH1J.mjs} +6 -4
  304. package/dist/search-C7t3PH1J.mjs.map +1 -0
  305. package/dist/{sections-C-umuuLj.mjs → sections-Dm0CVX23.mjs} +3 -3
  306. package/dist/{sections-C-umuuLj.mjs.map → sections-Dm0CVX23.mjs.map} +1 -1
  307. package/dist/seed/index.d.mts +2 -2
  308. package/dist/seed/index.mjs +15 -15
  309. package/dist/{seo-BNzkiK_W.mjs → seo-Dd3tbY_k.mjs} +3 -3
  310. package/dist/{seo-BNzkiK_W.mjs.map → seo-Dd3tbY_k.mjs.map} +1 -1
  311. package/dist/{service-CQHK_10l.mjs → service-CTrqp_Jy.mjs} +2 -2
  312. package/dist/{service-CQHK_10l.mjs.map → service-CTrqp_Jy.mjs.map} +1 -1
  313. package/dist/{settings-C4tXRYiG.mjs → settings-BX8cWBus.mjs} +4 -4
  314. package/dist/{settings-C4tXRYiG.mjs.map → settings-BX8cWBus.mjs.map} +1 -1
  315. package/dist/{settings-fPSR6dJa.mjs → settings-CZ7ZP9cW.mjs} +3 -3
  316. package/dist/{settings-fPSR6dJa.mjs.map → settings-CZ7ZP9cW.mjs.map} +1 -1
  317. package/dist/storage/local.d.mts +1 -1
  318. package/dist/storage/s3.d.mts +1 -1
  319. package/dist/{taxonomies-DbAtL6m4.mjs → taxonomies-DChKcVxf.mjs} +5 -4
  320. package/dist/taxonomies-DChKcVxf.mjs.map +1 -0
  321. package/dist/{taxonomies-n8w72lLQ.mjs → taxonomies-ckPjz-6d.mjs} +75 -20
  322. package/dist/taxonomies-ckPjz-6d.mjs.map +1 -0
  323. package/dist/{taxonomy-BBUlGug5.mjs → taxonomy-Cru-he6s.mjs} +4 -4
  324. package/dist/{taxonomy-BBUlGug5.mjs.map → taxonomy-Cru-he6s.mjs.map} +1 -1
  325. package/dist/{transport-BZ-03aFT.d.mts → transport-Blrl2k_o.d.mts} +1 -1
  326. package/dist/{transport-BZ-03aFT.d.mts.map → transport-Blrl2k_o.d.mts.map} +1 -1
  327. package/dist/{types-h2Cwbzi2.d.mts → types-BYnDBVwe.d.mts} +24 -5
  328. package/dist/{types-h2Cwbzi2.d.mts.map → types-BYnDBVwe.d.mts.map} +1 -1
  329. package/dist/{types-BG8_XTLj.d.mts → types-BkZ8DUEI.d.mts} +1 -1
  330. package/dist/{types-BG8_XTLj.d.mts.map → types-BkZ8DUEI.d.mts.map} +1 -1
  331. package/dist/{types-DrYMm9s5.d.mts → types-ByChcBgE.d.mts} +1 -1
  332. package/dist/{types-DrYMm9s5.d.mts.map → types-ByChcBgE.d.mts.map} +1 -1
  333. package/dist/{types-BWqGVhFn.d.mts → types-CvuKO5Pn.d.mts} +1 -1
  334. package/dist/{types-BWqGVhFn.d.mts.map → types-CvuKO5Pn.d.mts.map} +1 -1
  335. package/dist/{types-CmI1OyQg.mjs → types-DU4TSFS5.mjs} +2 -2
  336. package/dist/{types-CmI1OyQg.mjs.map → types-DU4TSFS5.mjs.map} +1 -1
  337. package/dist/{types-CUsXGRVj.d.mts → types-Dbqff978.d.mts} +1 -1
  338. package/dist/{types-CUsXGRVj.d.mts.map → types-Dbqff978.d.mts.map} +1 -1
  339. package/dist/{types-fS7-VTdR.d.mts → types-Y09-wtyU.d.mts} +1 -1
  340. package/dist/{types-fS7-VTdR.d.mts.map → types-Y09-wtyU.d.mts.map} +1 -1
  341. package/dist/{types-B-gIxFCE.d.mts → types-xIfVRNLp.d.mts} +38 -1
  342. package/dist/types-xIfVRNLp.d.mts.map +1 -0
  343. package/dist/{user-JAuc8VUf.mjs → user-DgGbKL9s.mjs} +3 -3
  344. package/dist/{user-JAuc8VUf.mjs.map → user-DgGbKL9s.mjs.map} +1 -1
  345. package/dist/{validate-Va_An3qb.d.mts → validate-9ECmtEpJ.d.mts} +10 -5
  346. package/dist/{validate-Va_An3qb.d.mts.map → validate-9ECmtEpJ.d.mts.map} +1 -1
  347. package/dist/{validate-BzXHWnkV.mjs → validate-CRkcYZAR.mjs} +2 -2
  348. package/dist/{validate-BzXHWnkV.mjs.map → validate-CRkcYZAR.mjs.map} +1 -1
  349. package/dist/{validation-B6DKPTtU.mjs → validation-sR26SOwD.mjs} +5 -5
  350. package/dist/{validation-B6DKPTtU.mjs.map → validation-sR26SOwD.mjs.map} +1 -1
  351. package/dist/version-CrqhKGWn.mjs +7 -0
  352. package/dist/{version-DHdCA24u.mjs.map → version-CrqhKGWn.mjs.map} +1 -1
  353. package/dist/{widgets-C2RbFN0G.mjs → widgets-DRgtn7Cl.mjs} +2 -2
  354. package/dist/{widgets-C2RbFN0G.mjs.map → widgets-DRgtn7Cl.mjs.map} +1 -1
  355. package/dist/{zod-generator-xEHODMJf.mjs → zod-generator-C5JaV--i.mjs} +6 -3
  356. package/dist/zod-generator-C5JaV--i.mjs.map +1 -0
  357. package/package.json +8 -8
  358. package/src/api/handlers/content.ts +59 -16
  359. package/src/api/handlers/plugins.ts +77 -10
  360. package/src/api/handlers/taxonomies.ts +5 -1
  361. package/src/astro/integration/virtual-modules.ts +15 -0
  362. package/src/astro/integration/vite-config.ts +19 -1
  363. package/src/astro/middleware/auth.ts +1 -0
  364. package/src/astro/middleware.ts +1 -0
  365. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +6 -1
  366. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +6 -1
  367. package/src/astro/routes/api/admin/plugins/[id]/index.ts +1 -0
  368. package/src/astro/routes/api/admin/plugins/index.ts +1 -0
  369. package/src/astro/routes/api/manifest.ts +20 -1
  370. package/src/astro/routes/api/setup/dev-bypass.ts +7 -2
  371. package/src/astro/routes/sitemap-[collection].xml.ts +5 -4
  372. package/src/astro/types.ts +4 -0
  373. package/src/cli/commands/seed.ts +1 -1
  374. package/src/components/EmDashHead.astro +23 -3
  375. package/src/components/JsonLdScript.astro +9 -0
  376. package/src/components/LiveSearch.astro +40 -4
  377. package/src/components/live-search-routing.ts +30 -0
  378. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +39 -18
  379. package/src/database/migrations/046_media_usage_index.ts +115 -0
  380. package/src/database/migrations/047_restore_taxonomy_parent_index.ts +29 -0
  381. package/src/database/migrations/048_restore_content_taxonomies_term_index.ts +32 -0
  382. package/src/database/migrations/runner.ts +6 -0
  383. package/src/database/repositories/media-usage.ts +444 -0
  384. package/src/database/types.ts +39 -0
  385. package/src/emdash-runtime.ts +61 -52
  386. package/src/index.ts +3 -0
  387. package/src/loader.ts +110 -31
  388. package/src/media/usage/extractor.ts +302 -0
  389. package/src/media/usage/types.ts +46 -0
  390. package/src/object-cache/index.ts +8 -2
  391. package/src/page/metadata.ts +23 -3
  392. package/src/plugin-types.ts +10 -0
  393. package/src/plugins/define-plugin.ts +14 -5
  394. package/src/plugins/hooks.ts +53 -65
  395. package/src/plugins/index.ts +5 -0
  396. package/src/plugins/manager.ts +22 -0
  397. package/src/plugins/manifest-schema.ts +2 -0
  398. package/src/plugins/types.ts +35 -3
  399. package/src/schema/zod-generator.ts +9 -1
  400. package/src/search/query.ts +3 -0
  401. package/src/search/types.ts +2 -0
  402. package/src/seed/apply.ts +8 -2
  403. package/src/seed/types.ts +6 -1
  404. package/src/taxonomies/index.ts +121 -18
  405. package/dist/api-D2_sbavn.mjs.map +0 -1
  406. package/dist/apply-Bk2mAuLn.mjs.map +0 -1
  407. package/dist/index-Cz6_JBL3.d.mts.map +0 -1
  408. package/dist/loader-DrpofRon.mjs.map +0 -1
  409. package/dist/manifest-schema-BOfPXse0.mjs.map +0 -1
  410. package/dist/menus-CxqJ-z-N.mjs.map +0 -1
  411. package/dist/object-cache-SEb2IM4Z.mjs.map +0 -1
  412. package/dist/runner-BsquExlK.mjs.map +0 -1
  413. package/dist/search-Gl747zMP.mjs.map +0 -1
  414. package/dist/taxonomies-DbAtL6m4.mjs.map +0 -1
  415. package/dist/taxonomies-n8w72lLQ.mjs.map +0 -1
  416. package/dist/types-B-gIxFCE.d.mts.map +0 -1
  417. package/dist/version-DHdCA24u.mjs +0 -7
  418. package/dist/zod-generator-xEHODMJf.mjs.map +0 -1
@@ -0,0 +1,444 @@
1
+ import type { Kysely, Selectable, Transaction } from "kysely";
2
+ import { ulid } from "ulidx";
3
+
4
+ import type { MediaKind, MediaUsageReferenceType } from "../../media/usage/types.js";
5
+ import { chunks, SQL_BATCH_SIZE } from "../../utils/chunks.js";
6
+ import { withTransaction } from "../transaction.js";
7
+ import type { Database, MediaUsageSourceTable, MediaUsageTable } from "../types.js";
8
+
9
+ type DatabaseExecutor = Kysely<Database> | Transaction<Database>;
10
+
11
+ const OCCURRENCE_BIND_COLUMNS = 12;
12
+ const OCCURRENCE_INSERT_BATCH_SIZE = Math.max(
13
+ 1,
14
+ Math.floor(SQL_BATCH_SIZE / OCCURRENCE_BIND_COLUMNS),
15
+ );
16
+
17
+ export interface MediaUsageSourceInput {
18
+ sourceKey: string;
19
+ sourceType: string;
20
+ collectionSlug?: string | null;
21
+ contentId?: string | null;
22
+ sourceVariant: string;
23
+ locale?: string | null;
24
+ translationGroup?: string | null;
25
+ contentSlug?: string | null;
26
+ contentTitle?: string | null;
27
+ contentStatus?: string | null;
28
+ contentScheduledAt?: string | null;
29
+ contentDeletedAt?: string | null;
30
+ revisionId?: string | null;
31
+ schemaVersion?: number;
32
+ }
33
+
34
+ export interface MediaUsageOccurrenceInput {
35
+ fieldSlug: string;
36
+ fieldPath: string;
37
+ occurrenceIndex?: number;
38
+ referenceType: MediaUsageReferenceType;
39
+ mediaId: string | null;
40
+ provider: string;
41
+ providerAssetId: string;
42
+ mediaKind?: MediaKind | null;
43
+ mimeType?: string | null;
44
+ }
45
+
46
+ export interface MediaUsageSource {
47
+ sourceKey: string;
48
+ sourceType: string;
49
+ collectionSlug: string | null;
50
+ contentId: string | null;
51
+ sourceVariant: string;
52
+ locale: string | null;
53
+ translationGroup: string | null;
54
+ contentSlug: string | null;
55
+ contentTitle: string | null;
56
+ contentStatus: string | null;
57
+ contentScheduledAt: string | null;
58
+ contentDeletedAt: string | null;
59
+ revisionId: string | null;
60
+ currentGeneration: string;
61
+ schemaVersion: number;
62
+ indexedAt: string;
63
+ createdAt: string;
64
+ updatedAt: string;
65
+ }
66
+
67
+ export interface MediaUsageOccurrence {
68
+ id: string;
69
+ sourceKey: string;
70
+ generation: string;
71
+ fieldSlug: string;
72
+ fieldPath: string;
73
+ occurrenceIndex: number;
74
+ referenceType: string;
75
+ mediaId: string | null;
76
+ provider: string;
77
+ providerAssetId: string;
78
+ mediaKind: string | null;
79
+ mimeType: string | null;
80
+ createdAt: string;
81
+ }
82
+
83
+ export interface MediaUsageRecord {
84
+ source: MediaUsageSource;
85
+ occurrence: MediaUsageOccurrence;
86
+ }
87
+
88
+ interface JoinedUsageRow {
89
+ source_key: string;
90
+ source_type: string;
91
+ collection_slug: string | null;
92
+ content_id: string | null;
93
+ source_variant: string;
94
+ locale: string | null;
95
+ translation_group: string | null;
96
+ content_slug: string | null;
97
+ content_title: string | null;
98
+ content_status: string | null;
99
+ content_scheduled_at: string | null;
100
+ content_deleted_at: string | null;
101
+ revision_id: string | null;
102
+ current_generation: string;
103
+ schema_version: number;
104
+ indexed_at: string;
105
+ source_created_at: string;
106
+ source_updated_at: string;
107
+ occurrence_id: string;
108
+ generation: string;
109
+ field_slug: string;
110
+ field_path: string;
111
+ occurrence_index: number;
112
+ reference_type: string;
113
+ media_id: string | null;
114
+ provider: string;
115
+ provider_asset_id: string;
116
+ media_kind: string | null;
117
+ mime_type: string | null;
118
+ occurrence_created_at: string;
119
+ }
120
+
121
+ /** Persistence-only repository for the internal media usage projection tables. */
122
+ export class MediaUsageRepository {
123
+ constructor(private db: Kysely<Database>) {}
124
+
125
+ async replaceSource(
126
+ source: MediaUsageSourceInput,
127
+ occurrences: readonly MediaUsageOccurrenceInput[],
128
+ ): Promise<MediaUsageSource> {
129
+ const generation = ulid();
130
+ const now = new Date().toISOString();
131
+
132
+ await withTransaction(this.db, async (trx) => {
133
+ await this.insertOccurrences(trx, source.sourceKey, generation, occurrences);
134
+ await this.upsertSource(trx, source, generation, now);
135
+
136
+ try {
137
+ await this.deleteStaleGenerations(trx, source.sourceKey, generation);
138
+ } catch (error) {
139
+ console.error("[media-usage] failed to delete stale generations:", error);
140
+ }
141
+ });
142
+
143
+ const replaced = await this.findSource(source.sourceKey);
144
+ if (!replaced) {
145
+ throw new Error(`Media usage source ${source.sourceKey} was not persisted`);
146
+ }
147
+ return replaced;
148
+ }
149
+
150
+ async findSource(sourceKey: string): Promise<MediaUsageSource | null> {
151
+ const row = await this.db
152
+ .selectFrom("_emdash_media_usage_sources")
153
+ .selectAll()
154
+ .where("source_key", "=", sourceKey)
155
+ .executeTakeFirst();
156
+
157
+ return row ? rowToSource(row) : null;
158
+ }
159
+
160
+ async findCurrentUsageByMediaId(mediaId: string): Promise<MediaUsageRecord[]> {
161
+ const rows = await this.db
162
+ .selectFrom("_emdash_media_usage_sources as s")
163
+ .innerJoin("_emdash_media_usage as u", (join) =>
164
+ join
165
+ .onRef("u.source_key", "=", "s.source_key")
166
+ .onRef("u.generation", "=", "s.current_generation"),
167
+ )
168
+ .select(currentUsageSelect)
169
+ .where("u.media_id", "=", mediaId)
170
+ .orderBy("s.source_key", "asc")
171
+ .orderBy("u.field_path", "asc")
172
+ .orderBy("u.occurrence_index", "asc")
173
+ .execute();
174
+
175
+ return rows.map(rowToUsageRecord);
176
+ }
177
+
178
+ async findCurrentUsageByProviderAsset(
179
+ provider: string,
180
+ providerAssetId: string,
181
+ ): Promise<MediaUsageRecord[]> {
182
+ const rows = await this.db
183
+ .selectFrom("_emdash_media_usage_sources as s")
184
+ .innerJoin("_emdash_media_usage as u", (join) =>
185
+ join
186
+ .onRef("u.source_key", "=", "s.source_key")
187
+ .onRef("u.generation", "=", "s.current_generation"),
188
+ )
189
+ .select(currentUsageSelect)
190
+ .where("u.provider", "=", provider)
191
+ .where("u.provider_asset_id", "=", providerAssetId)
192
+ .orderBy("s.source_key", "asc")
193
+ .orderBy("u.field_path", "asc")
194
+ .orderBy("u.occurrence_index", "asc")
195
+ .execute();
196
+
197
+ return rows.map(rowToUsageRecord);
198
+ }
199
+
200
+ async deleteSource(sourceKey: string): Promise<number> {
201
+ return withTransaction(this.db, async (trx) => {
202
+ await trx.deleteFrom("_emdash_media_usage").where("source_key", "=", sourceKey).execute();
203
+ const result = await trx
204
+ .deleteFrom("_emdash_media_usage_sources")
205
+ .where("source_key", "=", sourceKey)
206
+ .executeTakeFirst();
207
+ return Number(result.numDeletedRows ?? 0);
208
+ });
209
+ }
210
+
211
+ async deleteContentSources(collectionSlug: string, contentId: string): Promise<number> {
212
+ const sourceRows = await this.db
213
+ .selectFrom("_emdash_media_usage_sources")
214
+ .select("source_key")
215
+ .where("source_type", "=", "content")
216
+ .where("collection_slug", "=", collectionSlug)
217
+ .where("content_id", "=", contentId)
218
+ .execute();
219
+ const sourceKeys = sourceRows.map((row) => row.source_key);
220
+ if (sourceKeys.length === 0) return 0;
221
+
222
+ return withTransaction(this.db, async (trx) => {
223
+ let deleted = 0;
224
+ for (const sourceKeyBatch of chunks(sourceKeys, SQL_BATCH_SIZE)) {
225
+ await trx
226
+ .deleteFrom("_emdash_media_usage")
227
+ .where("source_key", "in", sourceKeyBatch)
228
+ .execute();
229
+ const result = await trx
230
+ .deleteFrom("_emdash_media_usage_sources")
231
+ .where("source_key", "in", sourceKeyBatch)
232
+ .executeTakeFirst();
233
+ deleted += Number(result.numDeletedRows ?? 0);
234
+ }
235
+ return deleted;
236
+ });
237
+ }
238
+
239
+ private async insertOccurrences(
240
+ db: DatabaseExecutor,
241
+ sourceKey: string,
242
+ generation: string,
243
+ occurrences: readonly MediaUsageOccurrenceInput[],
244
+ ): Promise<void> {
245
+ if (occurrences.length === 0) return;
246
+
247
+ const rows = occurrences.map((occurrence) => ({
248
+ id: ulid(),
249
+ source_key: sourceKey,
250
+ generation,
251
+ field_slug: occurrence.fieldSlug,
252
+ field_path: occurrence.fieldPath,
253
+ occurrence_index: occurrence.occurrenceIndex ?? 0,
254
+ reference_type: occurrence.referenceType,
255
+ media_id: occurrence.mediaId,
256
+ provider: occurrence.provider,
257
+ provider_asset_id: occurrence.providerAssetId,
258
+ media_kind: occurrence.mediaKind ?? null,
259
+ mime_type: occurrence.mimeType ?? null,
260
+ }));
261
+
262
+ for (const rowBatch of chunks(rows, OCCURRENCE_INSERT_BATCH_SIZE)) {
263
+ await db.insertInto("_emdash_media_usage").values(rowBatch).execute();
264
+ }
265
+ }
266
+
267
+ private async upsertSource(
268
+ db: DatabaseExecutor,
269
+ source: MediaUsageSourceInput,
270
+ generation: string,
271
+ now: string,
272
+ ): Promise<void> {
273
+ const row = {
274
+ source_key: source.sourceKey,
275
+ source_type: source.sourceType,
276
+ collection_slug: source.collectionSlug ?? null,
277
+ content_id: source.contentId ?? null,
278
+ source_variant: source.sourceVariant,
279
+ locale: source.locale ?? null,
280
+ translation_group: source.translationGroup ?? null,
281
+ content_slug: source.contentSlug ?? null,
282
+ content_title: source.contentTitle ?? null,
283
+ content_status: source.contentStatus ?? null,
284
+ content_scheduled_at: source.contentScheduledAt ?? null,
285
+ content_deleted_at: source.contentDeletedAt ?? null,
286
+ revision_id: source.revisionId ?? null,
287
+ current_generation: generation,
288
+ schema_version: source.schemaVersion ?? 1,
289
+ indexed_at: now,
290
+ updated_at: now,
291
+ };
292
+
293
+ await db
294
+ .insertInto("_emdash_media_usage_sources")
295
+ .values(row)
296
+ .onConflict((oc) =>
297
+ oc.column("source_key").doUpdateSet({
298
+ source_type: row.source_type,
299
+ collection_slug: row.collection_slug,
300
+ content_id: row.content_id,
301
+ source_variant: row.source_variant,
302
+ locale: row.locale,
303
+ translation_group: row.translation_group,
304
+ content_slug: row.content_slug,
305
+ content_title: row.content_title,
306
+ content_status: row.content_status,
307
+ content_scheduled_at: row.content_scheduled_at,
308
+ content_deleted_at: row.content_deleted_at,
309
+ revision_id: row.revision_id,
310
+ current_generation: row.current_generation,
311
+ schema_version: row.schema_version,
312
+ indexed_at: row.indexed_at,
313
+ updated_at: row.updated_at,
314
+ }),
315
+ )
316
+ .execute();
317
+ }
318
+
319
+ private async deleteStaleGenerations(
320
+ db: DatabaseExecutor,
321
+ sourceKey: string,
322
+ currentGeneration: string,
323
+ ): Promise<void> {
324
+ await db
325
+ .deleteFrom("_emdash_media_usage")
326
+ .where("source_key", "=", sourceKey)
327
+ .where("generation", "!=", currentGeneration)
328
+ .execute();
329
+ }
330
+ }
331
+
332
+ const currentUsageSelect = [
333
+ "s.source_key as source_key",
334
+ "s.source_type as source_type",
335
+ "s.collection_slug as collection_slug",
336
+ "s.content_id as content_id",
337
+ "s.source_variant as source_variant",
338
+ "s.locale as locale",
339
+ "s.translation_group as translation_group",
340
+ "s.content_slug as content_slug",
341
+ "s.content_title as content_title",
342
+ "s.content_status as content_status",
343
+ "s.content_scheduled_at as content_scheduled_at",
344
+ "s.content_deleted_at as content_deleted_at",
345
+ "s.revision_id as revision_id",
346
+ "s.current_generation as current_generation",
347
+ "s.schema_version as schema_version",
348
+ "s.indexed_at as indexed_at",
349
+ "s.created_at as source_created_at",
350
+ "s.updated_at as source_updated_at",
351
+ "u.id as occurrence_id",
352
+ "u.generation as generation",
353
+ "u.field_slug as field_slug",
354
+ "u.field_path as field_path",
355
+ "u.occurrence_index as occurrence_index",
356
+ "u.reference_type as reference_type",
357
+ "u.media_id as media_id",
358
+ "u.provider as provider",
359
+ "u.provider_asset_id as provider_asset_id",
360
+ "u.media_kind as media_kind",
361
+ "u.mime_type as mime_type",
362
+ "u.created_at as occurrence_created_at",
363
+ ] as const;
364
+
365
+ function rowToSource(row: Selectable<MediaUsageSourceTable>): MediaUsageSource {
366
+ return {
367
+ sourceKey: row.source_key,
368
+ sourceType: row.source_type,
369
+ collectionSlug: row.collection_slug,
370
+ contentId: row.content_id,
371
+ sourceVariant: row.source_variant,
372
+ locale: row.locale,
373
+ translationGroup: row.translation_group,
374
+ contentSlug: row.content_slug,
375
+ contentTitle: row.content_title,
376
+ contentStatus: row.content_status,
377
+ contentScheduledAt: row.content_scheduled_at,
378
+ contentDeletedAt: row.content_deleted_at,
379
+ revisionId: row.revision_id,
380
+ currentGeneration: row.current_generation,
381
+ schemaVersion: Number(row.schema_version),
382
+ indexedAt: row.indexed_at,
383
+ createdAt: row.created_at,
384
+ updatedAt: row.updated_at,
385
+ };
386
+ }
387
+
388
+ function rowToOccurrence(row: Selectable<MediaUsageTable>): MediaUsageOccurrence {
389
+ return {
390
+ id: row.id,
391
+ sourceKey: row.source_key,
392
+ generation: row.generation,
393
+ fieldSlug: row.field_slug,
394
+ fieldPath: row.field_path,
395
+ occurrenceIndex: Number(row.occurrence_index),
396
+ referenceType: row.reference_type,
397
+ mediaId: row.media_id,
398
+ provider: row.provider,
399
+ providerAssetId: row.provider_asset_id,
400
+ mediaKind: row.media_kind,
401
+ mimeType: row.mime_type,
402
+ createdAt: row.created_at,
403
+ };
404
+ }
405
+
406
+ function rowToUsageRecord(row: JoinedUsageRow): MediaUsageRecord {
407
+ return {
408
+ source: rowToSource({
409
+ source_key: row.source_key,
410
+ source_type: row.source_type,
411
+ collection_slug: row.collection_slug,
412
+ content_id: row.content_id,
413
+ source_variant: row.source_variant,
414
+ locale: row.locale,
415
+ translation_group: row.translation_group,
416
+ content_slug: row.content_slug,
417
+ content_title: row.content_title,
418
+ content_status: row.content_status,
419
+ content_scheduled_at: row.content_scheduled_at,
420
+ content_deleted_at: row.content_deleted_at,
421
+ revision_id: row.revision_id,
422
+ current_generation: row.current_generation,
423
+ schema_version: row.schema_version,
424
+ indexed_at: row.indexed_at,
425
+ created_at: row.source_created_at,
426
+ updated_at: row.source_updated_at,
427
+ }),
428
+ occurrence: rowToOccurrence({
429
+ id: row.occurrence_id,
430
+ source_key: row.source_key,
431
+ generation: row.generation,
432
+ field_slug: row.field_slug,
433
+ field_path: row.field_path,
434
+ occurrence_index: row.occurrence_index,
435
+ reference_type: row.reference_type,
436
+ media_id: row.media_id,
437
+ provider: row.provider,
438
+ provider_asset_id: row.provider_asset_id,
439
+ media_kind: row.media_kind,
440
+ mime_type: row.mime_type,
441
+ created_at: row.occurrence_created_at,
442
+ }),
443
+ };
444
+ }
@@ -60,6 +60,43 @@ export interface MediaTable {
60
60
  author_id: string | null;
61
61
  }
62
62
 
63
+ export interface MediaUsageSourceTable {
64
+ source_key: string;
65
+ source_type: string;
66
+ collection_slug: string | null;
67
+ content_id: string | null;
68
+ source_variant: string;
69
+ locale: string | null;
70
+ translation_group: string | null;
71
+ content_slug: string | null;
72
+ content_title: string | null;
73
+ content_status: string | null;
74
+ content_scheduled_at: string | null;
75
+ content_deleted_at: string | null;
76
+ revision_id: string | null;
77
+ current_generation: string;
78
+ schema_version: Generated<number>;
79
+ indexed_at: Generated<string>;
80
+ created_at: Generated<string>;
81
+ updated_at: Generated<string>;
82
+ }
83
+
84
+ export interface MediaUsageTable {
85
+ id: string;
86
+ source_key: string;
87
+ generation: string;
88
+ field_slug: string;
89
+ field_path: string;
90
+ occurrence_index: Generated<number>;
91
+ reference_type: string;
92
+ media_id: string | null;
93
+ provider: Generated<string>;
94
+ provider_asset_id: string;
95
+ media_kind: string | null;
96
+ mime_type: string | null;
97
+ created_at: Generated<string>;
98
+ }
99
+
63
100
  export interface UserTable {
64
101
  id: string;
65
102
  email: string;
@@ -414,6 +451,8 @@ export interface Database {
414
451
  content_taxonomies: ContentTaxonomyTable;
415
452
  _emdash_taxonomy_defs: TaxonomyDefTable;
416
453
  media: MediaTable;
454
+ _emdash_media_usage_sources: MediaUsageSourceTable;
455
+ _emdash_media_usage: MediaUsageTable;
417
456
  users: UserTable;
418
457
  credentials: CredentialTable;
419
458
  auth_tokens: AuthTokenTable;
@@ -2857,11 +2857,25 @@ export class EmDashRuntime {
2857
2857
  }
2858
2858
 
2859
2859
  async handleContentSchedule(collection: string, id: string, scheduledAt: string) {
2860
- return handleContentSchedule(this.db, collection, id, scheduledAt);
2860
+ const result = await handleContentSchedule(this.db, collection, id, scheduledAt);
2861
+
2862
+ // Run afterSchedule hooks (fire-and-forget)
2863
+ if (result.success && result.data) {
2864
+ this.runAfterScheduleHooks(contentItemToRecord(result.data.item), collection);
2865
+ }
2866
+
2867
+ return result;
2861
2868
  }
2862
2869
 
2863
2870
  async handleContentUnschedule(collection: string, id: string) {
2864
- return handleContentUnschedule(this.db, collection, id);
2871
+ const result = await handleContentUnschedule(this.db, collection, id);
2872
+
2873
+ // Run afterUnschedule hooks (fire-and-forget)
2874
+ if (result.success && result.data) {
2875
+ this.runAfterUnscheduleHooks(contentItemToRecord(result.data.item), collection);
2876
+ }
2877
+
2878
+ return result;
2865
2879
  }
2866
2880
 
2867
2881
  async handleContentCountScheduled(collection: string) {
@@ -3320,14 +3334,41 @@ export class EmDashRuntime {
3320
3334
  }
3321
3335
  }
3322
3336
 
3323
- private runAfterPublishHooks(content: Record<string, unknown>, collection: string): void {
3337
+ private runDeferredContentHook(
3338
+ name:
3339
+ | "content:afterPublish"
3340
+ | "content:afterUnpublish"
3341
+ | "content:afterRestore"
3342
+ | "content:afterSchedule"
3343
+ | "content:afterUnschedule",
3344
+ content: Record<string, unknown>,
3345
+ collection: string,
3346
+ ): void {
3347
+ const label = name.slice("content:".length);
3348
+
3324
3349
  after(async () => {
3325
3350
  // Trusted plugins
3326
- if (this.hooks.hasHooks("content:afterPublish")) {
3351
+ if (this.hooks.hasHooks(name)) {
3327
3352
  try {
3328
- await this.hooks.runContentAfterPublish(content, collection);
3353
+ switch (name) {
3354
+ case "content:afterPublish":
3355
+ await this.hooks.runContentAfterPublish(content, collection);
3356
+ break;
3357
+ case "content:afterUnpublish":
3358
+ await this.hooks.runContentAfterUnpublish(content, collection);
3359
+ break;
3360
+ case "content:afterRestore":
3361
+ await this.hooks.runContentAfterRestore(content, collection);
3362
+ break;
3363
+ case "content:afterSchedule":
3364
+ await this.hooks.runContentAfterSchedule(content, collection);
3365
+ break;
3366
+ case "content:afterUnschedule":
3367
+ await this.hooks.runContentAfterUnschedule(content, collection);
3368
+ break;
3369
+ }
3329
3370
  } catch (err) {
3330
- console.error("EmDash afterPublish hook error:", err);
3371
+ console.error(`EmDash ${label} hook error:`, err);
3331
3372
  }
3332
3373
  }
3333
3374
 
@@ -3340,9 +3381,9 @@ export class EmDashRuntime {
3340
3381
  tasks.push(
3341
3382
  (async () => {
3342
3383
  try {
3343
- await plugin.invokeHook("content:afterPublish", { content, collection });
3384
+ await plugin.invokeHook(name, { content, collection });
3344
3385
  } catch (err) {
3345
- console.error(`EmDash: Sandboxed plugin ${pluginId} afterPublish error:`, err);
3386
+ console.error(`EmDash: Sandboxed plugin ${pluginId} ${label} error:`, err);
3346
3387
  }
3347
3388
  })(),
3348
3389
  );
@@ -3351,56 +3392,24 @@ export class EmDashRuntime {
3351
3392
  });
3352
3393
  }
3353
3394
 
3354
- private runAfterUnpublishHooks(content: Record<string, unknown>, collection: string): void {
3355
- // Trusted plugins
3356
- if (this.hooks.hasHooks("content:afterUnpublish")) {
3357
- this.hooks
3358
- .runContentAfterUnpublish(content, collection)
3359
- .catch((err) => console.error("EmDash afterUnpublish hook error:", err));
3360
- }
3361
-
3362
- // Sandboxed plugins
3363
- for (const [pluginKey, plugin] of this.sandboxedPlugins) {
3364
- const [pluginId] = pluginKey.split(":");
3365
- if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
3395
+ private runAfterPublishHooks(content: Record<string, unknown>, collection: string): void {
3396
+ this.runDeferredContentHook("content:afterPublish", content, collection);
3397
+ }
3366
3398
 
3367
- plugin
3368
- .invokeHook("content:afterUnpublish", { content, collection })
3369
- .catch((err) =>
3370
- console.error(`EmDash: Sandboxed plugin ${pluginId} afterUnpublish error:`, err),
3371
- );
3372
- }
3399
+ private runAfterUnpublishHooks(content: Record<string, unknown>, collection: string): void {
3400
+ this.runDeferredContentHook("content:afterUnpublish", content, collection);
3373
3401
  }
3374
3402
 
3375
3403
  private runAfterRestoreHooks(content: Record<string, unknown>, collection: string): void {
3376
- after(async () => {
3377
- // Trusted plugins
3378
- if (this.hooks.hasHooks("content:afterRestore")) {
3379
- try {
3380
- await this.hooks.runContentAfterRestore(content, collection);
3381
- } catch (err) {
3382
- console.error("EmDash afterRestore hook error:", err);
3383
- }
3384
- }
3404
+ this.runDeferredContentHook("content:afterRestore", content, collection);
3405
+ }
3385
3406
 
3386
- // Sandboxed plugins
3387
- const tasks: Promise<void>[] = [];
3388
- for (const [pluginKey, plugin] of this.sandboxedPlugins) {
3389
- const [pluginId] = pluginKey.split(":");
3390
- if (!pluginId || !this.isPluginEnabled(pluginId)) continue;
3407
+ private runAfterScheduleHooks(content: Record<string, unknown>, collection: string): void {
3408
+ this.runDeferredContentHook("content:afterSchedule", content, collection);
3409
+ }
3391
3410
 
3392
- tasks.push(
3393
- (async () => {
3394
- try {
3395
- await plugin.invokeHook("content:afterRestore", { content, collection });
3396
- } catch (err) {
3397
- console.error(`EmDash: Sandboxed plugin ${pluginId} afterRestore error:`, err);
3398
- }
3399
- })(),
3400
- );
3401
- }
3402
- await Promise.allSettled(tasks);
3403
- });
3411
+ private runAfterUnscheduleHooks(content: Record<string, unknown>, collection: string): void {
3412
+ this.runDeferredContentHook("content:afterUnschedule", content, collection);
3404
3413
  }
3405
3414
 
3406
3415
  private async handleSandboxedRoute(
package/src/index.ts CHANGED
@@ -255,6 +255,9 @@ export type {
255
255
  ContentHookEvent,
256
256
  ContentDeleteEvent,
257
257
  ContentPublishStateChangeEvent,
258
+ ContentRestoreStateChangeEvent,
259
+ ContentScheduleStateChangeEvent,
260
+ ContentStateChangeEvent,
258
261
  MediaUploadEvent,
259
262
  HookResult,
260
263
  PluginRoute,