emdash 0.27.0 → 0.28.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 (534) hide show
  1. package/dist/{adapters-u037EnTR.d.mts → adapters-hUy8vOB-.d.mts} +1 -1
  2. package/dist/{adapters-u037EnTR.d.mts.map → adapters-hUy8vOB-.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-D5FxMUo8.mjs → allowed-origins-CRsJ6BPM.mjs} +2 -2
  4. package/dist/{allowed-origins-D5FxMUo8.mjs.map → allowed-origins-CRsJ6BPM.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +17 -16
  7. package/dist/api/route-utils.mjs.map +1 -1
  8. package/dist/api/schemas/index.d.mts +1 -1
  9. package/dist/api/schemas/index.mjs +3 -3
  10. package/dist/{api-80kycR9o.mjs → api-BFURZn1i.mjs} +33 -23
  11. package/dist/api-BFURZn1i.mjs.map +1 -0
  12. package/dist/{api-tokens-D6ppjIVi.mjs → api-tokens-DvqeZmVq.mjs} +2 -2
  13. package/dist/{api-tokens-D6ppjIVi.mjs.map → api-tokens-DvqeZmVq.mjs.map} +1 -1
  14. package/dist/{apply-DSypk6Iu.mjs → apply-Bu-8nYHL.mjs} +111 -74
  15. package/dist/apply-Bu-8nYHL.mjs.map +1 -0
  16. package/dist/astro/index.d.mts +12 -12
  17. package/dist/astro/index.mjs +3 -3
  18. package/dist/astro/index.mjs.map +1 -1
  19. package/dist/astro/middleware/auth.d.mts +10 -10
  20. package/dist/astro/middleware/auth.d.mts.map +1 -1
  21. package/dist/astro/middleware/auth.mjs +50 -11
  22. package/dist/astro/middleware/auth.mjs.map +1 -1
  23. package/dist/astro/middleware/redirect.mjs +5 -5
  24. package/dist/astro/middleware/request-context.mjs +2 -2
  25. package/dist/astro/middleware/setup.mjs +1 -1
  26. package/dist/astro/middleware.d.mts +2 -2
  27. package/dist/astro/middleware.mjs +124 -71
  28. package/dist/astro/middleware.mjs.map +1 -1
  29. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +6 -6
  30. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +6 -6
  31. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  32. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  34. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
  35. package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
  36. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
  37. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +14 -14
  38. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +14 -14
  39. package/dist/astro/routes/api/admin/bylines/index.mjs +14 -14
  40. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +12 -12
  41. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -6
  42. package/dist/astro/routes/api/admin/comments/bulk.mjs +10 -10
  43. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -6
  44. package/dist/astro/routes/api/admin/comments/index.mjs +10 -10
  45. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  46. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  47. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  48. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  49. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +37 -36
  50. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  51. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +37 -36
  52. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  53. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +36 -35
  54. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  55. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +36 -35
  56. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  57. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +36 -35
  58. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  59. package/dist/astro/routes/api/admin/plugins/index.mjs +36 -35
  60. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  61. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  62. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +36 -35
  63. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +36 -35
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  66. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +36 -35
  67. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  68. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +36 -35
  69. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  70. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +37 -36
  71. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  72. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +36 -35
  73. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  74. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +37 -36
  75. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  76. package/dist/astro/routes/api/admin/plugins/updates.mjs +36 -35
  77. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +36 -35
  79. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  81. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +36 -35
  82. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  83. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  84. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  85. package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
  86. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  87. package/dist/astro/routes/api/admin/users/index.mjs +6 -6
  88. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  89. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  90. package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
  91. package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
  92. package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
  93. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  94. package/dist/astro/routes/api/auth/magic-link/send.mjs +9 -9
  95. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  96. package/dist/astro/routes/api/auth/me.mjs +7 -7
  97. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  98. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  99. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  100. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -6
  101. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  102. package/dist/astro/routes/api/auth/passkey/options.mjs +11 -11
  103. package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
  104. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
  105. package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
  106. package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
  107. package/dist/astro/routes/api/auth/signup/request.mjs +9 -9
  108. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  109. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +13 -13
  110. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +12 -12
  111. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  112. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  113. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  114. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  115. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +10 -10
  116. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +7 -7
  117. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  118. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  119. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +7 -7
  120. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +13 -13
  121. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  122. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  123. package/dist/astro/routes/api/content/_collection_/_id_.mjs +7 -7
  124. package/dist/astro/routes/api/content/_collection_/authors.mjs +3 -3
  125. package/dist/astro/routes/api/content/_collection_/index.mjs +7 -7
  126. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -7
  127. package/dist/astro/routes/api/dashboard.mjs +8 -8
  128. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  129. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  130. package/dist/astro/routes/api/import/probe.mjs +19 -11
  131. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  132. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  133. package/dist/astro/routes/api/import/wordpress/execute.d.mts +11 -41
  134. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  135. package/dist/astro/routes/api/import/wordpress/execute.mjs +12 -407
  136. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  137. package/dist/astro/routes/api/import/wordpress/media.d.mts +10 -10
  138. package/dist/astro/routes/api/import/wordpress/media.mjs +9 -9
  139. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  140. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +19 -1
  141. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  142. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +97 -79
  143. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  144. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  145. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +19 -11
  146. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  147. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +40 -2
  148. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  149. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +519 -39
  150. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  151. package/dist/astro/routes/api/manifest.mjs +4 -4
  152. package/dist/astro/routes/api/mcp.mjs +39 -39
  153. package/dist/astro/routes/api/media/_id_/confirm.mjs +7 -7
  154. package/dist/astro/routes/api/media/_id_.mjs +7 -7
  155. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  156. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  157. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  158. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  159. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  160. package/dist/astro/routes/api/media.mjs +9 -9
  161. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +9 -9
  162. package/dist/astro/routes/api/menus/_name_/items.mjs +9 -9
  163. package/dist/astro/routes/api/menus/_name_/reorder.mjs +9 -9
  164. package/dist/astro/routes/api/menus/_name_/translations.mjs +9 -9
  165. package/dist/astro/routes/api/menus/_name_.mjs +9 -9
  166. package/dist/astro/routes/api/menus/index.mjs +9 -9
  167. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  168. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  169. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  170. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  171. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  172. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  173. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  174. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  175. package/dist/astro/routes/api/openapi.json.mjs +4 -4
  176. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  177. package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
  178. package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
  179. package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
  180. package/dist/astro/routes/api/redirects/index.mjs +10 -10
  181. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  182. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  183. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +36 -35
  184. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  185. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +36 -35
  186. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  187. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +36 -35
  188. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  189. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +36 -35
  190. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  191. package/dist/astro/routes/api/schema/collections/index.mjs +36 -35
  192. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  193. package/dist/astro/routes/api/schema/index.mjs +7 -6
  194. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  195. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +36 -35
  196. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  197. package/dist/astro/routes/api/schema/orphans/index.mjs +36 -35
  198. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  199. package/dist/astro/routes/api/search/enable.mjs +10 -10
  200. package/dist/astro/routes/api/search/index.mjs +9 -9
  201. package/dist/astro/routes/api/search/rebuild.mjs +10 -10
  202. package/dist/astro/routes/api/search/stats.mjs +6 -6
  203. package/dist/astro/routes/api/search/suggest.mjs +9 -9
  204. package/dist/astro/routes/api/sections/_slug_.mjs +9 -9
  205. package/dist/astro/routes/api/sections/index.mjs +9 -9
  206. package/dist/astro/routes/api/settings/email.mjs +4 -4
  207. package/dist/astro/routes/api/settings.mjs +12 -12
  208. package/dist/astro/routes/api/setup/admin-verify.mjs +11 -11
  209. package/dist/astro/routes/api/setup/admin.mjs +10 -10
  210. package/dist/astro/routes/api/setup/dev-bypass.mjs +25 -24
  211. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  212. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  213. package/dist/astro/routes/api/setup/index.mjs +26 -25
  214. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  215. package/dist/astro/routes/api/setup/status.mjs +4 -4
  216. package/dist/astro/routes/api/snapshot.mjs +6 -6
  217. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +13 -13
  218. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +13 -13
  219. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +13 -13
  220. package/dist/astro/routes/api/taxonomies/index.mjs +13 -13
  221. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  222. package/dist/astro/routes/api/typegen.mjs +5 -5
  223. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  224. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  225. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  226. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +7 -7
  227. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -9
  228. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -9
  229. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  230. package/dist/astro/routes/api/widget-areas/index.mjs +9 -9
  231. package/dist/astro/routes/api/widget-components.mjs +3 -3
  232. package/dist/astro/routes/robots.txt.mjs +6 -6
  233. package/dist/astro/routes/sitemap-_collection_.xml.mjs +9 -9
  234. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  235. package/dist/astro/types.d.mts +13 -13
  236. package/dist/auth/providers/github.d.mts +1 -1
  237. package/dist/auth/providers/google.d.mts +1 -1
  238. package/dist/{authorize-C3a_zGsM.mjs → authorize-Dz88F_Fw.mjs} +2 -2
  239. package/dist/{authorize-C3a_zGsM.mjs.map → authorize-Dz88F_Fw.mjs.map} +1 -1
  240. package/dist/{byline-DEKSVPTy.mjs → byline-Bm8ZgUP9.mjs} +6 -6
  241. package/dist/{byline-DEKSVPTy.mjs.map → byline-Bm8ZgUP9.mjs.map} +1 -1
  242. package/dist/{byline-fields-eyJMblSr.mjs → byline-fields-2Lp5Hbgf.mjs} +18 -3
  243. package/dist/byline-fields-2Lp5Hbgf.mjs.map +1 -0
  244. package/dist/{byline-fields-DaMKzkhO.mjs → byline-fields-CIx_GuN4.mjs} +1 -1
  245. package/dist/{byline-fields-DaMKzkhO.mjs.map → byline-fields-CIx_GuN4.mjs.map} +1 -1
  246. package/dist/{byline-fields-CtQ6blXd.d.mts → byline-fields-Cgrt9-aL.d.mts} +49 -34
  247. package/dist/{byline-fields-CtQ6blXd.d.mts.map → byline-fields-Cgrt9-aL.d.mts.map} +1 -1
  248. package/dist/{bylines-Ds4-otXl.mjs → bylines-6tm9mgQb.mjs} +4 -4
  249. package/dist/{bylines-Ds4-otXl.mjs.map → bylines-6tm9mgQb.mjs.map} +1 -1
  250. package/dist/{bylines-CiqgTHWF.mjs → bylines-Woq87129.mjs} +6 -6
  251. package/dist/{bylines-CiqgTHWF.mjs.map → bylines-Woq87129.mjs.map} +1 -1
  252. package/dist/{cache-Ciu3e3AF.mjs → cache-CEBAZjir.mjs} +2 -2
  253. package/dist/{cache-Ciu3e3AF.mjs.map → cache-CEBAZjir.mjs.map} +1 -1
  254. package/dist/{challenge-store-LhiqMccz.mjs → challenge-store-anhwVER0.mjs} +1 -1
  255. package/dist/{challenge-store-LhiqMccz.mjs.map → challenge-store-anhwVER0.mjs.map} +1 -1
  256. package/dist/{chunks-CZFiauig.mjs → chunks-B2isWQhr.mjs} +2 -2
  257. package/dist/{chunks-CZFiauig.mjs.map → chunks-B2isWQhr.mjs.map} +1 -1
  258. package/dist/cli/index.mjs +22 -21
  259. package/dist/cli/index.mjs.map +1 -1
  260. package/dist/client/cf-access.d.mts +1 -1
  261. package/dist/client/index.d.mts +1 -1
  262. package/dist/client/index.mjs +2 -2
  263. package/dist/{comment-CH1IrFFs.mjs → comment-CzeatwBV.mjs} +3 -3
  264. package/dist/{comment-CH1IrFFs.mjs.map → comment-CzeatwBV.mjs.map} +1 -1
  265. package/dist/{comment-reaction-kruNY-kP.mjs → comment-reaction-Cj9QJY7I.mjs} +2 -2
  266. package/dist/{comment-reaction-kruNY-kP.mjs.map → comment-reaction-Cj9QJY7I.mjs.map} +1 -1
  267. package/dist/{comments-BUJyXbgq.mjs → comments-BLE-jv5k.mjs} +3 -3
  268. package/dist/{comments-BUJyXbgq.mjs.map → comments-BLE-jv5k.mjs.map} +1 -1
  269. package/dist/{components-CYt4uVK9.mjs → components-B_sATNUc.mjs} +1 -1
  270. package/dist/{components-CYt4uVK9.mjs.map → components-B_sATNUc.mjs.map} +1 -1
  271. package/dist/{content-RmfHoWqK.mjs → content-DhgEth4k.mjs} +4 -4
  272. package/dist/{content-RmfHoWqK.mjs.map → content-DhgEth4k.mjs.map} +1 -1
  273. package/dist/content-refresh-CA4uKwzH.mjs +1531 -0
  274. package/dist/content-refresh-CA4uKwzH.mjs.map +1 -0
  275. package/dist/{context-CzUU_WzL.mjs → context-CUsR9dXL.mjs} +76 -54
  276. package/dist/context-CUsR9dXL.mjs.map +1 -0
  277. package/dist/{cron-C5LVoNmP.mjs → cron-v4FTEFR_.mjs} +1 -1
  278. package/dist/{cron-C5LVoNmP.mjs.map → cron-v4FTEFR_.mjs.map} +1 -1
  279. package/dist/{dashboard-CVyGhift.mjs → dashboard-EvEKF5en.mjs} +4 -4
  280. package/dist/{dashboard-CVyGhift.mjs.map → dashboard-EvEKF5en.mjs.map} +1 -1
  281. package/dist/db/index.d.mts +3 -3
  282. package/dist/db/index.mjs +1 -1
  283. package/dist/db/libsql.d.mts +1 -1
  284. package/dist/db/postgres.d.mts +1 -1
  285. package/dist/db/sqlite.d.mts +1 -1
  286. package/dist/{default-CeRG-Ot4.mjs → default-CM_D83Mg.mjs} +1 -1
  287. package/dist/{default-CeRG-Ot4.mjs.map → default-CM_D83Mg.mjs.map} +1 -1
  288. package/dist/{device-flow-DENDCQ9F.mjs → device-flow-CfGP18Uw.mjs} +4 -4
  289. package/dist/{device-flow-DENDCQ9F.mjs.map → device-flow-CfGP18Uw.mjs.map} +1 -1
  290. package/dist/{email-console-DJP32ucW.mjs → email-console-CIf4Lfvv.mjs} +1 -1
  291. package/dist/{email-console-DJP32ucW.mjs.map → email-console-CIf4Lfvv.mjs.map} +1 -1
  292. package/dist/{error-BHkLZk-w.mjs → error-CkAseSqZ.mjs} +2 -2
  293. package/dist/{error-BHkLZk-w.mjs.map → error-CkAseSqZ.mjs.map} +1 -1
  294. package/dist/{escape-Bjio4ZsM.mjs → escape-DqD0aCKu.mjs} +1 -1
  295. package/dist/{escape-Bjio4ZsM.mjs.map → escape-DqD0aCKu.mjs.map} +1 -1
  296. package/dist/{field-defs-cache-BA-8ZPiT.mjs → field-defs-cache-WUI88LX5.mjs} +2 -2
  297. package/dist/{field-defs-cache-BA-8ZPiT.mjs.map → field-defs-cache-WUI88LX5.mjs.map} +1 -1
  298. package/dist/{fts-manager-Db9jGavf.mjs → fts-manager-BbFaF_V8.mjs} +2 -2
  299. package/dist/{fts-manager-Db9jGavf.mjs.map → fts-manager-BbFaF_V8.mjs.map} +1 -1
  300. package/dist/{import-Bb1T9WJS.mjs → import-fYLf14Co.mjs} +514 -25
  301. package/dist/import-fYLf14Co.mjs.map +1 -0
  302. package/dist/{index-CDZZjrLT.d.mts → index-B9sIxwe4.d.mts} +21 -22
  303. package/dist/{index-CDZZjrLT.d.mts.map → index-B9sIxwe4.d.mts.map} +1 -1
  304. package/dist/{index-DGIjmUXQ.d.mts → index-Bm-Gy8Mh.d.mts} +25 -4
  305. package/dist/index-Bm-Gy8Mh.d.mts.map +1 -0
  306. package/dist/index.d.mts +18 -18
  307. package/dist/index.mjs +54 -53
  308. package/dist/{load-DpHICVPh.mjs → load-Djn3HWQS.mjs} +2 -2
  309. package/dist/{load-DpHICVPh.mjs.map → load-Djn3HWQS.mjs.map} +1 -1
  310. package/dist/{loader-4K37qA-y.mjs → loader-CB6YHeul.mjs} +6 -5
  311. package/dist/loader-CB6YHeul.mjs.map +1 -0
  312. package/dist/{manifest-schema-kPGX7VS-.mjs → manifest-schema-BHlgZM1W.mjs} +1 -1
  313. package/dist/{manifest-schema-kPGX7VS-.mjs.map → manifest-schema-BHlgZM1W.mjs.map} +1 -1
  314. package/dist/media/index.d.mts +1 -1
  315. package/dist/media/local-runtime.d.mts +12 -12
  316. package/dist/media/local-runtime.mjs +5 -5
  317. package/dist/{media-C0nRRfs1.mjs → media-BrXIaMFN.mjs} +2 -2
  318. package/dist/{media-C0nRRfs1.mjs.map → media-BrXIaMFN.mjs.map} +1 -1
  319. package/dist/{media-allowlist-Du8t1u6a.mjs → media-allowlist-CRHEeJ_i.mjs} +1 -1
  320. package/dist/{media-allowlist-Du8t1u6a.mjs.map → media-allowlist-CRHEeJ_i.mjs.map} +1 -1
  321. package/dist/{media-url-O4rm9-SQ.mjs → media-url-CKi5XSw4.mjs} +1 -1
  322. package/dist/{media-url-O4rm9-SQ.mjs.map → media-url-CKi5XSw4.mjs.map} +1 -1
  323. package/dist/{menus-SL2K0xq2.mjs → menus-Cfivc2Ad.mjs} +3 -3
  324. package/dist/{menus-SL2K0xq2.mjs.map → menus-Cfivc2Ad.mjs.map} +1 -1
  325. package/dist/{menus-DzRyC1ID.mjs → menus-CsZ2ZEK2.mjs} +16 -12
  326. package/dist/{menus-DzRyC1ID.mjs.map → menus-CsZ2ZEK2.mjs.map} +1 -1
  327. package/dist/{mode-BB0F8xTC.mjs → mode-BM9QgEmt.mjs} +1 -1
  328. package/dist/{mode-BB0F8xTC.mjs.map → mode-BM9QgEmt.mjs.map} +1 -1
  329. package/dist/{oauth-authorization-CsvzIp_F.mjs → oauth-authorization-CXWkIGT4.mjs} +4 -4
  330. package/dist/{oauth-authorization-CsvzIp_F.mjs.map → oauth-authorization-CXWkIGT4.mjs.map} +1 -1
  331. package/dist/{oauth-clients-C9SYwEbZ.mjs → oauth-clients-BmTI5rsl.mjs} +1 -1
  332. package/dist/{oauth-clients-C9SYwEbZ.mjs.map → oauth-clients-BmTI5rsl.mjs.map} +1 -1
  333. package/dist/{oauth-state-store---zrApfB.mjs → oauth-state-store-YLFLcH5F.mjs} +1 -1
  334. package/dist/{oauth-state-store---zrApfB.mjs.map → oauth-state-store-YLFLcH5F.mjs.map} +1 -1
  335. package/dist/{oauth-user-lookup-SHsWRlG9.mjs → oauth-user-lookup-Bsc_GsX-.mjs} +1 -1
  336. package/dist/{oauth-user-lookup-SHsWRlG9.mjs.map → oauth-user-lookup-Bsc_GsX-.mjs.map} +1 -1
  337. package/dist/object-cache/memory.d.mts +1 -1
  338. package/dist/{object-cache-CHbHv83-.mjs → object-cache-Bok5j2ae.mjs} +43 -3
  339. package/dist/object-cache-Bok5j2ae.mjs.map +1 -0
  340. package/dist/{options-41nCWqi9.d.mts → options-iMpRRxIe.d.mts} +3 -3
  341. package/dist/{options-41nCWqi9.d.mts.map → options-iMpRRxIe.d.mts.map} +1 -1
  342. package/dist/page/index.d.mts +2 -2
  343. package/dist/{parse-CqyZj3Hp.mjs → parse-GmjecGct.mjs} +2 -2
  344. package/dist/{parse-CqyZj3Hp.mjs.map → parse-GmjecGct.mjs.map} +1 -1
  345. package/dist/{passkey-config-C0YfSBko.mjs → passkey-config-De0ahnRg.mjs} +1 -1
  346. package/dist/{passkey-config-C0YfSBko.mjs.map → passkey-config-De0ahnRg.mjs.map} +1 -1
  347. package/dist/{placeholder-Cuce9U-m.d.mts → placeholder-BSKwzRe4.d.mts} +1 -1
  348. package/dist/{placeholder-Cuce9U-m.d.mts.map → placeholder-BSKwzRe4.d.mts.map} +1 -1
  349. package/dist/plugin-types.d.mts +1 -1
  350. package/dist/plugin-utils.d.mts +10 -10
  351. package/dist/plugins/adapt-sandbox-entry.d.mts +10 -10
  352. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  353. package/dist/{portable-text-BICg8bTk.mjs → portable-text-cCa0cGV6.mjs} +1 -1
  354. package/dist/{portable-text-BICg8bTk.mjs.map → portable-text-cCa0cGV6.mjs.map} +1 -1
  355. package/dist/{preview-DKGCt2_p.mjs → preview-SSXNVPAC.mjs} +2 -2
  356. package/dist/{preview-DKGCt2_p.mjs.map → preview-SSXNVPAC.mjs.map} +1 -1
  357. package/dist/{public-url-CTVqgMmg.mjs → public-url-Danv47cS.mjs} +1 -1
  358. package/dist/{public-url-CTVqgMmg.mjs.map → public-url-Danv47cS.mjs.map} +1 -1
  359. package/dist/{query-B0M-9LYR.mjs → query-ByGq6ver.mjs} +14 -14
  360. package/dist/{query-B0M-9LYR.mjs.map → query-ByGq6ver.mjs.map} +1 -1
  361. package/dist/{rate-limit-BwoUdIpC.mjs → rate-limit-C_Lf63Dd.mjs} +2 -2
  362. package/dist/{rate-limit-BwoUdIpC.mjs.map → rate-limit-C_Lf63Dd.mjs.map} +1 -1
  363. package/dist/{redirect-CS-PHtNh.mjs → redirect-CoW3G-0U.mjs} +1 -1
  364. package/dist/{redirect-CS-PHtNh.mjs.map → redirect-CoW3G-0U.mjs.map} +1 -1
  365. package/dist/{redirect-lMOzG04S.mjs → redirect-IyfNirgS.mjs} +2 -2
  366. package/dist/{redirect-lMOzG04S.mjs.map → redirect-IyfNirgS.mjs.map} +1 -1
  367. package/dist/{redirects-9218MmYl.mjs → redirects-Bs1g42Ri.mjs} +4 -4
  368. package/dist/{redirects-9218MmYl.mjs.map → redirects-Bs1g42Ri.mjs.map} +1 -1
  369. package/dist/{redirects-Dcbuisoj.mjs → redirects-DXEXBAII.mjs} +2 -2
  370. package/dist/{redirects-Dcbuisoj.mjs.map → redirects-DXEXBAII.mjs.map} +1 -1
  371. package/dist/{registry-DP-iEtdR.mjs → registry-B65mUtPa.mjs} +122 -79
  372. package/dist/registry-B65mUtPa.mjs.map +1 -0
  373. package/dist/{request-meta-CmS1tDFf.mjs → request-meta-DbvXaAvU.mjs} +2 -2
  374. package/dist/{request-meta-CmS1tDFf.mjs.map → request-meta-DbvXaAvU.mjs.map} +1 -1
  375. package/dist/{resolve-C7I0qiR0.mjs → resolve-DR3wqMTy.mjs} +1 -1
  376. package/dist/{resolve-C7I0qiR0.mjs.map → resolve-DR3wqMTy.mjs.map} +1 -1
  377. package/dist/{runner-BbR3DfrL.d.mts → runner-DvFWoz8-.d.mts} +2 -2
  378. package/dist/{runner-BbR3DfrL.d.mts.map → runner-DvFWoz8-.d.mts.map} +1 -1
  379. package/dist/{runner-CFngB4WZ.mjs → runner-K8XK101B.mjs} +309 -190
  380. package/dist/runner-K8XK101B.mjs.map +1 -0
  381. package/dist/runtime.d.mts +11 -11
  382. package/dist/runtime.mjs +2 -2
  383. package/dist/{scheduled-publish-BMljtY5G.d.mts → scheduled-publish-Drffrf2a.d.mts} +1 -1
  384. package/dist/scheduled-publish-Drffrf2a.d.mts.map +1 -0
  385. package/dist/{schema-BfJ7bIXH.mjs → schema-Blhoxp3P.mjs} +5 -5
  386. package/dist/{schema-BfJ7bIXH.mjs.map → schema-Blhoxp3P.mjs.map} +1 -1
  387. package/dist/{search-C7t3PH1J.mjs → search-DZN2HZ-V.mjs} +4 -4
  388. package/dist/{search-C7t3PH1J.mjs.map → search-DZN2HZ-V.mjs.map} +1 -1
  389. package/dist/{secrets-BSf9pRRY.mjs → secrets-kp760LlD.mjs} +2 -2
  390. package/dist/{secrets-BSf9pRRY.mjs.map → secrets-kp760LlD.mjs.map} +1 -1
  391. package/dist/{sections-Dm0CVX23.mjs → sections-CpF5SaGr.mjs} +3 -3
  392. package/dist/{sections-Dm0CVX23.mjs.map → sections-CpF5SaGr.mjs.map} +1 -1
  393. package/dist/seed/index.d.mts +2 -2
  394. package/dist/seed/index.mjs +19 -18
  395. package/dist/seo/index.d.mts +1 -1
  396. package/dist/seo/index.mjs +1 -1
  397. package/dist/{seo-BkhuuaaE.mjs → seo-89-53DDs.mjs} +1 -1
  398. package/dist/{seo-BkhuuaaE.mjs.map → seo-89-53DDs.mjs.map} +1 -1
  399. package/dist/{seo-Dd3tbY_k.mjs → seo-DXu2UQnC.mjs} +3 -3
  400. package/dist/{seo-Dd3tbY_k.mjs.map → seo-DXu2UQnC.mjs.map} +1 -1
  401. package/dist/{service-CTrqp_Jy.mjs → service-DQmiBMzt.mjs} +3 -3
  402. package/dist/{service-CTrqp_Jy.mjs.map → service-DQmiBMzt.mjs.map} +1 -1
  403. package/dist/{session-user-B8aLtKAH.mjs → session-user-Cascbax7.mjs} +1 -1
  404. package/dist/{session-user-B8aLtKAH.mjs.map → session-user-Cascbax7.mjs.map} +1 -1
  405. package/dist/{settings-CZ7ZP9cW.mjs → settings-rZyHEcNT.mjs} +3 -3
  406. package/dist/{settings-CZ7ZP9cW.mjs.map → settings-rZyHEcNT.mjs.map} +1 -1
  407. package/dist/{settings-BX8cWBus.mjs → settings-zhmdKyJQ.mjs} +5 -5
  408. package/dist/{settings-BX8cWBus.mjs.map → settings-zhmdKyJQ.mjs.map} +1 -1
  409. package/dist/{setup-complete-gEiySUc-.mjs → setup-complete-Cb3LRyzy.mjs} +1 -1
  410. package/dist/{setup-complete-gEiySUc-.mjs.map → setup-complete-Cb3LRyzy.mjs.map} +1 -1
  411. package/dist/{setup-nonce-DzS50zme.mjs → setup-nonce-Z8x0tHf8.mjs} +1 -1
  412. package/dist/{setup-nonce-DzS50zme.mjs.map → setup-nonce-Z8x0tHf8.mjs.map} +1 -1
  413. package/dist/{single-flight-cache-Cdfkic3t.mjs → single-flight-cache-BG3B_GhN.mjs} +1 -1
  414. package/dist/{single-flight-cache-Cdfkic3t.mjs.map → single-flight-cache-BG3B_GhN.mjs.map} +1 -1
  415. package/dist/{site-url-BLebyON8.mjs → site-url-BBfDTgZB.mjs} +1 -1
  416. package/dist/{site-url-BLebyON8.mjs.map → site-url-BBfDTgZB.mjs.map} +1 -1
  417. package/dist/{ssrf-BRKb343l.mjs → ssrf-1g7usGBg.mjs} +1 -1
  418. package/dist/{ssrf-BRKb343l.mjs.map → ssrf-1g7usGBg.mjs.map} +1 -1
  419. package/dist/{status-vUK0SA17.mjs → status-CqJQX1QN.mjs} +1 -1
  420. package/dist/{status-vUK0SA17.mjs.map → status-CqJQX1QN.mjs.map} +1 -1
  421. package/dist/storage/local.d.mts +1 -1
  422. package/dist/storage/local.mjs +1 -1
  423. package/dist/storage/s3.d.mts +1 -1
  424. package/dist/storage/s3.mjs +1 -1
  425. package/dist/{taxonomies-DChKcVxf.mjs → taxonomies-BGBd16Eu.mjs} +4 -4
  426. package/dist/{taxonomies-DChKcVxf.mjs.map → taxonomies-BGBd16Eu.mjs.map} +1 -1
  427. package/dist/{taxonomies-ckPjz-6d.mjs → taxonomies-Cnb4F-Pb.mjs} +7 -7
  428. package/dist/{taxonomies-ckPjz-6d.mjs.map → taxonomies-Cnb4F-Pb.mjs.map} +1 -1
  429. package/dist/{taxonomy-Cru-he6s.mjs → taxonomy-BxGxZZdu.mjs} +4 -4
  430. package/dist/{taxonomy-Cru-he6s.mjs.map → taxonomy-BxGxZZdu.mjs.map} +1 -1
  431. package/dist/{tokens-LeuXF9gG.mjs → tokens-BGT0TUUo.mjs} +1 -1
  432. package/dist/{tokens-LeuXF9gG.mjs.map → tokens-BGT0TUUo.mjs.map} +1 -1
  433. package/dist/{transport-Blrl2k_o.d.mts → transport-BMDWHSgZ.d.mts} +1 -1
  434. package/dist/{transport-Blrl2k_o.d.mts.map → transport-BMDWHSgZ.d.mts.map} +1 -1
  435. package/dist/{transport-_2nBz7e9.mjs → transport-DPefPMcz.mjs} +1 -1
  436. package/dist/{transport-_2nBz7e9.mjs.map → transport-DPefPMcz.mjs.map} +1 -1
  437. package/dist/{trusted-proxy-DZY5WCn2.mjs → trusted-proxy-VTPRiX2s.mjs} +1 -1
  438. package/dist/{trusted-proxy-DZY5WCn2.mjs.map → trusted-proxy-VTPRiX2s.mjs.map} +1 -1
  439. package/dist/{types-ETmO_jQr.d.mts → types-BcLUUbbR.d.mts} +2 -2
  440. package/dist/{types-ETmO_jQr.d.mts.map → types-BcLUUbbR.d.mts.map} +1 -1
  441. package/dist/{types-BYnDBVwe.d.mts → types-CGbYowGQ.d.mts} +2 -2
  442. package/dist/{types-BYnDBVwe.d.mts.map → types-CGbYowGQ.d.mts.map} +1 -1
  443. package/dist/{types-CvuKO5Pn.d.mts → types-CgvhU-hF.d.mts} +1 -1
  444. package/dist/{types-CvuKO5Pn.d.mts.map → types-CgvhU-hF.d.mts.map} +1 -1
  445. package/dist/{types-Y09-wtyU.d.mts → types-ClUkdbWb.d.mts} +1 -1
  446. package/dist/{types-Y09-wtyU.d.mts.map → types-ClUkdbWb.d.mts.map} +1 -1
  447. package/dist/{types-DU4TSFS5.mjs → types-CuW0zWDA.mjs} +2 -2
  448. package/dist/{types-DU4TSFS5.mjs.map → types-CuW0zWDA.mjs.map} +1 -1
  449. package/dist/{types-BkZ8DUEI.d.mts → types-DmHk7vAt.d.mts} +1 -1
  450. package/dist/{types-BkZ8DUEI.d.mts.map → types-DmHk7vAt.d.mts.map} +1 -1
  451. package/dist/{types-CQAugunJ.mjs → types-Jo3UYd6b.mjs} +1 -1
  452. package/dist/{types-CQAugunJ.mjs.map → types-Jo3UYd6b.mjs.map} +1 -1
  453. package/dist/{types-xIfVRNLp.d.mts → types-_HFLRzTn.d.mts} +22 -1
  454. package/dist/types-_HFLRzTn.d.mts.map +1 -0
  455. package/dist/{types-ByChcBgE.d.mts → types-ea9sAPck.d.mts} +1 -1
  456. package/dist/{types-ByChcBgE.d.mts.map → types-ea9sAPck.d.mts.map} +1 -1
  457. package/dist/{types-CNlaBFzx.d.mts → types-g_aFIdW0.d.mts} +1 -1
  458. package/dist/{types-CNlaBFzx.d.mts.map → types-g_aFIdW0.d.mts.map} +1 -1
  459. package/dist/{types-Dbqff978.d.mts → types-vgEWF18A.d.mts} +19 -1
  460. package/dist/{types-Dbqff978.d.mts.map → types-vgEWF18A.d.mts.map} +1 -1
  461. package/dist/{user-DgGbKL9s.mjs → user-BjAOvU3Z.mjs} +3 -3
  462. package/dist/{user-DgGbKL9s.mjs.map → user-BjAOvU3Z.mjs.map} +1 -1
  463. package/dist/{utils-B7A57fm9.mjs → utils-BJXElxdw.mjs} +156 -7
  464. package/dist/utils-BJXElxdw.mjs.map +1 -0
  465. package/dist/{validate-CRkcYZAR.mjs → validate-CWSnKVIJ.mjs} +2 -2
  466. package/dist/{validate-CRkcYZAR.mjs.map → validate-CWSnKVIJ.mjs.map} +1 -1
  467. package/dist/{validate-9ECmtEpJ.d.mts → validate-Z1b86_3B.d.mts} +5 -5
  468. package/dist/{validate-9ECmtEpJ.d.mts.map → validate-Z1b86_3B.d.mts.map} +1 -1
  469. package/dist/{validation-sR26SOwD.mjs → validation-c8WjhH8z.mjs} +8 -5
  470. package/dist/{validation-sR26SOwD.mjs.map → validation-c8WjhH8z.mjs.map} +1 -1
  471. package/dist/version-CaccU7DM.mjs +7 -0
  472. package/dist/{version-CrqhKGWn.mjs.map → version-CaccU7DM.mjs.map} +1 -1
  473. package/dist/{widgets-DRgtn7Cl.mjs → widgets-hWcIicX8.mjs} +3 -3
  474. package/dist/{widgets-DRgtn7Cl.mjs.map → widgets-hWcIicX8.mjs.map} +1 -1
  475. package/dist/wxr-taxonomies-0_uxSrmf.d.mts +34 -0
  476. package/dist/wxr-taxonomies-0_uxSrmf.d.mts.map +1 -0
  477. package/dist/wxr-taxonomies-BC3OYpvx.mjs +425 -0
  478. package/dist/wxr-taxonomies-BC3OYpvx.mjs.map +1 -0
  479. package/dist/{zod-generator-C5JaV--i.mjs → zod-generator-CacrR-i8.mjs} +2 -2
  480. package/dist/{zod-generator-C5JaV--i.mjs.map → zod-generator-CacrR-i8.mjs.map} +1 -1
  481. package/package.json +7 -7
  482. package/src/api/handlers/content.ts +10 -7
  483. package/src/api/schemas/import.ts +19 -0
  484. package/src/astro/integration/runtime.ts +3 -6
  485. package/src/astro/middleware/auth.ts +9 -3
  486. package/src/astro/middleware/csp.ts +54 -3
  487. package/src/astro/routes/admin.astro +9 -0
  488. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +122 -98
  489. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +794 -44
  490. package/src/components/EmDashImage.astro +59 -23
  491. package/src/components/Image.astro +36 -35
  492. package/src/database/migrations/049_taxonomies_name_locale_index.ts +42 -0
  493. package/src/database/migrations/050_media_usage_index_status.ts +142 -0
  494. package/src/database/migrations/runner.ts +4 -0
  495. package/src/database/repositories/media-usage.ts +932 -58
  496. package/src/database/types.ts +22 -0
  497. package/src/emdash-runtime.ts +123 -3
  498. package/src/import/comments.ts +159 -0
  499. package/src/import/index.ts +8 -1
  500. package/src/import/settings.ts +65 -189
  501. package/src/import/sources/wordpress-plugin.ts +338 -42
  502. package/src/import/sources/wxr.ts +4 -1
  503. package/src/import/types.ts +12 -0
  504. package/src/import/utils.ts +207 -0
  505. package/src/import/wxr-taxonomies.ts +39 -0
  506. package/src/loader.ts +13 -2
  507. package/src/media/usage/content-fields.ts +119 -0
  508. package/src/media/usage/content-refresh.ts +524 -0
  509. package/src/media/usage/content-repair.ts +491 -0
  510. package/src/media/usage/content-snapshots.ts +435 -0
  511. package/src/media/usage/extractor.ts +4 -4
  512. package/src/media/usage/source-key.ts +22 -0
  513. package/src/menus/index.ts +17 -1
  514. package/src/object-cache/index.ts +82 -7
  515. package/src/plugins/context.ts +100 -71
  516. package/src/schema/registry.ts +240 -154
  517. package/src/seed/apply.ts +156 -99
  518. package/dist/api-80kycR9o.mjs.map +0 -1
  519. package/dist/apply-DSypk6Iu.mjs.map +0 -1
  520. package/dist/byline-fields-eyJMblSr.mjs.map +0 -1
  521. package/dist/context-CzUU_WzL.mjs.map +0 -1
  522. package/dist/import-Bb1T9WJS.mjs.map +0 -1
  523. package/dist/index-DGIjmUXQ.d.mts.map +0 -1
  524. package/dist/loader-4K37qA-y.mjs.map +0 -1
  525. package/dist/object-cache-CHbHv83-.mjs.map +0 -1
  526. package/dist/registry-DP-iEtdR.mjs.map +0 -1
  527. package/dist/runner-CFngB4WZ.mjs.map +0 -1
  528. package/dist/scheduled-publish-BMljtY5G.d.mts.map +0 -1
  529. package/dist/types-xIfVRNLp.d.mts.map +0 -1
  530. package/dist/utils-B7A57fm9.mjs.map +0 -1
  531. package/dist/version-CrqhKGWn.mjs +0 -7
  532. /package/dist/{api-tokens-B4BQybOp.mjs → api-tokens-DsvvCtdh.mjs} +0 -0
  533. /package/dist/{ssrf-CcX9zvMK.mjs → ssrf-CmuGgCq3.mjs} +0 -0
  534. /package/dist/{types-BvbeGEtr.mjs → types-DROWRxYV.mjs} +0 -0
@@ -0,0 +1,435 @@
1
+ import { sql, type Kysely } from "kysely";
2
+
3
+ import type {
4
+ MediaUsageOccurrenceInput,
5
+ MediaUsageSourceInput,
6
+ } from "../../database/repositories/media-usage.js";
7
+ import type { Database } from "../../database/types.js";
8
+ import { validateIdentifier } from "../../database/validate.js";
9
+ import { hashString } from "../../utils/hash.js";
10
+ import {
11
+ loadContentMediaUsageFields,
12
+ type ContentMediaUsageField,
13
+ type ContentMediaUsageFieldDiscovery,
14
+ } from "./content-fields.js";
15
+ import { extractMediaUsageOccurrences } from "./extractor.js";
16
+ import {
17
+ buildContentMediaUsageSourceKey,
18
+ type MediaUsageContentSourceVariant,
19
+ } from "./source-key.js";
20
+
21
+ export const CONTENT_SOURCE_SCHEMA_VERSION = 1;
22
+
23
+ const CONTENT_SYSTEM_COLUMNS = [
24
+ "id",
25
+ "slug",
26
+ "status",
27
+ "created_at",
28
+ "updated_at",
29
+ "published_at",
30
+ "scheduled_at",
31
+ "deleted_at",
32
+ "version",
33
+ "live_revision_id",
34
+ "draft_revision_id",
35
+ "locale",
36
+ "translation_group",
37
+ ] as const;
38
+
39
+ export type LoadContentMediaUsageSnapshotsResult =
40
+ | { success: true; snapshots: ContentMediaUsageSnapshot[] }
41
+ | {
42
+ success: false;
43
+ error:
44
+ | "CONTENT_NOT_FOUND"
45
+ | "DRAFT_REVISION_NOT_FOUND"
46
+ | "DRAFT_REVISION_MISMATCH"
47
+ | "DRAFT_REVISION_INVALID";
48
+ source?: MediaUsageSourceInput;
49
+ };
50
+
51
+ export interface ContentMediaUsageSnapshot {
52
+ source: MediaUsageSourceInput;
53
+ occurrences: MediaUsageOccurrenceInput[];
54
+ fields: readonly ContentMediaUsageField[];
55
+ }
56
+
57
+ export async function loadContentMediaUsageSnapshots(
58
+ db: Kysely<Database>,
59
+ collectionSlug: string,
60
+ contentId: string,
61
+ fieldDiscovery?: ContentMediaUsageFieldDiscovery,
62
+ ): Promise<LoadContentMediaUsageSnapshotsResult> {
63
+ validateIdentifier(collectionSlug, "collection slug");
64
+ const discovery = fieldDiscovery ?? (await loadContentMediaUsageFields(db, collectionSlug));
65
+ const row = await loadContentRow(db, collectionSlug, contentId, [
66
+ ...discovery.extractionFields.map((field) => field.slug),
67
+ ...discovery.displayFieldSlugs,
68
+ ]);
69
+
70
+ if (!row) return { success: false, error: "CONTENT_NOT_FOUND" };
71
+
72
+ const columnsData = projectData(
73
+ row,
74
+ discovery.extractionFields.map((field) => field.slug),
75
+ );
76
+ const displayData = projectRawData(row, discovery.displayFieldSlugs);
77
+ const occurrences = extractMediaUsageOccurrences({
78
+ fields: discovery.extractionFields,
79
+ data: columnsData,
80
+ });
81
+ const columnsRevisionId = readNullableString(row.live_revision_id);
82
+ const columnsFingerprint = await buildSourceFingerprint({
83
+ collectionSlug,
84
+ sourceVariant: "columns",
85
+ revisionId: columnsRevisionId,
86
+ fields: discovery.extractionFields,
87
+ data: columnsData,
88
+ });
89
+ const snapshots: ContentMediaUsageSnapshot[] = [
90
+ {
91
+ source: buildContentSource({
92
+ collectionSlug,
93
+ row,
94
+ displayData,
95
+ sourceVariant: "columns",
96
+ revisionId: columnsRevisionId,
97
+ sourceFingerprint: columnsFingerprint,
98
+ }),
99
+ occurrences,
100
+ fields: discovery.extractionFields,
101
+ },
102
+ ];
103
+
104
+ const draftRevisionId = readNullableString(row.draft_revision_id);
105
+ if (draftRevisionId) {
106
+ const attemptedDraftSource = buildContentSource({
107
+ collectionSlug,
108
+ row,
109
+ displayData,
110
+ sourceVariant: "draft_overlay",
111
+ revisionId: draftRevisionId,
112
+ });
113
+ const revisionResult = await loadRevisionRow(db, draftRevisionId);
114
+ if (!revisionResult) {
115
+ return {
116
+ success: false,
117
+ error: "DRAFT_REVISION_NOT_FOUND",
118
+ source: attemptedDraftSource,
119
+ };
120
+ }
121
+ if (!revisionResult.success) {
122
+ return {
123
+ success: false,
124
+ error: "DRAFT_REVISION_INVALID",
125
+ source: attemptedDraftSource,
126
+ };
127
+ }
128
+ const revision = revisionResult.revision;
129
+ if (revision.collection !== collectionSlug || revision.entryId !== row.id) {
130
+ return {
131
+ success: false,
132
+ error: "DRAFT_REVISION_MISMATCH",
133
+ source: attemptedDraftSource,
134
+ };
135
+ }
136
+
137
+ const revisionData = stripRevisionMetadata(revision.data);
138
+ const draftOverlayData = { ...columnsData, ...revisionData };
139
+ const draftDisplayData = {
140
+ ...displayData,
141
+ ...projectPresentData(revisionData, discovery.displayFieldSlugs),
142
+ };
143
+ const draftContentSlug =
144
+ readNullableString(revision.data._slug) ?? readNullableString(row.slug);
145
+ const draftFingerprint = await buildSourceFingerprint({
146
+ collectionSlug,
147
+ sourceVariant: "draft_overlay",
148
+ revisionId: draftRevisionId,
149
+ fields: discovery.extractionFields,
150
+ data: draftOverlayData,
151
+ });
152
+ snapshots.push({
153
+ source: buildContentSource({
154
+ collectionSlug,
155
+ row,
156
+ displayData: draftDisplayData,
157
+ sourceVariant: "draft_overlay",
158
+ revisionId: draftRevisionId,
159
+ contentSlug: draftContentSlug,
160
+ sourceFingerprint: draftFingerprint,
161
+ }),
162
+ occurrences: extractMediaUsageOccurrences({
163
+ fields: discovery.extractionFields,
164
+ data: draftOverlayData,
165
+ }),
166
+ fields: discovery.extractionFields,
167
+ });
168
+ }
169
+
170
+ return {
171
+ success: true,
172
+ snapshots,
173
+ };
174
+ }
175
+
176
+ interface RevisionSnapshotRow {
177
+ id: string;
178
+ collection: string;
179
+ entryId: string;
180
+ data: Record<string, unknown>;
181
+ }
182
+
183
+ async function loadContentRow(
184
+ db: Kysely<Database>,
185
+ collectionSlug: string,
186
+ contentId: string,
187
+ fieldSlugs: readonly string[],
188
+ ): Promise<Record<string, unknown> | null> {
189
+ const tableName = getContentTableName(collectionSlug);
190
+ const columns = uniqueColumns([...CONTENT_SYSTEM_COLUMNS, ...fieldSlugs]);
191
+ const columnRefs = columns.map((column) => sql.ref(column));
192
+ const result = await sql<Record<string, unknown>>`
193
+ SELECT ${sql.join(columnRefs, sql`, `)}
194
+ FROM ${sql.ref(tableName)}
195
+ WHERE id = ${contentId}
196
+ LIMIT 1
197
+ `.execute(db);
198
+
199
+ return result.rows[0] ?? null;
200
+ }
201
+
202
+ async function loadRevisionRow(
203
+ db: Kysely<Database>,
204
+ revisionId: string,
205
+ ): Promise<{ success: true; revision: RevisionSnapshotRow } | { success: false } | null> {
206
+ const row = await db
207
+ .selectFrom("revisions")
208
+ .select(["id", "collection", "entry_id", "data"])
209
+ .where("id", "=", revisionId)
210
+ .executeTakeFirst();
211
+ if (!row) return null;
212
+ const data = parseRevisionData(row.data);
213
+ if (!data) return { success: false };
214
+ return {
215
+ success: true,
216
+ revision: {
217
+ id: row.id,
218
+ collection: row.collection,
219
+ entryId: row.entry_id,
220
+ data,
221
+ },
222
+ };
223
+ }
224
+
225
+ function buildContentSource(input: {
226
+ collectionSlug: string;
227
+ row: Record<string, unknown>;
228
+ displayData: Record<string, unknown>;
229
+ sourceVariant: MediaUsageContentSourceVariant;
230
+ revisionId: string | null;
231
+ contentSlug?: string | null;
232
+ sourceFingerprint?: string | null;
233
+ }): MediaUsageSourceInput {
234
+ const { collectionSlug, row, displayData, sourceVariant, revisionId } = input;
235
+ const contentId = readString(row.id) ?? "";
236
+ const contentSlug = input.contentSlug ?? readNullableString(row.slug);
237
+ const source: MediaUsageSourceInput = {
238
+ sourceKey: buildContentMediaUsageSourceKey({
239
+ collectionSlug,
240
+ contentId,
241
+ sourceVariant,
242
+ }),
243
+ sourceType: "content",
244
+ collectionSlug,
245
+ contentId,
246
+ sourceVariant,
247
+ locale: readNullableString(row.locale),
248
+ translationGroup: readNullableString(row.translation_group),
249
+ contentSlug,
250
+ contentTitle: deriveContentTitle(displayData, contentSlug, contentId),
251
+ contentStatus: readNullableString(row.status),
252
+ contentScheduledAt: readNullableString(row.scheduled_at),
253
+ contentDeletedAt: readNullableString(row.deleted_at),
254
+ revisionId,
255
+ schemaVersion: CONTENT_SOURCE_SCHEMA_VERSION,
256
+ sourceUpdatedAt: readNullableString(row.updated_at),
257
+ sourceVersion: readNumber(row.version),
258
+ };
259
+ if (input.sourceFingerprint !== undefined) source.sourceFingerprint = input.sourceFingerprint;
260
+ return source;
261
+ }
262
+
263
+ async function buildSourceFingerprint(input: {
264
+ collectionSlug: string;
265
+ sourceVariant: MediaUsageContentSourceVariant;
266
+ revisionId: string | null;
267
+ fields: readonly ContentMediaUsageField[];
268
+ data: Record<string, unknown>;
269
+ }): Promise<string> {
270
+ return hashString(
271
+ canonicalJson({
272
+ schemaVersion: CONTENT_SOURCE_SCHEMA_VERSION,
273
+ collectionSlug: input.collectionSlug,
274
+ sourceVariant: input.sourceVariant,
275
+ fields: normalizeFingerprintFields(input.fields),
276
+ values: projectFingerprintData(input.data, input.fields),
277
+ revisionId: input.sourceVariant === "draft_overlay" ? input.revisionId : null,
278
+ }),
279
+ );
280
+ }
281
+
282
+ function normalizeFingerprintFields(
283
+ fields: readonly ContentMediaUsageField[],
284
+ ): Record<string, unknown>[] {
285
+ return fields
286
+ .map((field) => {
287
+ if (field.type !== "repeater") return { slug: field.slug, type: field.type };
288
+ return {
289
+ slug: field.slug,
290
+ type: field.type,
291
+ subFields: (field.validation?.subFields ?? [])
292
+ .map((subField) => ({ slug: subField.slug, type: subField.type }))
293
+ .toSorted((a, b) => a.slug.localeCompare(b.slug)),
294
+ };
295
+ })
296
+ .toSorted((a, b) => String(a.slug).localeCompare(String(b.slug)));
297
+ }
298
+
299
+ function projectFingerprintData(
300
+ data: Record<string, unknown>,
301
+ fields: readonly ContentMediaUsageField[],
302
+ ): Record<string, unknown> {
303
+ const projected: Record<string, unknown> = {};
304
+ for (const field of fields) {
305
+ projected[field.slug] = Object.hasOwn(data, field.slug) ? data[field.slug] : null;
306
+ }
307
+ return projected;
308
+ }
309
+
310
+ function canonicalJson(value: unknown): string {
311
+ return JSON.stringify(canonicalize(value));
312
+ }
313
+
314
+ function canonicalize(value: unknown): unknown {
315
+ if (value === undefined) return null;
316
+ if (typeof value === "bigint") return value.toString();
317
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
318
+ if (Array.isArray(value)) return value.map((item) => canonicalize(item));
319
+ if (!isRecord(value)) return value;
320
+
321
+ const canonical: Record<string, unknown> = {};
322
+ for (const key of Object.keys(value).toSorted()) {
323
+ canonical[key] = canonicalize(value[key]);
324
+ }
325
+ return canonical;
326
+ }
327
+
328
+ function projectData(
329
+ row: Record<string, unknown>,
330
+ fieldSlugs: readonly string[],
331
+ ): Record<string, unknown> {
332
+ const data: Record<string, unknown> = {};
333
+ for (const fieldSlug of fieldSlugs) {
334
+ data[fieldSlug] = deserializeValue(row[fieldSlug] ?? null);
335
+ }
336
+ return data;
337
+ }
338
+
339
+ function projectRawData(
340
+ row: Record<string, unknown>,
341
+ fieldSlugs: readonly string[],
342
+ ): Record<string, unknown> {
343
+ const data: Record<string, unknown> = {};
344
+ for (const fieldSlug of fieldSlugs) {
345
+ data[fieldSlug] = row[fieldSlug] ?? null;
346
+ }
347
+ return data;
348
+ }
349
+
350
+ function projectPresentData(
351
+ row: Record<string, unknown>,
352
+ fieldSlugs: readonly string[],
353
+ ): Record<string, unknown> {
354
+ const data: Record<string, unknown> = {};
355
+ for (const fieldSlug of fieldSlugs) {
356
+ if (Object.hasOwn(row, fieldSlug)) data[fieldSlug] = row[fieldSlug];
357
+ }
358
+ return data;
359
+ }
360
+
361
+ function uniqueColumns(columns: readonly string[]): string[] {
362
+ const unique = [...new Set(columns)];
363
+ for (const column of unique) validateIdentifier(column, "content media usage column");
364
+ return unique;
365
+ }
366
+
367
+ function getContentTableName(collectionSlug: string): string {
368
+ validateIdentifier(collectionSlug, "collection slug");
369
+ return `ec_${collectionSlug}`;
370
+ }
371
+
372
+ function deserializeValue(value: unknown): unknown {
373
+ if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
374
+ try {
375
+ return JSON.parse(value);
376
+ } catch {
377
+ return value;
378
+ }
379
+ }
380
+ return value;
381
+ }
382
+
383
+ function parseRevisionData(value: unknown): Record<string, unknown> | null {
384
+ if (typeof value === "string") {
385
+ try {
386
+ const parsed: unknown = JSON.parse(value);
387
+ return isRecord(parsed) ? parsed : null;
388
+ } catch {
389
+ return null;
390
+ }
391
+ }
392
+ return isRecord(value) ? value : null;
393
+ }
394
+
395
+ function stripRevisionMetadata(data: Record<string, unknown>): Record<string, unknown> {
396
+ const stripped: Record<string, unknown> = {};
397
+ for (const [key, value] of Object.entries(data)) {
398
+ if (!key.startsWith("_")) stripped[key] = value;
399
+ }
400
+ return stripped;
401
+ }
402
+
403
+ function deriveContentTitle(
404
+ displayData: Record<string, unknown>,
405
+ contentSlug: string | null,
406
+ contentId: string,
407
+ ): string | null {
408
+ for (const fieldSlug of ["title", "name"] as const) {
409
+ const value = displayData[fieldSlug];
410
+ if (typeof value === "string" && value.trim()) return value;
411
+ }
412
+ return contentSlug ?? contentId;
413
+ }
414
+
415
+ function readString(value: unknown): string | null {
416
+ return typeof value === "string" ? value : null;
417
+ }
418
+
419
+ function readNullableString(value: unknown): string | null {
420
+ return value === null || value === undefined ? null : readString(value);
421
+ }
422
+
423
+ function readNumber(value: unknown): number | null {
424
+ if (typeof value === "number" && Number.isFinite(value)) return value;
425
+ if (typeof value === "bigint") return Number(value);
426
+ if (typeof value === "string" && value) {
427
+ const parsed = Number(value);
428
+ return Number.isFinite(parsed) ? parsed : null;
429
+ }
430
+ return null;
431
+ }
432
+
433
+ function isRecord(value: unknown): value is Record<string, unknown> {
434
+ return typeof value === "object" && value !== null && !Array.isArray(value);
435
+ }
@@ -1,4 +1,5 @@
1
1
  import { normalizeMime } from "../mime.js";
2
+ import { INTERNAL_MEDIA_PREFIX } from "../normalize.js";
2
3
  import type {
3
4
  ExtractedMediaUsageOccurrence,
4
5
  ExtractMediaUsageOccurrencesInput,
@@ -7,7 +8,6 @@ import type {
7
8
  MediaUsageReferenceType,
8
9
  } from "./types.js";
9
10
 
10
- const INTERNAL_MEDIA_PREFIX = "/_emdash/api/media/file/";
11
11
  const URL_LIKE_RE = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
12
12
 
13
13
  interface MediaRef {
@@ -84,14 +84,14 @@ function extractRepeaterOccurrences(
84
84
  if (!isRecord(item)) continue;
85
85
 
86
86
  for (const subField of subFields) {
87
- if (subField.type !== "image" && subField.type !== "file") continue;
87
+ if (subField.type !== "image") continue;
88
88
 
89
89
  addOccurrence(occurrences, seen, {
90
90
  fieldSlug,
91
91
  fieldPath: `${fieldSlug}[${itemIndex}].${subField.slug}`,
92
- referenceType: subField.type === "image" ? "image_field" : "file_field",
92
+ referenceType: "image_field",
93
93
  value: item[subField.slug],
94
- fallbackKind: subField.type === "image" ? "image" : null,
94
+ fallbackKind: "image",
95
95
  });
96
96
  }
97
97
  }
@@ -0,0 +1,22 @@
1
+ export const MEDIA_USAGE_CONTENT_SOURCE_VARIANTS = ["columns", "draft_overlay"] as const;
2
+
3
+ export type MediaUsageContentSourceVariant = (typeof MEDIA_USAGE_CONTENT_SOURCE_VARIANTS)[number];
4
+
5
+ export interface ContentMediaUsageSourceKeyInput {
6
+ collectionSlug: string;
7
+ contentId: string;
8
+ sourceVariant: MediaUsageContentSourceVariant;
9
+ }
10
+
11
+ export function isMediaUsageContentSourceVariant(
12
+ value: unknown,
13
+ ): value is MediaUsageContentSourceVariant {
14
+ return (
15
+ typeof value === "string" &&
16
+ (MEDIA_USAGE_CONTENT_SOURCE_VARIANTS as readonly string[]).includes(value)
17
+ );
18
+ }
19
+
20
+ export function buildContentMediaUsageSourceKey(input: ContentMediaUsageSourceKeyInput): string {
21
+ return `content:${input.collectionSlug}:${input.contentId}:${input.sourceVariant}`;
22
+ }
@@ -235,7 +235,23 @@ async function resolveMenuItem(
235
235
  break;
236
236
 
237
237
  case "collection":
238
- url = `/${item.reference_collection}/`;
238
+ // Two shapes share this type: the admin content picker stores
239
+ // entries from custom collections as "collection" with a
240
+ // reference_id, while archive links carry only the collection
241
+ // slug. Entry references resolve like page/post items.
242
+ if (!item.reference_collection) return null;
243
+ if (item.reference_id) {
244
+ url = await resolveContentUrl(
245
+ item.reference_collection,
246
+ item.reference_id,
247
+ db,
248
+ urlPatterns,
249
+ locale,
250
+ );
251
+ if (url === null) return null;
252
+ } else {
253
+ url = `/${item.reference_collection}/`;
254
+ }
239
255
  break;
240
256
 
241
257
  default:
@@ -77,6 +77,55 @@ interface EpochEntry {
77
77
  at: number;
78
78
  /** In-flight read, so concurrent callers share one backend round-trip. */
79
79
  promise?: Promise<number>;
80
+ /**
81
+ * `Date.now()` at which the in-flight read started. Callers use it to
82
+ * decide whether the read's owner can still be alive (see
83
+ * {@link epochReadDeadline}) — past the deadline the promise is presumed
84
+ * dead and the next caller reclaims by starting a fresh read.
85
+ */
86
+ promiseAt?: number;
87
+ }
88
+
89
+ /**
90
+ * Extra time past the configured read timeout before an in-flight epoch read
91
+ * is presumed dead. A live owner's read settles within `timeout` (enforced by
92
+ * {@link withTimeout}), so the grace only needs to absorb scheduling jitter.
93
+ */
94
+ const EPOCH_READ_GRACE_MS = 1_000;
95
+
96
+ /**
97
+ * How long an in-flight epoch read may be trusted. A read older than this can
98
+ * only exist because its owning request was cancelled mid-await — on workerd
99
+ * a cancelled request's continuations never run, *including the timeout's own
100
+ * `setTimeout` callback*, so the shared promise never settles and is never
101
+ * replaced. With the timeout disabled (`timeout: 0`) the default is used as
102
+ * the deadline; the worst case of guessing too short is one duplicate
103
+ * backend read.
104
+ */
105
+ function epochReadDeadline(): number {
106
+ const timeout = holder.config.timeout > 0 ? holder.config.timeout : DEFAULT_TIMEOUT_MS;
107
+ return timeout + EPOCH_READ_GRACE_MS;
108
+ }
109
+
110
+ /**
111
+ * Await another request's in-flight epoch read, bounded by the waiter's own
112
+ * timer. The bare promise must never be awaited across requests: if the
113
+ * owning request is cancelled, the promise never settles (see
114
+ * {@link epochReadDeadline}) and an unguarded waiter hangs until the isolate
115
+ * is evicted. The race timer below belongs to the *waiter's* request context
116
+ * and therefore always fires; on timeout the waiter degrades to `fallback`
117
+ * (the last known epoch), the same contract as a failed backend read.
118
+ */
119
+ function raceInFlightEpochRead(
120
+ promise: Promise<number>,
121
+ ms: number,
122
+ fallback: number,
123
+ ): Promise<number> {
124
+ let timer: ReturnType<typeof setTimeout>;
125
+ const timeout = new Promise<number>((resolve) => {
126
+ timer = setTimeout(resolve, Math.max(ms, 1), fallback);
127
+ });
128
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
80
129
  }
81
130
 
82
131
  const BACKEND_KEY = Symbol.for("emdash:object-cache:backend");
@@ -263,7 +312,17 @@ async function getEpoch(namespace: string, backend: ObjectCacheBackend): Promise
263
312
  if (cached && now - cached.at < holder.config.revalidate) {
264
313
  return cached.value;
265
314
  }
266
- if (cached?.promise) return cached.promise;
315
+ if (cached?.promise) {
316
+ // Share the in-flight read only while its owner can still be alive,
317
+ // and never await it bare (a cancelled owner's promise never settles;
318
+ // see epochReadDeadline). Past the deadline, fall through and reclaim
319
+ // with a fresh read — the dead entry is overwritten below.
320
+ const age = now - (cached.promiseAt ?? 0);
321
+ const deadline = epochReadDeadline();
322
+ if (age < deadline) {
323
+ return raceInFlightEpochRead(cached.promise, deadline - age, cached.value);
324
+ }
325
+ }
267
326
 
268
327
  const promise = (async () => {
269
328
  let value: number;
@@ -287,12 +346,28 @@ async function getEpoch(namespace: string, backend: ObjectCacheBackend): Promise
287
346
  return merged;
288
347
  })();
289
348
 
290
- // Concurrent callers share this in-flight read (dedup). The timeout above
291
- // guarantees `promise` settles its success/catch handler then replaces
292
- // this entry with a fresh, promise-free one so a stalled backend can no
293
- // longer pin the namespace to a never-settling promise (the bug that
294
- // poisoned an isolate until it was recycled).
295
- epochCache.set(namespace, { value: cached?.value ?? 0, at: cached?.at ?? 0, promise });
349
+ // Anchor the read on the host's lifetime extender: if the owning request
350
+ // is cancelled mid-await, the anchored copy keeps the read alive so it
351
+ // still settles and its handler replaces this entry with a fresh,
352
+ // promise-free one. Where no extender exists, the deadline reclaim above
353
+ // recovers instead.
354
+ after(() =>
355
+ promise.then(
356
+ () => undefined,
357
+ () => undefined,
358
+ ),
359
+ );
360
+
361
+ // Concurrent callers share this in-flight read (dedup) — bounded by their
362
+ // own timers via raceInFlightEpochRead, never awaited bare. The timeout
363
+ // above makes a live owner's read settle; `promiseAt` lets callers detect
364
+ // a dead one (cancelled owner) and reclaim.
365
+ epochCache.set(namespace, {
366
+ value: cached?.value ?? 0,
367
+ at: cached?.at ?? 0,
368
+ promise,
369
+ promiseAt: now,
370
+ });
296
371
  return promise;
297
372
  }
298
373