emdash 0.17.1 → 0.18.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 (285) hide show
  1. package/dist/api/route-utils.mjs +11 -11
  2. package/dist/{api-Dmz40c2V.mjs → api-Cs7DAACP.mjs} +12 -12
  3. package/dist/{api-Dmz40c2V.mjs.map → api-Cs7DAACP.mjs.map} +1 -1
  4. package/dist/{apply-CuuZG6op.mjs → apply-BWMV4Zmw.mjs} +16 -16
  5. package/dist/{apply-CuuZG6op.mjs.map → apply-BWMV4Zmw.mjs.map} +1 -1
  6. package/dist/astro/index.mjs +1 -1
  7. package/dist/astro/middleware/auth.mjs +2 -2
  8. package/dist/astro/middleware/redirect.mjs +5 -5
  9. package/dist/astro/middleware.d.mts.map +1 -1
  10. package/dist/astro/middleware.mjs +274 -91
  11. package/dist/astro/middleware.mjs.map +1 -1
  12. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +3 -3
  13. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +3 -3
  14. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
  15. package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
  16. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
  17. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +4 -4
  18. package/dist/astro/routes/api/admin/byline-fields/index.mjs +4 -4
  19. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +4 -4
  20. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +9 -9
  21. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +9 -9
  22. package/dist/astro/routes/api/admin/bylines/index.mjs +9 -9
  23. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +7 -7
  24. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  25. package/dist/astro/routes/api/admin/comments/bulk.mjs +6 -6
  26. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  27. package/dist/astro/routes/api/admin/comments/index.mjs +6 -6
  28. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  29. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  30. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  31. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  32. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +26 -26
  33. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +26 -26
  34. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +26 -26
  35. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +26 -26
  36. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +26 -26
  37. package/dist/astro/routes/api/admin/plugins/index.mjs +26 -26
  38. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  39. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +26 -26
  40. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +26 -26
  41. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +26 -26
  42. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +26 -26
  43. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +27 -27
  44. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +26 -26
  45. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +27 -27
  46. package/dist/astro/routes/api/admin/plugins/updates.mjs +26 -26
  47. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +26 -26
  48. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  49. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +26 -26
  50. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  51. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  52. package/dist/astro/routes/api/admin/users/_id_/index.mjs +3 -3
  53. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  54. package/dist/astro/routes/api/admin/users/index.mjs +3 -3
  55. package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
  56. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  57. package/dist/astro/routes/api/auth/invite/complete.mjs +3 -3
  58. package/dist/astro/routes/api/auth/invite/index.mjs +3 -3
  59. package/dist/astro/routes/api/auth/invite/register-options.mjs +3 -3
  60. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  61. package/dist/astro/routes/api/auth/magic-link/send.mjs +4 -4
  62. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  63. package/dist/astro/routes/api/auth/me.mjs +4 -4
  64. package/dist/astro/routes/api/auth/passkey/_id_.mjs +3 -3
  65. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  66. package/dist/astro/routes/api/auth/passkey/options.mjs +4 -4
  67. package/dist/astro/routes/api/auth/passkey/register/options.mjs +3 -3
  68. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +3 -3
  69. package/dist/astro/routes/api/auth/passkey/verify.mjs +3 -3
  70. package/dist/astro/routes/api/auth/signup/complete.mjs +3 -3
  71. package/dist/astro/routes/api/auth/signup/request.mjs +4 -4
  72. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  73. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +6 -6
  74. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  75. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  76. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  77. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  78. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +4 -4
  79. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +4 -4
  80. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  81. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  82. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +4 -4
  83. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +9 -9
  84. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  85. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  86. package/dist/astro/routes/api/content/_collection_/_id_.mjs +4 -4
  87. package/dist/astro/routes/api/content/_collection_/index.mjs +4 -4
  88. package/dist/astro/routes/api/content/_collection_/trash.mjs +4 -4
  89. package/dist/astro/routes/api/dashboard.mjs +7 -7
  90. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  91. package/dist/astro/routes/api/import/probe.mjs +4 -4
  92. package/dist/astro/routes/api/import/wordpress/analyze.mjs +3 -3
  93. package/dist/astro/routes/api/import/wordpress/execute.mjs +8 -8
  94. package/dist/astro/routes/api/import/wordpress/media.mjs +4 -4
  95. package/dist/astro/routes/api/import/wordpress/prepare.mjs +6 -6
  96. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +5 -5
  97. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +4 -4
  98. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +6 -6
  99. package/dist/astro/routes/api/manifest.mjs +3 -3
  100. package/dist/astro/routes/api/mcp.mjs +26 -26
  101. package/dist/astro/routes/api/media/_id_/confirm.mjs +4 -4
  102. package/dist/astro/routes/api/media/_id_.mjs +4 -4
  103. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  104. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  105. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  106. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  107. package/dist/astro/routes/api/media/upload-url.mjs +4 -4
  108. package/dist/astro/routes/api/media.mjs +5 -5
  109. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +5 -5
  110. package/dist/astro/routes/api/menus/_name_/items.mjs +5 -5
  111. package/dist/astro/routes/api/menus/_name_/reorder.mjs +5 -5
  112. package/dist/astro/routes/api/menus/_name_/translations.mjs +5 -5
  113. package/dist/astro/routes/api/menus/_name_.mjs +5 -5
  114. package/dist/astro/routes/api/menus/index.mjs +5 -5
  115. package/dist/astro/routes/api/oauth/device/authorize.mjs +3 -3
  116. package/dist/astro/routes/api/oauth/device/code.mjs +4 -4
  117. package/dist/astro/routes/api/oauth/device/token.mjs +4 -4
  118. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  119. package/dist/astro/routes/api/oauth/token/refresh.mjs +3 -3
  120. package/dist/astro/routes/api/oauth/token/revoke.mjs +3 -3
  121. package/dist/astro/routes/api/oauth/token.mjs +2 -2
  122. package/dist/astro/routes/api/openapi.json.mjs +2 -2
  123. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
  124. package/dist/astro/routes/api/redirects/404s/index.mjs +7 -7
  125. package/dist/astro/routes/api/redirects/404s/summary.mjs +7 -7
  126. package/dist/astro/routes/api/redirects/_id_.mjs +8 -8
  127. package/dist/astro/routes/api/redirects/index.mjs +8 -8
  128. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  129. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  130. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +26 -26
  131. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +26 -26
  132. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +26 -26
  133. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +26 -26
  134. package/dist/astro/routes/api/schema/collections/index.mjs +26 -26
  135. package/dist/astro/routes/api/schema/index.mjs +7 -7
  136. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +26 -26
  137. package/dist/astro/routes/api/schema/orphans/index.mjs +26 -26
  138. package/dist/astro/routes/api/search/enable.mjs +8 -8
  139. package/dist/astro/routes/api/search/index.mjs +7 -7
  140. package/dist/astro/routes/api/search/rebuild.mjs +8 -8
  141. package/dist/astro/routes/api/search/stats.mjs +7 -7
  142. package/dist/astro/routes/api/search/suggest.mjs +7 -7
  143. package/dist/astro/routes/api/sections/_slug_.mjs +7 -7
  144. package/dist/astro/routes/api/sections/index.mjs +7 -7
  145. package/dist/astro/routes/api/settings/email.mjs +4 -4
  146. package/dist/astro/routes/api/settings.mjs +9 -9
  147. package/dist/astro/routes/api/setup/admin-verify.mjs +3 -3
  148. package/dist/astro/routes/api/setup/admin.mjs +3 -3
  149. package/dist/astro/routes/api/setup/dev-bypass.mjs +16 -16
  150. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  151. package/dist/astro/routes/api/setup/index.mjs +17 -17
  152. package/dist/astro/routes/api/setup/status.mjs +3 -3
  153. package/dist/astro/routes/api/snapshot.mjs +3 -3
  154. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +9 -9
  155. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +9 -9
  156. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +9 -9
  157. package/dist/astro/routes/api/taxonomies/index.mjs +9 -9
  158. package/dist/astro/routes/api/themes/preview.mjs +3 -3
  159. package/dist/astro/routes/api/typegen.mjs +5 -5
  160. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +4 -4
  161. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +7 -7
  162. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +7 -7
  163. package/dist/astro/routes/api/widget-areas/_name_.mjs +6 -6
  164. package/dist/astro/routes/api/widget-areas/index.mjs +7 -7
  165. package/dist/astro/routes/api/widget-components.mjs +2 -2
  166. package/dist/astro/routes/robots.txt.mjs +5 -5
  167. package/dist/astro/routes/sitemap-_collection_.xml.mjs +5 -5
  168. package/dist/astro/routes/sitemap.xml.mjs +5 -5
  169. package/dist/{authorize-_wWM_44T.mjs → authorize-CotM4Yiu.mjs} +2 -2
  170. package/dist/{authorize-_wWM_44T.mjs.map → authorize-CotM4Yiu.mjs.map} +1 -1
  171. package/dist/{byline-BrIVWLm-.mjs → byline-CWQ9aSoz.mjs} +4 -4
  172. package/dist/{byline-BrIVWLm-.mjs.map → byline-CWQ9aSoz.mjs.map} +1 -1
  173. package/dist/{bylines-C_POWmGT.mjs → bylines-BJSva1Un.mjs} +4 -4
  174. package/dist/{bylines-C_POWmGT.mjs.map → bylines-BJSva1Un.mjs.map} +1 -1
  175. package/dist/{bylines-sqExMElV.mjs → bylines-LJMgENMI.mjs} +3 -3
  176. package/dist/{bylines-sqExMElV.mjs.map → bylines-LJMgENMI.mjs.map} +1 -1
  177. package/dist/{cache-wsDkA8ru.mjs → cache-lZL7SgVb.mjs} +2 -2
  178. package/dist/{cache-wsDkA8ru.mjs.map → cache-lZL7SgVb.mjs.map} +1 -1
  179. package/dist/{chunks-BAYkM-CF.mjs → chunks-BU-vP9Dh.mjs} +2 -2
  180. package/dist/{chunks-BAYkM-CF.mjs.map → chunks-BU-vP9Dh.mjs.map} +1 -1
  181. package/dist/cli/index.mjs +14 -14
  182. package/dist/{comment-Cd29aktf.mjs → comment-C4jVbCM8.mjs} +2 -2
  183. package/dist/{comment-Cd29aktf.mjs.map → comment-C4jVbCM8.mjs.map} +1 -1
  184. package/dist/{comments-B7ufhkxN.mjs → comments-BTAbC0Ek.mjs} +3 -3
  185. package/dist/{comments-B7ufhkxN.mjs.map → comments-BTAbC0Ek.mjs.map} +1 -1
  186. package/dist/{content-BbqKo3Kc.mjs → content-CyqOmOzm.mjs} +3 -3
  187. package/dist/{content-BbqKo3Kc.mjs.map → content-CyqOmOzm.mjs.map} +1 -1
  188. package/dist/{context-BsF1rhoI.mjs → context-DZ7bEh5-.mjs} +8 -8
  189. package/dist/{context-BsF1rhoI.mjs.map → context-DZ7bEh5-.mjs.map} +1 -1
  190. package/dist/{dashboard-BwIX9r-X.mjs → dashboard-B5WQpNTP.mjs} +4 -4
  191. package/dist/{dashboard-BwIX9r-X.mjs.map → dashboard-B5WQpNTP.mjs.map} +1 -1
  192. package/dist/db/index.mjs +2 -2
  193. package/dist/{dialect-helpers-BKCvISIQ.mjs → dialect-helpers-DRI5pyY3.mjs} +3 -3
  194. package/dist/dialect-helpers-DRI5pyY3.mjs.map +1 -0
  195. package/dist/{error-npZWBSb7.mjs → error-DJOsMVSt.mjs} +2 -2
  196. package/dist/{error-npZWBSb7.mjs.map → error-DJOsMVSt.mjs.map} +1 -1
  197. package/dist/{fts-manager-DmUAk-kQ.mjs → fts-manager-DR1ERA0c.mjs} +3 -3
  198. package/dist/{fts-manager-DmUAk-kQ.mjs.map → fts-manager-DR1ERA0c.mjs.map} +1 -1
  199. package/dist/index-CjKdMZ3U.d.mts.map +1 -1
  200. package/dist/index.mjs +35 -35
  201. package/dist/{load-DsoLq7ex.mjs → load-6ZrRhepW.mjs} +2 -2
  202. package/dist/{load-DsoLq7ex.mjs.map → load-6ZrRhepW.mjs.map} +1 -1
  203. package/dist/{loader-CJ6lWO0d.mjs → loader-Dyx8dhFV.mjs} +4 -4
  204. package/dist/{loader-CJ6lWO0d.mjs.map → loader-Dyx8dhFV.mjs.map} +1 -1
  205. package/dist/media/local-runtime.mjs +5 -5
  206. package/dist/{media-jk_HzzOl.mjs → media-C-oovGCG.mjs} +2 -2
  207. package/dist/{media-jk_HzzOl.mjs.map → media-C-oovGCG.mjs.map} +1 -1
  208. package/dist/{menus-CyMO6GBx.mjs → menus-BKkxXCmd.mjs} +30 -11
  209. package/dist/menus-BKkxXCmd.mjs.map +1 -0
  210. package/dist/{menus-B-5-3aon.mjs → menus-DugoYwTX.mjs} +2 -2
  211. package/dist/{menus-B-5-3aon.mjs.map → menus-DugoYwTX.mjs.map} +1 -1
  212. package/dist/{parse-4zO5Y2DL.mjs → parse-BBkFmLVr.mjs} +2 -2
  213. package/dist/{parse-4zO5Y2DL.mjs.map → parse-BBkFmLVr.mjs.map} +1 -1
  214. package/dist/{query-Bt52mHXp.mjs → query-Ctlq1aOk.mjs} +10 -10
  215. package/dist/{query-Bt52mHXp.mjs.map → query-Ctlq1aOk.mjs.map} +1 -1
  216. package/dist/{rate-limit-D6VQqBk_.mjs → rate-limit-CH6W6ikK.mjs} +2 -2
  217. package/dist/{rate-limit-D6VQqBk_.mjs.map → rate-limit-CH6W6ikK.mjs.map} +1 -1
  218. package/dist/{redirect-BZUJltlj.mjs → redirect-C6tJA7tk.mjs} +3 -3
  219. package/dist/{redirect-BZUJltlj.mjs.map → redirect-C6tJA7tk.mjs.map} +1 -1
  220. package/dist/{redirects-DnYuqsEf.mjs → redirects-CacE9eQa.mjs} +3 -3
  221. package/dist/{redirects-DnYuqsEf.mjs.map → redirects-CacE9eQa.mjs.map} +1 -1
  222. package/dist/{registry-Dn6gsx3L.mjs → registry-CIDxZbhh.mjs} +5 -5
  223. package/dist/{registry-Dn6gsx3L.mjs.map → registry-CIDxZbhh.mjs.map} +1 -1
  224. package/dist/runner-DM1yR5qd.d.mts.map +1 -1
  225. package/dist/{runner-eAgyIkeg.mjs → runner-pt6Wl-l-.mjs} +11 -6
  226. package/dist/runner-pt6Wl-l-.mjs.map +1 -0
  227. package/dist/runtime.mjs +3 -3
  228. package/dist/{schema--mYZX4D7.mjs → schema-B4tk0HAG.mjs} +4 -4
  229. package/dist/{schema--mYZX4D7.mjs.map → schema-B4tk0HAG.mjs.map} +1 -1
  230. package/dist/{search-C6U_NvZI.mjs → search-f-fNfwab.mjs} +4 -4
  231. package/dist/{search-C6U_NvZI.mjs.map → search-f-fNfwab.mjs.map} +1 -1
  232. package/dist/{sections-Ba-rJLKb.mjs → sections-biElLfT9.mjs} +3 -3
  233. package/dist/{sections-Ba-rJLKb.mjs.map → sections-biElLfT9.mjs.map} +1 -1
  234. package/dist/seed/index.mjs +14 -14
  235. package/dist/seo/index.mjs +1 -0
  236. package/dist/seo/index.mjs.map +1 -1
  237. package/dist/{seo-BTzb5ksq.mjs → seo-BR39kvTF.mjs} +2 -2
  238. package/dist/{seo-BTzb5ksq.mjs.map → seo-BR39kvTF.mjs.map} +1 -1
  239. package/dist/{service-Cn-kIfZn.mjs → service-BhR2acnc.mjs} +2 -2
  240. package/dist/{service-Cn-kIfZn.mjs.map → service-BhR2acnc.mjs.map} +1 -1
  241. package/dist/{settings-C65OSm41.mjs → settings-D_NJvjgN.mjs} +3 -3
  242. package/dist/{settings-C65OSm41.mjs.map → settings-D_NJvjgN.mjs.map} +1 -1
  243. package/dist/{settings-ChlQbwU0.mjs → settings-b5zW1R1T.mjs} +3 -3
  244. package/dist/{settings-ChlQbwU0.mjs.map → settings-b5zW1R1T.mjs.map} +1 -1
  245. package/dist/{taxonomies-ByLlXrv5.mjs → taxonomies-Crtzy4MT.mjs} +8 -7
  246. package/dist/taxonomies-Crtzy4MT.mjs.map +1 -0
  247. package/dist/{taxonomies-CbO6v7EE.mjs → taxonomies-Mhn9rjTQ.mjs} +4 -4
  248. package/dist/{taxonomies-CbO6v7EE.mjs.map → taxonomies-Mhn9rjTQ.mjs.map} +1 -1
  249. package/dist/{taxonomy-BBK-UAEo.mjs → taxonomy-DTZrIQpi.mjs} +3 -3
  250. package/dist/{taxonomy-BBK-UAEo.mjs.map → taxonomy-DTZrIQpi.mjs.map} +1 -1
  251. package/dist/{types-SF1DwGf2.mjs → types-K3MDsxpy.mjs} +2 -2
  252. package/dist/{types-SF1DwGf2.mjs.map → types-K3MDsxpy.mjs.map} +1 -1
  253. package/dist/{user-X4rtyO4Y.mjs → user-DzEUl5zA.mjs} +2 -2
  254. package/dist/{user-X4rtyO4Y.mjs.map → user-DzEUl5zA.mjs.map} +1 -1
  255. package/dist/{validate-DactmcJG.mjs → validate-JCXcsqiY.mjs} +2 -2
  256. package/dist/{validate-DactmcJG.mjs.map → validate-JCXcsqiY.mjs.map} +1 -1
  257. package/dist/{validation-BYA4i85b.mjs → validation-Bq-VyKJg.mjs} +6 -6
  258. package/dist/{validation-BYA4i85b.mjs.map → validation-Bq-VyKJg.mjs.map} +1 -1
  259. package/dist/version-CnS-Cr8A.mjs +7 -0
  260. package/dist/{version-CWbvq9LG.mjs.map → version-CnS-Cr8A.mjs.map} +1 -1
  261. package/dist/{widgets-DG-1jxnz.mjs → widgets-Bap1eS1X.mjs} +2 -2
  262. package/dist/{widgets-DG-1jxnz.mjs.map → widgets-Bap1eS1X.mjs.map} +1 -1
  263. package/dist/{zod-generator-BNAObjSt.mjs → zod-generator-BSDpkqSH.mjs} +4 -3
  264. package/dist/zod-generator-BSDpkqSH.mjs.map +1 -0
  265. package/package.json +7 -7
  266. package/src/astro/middleware/stream-end-metrics.ts +96 -0
  267. package/src/astro/middleware.ts +114 -40
  268. package/src/components/EmDashImage.astro +1 -0
  269. package/src/database/dialect-helpers.ts +8 -2
  270. package/src/database/migrations/019_i18n.ts +2 -2
  271. package/src/database/migrations/runner.ts +7 -2
  272. package/src/emdash-runtime.ts +177 -126
  273. package/src/menus/index.ts +27 -9
  274. package/src/plugins/hooks.ts +35 -6
  275. package/src/plugins/manager.ts +1 -0
  276. package/src/schema/zod-generator.ts +6 -2
  277. package/src/seo/index.ts +10 -1
  278. package/src/taxonomies/index.ts +12 -8
  279. package/src/utils/init-lock.ts +143 -0
  280. package/dist/dialect-helpers-BKCvISIQ.mjs.map +0 -1
  281. package/dist/menus-CyMO6GBx.mjs.map +0 -1
  282. package/dist/runner-eAgyIkeg.mjs.map +0 -1
  283. package/dist/taxonomies-ByLlXrv5.mjs.map +0 -1
  284. package/dist/version-CWbvq9LG.mjs +0 -7
  285. package/dist/zod-generator-BNAObjSt.mjs.map +0 -1
@@ -27,12 +27,14 @@ import { sandboxedPlugins as virtualSandboxedPlugins } from "virtual:emdash/sand
27
27
  // @ts-ignore - virtual module
28
28
  import { createStorage as virtualCreateStorage } from "virtual:emdash/storage";
29
29
 
30
+ import { after } from "../after.js";
30
31
  import {
31
32
  createRecorder,
32
33
  flushRecorder,
33
34
  isInstrumentationEnabled,
34
35
  } from "../database/instrumentation.js";
35
36
  import {
37
+ DB_INIT_DEADLINE_MS,
36
38
  EmDashRuntime,
37
39
  type RuntimeDependencies,
38
40
  type SandboxedPluginEntry,
@@ -50,17 +52,21 @@ import {
50
52
  type RequestMetrics,
51
53
  runWithContext,
52
54
  } from "../request-context.js";
55
+ import { isMissingTableError } from "../utils/db-errors.js";
56
+ import { createInitLock, type InitLock, initWithLock } from "../utils/init-lock.js";
53
57
  import type { EmDashConfig } from "./integration/runtime.js";
58
+ import { wrapBodyForStreamMetrics } from "./middleware/stream-end-metrics.js";
54
59
  import { createPublicPluginApiRouteHandler } from "./public-plugin-api-routes.js";
55
60
  import type { EmDashHandlers } from "./types.js";
56
61
 
57
- // Cached runtime instance (persists across requests within worker)
58
- let runtimeInstance: EmDashRuntime | null = null;
59
- // Whether initialization is in progress (prevents concurrent init attempts)
60
- let runtimeInitializing = false;
61
-
62
- /** Whether i18n config has been initialized from the virtual module */
63
- let i18nInitialized = false;
62
+ /**
63
+ * Runtime init lock reclaim deadline. Must be strictly larger than the db
64
+ * init deadline: this lock wraps EmDashRuntime.create() getDatabase()
65
+ * the db init lock, and equal deadlines would let this outer lock reclaim
66
+ * (spawning a second cron scheduler and sandbox runner) while the inner db
67
+ * init is legitimately still working through a contended migration.
68
+ */
69
+ const RUNTIME_INIT_DEADLINE_MS = DB_INIT_DEADLINE_MS + 15_000;
64
70
 
65
71
  /**
66
72
  * Whether we've verified the database has been set up.
@@ -69,8 +75,50 @@ let i18nInitialized = false;
69
75
  * would query an empty database and crash. Once verified (or once the runtime
70
76
  * has initialized via an admin/API request), this stays true for the worker's
71
77
  * lifetime.
78
+ *
79
+ * Stored on globalThis behind a Symbol key so the flag is a true singleton
80
+ * even when the bundler duplicates this module across SSR chunks (same
81
+ * pattern as request-cache.ts). A plain module-scoped `let` becomes multiple
82
+ * independent variables, which would make the setup probe re-run far more
83
+ * often than intended — and every re-run is another chance for a transient
84
+ * DB error to be misread as "fresh install" and bounce visitors to setup.
72
85
  */
73
- let setupVerified = false;
86
+ const SETUP_VERIFIED_KEY = Symbol.for("emdash:setup-verified");
87
+ const setupFlagStore = globalThis as Record<symbol, unknown>;
88
+
89
+ function isSetupVerified(): boolean {
90
+ return setupFlagStore[SETUP_VERIFIED_KEY] === true;
91
+ }
92
+
93
+ function markSetupVerified(): void {
94
+ setupFlagStore[SETUP_VERIFIED_KEY] = true;
95
+ }
96
+
97
+ /**
98
+ * The runtime singleton and its init lock live on globalThis behind a
99
+ * Symbol — same reasoning as SETUP_VERIFIED_KEY above: the bundler can
100
+ * duplicate this module across SSR chunks, and a duplicated instance/lock
101
+ * would mean multiple runtimes (each with its own cron scheduler) per
102
+ * isolate, initializing and reclaiming independently.
103
+ */
104
+ const RUNTIME_HOLDER_KEY = Symbol.for("emdash:runtime-holder");
105
+ interface RuntimeHolder {
106
+ instance: EmDashRuntime | null;
107
+ lock: InitLock;
108
+ }
109
+
110
+ function getRuntimeHolder(): RuntimeHolder {
111
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis symbol slot, written only below
112
+ let holder = setupFlagStore[RUNTIME_HOLDER_KEY] as RuntimeHolder | undefined;
113
+ if (!holder) {
114
+ holder = { instance: null, lock: createInitLock() };
115
+ setupFlagStore[RUNTIME_HOLDER_KEY] = holder;
116
+ }
117
+ return holder;
118
+ }
119
+
120
+ /** Whether i18n config has been initialized from the virtual module */
121
+ let i18nInitialized = false;
74
122
 
75
123
  /**
76
124
  * Get EmDash configuration from virtual module
@@ -159,29 +207,40 @@ async function getRuntime(
159
207
  config: EmDashConfig,
160
208
  initTimings?: Array<{ name: string; dur: number; desc?: string }>,
161
209
  ): Promise<EmDashRuntime> {
162
- // Return cached instance if available
163
- if (runtimeInstance) {
164
- return runtimeInstance;
165
- }
166
-
167
- // If another request is already initializing, wait and retry.
168
- // We don't share the promise across requests because workerd flags
169
- // cross-request promise resolution (causes warnings + potential hangs).
170
- if (runtimeInitializing) {
171
- // Poll until the initializing request finishes
172
- await new Promise((resolve) => setTimeout(resolve, 50));
173
- return getRuntime(config, initTimings);
174
- }
175
-
176
- runtimeInitializing = true;
177
- try {
178
- const deps = buildDependencies(config);
179
- const runtime = await EmDashRuntime.create(deps, initTimings);
180
- runtimeInstance = runtime;
181
- return runtime;
182
- } finally {
183
- runtimeInitializing = false;
184
- }
210
+ // Waiters poll rather than awaiting the initializing request's promise —
211
+ // workerd flags cross-request promise resolution (warnings + potential
212
+ // hangs). If the initializing request is cancelled mid-create (client
213
+ // disconnect tears down its continuation, skipping any `finally`), the
214
+ // anchored init keeps running under waitUntil and populates the cache;
215
+ // failing that, the stale lock is reclaimed after a deadline instead of
216
+ // hanging every subsequent request in the isolate until eviction.
217
+ const holder = getRuntimeHolder();
218
+ return initWithLock(
219
+ holder.lock,
220
+ () => holder.instance,
221
+ async (isCurrentClaim) => {
222
+ const deps = buildDependencies(config);
223
+ const runtime = await EmDashRuntime.create(deps, initTimings);
224
+ if (isCurrentClaim()) {
225
+ holder.instance = runtime;
226
+ } else {
227
+ // This init was reclaimed mid-flight (it ran past the deadline
228
+ // and a waiter started its own). Don't overwrite the
229
+ // reclaimer's published runtime, and stop this one's cron
230
+ // scheduler so it doesn't keep firing unreferenced. The
231
+ // runtime is still returned — it's fully functional for the
232
+ // request that built it.
233
+ runtime.stopCron().catch((error: unknown) => {
234
+ console.error("[emdash] failed to stop superseded runtime's cron:", error);
235
+ });
236
+ }
237
+ return runtime;
238
+ },
239
+ {
240
+ deadlineMs: RUNTIME_INIT_DEADLINE_MS,
241
+ anchor: (promise) => after(() => promise),
242
+ },
243
+ );
185
244
  }
186
245
 
187
246
  /**
@@ -338,7 +397,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
338
397
  // Do a one-time lightweight probe using the same getDb() instance the
339
398
  // page will use: if the migrations table doesn't exist, no migrations
340
399
  // have ever run -- redirect to the setup wizard.
341
- if (!setupVerified) {
400
+ if (!isSetupVerified()) {
342
401
  const t0 = performance.now();
343
402
  try {
344
403
  const { getDb } = await import("../loader.js");
@@ -348,10 +407,19 @@ export const onRequest = defineMiddleware(async (context, next) => {
348
407
  .selectAll()
349
408
  .limit(1)
350
409
  .execute();
351
- setupVerified = true;
352
- } catch {
353
- // Table doesn't exist -> fresh database, redirect to setup
354
- return context.redirect("/_emdash/admin/setup");
410
+ markSetupVerified();
411
+ } catch (error) {
412
+ // Only a genuinely-missing migrations table means a fresh,
413
+ // un-set-up database — redirect to the setup wizard.
414
+ if (isMissingTableError(error)) {
415
+ return context.redirect("/_emdash/admin/setup");
416
+ }
417
+ // Any other failure (transient D1/replica error, timeout, cold-start
418
+ // race, locked SQLite) must NOT be read as "fresh install" — doing so
419
+ // bounces real visitors on a set-up site to /_emdash/admin/setup.
420
+ // Leave the flag unset so a later request can re-verify, and fall
421
+ // through to render the page normally.
422
+ console.error("Setup probe failed (non-fatal):", error);
355
423
  }
356
424
  timings.push({ name: "setup", dur: performance.now() - t0, desc: "Setup probe" });
357
425
  }
@@ -368,7 +436,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
368
436
  const t0 = performance.now();
369
437
  try {
370
438
  const runtime = await getRuntime(config, initSubTimings);
371
- setupVerified = true;
439
+ markSetupVerified();
372
440
  const handlePublicPluginApiRoute = createPublicPluginApiRouteHandler(runtime);
373
441
  // eslint-disable-next-line typescript/no-unsafe-type-assertion -- partial object; getPageRuntime() only checks for the page-contribution methods
374
442
  locals.emdash = {
@@ -403,7 +471,10 @@ export const onRequest = defineMiddleware(async (context, next) => {
403
471
  timings.push({ name: "render", dur: performance.now() - t0, desc: "Page render" });
404
472
  timings.push({ name: "mw", dur: performance.now() - mwStart, desc: "Total middleware" });
405
473
  pushMetricsTimings(timings, metrics);
406
- return finalizeResponse(response, timings);
474
+ // Server-Timing only sees pre-stream queries; the stream-end
475
+ // wrapper (instrumentation-gated, no-op otherwise) emits the
476
+ // final counters once the body finishes streaming.
477
+ return wrapBodyForStreamMetrics(finalizeResponse(response, timings));
407
478
  };
408
479
  if (anonScoped) {
409
480
  const parent = getRequestContext();
@@ -448,7 +519,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
448
519
  for (const sub of initSubTimings) timings.push(sub);
449
520
 
450
521
  // Runtime init runs migrations, so the DB is guaranteed set up
451
- setupVerified = true;
522
+ markSetupVerified();
452
523
 
453
524
  // The manifest is no longer pre-loaded here. It's admin-only
454
525
  // content that public/anonymous requests never read, and
@@ -570,7 +641,10 @@ export const onRequest = defineMiddleware(async (context, next) => {
570
641
  timings.push({ name: "render", dur: performance.now() - t0, desc: "Page render" });
571
642
  timings.push({ name: "mw", dur: performance.now() - mwStart, desc: "Total middleware" });
572
643
  pushMetricsTimings(timings, metrics);
573
- return finalizeResponse(response, timings);
644
+ // Server-Timing only sees pre-stream queries; the stream-end
645
+ // wrapper (instrumentation-gated, no-op otherwise) emits the
646
+ // final counters once the body finishes streaming.
647
+ return wrapBodyForStreamMetrics(finalizeResponse(response, timings));
574
648
  };
575
649
 
576
650
  if (scoped) {
@@ -170,6 +170,7 @@ const imgProps: Record<string, unknown> = {
170
170
  height: finalHeight,
171
171
  alt: finalAlt,
172
172
  loading: priority ? "eager" : "lazy",
173
+ fetchpriority: priority ? "high" : undefined,
173
174
  decoding: "async",
174
175
  style: placeholderStyle ? `${baseStyle} ${placeholderStyle}` : baseStyle,
175
176
  ...attrs,
@@ -74,10 +74,12 @@ export function currentTimestampValue(db: Kysely<any>): RawBuilder<string> {
74
74
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance
75
75
  export async function tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {
76
76
  if (isPostgres(db)) {
77
+ // Scope to the active schema (matches indexExists/columnExists below).
78
+ // Hardcoding 'public' breaks non-public-schema Postgres deployments.
77
79
  const result = await sql<{ exists: boolean }>`
78
80
  SELECT EXISTS(
79
81
  SELECT 1 FROM information_schema.tables
80
- WHERE table_schema = 'public' AND table_name = ${tableName}
82
+ WHERE table_schema = current_schema() AND table_name = ${tableName}
81
83
  ) as exists
82
84
  `.execute(db);
83
85
  return result.rows[0]?.exists === true;
@@ -146,9 +148,13 @@ export async function columnExists(
146
148
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance
147
149
  export async function listTablesLike(db: Kysely<any>, pattern: string): Promise<string[]> {
148
150
  if (isPostgres(db)) {
151
+ // Scope to the connection's active schema rather than hardcoding
152
+ // 'public'. A Postgres deployment using a non-public schema (per-tenant
153
+ // or shared-cluster setups), or per-test schemas, otherwise sees tables
154
+ // from the wrong schema — or none at all. Mirrors migration 038.
149
155
  const result = await sql<{ table_name: string }>`
150
156
  SELECT table_name FROM information_schema.tables
151
- WHERE table_schema = 'public' AND table_name LIKE ${pattern}
157
+ WHERE table_schema = current_schema() AND table_name LIKE ${pattern}
152
158
  `.execute(db);
153
159
  return result.rows.map((r) => r.table_name);
154
160
  }
@@ -142,7 +142,7 @@ async function upPostgres(db: Kysely<unknown>): Promise<void> {
142
142
  const hasLocale = await sql<{ exists: boolean }>`
143
143
  SELECT EXISTS(
144
144
  SELECT 1 FROM information_schema.columns
145
- WHERE table_schema = 'public' AND table_name = ${t} AND column_name = 'locale'
145
+ WHERE table_schema = current_schema() AND table_name = ${t} AND column_name = 'locale'
146
146
  ) as exists
147
147
  `.execute(db);
148
148
  if (hasLocale.rows[0]?.exists === true) continue;
@@ -189,7 +189,7 @@ async function upPostgres(db: Kysely<unknown>): Promise<void> {
189
189
  const hasTranslatable = await sql<{ exists: boolean }>`
190
190
  SELECT EXISTS(
191
191
  SELECT 1 FROM information_schema.columns
192
- WHERE table_schema = 'public' AND table_name = '_emdash_fields' AND column_name = 'translatable'
192
+ WHERE table_schema = current_schema() AND table_name = '_emdash_fields' AND column_name = 'translatable'
193
193
  ) as exists
194
194
  `.execute(db);
195
195
  if (hasTranslatable.rows[0]?.exists !== true) {
@@ -178,8 +178,13 @@ const MIGRATION_RACE_PATTERN = new RegExp(
178
178
  "i",
179
179
  );
180
180
 
181
- /** How long to wait for a concurrent migrator to finish before giving up. */
182
- const MIGRATION_RACE_WAIT_MS = 10_000;
181
+ /**
182
+ * How long to wait for a concurrent migrator to finish before giving up.
183
+ * Exported because the db init lock's reclaim deadline must comfortably
184
+ * exceed it (see DB_INIT_DEADLINE_MS in emdash-runtime.ts) — a healthy
185
+ * init can legitimately block this long inside waitForConcurrentMigrator.
186
+ */
187
+ export const MIGRATION_RACE_WAIT_MS = 10_000;
183
188
  /** Polling interval while waiting for a concurrent migrator. */
184
189
  const MIGRATION_RACE_POLL_MS = 100;
185
190