emdash 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/dist/{adapters-hUy8vOB-.d.mts → adapters-DAAjOID4.d.mts} +1 -1
  2. package/dist/{adapters-hUy8vOB-.d.mts.map → adapters-DAAjOID4.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-DjlhyfNN.mjs → allowed-origins-D5FxMUo8.mjs} +2 -2
  4. package/dist/{allowed-origins-DjlhyfNN.mjs.map → allowed-origins-D5FxMUo8.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +11 -11
  7. package/dist/api/schemas/index.d.mts +1 -1
  8. package/dist/api/schemas/index.mjs +3 -3
  9. package/dist/{api-BDuM4bEy.mjs → api-BQ_yKRdG.mjs} +12 -12
  10. package/dist/{api-BDuM4bEy.mjs.map → api-BQ_yKRdG.mjs.map} +1 -1
  11. package/dist/{api-tokens-ViYKeIp9.mjs → api-tokens-D6ppjIVi.mjs} +2 -2
  12. package/dist/{api-tokens-ViYKeIp9.mjs.map → api-tokens-D6ppjIVi.mjs.map} +1 -1
  13. package/dist/{apply-wDqQoxX4.mjs → apply-CWRyxIoO.mjs} +12 -12
  14. package/dist/{apply-wDqQoxX4.mjs.map → apply-CWRyxIoO.mjs.map} +1 -1
  15. package/dist/astro/index.d.mts +11 -11
  16. package/dist/astro/index.mjs +12 -6
  17. package/dist/astro/index.mjs.map +1 -1
  18. package/dist/astro/middleware/auth.d.mts +9 -9
  19. package/dist/astro/middleware/auth.mjs +6 -6
  20. package/dist/astro/middleware/redirect.mjs +3 -3
  21. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  22. package/dist/astro/middleware/request-context.mjs +5 -3
  23. package/dist/astro/middleware/request-context.mjs.map +1 -1
  24. package/dist/astro/middleware/setup.mjs +1 -1
  25. package/dist/astro/middleware.d.mts +1 -1
  26. package/dist/astro/middleware.d.mts.map +1 -1
  27. package/dist/astro/middleware.mjs +349 -128
  28. package/dist/astro/middleware.mjs.map +1 -1
  29. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  30. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  31. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +3 -3
  32. package/dist/astro/routes/api/admin/api-tokens/index.mjs +4 -4
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +3 -3
  34. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +7 -7
  35. package/dist/astro/routes/api/admin/byline-fields/index.mjs +7 -7
  36. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +7 -7
  37. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +12 -11
  38. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  39. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +12 -11
  40. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
  41. package/dist/astro/routes/api/admin/bylines/index.mjs +12 -11
  42. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  43. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +9 -9
  44. package/dist/astro/routes/api/admin/comments/_id_.mjs +3 -3
  45. package/dist/astro/routes/api/admin/comments/bulk.mjs +7 -7
  46. package/dist/astro/routes/api/admin/comments/counts.mjs +3 -3
  47. package/dist/astro/routes/api/admin/comments/index.mjs +7 -7
  48. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +3 -3
  49. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +2 -2
  50. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  51. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  52. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +27 -26
  53. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  54. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +27 -26
  55. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  56. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +26 -25
  57. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  58. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +26 -25
  59. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  60. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +26 -25
  61. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  62. package/dist/astro/routes/api/admin/plugins/index.mjs +26 -25
  63. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +26 -25
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +26 -25
  68. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +26 -25
  70. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +26 -25
  72. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +27 -26
  74. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  75. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +26 -25
  76. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  77. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +27 -26
  78. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  79. package/dist/astro/routes/api/admin/plugins/updates.mjs +26 -25
  80. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  81. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +26 -25
  82. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  83. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  84. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +26 -25
  85. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
  87. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
  88. package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
  89. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +2 -2
  90. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  91. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  92. package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
  93. package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
  94. package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
  95. package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
  96. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  97. package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
  98. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  99. package/dist/astro/routes/api/auth/me.mjs +5 -5
  100. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  101. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  102. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  103. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  104. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  105. package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
  106. package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
  107. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
  108. package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
  109. package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
  110. package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
  111. package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
  112. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +10 -10
  113. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +9 -9
  114. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  115. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +2 -2
  116. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +2 -2
  117. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +2 -2
  118. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
  119. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
  120. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +2 -2
  121. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  122. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
  123. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +9 -9
  124. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  125. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +2 -2
  126. package/dist/astro/routes/api/content/_collection_/_id_.mjs +6 -6
  127. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  128. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  129. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  130. package/dist/astro/routes/api/dashboard.mjs +3 -3
  131. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  132. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  133. package/dist/astro/routes/api/import/probe.mjs +10 -10
  134. package/dist/astro/routes/api/import/wordpress/analyze.mjs +2 -2
  135. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  136. package/dist/astro/routes/api/import/wordpress/execute.mjs +8 -7
  137. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  138. package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
  139. package/dist/astro/routes/api/import/wordpress/prepare.mjs +8 -8
  140. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
  141. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  142. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
  143. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  144. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +12 -11
  145. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  146. package/dist/astro/routes/api/manifest.mjs +3 -3
  147. package/dist/astro/routes/api/mcp.mjs +29 -29
  148. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  149. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  150. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  151. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  152. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  153. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  154. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  155. package/dist/astro/routes/api/media.mjs +10 -10
  156. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +6 -6
  157. package/dist/astro/routes/api/menus/_name_/items.mjs +6 -6
  158. package/dist/astro/routes/api/menus/_name_/reorder.mjs +6 -6
  159. package/dist/astro/routes/api/menus/_name_/translations.mjs +6 -6
  160. package/dist/astro/routes/api/menus/_name_.mjs +6 -6
  161. package/dist/astro/routes/api/menus/index.mjs +6 -6
  162. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  163. package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
  164. package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
  165. package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
  166. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  167. package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
  168. package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
  169. package/dist/astro/routes/api/oauth/token.mjs +5 -5
  170. package/dist/astro/routes/api/openapi.json.mjs +3 -3
  171. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
  172. package/dist/astro/routes/api/redirects/404s/index.mjs +7 -7
  173. package/dist/astro/routes/api/redirects/404s/summary.mjs +7 -7
  174. package/dist/astro/routes/api/redirects/_id_.mjs +8 -8
  175. package/dist/astro/routes/api/redirects/index.mjs +8 -8
  176. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  177. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  178. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +26 -25
  179. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  180. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +26 -25
  181. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  182. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +26 -25
  183. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  184. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +26 -25
  185. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  186. package/dist/astro/routes/api/schema/collections/index.mjs +26 -25
  187. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  188. package/dist/astro/routes/api/schema/index.mjs +7 -6
  189. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  190. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +26 -25
  191. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  192. package/dist/astro/routes/api/schema/orphans/index.mjs +26 -25
  193. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  194. package/dist/astro/routes/api/search/enable.mjs +9 -9
  195. package/dist/astro/routes/api/search/index.mjs +8 -8
  196. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  197. package/dist/astro/routes/api/search/stats.mjs +5 -5
  198. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  199. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  200. package/dist/astro/routes/api/sections/index.mjs +8 -8
  201. package/dist/astro/routes/api/settings/email.mjs +3 -3
  202. package/dist/astro/routes/api/settings.mjs +9 -9
  203. package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
  204. package/dist/astro/routes/api/setup/admin.mjs +9 -9
  205. package/dist/astro/routes/api/setup/dev-bypass.mjs +17 -16
  206. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  207. package/dist/astro/routes/api/setup/dev-reset.mjs +1 -1
  208. package/dist/astro/routes/api/setup/index.mjs +18 -17
  209. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  210. package/dist/astro/routes/api/setup/status.mjs +3 -3
  211. package/dist/astro/routes/api/snapshot.mjs +5 -5
  212. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +10 -10
  213. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +10 -10
  214. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +10 -10
  215. package/dist/astro/routes/api/taxonomies/index.mjs +10 -10
  216. package/dist/astro/routes/api/themes/preview.mjs +4 -4
  217. package/dist/astro/routes/api/typegen.mjs +4 -4
  218. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  219. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  220. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  221. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  222. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
  223. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
  224. package/dist/astro/routes/api/widget-areas/_name_.mjs +4 -4
  225. package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
  226. package/dist/astro/routes/api/widget-components.mjs +2 -2
  227. package/dist/astro/routes/robots.txt.mjs +3 -3
  228. package/dist/astro/routes/sitemap-_collection_.xml.mjs +6 -6
  229. package/dist/astro/routes/sitemap.xml.mjs +4 -4
  230. package/dist/astro/types.d.mts +12 -12
  231. package/dist/auth/providers/github.d.mts +1 -1
  232. package/dist/auth/providers/google.d.mts +1 -1
  233. package/dist/{authorize-C0EYoUeV.mjs → authorize-Cse0k7B0.mjs} +2 -2
  234. package/dist/{authorize-C0EYoUeV.mjs.map → authorize-Cse0k7B0.mjs.map} +1 -1
  235. package/dist/{byline-CC0WS4Gu.mjs → byline-DVo-liaP.mjs} +15 -73
  236. package/dist/byline-DVo-liaP.mjs.map +1 -0
  237. package/dist/{byline-fields-53i9Et0x.mjs → byline-fields-B-KXkg5R.mjs} +2 -2
  238. package/dist/{byline-fields-53i9Et0x.mjs.map → byline-fields-B-KXkg5R.mjs.map} +1 -1
  239. package/dist/{byline-fields-DNp0HNKc.mjs → byline-fields-DaMKzkhO.mjs} +1 -1
  240. package/dist/{byline-fields-DNp0HNKc.mjs.map → byline-fields-DaMKzkhO.mjs.map} +1 -1
  241. package/dist/{byline-fields-jy07PZJM.d.mts → byline-fields-RFPkDLRw.d.mts} +21 -1
  242. package/dist/byline-fields-RFPkDLRw.d.mts.map +1 -0
  243. package/dist/{bylines-CCO1CYnH.mjs → bylines-f5ppBpD5.mjs} +6 -6
  244. package/dist/{bylines-CCO1CYnH.mjs.map → bylines-f5ppBpD5.mjs.map} +1 -1
  245. package/dist/{bylines-DGekMGGm.mjs → bylines-pIKgc_TL.mjs} +2 -2
  246. package/dist/{bylines-DGekMGGm.mjs.map → bylines-pIKgc_TL.mjs.map} +1 -1
  247. package/dist/{cache-pXTpun6s.mjs → cache-Q6V4U-Xz.mjs} +1 -1
  248. package/dist/{cache-pXTpun6s.mjs.map → cache-Q6V4U-Xz.mjs.map} +1 -1
  249. package/dist/{challenge-store-C6E_kWTs.mjs → challenge-store-LhiqMccz.mjs} +1 -1
  250. package/dist/{challenge-store-C6E_kWTs.mjs.map → challenge-store-LhiqMccz.mjs.map} +1 -1
  251. package/dist/cli/index.mjs +16 -15
  252. package/dist/cli/index.mjs.map +1 -1
  253. package/dist/client/cf-access.d.mts +1 -1
  254. package/dist/client/index.d.mts +1 -1
  255. package/dist/client/index.mjs +2 -2
  256. package/dist/{comment-reaction-B6AdcpXw.mjs → comment-reaction-Dyb-AutY.mjs} +1 -1
  257. package/dist/{comment-reaction-B6AdcpXw.mjs.map → comment-reaction-Dyb-AutY.mjs.map} +1 -1
  258. package/dist/{comments-CtPkT2tp.mjs → comments-Cczx7AvD.mjs} +1 -1
  259. package/dist/{comments-CtPkT2tp.mjs.map → comments-Cczx7AvD.mjs.map} +1 -1
  260. package/dist/{components-D6ZnrzbB.mjs → components-CYt4uVK9.mjs} +1 -1
  261. package/dist/{components-D6ZnrzbB.mjs.map → components-CYt4uVK9.mjs.map} +1 -1
  262. package/dist/{context-f1__jpzF.mjs → context-B1W8soLv.mjs} +58 -20
  263. package/dist/context-B1W8soLv.mjs.map +1 -0
  264. package/dist/{cron-CQPxBjYs.mjs → cron-C5LVoNmP.mjs} +14 -2
  265. package/dist/cron-C5LVoNmP.mjs.map +1 -0
  266. package/dist/{dashboard-BOESNcwE.mjs → dashboard-CYjpQZ6-.mjs} +1 -1
  267. package/dist/{dashboard-BOESNcwE.mjs.map → dashboard-CYjpQZ6-.mjs.map} +1 -1
  268. package/dist/db/index.d.mts +3 -3
  269. package/dist/db/libsql.d.mts +1 -1
  270. package/dist/db/postgres.d.mts +1 -1
  271. package/dist/db/sqlite.d.mts +1 -1
  272. package/dist/{db-errors-CrC5w3Jz.mjs → db-errors-UXB1CK42.mjs} +1 -1
  273. package/dist/{db-errors-CrC5w3Jz.mjs.map → db-errors-UXB1CK42.mjs.map} +1 -1
  274. package/dist/{default-CpBEPn6a.mjs → default-CeRG-Ot4.mjs} +1 -1
  275. package/dist/{default-CpBEPn6a.mjs.map → default-CeRG-Ot4.mjs.map} +1 -1
  276. package/dist/{device-flow-Bn-qiDrw.mjs → device-flow-DENDCQ9F.mjs} +4 -4
  277. package/dist/{device-flow-Bn-qiDrw.mjs.map → device-flow-DENDCQ9F.mjs.map} +1 -1
  278. package/dist/{email-console-B9VS6eN4.mjs → email-console-DJP32ucW.mjs} +1 -1
  279. package/dist/{email-console-B9VS6eN4.mjs.map → email-console-DJP32ucW.mjs.map} +1 -1
  280. package/dist/{error-BQ1pxs0L.mjs → error-Bl6kZgtt.mjs} +1 -1
  281. package/dist/{error-BQ1pxs0L.mjs.map → error-Bl6kZgtt.mjs.map} +1 -1
  282. package/dist/{escape-BtbJWyaW.mjs → escape-Bjio4ZsM.mjs} +1 -1
  283. package/dist/{escape-BtbJWyaW.mjs.map → escape-Bjio4ZsM.mjs.map} +1 -1
  284. package/dist/field-defs-cache-ztrdzUGb.mjs +77 -0
  285. package/dist/field-defs-cache-ztrdzUGb.mjs.map +1 -0
  286. package/dist/{fts-manager-DtiWqwNJ.mjs → fts-manager-CQuHt-vS.mjs} +1 -1
  287. package/dist/{fts-manager-DtiWqwNJ.mjs.map → fts-manager-CQuHt-vS.mjs.map} +1 -1
  288. package/dist/{hash-BowcuPwv.mjs → hash-DrvzIXcz.mjs} +1 -1
  289. package/dist/{hash-BowcuPwv.mjs.map → hash-DrvzIXcz.mjs.map} +1 -1
  290. package/dist/{import-DqSGOlmR.mjs → import-Bb1T9WJS.mjs} +3 -3
  291. package/dist/{import-DqSGOlmR.mjs.map → import-Bb1T9WJS.mjs.map} +1 -1
  292. package/dist/{index-C2dLNT6S.d.mts → index-BaIj5hIq.d.mts} +39 -17
  293. package/dist/index-BaIj5hIq.d.mts.map +1 -0
  294. package/dist/{index-ZDEwR7qW.d.mts → index-qbL02uhs.d.mts} +3 -3
  295. package/dist/{index-ZDEwR7qW.d.mts.map → index-qbL02uhs.d.mts.map} +1 -1
  296. package/dist/index.d.mts +17 -17
  297. package/dist/index.mjs +46 -45
  298. package/dist/{load-Dtoo7KcJ.mjs → load-BNo-ER8C.mjs} +1 -1
  299. package/dist/{load-Dtoo7KcJ.mjs.map → load-BNo-ER8C.mjs.map} +1 -1
  300. package/dist/{loader-C8Z48Uof.mjs → loader-Dn74CG1b.mjs} +68 -9
  301. package/dist/loader-Dn74CG1b.mjs.map +1 -0
  302. package/dist/{manifest-schema-DDSbwkAL.mjs → manifest-schema-BWKnQYQF.mjs} +1 -1
  303. package/dist/{manifest-schema-DDSbwkAL.mjs.map → manifest-schema-BWKnQYQF.mjs.map} +1 -1
  304. package/dist/media/image-endpoint.mjs +1 -1
  305. package/dist/media/index.d.mts +1 -1
  306. package/dist/media/index.mjs +2 -2
  307. package/dist/media/local-runtime.d.mts +19 -11
  308. package/dist/media/local-runtime.d.mts.map +1 -1
  309. package/dist/media/local-runtime.mjs +9 -7
  310. package/dist/media/local-runtime.mjs.map +1 -1
  311. package/dist/{media-allowlist-DunzrKFM.mjs → media-allowlist-B77I5_bw.mjs} +2 -2
  312. package/dist/{media-allowlist-DunzrKFM.mjs.map → media-allowlist-B77I5_bw.mjs.map} +1 -1
  313. package/dist/{media-url-S22B6aPr.mjs → media-url-O4rm9-SQ.mjs} +1 -1
  314. package/dist/{media-url-S22B6aPr.mjs.map → media-url-O4rm9-SQ.mjs.map} +1 -1
  315. package/dist/{menus-DOs1MQJg.mjs → menus-DS8VTZgo.mjs} +56 -13
  316. package/dist/menus-DS8VTZgo.mjs.map +1 -0
  317. package/dist/{mime-DYpsOAny.mjs → mime-BTzvzJ8M.mjs} +1 -1
  318. package/dist/{mime-DYpsOAny.mjs.map → mime-BTzvzJ8M.mjs.map} +1 -1
  319. package/dist/{mode-CFh8Dw8G.mjs → mode-BB0F8xTC.mjs} +1 -1
  320. package/dist/{mode-CFh8Dw8G.mjs.map → mode-BB0F8xTC.mjs.map} +1 -1
  321. package/dist/{normalize-Uam4_Vkr.mjs → normalize-ClbNIenm.mjs} +1 -1
  322. package/dist/{normalize-Uam4_Vkr.mjs.map → normalize-ClbNIenm.mjs.map} +1 -1
  323. package/dist/{oauth-authorization-BN-t83Uy.mjs → oauth-authorization-CsvzIp_F.mjs} +4 -4
  324. package/dist/{oauth-authorization-BN-t83Uy.mjs.map → oauth-authorization-CsvzIp_F.mjs.map} +1 -1
  325. package/dist/{oauth-clients-R6I_V0qz.mjs → oauth-clients-C9SYwEbZ.mjs} +1 -1
  326. package/dist/{oauth-clients-R6I_V0qz.mjs.map → oauth-clients-C9SYwEbZ.mjs.map} +1 -1
  327. package/dist/{oauth-state-store-Csoc6kkR.mjs → oauth-state-store---zrApfB.mjs} +1 -1
  328. package/dist/{oauth-state-store-Csoc6kkR.mjs.map → oauth-state-store---zrApfB.mjs.map} +1 -1
  329. package/dist/{oauth-user-lookup-d7VYjTpx.mjs → oauth-user-lookup-SHsWRlG9.mjs} +1 -1
  330. package/dist/{oauth-user-lookup-d7VYjTpx.mjs.map → oauth-user-lookup-SHsWRlG9.mjs.map} +1 -1
  331. package/dist/object-cache/memory.d.mts +1 -1
  332. package/dist/{options-DFFpvNJU.d.mts → options-CqECG0gM.d.mts} +3 -3
  333. package/dist/{options-DFFpvNJU.d.mts.map → options-CqECG0gM.d.mts.map} +1 -1
  334. package/dist/page/index.d.mts +2 -2
  335. package/dist/{parse-qrHlnzTy.mjs → parse-C9hpjUyY.mjs} +2 -2
  336. package/dist/{parse-qrHlnzTy.mjs.map → parse-C9hpjUyY.mjs.map} +1 -1
  337. package/dist/{passkey-config-BJTbcnI5.mjs → passkey-config-C0YfSBko.mjs} +1 -1
  338. package/dist/{passkey-config-BJTbcnI5.mjs.map → passkey-config-C0YfSBko.mjs.map} +1 -1
  339. package/dist/{placeholder-CIDCpyEY.mjs → placeholder-B0s2mWu5.mjs} +1 -1
  340. package/dist/{placeholder-CIDCpyEY.mjs.map → placeholder-B0s2mWu5.mjs.map} +1 -1
  341. package/dist/{placeholder-CirPauNG.d.mts → placeholder-QoI4gEzP.d.mts} +1 -1
  342. package/dist/{placeholder-CirPauNG.d.mts.map → placeholder-QoI4gEzP.d.mts.map} +1 -1
  343. package/dist/plugin-types.d.mts +1 -1
  344. package/dist/plugin-utils.d.mts +9 -9
  345. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  346. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  347. package/dist/{portable-text-BIFhrU6T.mjs → portable-text-BICg8bTk.mjs} +1 -1
  348. package/dist/{portable-text-BIFhrU6T.mjs.map → portable-text-BICg8bTk.mjs.map} +1 -1
  349. package/dist/{preview-IDye9SPQ.mjs → preview-DKGCt2_p.mjs} +2 -2
  350. package/dist/{preview-IDye9SPQ.mjs.map → preview-DKGCt2_p.mjs.map} +1 -1
  351. package/dist/{public-url-8lFyQ8ZF.mjs → public-url-CTVqgMmg.mjs} +1 -1
  352. package/dist/{public-url-8lFyQ8ZF.mjs.map → public-url-CTVqgMmg.mjs.map} +1 -1
  353. package/dist/{query-B1RVFUNM.mjs → query-DgUHZLWB.mjs} +79 -8
  354. package/dist/query-DgUHZLWB.mjs.map +1 -0
  355. package/dist/{rate-limit-DfNAqIWW.mjs → rate-limit-BuQ5d4X_.mjs} +2 -2
  356. package/dist/{rate-limit-DfNAqIWW.mjs.map → rate-limit-BuQ5d4X_.mjs.map} +1 -1
  357. package/dist/{redirect-B4wuX2A5.mjs → redirect-CS-PHtNh.mjs} +1 -1
  358. package/dist/{redirect-B4wuX2A5.mjs.map → redirect-CS-PHtNh.mjs.map} +1 -1
  359. package/dist/{redirects-CT_vb3NV.mjs → redirects-BZ8Mxn8H.mjs} +2 -2
  360. package/dist/{redirects-CT_vb3NV.mjs.map → redirects-BZ8Mxn8H.mjs.map} +1 -1
  361. package/dist/{redirects-DUvXgzCX.mjs → redirects-x9eFPeyi.mjs} +4 -2
  362. package/dist/redirects-x9eFPeyi.mjs.map +1 -0
  363. package/dist/{registry-CjK96fHD.mjs → registry-CK1SS6pi.mjs} +2 -2
  364. package/dist/{registry-CjK96fHD.mjs.map → registry-CK1SS6pi.mjs.map} +1 -1
  365. package/dist/{request-meta-ei3ATilC.mjs → request-meta-CmS1tDFf.mjs} +2 -2
  366. package/dist/{request-meta-ei3ATilC.mjs.map → request-meta-CmS1tDFf.mjs.map} +1 -1
  367. package/dist/{resolve-CpbBglV0.mjs → resolve-C7I0qiR0.mjs} +1 -1
  368. package/dist/{resolve-CpbBglV0.mjs.map → resolve-C7I0qiR0.mjs.map} +1 -1
  369. package/dist/{runner-jdXtFEd3.d.mts → runner-CEtq-6Sm.d.mts} +2 -2
  370. package/dist/{runner-jdXtFEd3.d.mts.map → runner-CEtq-6Sm.d.mts.map} +1 -1
  371. package/dist/runtime.d.mts +10 -10
  372. package/dist/runtime.mjs +1 -1
  373. package/dist/{schema-5z2Jfnbm.mjs → schema-CbFRFoM7.mjs} +3 -3
  374. package/dist/{schema-5z2Jfnbm.mjs.map → schema-CbFRFoM7.mjs.map} +1 -1
  375. package/dist/{search-D9FkoM-k.mjs → search-C-waE_YW.mjs} +3 -3
  376. package/dist/{search-D9FkoM-k.mjs.map → search-C-waE_YW.mjs.map} +1 -1
  377. package/dist/{secrets-BUE5UQys.mjs → secrets-BSf9pRRY.mjs} +2 -2
  378. package/dist/{secrets-BUE5UQys.mjs.map → secrets-BSf9pRRY.mjs.map} +1 -1
  379. package/dist/{sections-DWYZo6HK.mjs → sections-osX9U-YJ.mjs} +2 -2
  380. package/dist/{sections-DWYZo6HK.mjs.map → sections-osX9U-YJ.mjs.map} +1 -1
  381. package/dist/seed/index.d.mts +2 -2
  382. package/dist/seed/index.mjs +12 -11
  383. package/dist/seo/index.d.mts +1 -1
  384. package/dist/seo/index.mjs +1 -1
  385. package/dist/{seo-Cu47j3mJ.mjs → seo-4FovMwNS.mjs} +1 -1
  386. package/dist/{seo-Cu47j3mJ.mjs.map → seo-4FovMwNS.mjs.map} +1 -1
  387. package/dist/{seo-DRnqnstF.mjs → seo-DCEF-AVr.mjs} +1 -1
  388. package/dist/{seo-DRnqnstF.mjs.map → seo-DCEF-AVr.mjs.map} +1 -1
  389. package/dist/{service-DTmtqCnw.mjs → service-jby1RRmU.mjs} +2 -2
  390. package/dist/{service-DTmtqCnw.mjs.map → service-jby1RRmU.mjs.map} +1 -1
  391. package/dist/{session-user-DmtPMNa1.mjs → session-user-B8aLtKAH.mjs} +1 -1
  392. package/dist/{session-user-DmtPMNa1.mjs.map → session-user-B8aLtKAH.mjs.map} +1 -1
  393. package/dist/{settings-DUrVDN0c.mjs → settings-4bRT2NIf.mjs} +2 -2
  394. package/dist/{settings-DUrVDN0c.mjs.map → settings-4bRT2NIf.mjs.map} +1 -1
  395. package/dist/{settings-yaxu9mU-.mjs → settings-t-H2jPuJ.mjs} +3 -3
  396. package/dist/{settings-yaxu9mU-.mjs.map → settings-t-H2jPuJ.mjs.map} +1 -1
  397. package/dist/{setup-complete-BWFHzgvZ.mjs → setup-complete-gEiySUc-.mjs} +1 -1
  398. package/dist/{setup-complete-BWFHzgvZ.mjs.map → setup-complete-gEiySUc-.mjs.map} +1 -1
  399. package/dist/{setup-nonce-DFWG-J5c.mjs → setup-nonce-DzS50zme.mjs} +1 -1
  400. package/dist/{setup-nonce-DFWG-J5c.mjs.map → setup-nonce-DzS50zme.mjs.map} +1 -1
  401. package/dist/{single-flight-cache-B5p5cNOL.mjs → single-flight-cache-Cdfkic3t.mjs} +1 -1
  402. package/dist/{single-flight-cache-B5p5cNOL.mjs.map → single-flight-cache-Cdfkic3t.mjs.map} +1 -1
  403. package/dist/{site-url-BOTPgmeM.mjs → site-url-BLebyON8.mjs} +1 -1
  404. package/dist/{site-url-BOTPgmeM.mjs.map → site-url-BLebyON8.mjs.map} +1 -1
  405. package/dist/{ssrf-B0VeRLrp.mjs → ssrf-BRKb343l.mjs} +1 -1
  406. package/dist/{ssrf-B0VeRLrp.mjs.map → ssrf-BRKb343l.mjs.map} +1 -1
  407. package/dist/{status-CB2basWJ.mjs → status-vUK0SA17.mjs} +1 -1
  408. package/dist/{status-CB2basWJ.mjs.map → status-vUK0SA17.mjs.map} +1 -1
  409. package/dist/storage/local.d.mts +1 -1
  410. package/dist/storage/local.mjs +1 -1
  411. package/dist/storage/s3.d.mts +1 -1
  412. package/dist/storage/s3.mjs +1 -1
  413. package/dist/{taxonomies-CJmkEpdS.mjs → taxonomies-BBB8O-CU.mjs} +2 -2
  414. package/dist/{taxonomies-CJmkEpdS.mjs.map → taxonomies-BBB8O-CU.mjs.map} +1 -1
  415. package/dist/{taxonomies-Be9B1jEj.mjs → taxonomies-Dxrc_szG.mjs} +26 -6
  416. package/dist/{taxonomies-Be9B1jEj.mjs.map → taxonomies-Dxrc_szG.mjs.map} +1 -1
  417. package/dist/{tokens-BvrJvIB6.mjs → tokens-LeuXF9gG.mjs} +1 -1
  418. package/dist/{tokens-BvrJvIB6.mjs.map → tokens-LeuXF9gG.mjs.map} +1 -1
  419. package/dist/{transport-k7YjfmEn.d.mts → transport-BZ-03aFT.d.mts} +1 -1
  420. package/dist/{transport-k7YjfmEn.d.mts.map → transport-BZ-03aFT.d.mts.map} +1 -1
  421. package/dist/{transport-B4rXnSTf.mjs → transport-_2nBz7e9.mjs} +1 -1
  422. package/dist/{transport-B4rXnSTf.mjs.map → transport-_2nBz7e9.mjs.map} +1 -1
  423. package/dist/{trusted-proxy-DY1_UqHr.mjs → trusted-proxy-DZY5WCn2.mjs} +1 -1
  424. package/dist/{trusted-proxy-DY1_UqHr.mjs.map → trusted-proxy-DZY5WCn2.mjs.map} +1 -1
  425. package/dist/{types-Czg1S3gB.d.mts → types-B-gIxFCE.d.mts} +1 -1
  426. package/dist/{types-Czg1S3gB.d.mts.map → types-B-gIxFCE.d.mts.map} +1 -1
  427. package/dist/{types-DXLVzV2w.d.mts → types-BG8_XTLj.d.mts} +1 -1
  428. package/dist/{types-DXLVzV2w.d.mts.map → types-BG8_XTLj.d.mts.map} +1 -1
  429. package/dist/{types-CWGYDYqF.d.mts → types-BWh2MjmA.d.mts} +15 -2
  430. package/dist/types-BWh2MjmA.d.mts.map +1 -0
  431. package/dist/{types-CgvhU-hF.d.mts → types-BWqGVhFn.d.mts} +1 -1
  432. package/dist/{types-CgvhU-hF.d.mts.map → types-BWqGVhFn.d.mts.map} +1 -1
  433. package/dist/{types-DYF2_Vf4.mjs → types-CQAugunJ.mjs} +1 -1
  434. package/dist/{types-DYF2_Vf4.mjs.map → types-CQAugunJ.mjs.map} +1 -1
  435. package/dist/{types-DPCpkzvS.d.mts → types-CTLJYMhN.d.mts} +1 -1
  436. package/dist/{types-DPCpkzvS.d.mts.map → types-CTLJYMhN.d.mts.map} +1 -1
  437. package/dist/{types-CmivgZbp.d.mts → types-CUsXGRVj.d.mts} +1 -1
  438. package/dist/{types-CmivgZbp.d.mts.map → types-CUsXGRVj.d.mts.map} +1 -1
  439. package/dist/types-DXOIbece.mjs.map +1 -1
  440. package/dist/{types-CKNXt63n.d.mts → types-DrYMm9s5.d.mts} +1 -1
  441. package/dist/{types-CKNXt63n.d.mts.map → types-DrYMm9s5.d.mts.map} +1 -1
  442. package/dist/{types-CIKX2HO5.d.mts → types-TTx8uP7V.d.mts} +2 -2
  443. package/dist/{types-CIKX2HO5.d.mts.map → types-TTx8uP7V.d.mts.map} +1 -1
  444. package/dist/{types-DCNNfeCv.d.mts → types-fS7-VTdR.d.mts} +1 -1
  445. package/dist/{types-DCNNfeCv.d.mts.map → types-fS7-VTdR.d.mts.map} +1 -1
  446. package/dist/{utils-LbHcSRTj.mjs → utils-B7A57fm9.mjs} +1 -1
  447. package/dist/{utils-LbHcSRTj.mjs.map → utils-B7A57fm9.mjs.map} +1 -1
  448. package/dist/{validate-Bwl64sxv.mjs → validate-0Utjspbs.mjs} +1 -1
  449. package/dist/{validate-Bwl64sxv.mjs.map → validate-0Utjspbs.mjs.map} +1 -1
  450. package/dist/{validate-CE2M0nvx.d.mts → validate-DOFrIb-c.d.mts} +5 -5
  451. package/dist/{validate-CE2M0nvx.d.mts.map → validate-DOFrIb-c.d.mts.map} +1 -1
  452. package/dist/{validation-C_yOvFaO.mjs → validation-D9EnzH1T.mjs} +5 -5
  453. package/dist/{validation-C_yOvFaO.mjs.map → validation-D9EnzH1T.mjs.map} +1 -1
  454. package/dist/version-BgVM_1MU.mjs +7 -0
  455. package/dist/{version-RnYXYjzD.mjs.map → version-BgVM_1MU.mjs.map} +1 -1
  456. package/dist/{widgets-8GONuRHo.mjs → widgets-BSTzPUYa.mjs} +3 -3
  457. package/dist/{widgets-8GONuRHo.mjs.map → widgets-BSTzPUYa.mjs.map} +1 -1
  458. package/dist/{zod-generator-D481JjzD.mjs → zod-generator-ElVQOav7.mjs} +50 -14
  459. package/dist/zod-generator-ElVQOav7.mjs.map +1 -0
  460. package/package.json +8 -7
  461. package/src/api/schemas/bylines.ts +8 -0
  462. package/src/astro/integration/virtual-modules.ts +8 -0
  463. package/src/astro/integration/vite-config.ts +9 -1
  464. package/src/astro/middleware/request-context.ts +6 -1
  465. package/src/astro/middleware/scoped-db.ts +131 -0
  466. package/src/astro/middleware/stream-end-metrics.ts +4 -8
  467. package/src/astro/middleware.ts +90 -28
  468. package/src/astro/routes/admin.astro +5 -1
  469. package/src/astro/routes/api/schema/index.ts +9 -3
  470. package/src/cli/commands/export-seed.ts +10 -7
  471. package/src/components/Block.astro +71 -0
  472. package/src/components/EmDashMedia.astro +1 -2
  473. package/src/components/Image.astro +36 -2
  474. package/src/components/InlinePortableTextEditor.tsx +10 -2
  475. package/src/components/index.ts +5 -0
  476. package/src/components/portable-text-text-align.ts +38 -0
  477. package/src/content/converters/portable-text-to-prosemirror.ts +5 -1
  478. package/src/content/converters/prosemirror-to-portable-text.ts +8 -0
  479. package/src/content/converters/types.ts +1 -0
  480. package/src/database/repositories/byline.ts +14 -0
  481. package/src/database/repositories/types.ts +13 -0
  482. package/src/emdash-runtime.ts +226 -71
  483. package/src/loader.ts +97 -5
  484. package/src/media/local-runtime.ts +18 -5
  485. package/src/plugins/context.ts +94 -22
  486. package/src/plugins/cron.ts +18 -2
  487. package/src/plugins/routes.ts +40 -1
  488. package/src/query.ts +108 -1
  489. package/src/schema/zod-generator.ts +53 -8
  490. package/src/taxonomies/index.ts +26 -0
  491. package/src/ui.ts +5 -0
  492. package/src/virtual-modules.d.ts +13 -0
  493. package/dist/byline-CC0WS4Gu.mjs.map +0 -1
  494. package/dist/byline-fields-jy07PZJM.d.mts.map +0 -1
  495. package/dist/context-f1__jpzF.mjs.map +0 -1
  496. package/dist/cron-CQPxBjYs.mjs.map +0 -1
  497. package/dist/index-C2dLNT6S.d.mts.map +0 -1
  498. package/dist/loader-C8Z48Uof.mjs.map +0 -1
  499. package/dist/menus-DOs1MQJg.mjs.map +0 -1
  500. package/dist/query-B1RVFUNM.mjs.map +0 -1
  501. package/dist/redirects-DUvXgzCX.mjs.map +0 -1
  502. package/dist/types-CWGYDYqF.d.mts.map +0 -1
  503. package/dist/version-RnYXYjzD.mjs +0 -7
  504. package/dist/zod-generator-D481JjzD.mjs.map +0 -1
  505. /package/dist/{api-tokens-BVH-H8Z9.mjs → api-tokens-B4BQybOp.mjs} +0 -0
  506. /package/dist/{ssrf-Cz1e2QPn.mjs → ssrf-CcX9zvMK.mjs} +0 -0
  507. /package/dist/{types-Bfr2Pj6z.mjs → types-BvbeGEtr.mjs} +0 -0
@@ -36,6 +36,7 @@ export { default as EmDashImage } from "./EmDashImage.astro";
36
36
  export { default as EmDashMedia } from "./EmDashMedia.astro";
37
37
 
38
38
  // Portable Text block type components
39
+ export { default as Block } from "./Block.astro";
39
40
  export { default as Image } from "./Image.astro";
40
41
  export { default as Code } from "./Code.astro";
41
42
  export { default as Embed } from "./Embed.astro";
@@ -57,6 +58,7 @@ export { default as Underline } from "./marks/Underline.astro";
57
58
  export { default as StrikeThrough } from "./marks/StrikeThrough.astro";
58
59
  export { default as Link } from "./marks/Link.astro";
59
60
 
61
+ import BlockComponent from "./Block.astro";
60
62
  import BreakComponent from "./Break.astro";
61
63
  import ButtonComponent from "./Button.astro";
62
64
  import ButtonsComponent from "./Buttons.astro";
@@ -77,11 +79,14 @@ import TableComponent from "./Table.astro";
77
79
  * Pre-configured components for EmDash Portable Text content
78
80
  *
79
81
  * Includes renderers for:
82
+ * - Block styles: paragraph, h1..h6, blockquote — with `textAlign` honoured
83
+ * as a WordPress-style `has-text-align-{value}` class (#1201)
80
84
  * - Block types: image, code, embed, gallery, columns, break, htmlBlock, table,
81
85
  * button, buttons, cover, file, pullquote
82
86
  * - Marks: superscript, subscript, underline, strike-through, link
83
87
  */
84
88
  export const emdashComponents = {
89
+ block: BlockComponent,
85
90
  type: {
86
91
  image: ImageComponent,
87
92
  code: CodeComponent,
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Maps a Portable Text block's `textAlign` to a WordPress-style class name
3
+ * (`has-text-align-{value}`) for public rendering. Used by the Portable Text
4
+ * `Block` override in `./Block.astro`.
5
+ *
6
+ * `left` is the document default and intentionally does not produce a class —
7
+ * this matches the converter's omit-on-default rule (see
8
+ * `src/content/converters/prosemirror-to-portable-text.ts`) so untouched
9
+ * content stays bytewise identical and renders without an extra class.
10
+ *
11
+ * Related: https://github.com/emdash-cms/emdash/issues/1201
12
+ */
13
+
14
+ type AlignClassName = "has-text-align-center" | "has-text-align-right" | "has-text-align-justify";
15
+
16
+ const ALIGN_CLASS_MAP: Record<string, AlignClassName> = {
17
+ center: "has-text-align-center",
18
+ right: "has-text-align-right",
19
+ justify: "has-text-align-justify",
20
+ };
21
+
22
+ /**
23
+ * Returns the CSS class for a textAlign value, or `undefined` when no class
24
+ * should be emitted (default left, missing, or unknown values).
25
+ *
26
+ * Allowlist-only by design: arbitrary strings are rejected so a hand-edited
27
+ * or imported Portable Text block cannot inject attacker-controlled class
28
+ * names into the rendered HTML.
29
+ */
30
+ export function textAlignClassName(value: string | undefined): AlignClassName | undefined {
31
+ if (value === undefined) return undefined;
32
+ // `Object.hasOwn` (not `in`) so prototype keys like "toString" or
33
+ // "constructor" can't slip through as valid alignments.
34
+ if (Object.hasOwn(ALIGN_CLASS_MAP, value)) {
35
+ return ALIGN_CLASS_MAP[value];
36
+ }
37
+ return undefined;
38
+ }
@@ -164,7 +164,10 @@ function convertTextBlock(block: PortableTextTextBlock): ProseMirrorNode | null
164
164
  const level = parseInt(style.substring(1), 10);
165
165
  return {
166
166
  type: "heading",
167
- attrs: { level },
167
+ attrs: {
168
+ level,
169
+ ...(block.textAlign ? { textAlign: block.textAlign } : {}),
170
+ },
168
171
  content: content.length > 0 ? content : undefined,
169
172
  };
170
173
  }
@@ -184,6 +187,7 @@ function convertTextBlock(block: PortableTextTextBlock): ProseMirrorNode | null
184
187
  default:
185
188
  return {
186
189
  type: "paragraph",
190
+ attrs: block.textAlign ? { textAlign: block.textAlign } : undefined,
187
191
  content: content.length > 0 ? content : undefined,
188
192
  };
189
193
  }
@@ -106,12 +106,16 @@ function convertParagraph(node: ProseMirrorNode): PortableTextTextBlock | null {
106
106
  return null;
107
107
  }
108
108
 
109
+ const ta = node.attrs?.textAlign;
110
+ const textAlign = ta === "center" || ta === "right" || ta === "justify" ? ta : undefined;
111
+
109
112
  return {
110
113
  _type: "block",
111
114
  _key: generateKey(),
112
115
  style: "normal",
113
116
  children,
114
117
  markDefs: markDefs.length > 0 ? markDefs : undefined,
118
+ ...(textAlign ? { textAlign } : {}),
115
119
  };
116
120
  }
117
121
 
@@ -147,12 +151,16 @@ function convertHeading(node: ProseMirrorNode): PortableTextTextBlock | null {
147
151
  return null;
148
152
  }
149
153
 
154
+ const ta = node.attrs?.textAlign;
155
+ const textAlign = ta === "center" || ta === "right" || ta === "justify" ? ta : undefined;
156
+
150
157
  return {
151
158
  _type: "block",
152
159
  _key: generateKey(),
153
160
  style,
154
161
  children,
155
162
  markDefs: markDefs.length > 0 ? markDefs : undefined,
163
+ ...(textAlign ? { textAlign } : {}),
156
164
  };
157
165
  }
158
166
 
@@ -43,6 +43,7 @@ export interface PortableTextTextBlock {
43
43
  level?: number;
44
44
  children: PortableTextSpan[];
45
45
  markDefs?: PortableTextMarkDef[];
46
+ textAlign?: "left" | "center" | "right" | "justify";
46
47
  }
47
48
 
48
49
  /**
@@ -37,6 +37,8 @@ type BylineRow = Selectable<BylineTable>;
37
37
  type BylineRowWithAvatar = BylineRow & {
38
38
  avatar_storage_key?: string | null;
39
39
  avatar_alt?: string | null;
40
+ avatar_blurhash?: string | null;
41
+ avatar_dominant_color?: string | null;
40
42
  };
41
43
 
42
44
  export interface CreateBylineInput {
@@ -113,6 +115,8 @@ function rowToByline(row: BylineRowWithAvatar): BylineSummary {
113
115
  avatarMediaId: row.avatar_media_id,
114
116
  avatarStorageKey: row.avatar_storage_key ?? null,
115
117
  avatarAlt: row.avatar_alt ?? null,
118
+ avatarBlurhash: row.avatar_blurhash ?? null,
119
+ avatarDominantColor: row.avatar_dominant_color ?? null,
116
120
  websiteUrl: row.website_url,
117
121
  userId: row.user_id,
118
122
  isGuest: row.is_guest === 1,
@@ -944,6 +948,8 @@ export class BylineRepository {
944
948
  "b.avatar_media_id as avatar_media_id",
945
949
  "m.storage_key as avatar_storage_key",
946
950
  "m.alt as avatar_alt",
951
+ "m.blurhash as avatar_blurhash",
952
+ "m.dominant_color as avatar_dominant_color",
947
953
  "b.website_url as website_url",
948
954
  "b.user_id as user_id",
949
955
  "b.is_guest as is_guest",
@@ -971,6 +977,8 @@ export class BylineRepository {
971
977
  avatar_media_id: row.avatar_media_id,
972
978
  avatar_storage_key: row.avatar_storage_key,
973
979
  avatar_alt: row.avatar_alt,
980
+ avatar_blurhash: row.avatar_blurhash,
981
+ avatar_dominant_color: row.avatar_dominant_color,
974
982
  website_url: row.website_url,
975
983
  user_id: row.user_id,
976
984
  is_guest: row.is_guest,
@@ -1080,6 +1088,8 @@ export class BylineRepository {
1080
1088
  "b.avatar_media_id as avatar_media_id",
1081
1089
  "m.storage_key as avatar_storage_key",
1082
1090
  "m.alt as avatar_alt",
1091
+ "m.blurhash as avatar_blurhash",
1092
+ "m.dominant_color as avatar_dominant_color",
1083
1093
  "b.website_url as website_url",
1084
1094
  "b.user_id as user_id",
1085
1095
  "b.is_guest as is_guest",
@@ -1104,6 +1114,8 @@ export class BylineRepository {
1104
1114
  avatar_media_id: row.avatar_media_id,
1105
1115
  avatar_storage_key: row.avatar_storage_key,
1106
1116
  avatar_alt: row.avatar_alt,
1117
+ avatar_blurhash: row.avatar_blurhash,
1118
+ avatar_dominant_color: row.avatar_dominant_color,
1107
1119
  website_url: row.website_url,
1108
1120
  user_id: row.user_id,
1109
1121
  is_guest: row.is_guest,
@@ -1182,6 +1194,8 @@ export class BylineRepository {
1182
1194
  "b.avatar_media_id as avatar_media_id",
1183
1195
  "m.storage_key as avatar_storage_key",
1184
1196
  "m.alt as avatar_alt",
1197
+ "m.blurhash as avatar_blurhash",
1198
+ "m.dominant_color as avatar_dominant_color",
1185
1199
  "b.website_url as website_url",
1186
1200
  "b.user_id as user_id",
1187
1201
  "b.is_guest as is_guest",
@@ -78,6 +78,19 @@ export interface BylineSummary {
78
78
  avatarStorageKey?: string | null;
79
79
  /** Avatar media alt text, from the same media join. Null when not joined. */
80
80
  avatarAlt?: string | null;
81
+ /**
82
+ * Avatar media blurhash (LQIP placeholder, migration 024), folded in by the
83
+ * same media join as `avatarStorageKey`. Lets a renderer paint a blurred
84
+ * placeholder while the full avatar loads, with no extra media lookup.
85
+ * Null when the byline has no avatar, the media row has no blurhash, or the
86
+ * byline was loaded through a finder that doesn't join media.
87
+ */
88
+ avatarBlurhash?: string | null;
89
+ /**
90
+ * Avatar media dominant colour (LQIP placeholder, migration 024), from the
91
+ * same media join. Null under the same conditions as `avatarBlurhash`.
92
+ */
93
+ avatarDominantColor?: string | null;
81
94
  websiteUrl: string | null;
82
95
  userId: string | null;
83
96
  isGuest: boolean;
@@ -244,6 +244,15 @@ export interface MediaProviderEntry {
244
244
  */
245
245
  export interface MediaProviderContext {
246
246
  db: Kysely<Database>;
247
+ /**
248
+ * Resolver for the live connection, preferred over `db` by providers that
249
+ * query EmDash's database. Resolves the current request/event-scoped
250
+ * connection from ALS so connection-backed adapters (Postgres over
251
+ * Hyperdrive) don't reuse the per-isolate singleton's socket across events.
252
+ * Providers should resolve per operation rather than capturing `db` once.
253
+ * Omitted-safe: falls back to `db` for stateless adapters (D1, Node SQLite).
254
+ */
255
+ getDb?: () => Kysely<Database>;
247
256
  storage: Storage | null;
248
257
  }
249
258
 
@@ -262,6 +271,16 @@ export interface RuntimeDependencies {
262
271
  plugins: ResolvedPlugin[];
263
272
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
264
273
  createDialect: (config: any) => Dialect;
274
+ /**
275
+ * Factory for a dialect that batches same-turn reads into one round trip
276
+ * ({@link EmDashRuntime.create} uses it for the cold-start read phase).
277
+ * Present only on batching backends (D1, DO); absent backends fall back to
278
+ * the singleton. Returns a fresh connection each call — it must never be the
279
+ * long-lived singleton, whose coalescing buffer would be shared across
280
+ * requests.
281
+ */
282
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
283
+ createCoalescingDialect?: (config: any) => Dialect | null;
265
284
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
266
285
  createStorage: ((config: any) => Storage) | null;
267
286
  sandboxEnabled: boolean;
@@ -323,6 +342,7 @@ export interface EmDashRuntimeParts {
323
342
  allPipelinePlugins: ResolvedPlugin[];
324
343
  pipelineFactoryOptions: {
325
344
  db: Kysely<Database>;
345
+ getDb?: () => Kysely<Database>;
326
346
  storage?: Storage;
327
347
  siteInfo?: { siteName?: string; siteUrl?: string; locale?: string };
328
348
  };
@@ -370,6 +390,28 @@ function getDbHolder(): DbHolder {
370
390
  }
371
391
  return holder;
372
392
  }
393
+
394
+ /**
395
+ * Auto-seed runs at most once per isolate per database. Its lock + "done" set
396
+ * live on globalThis (same bundler-duplication reasoning as the db cache) so a
397
+ * reclaimed-and-rerun `create()` can't seed a second time concurrently. The
398
+ * lock polls rather than sharing a promise, so it is safe to await across a
399
+ * cancelled owner in workerd.
400
+ */
401
+ const SEED_HOLDER_KEY = Symbol.for("emdash:seed-state");
402
+ interface SeedHolder {
403
+ done: Set<string>;
404
+ lock: InitLock;
405
+ }
406
+ function getSeedHolder(): SeedHolder {
407
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis symbol slot, written only below
408
+ let holder = globalSymbolStore[SEED_HOLDER_KEY] as SeedHolder | undefined;
409
+ if (!holder) {
410
+ holder = { done: new Set<string>(), lock: createInitLock() };
411
+ globalSymbolStore[SEED_HOLDER_KEY] = holder;
412
+ }
413
+ return holder;
414
+ }
373
415
  const storageCache = new Map<string, Storage>();
374
416
  const sandboxedPluginCache = new Map<string, SandboxedPluginInstance>();
375
417
  /**
@@ -414,7 +456,20 @@ export class EmDashRuntime {
414
456
  readonly configuredPlugins: ResolvedPlugin[];
415
457
  readonly sandboxedPlugins: Map<string, SandboxedPluginInstance>;
416
458
  readonly sandboxedPluginEntries: SandboxedPluginEntry[];
417
- readonly schemaRegistry: SchemaRegistry;
459
+ /**
460
+ * Schema registry bound to the current request/event-scoped connection.
461
+ * Built per access (SchemaRegistry just wraps a db) against `this.db`, the
462
+ * ALS-aware getter — never a captured snapshot of the singleton. On a
463
+ * connection-backed adapter (Postgres over Hyperdrive) a captured singleton
464
+ * would query a socket opened by an earlier event and trip workerd's
465
+ * cross-request I/O guard; the catch in handlers like handleContentUpdate
466
+ * would then silently treat a revision-enabled collection as non-revisioned
467
+ * and write draft edits to live columns. Same reasoning as the per-call
468
+ * registry in _buildManifest().
469
+ */
470
+ get schemaRegistry(): SchemaRegistry {
471
+ return new SchemaRegistry(this.db);
472
+ }
418
473
  private _hooks!: HookPipeline;
419
474
  readonly config: EmDashConfig;
420
475
  readonly mediaProviders: Map<string, MediaProvider>;
@@ -445,6 +500,7 @@ export class EmDashRuntime {
445
500
  /** Factory options for the hook pipeline context factory */
446
501
  private pipelineFactoryOptions: {
447
502
  db: Kysely<Database>;
503
+ getDb?: () => Kysely<Database>;
448
504
  storage?: Storage;
449
505
  siteInfo?: { siteName?: string; siteUrl?: string; locale?: string };
450
506
  };
@@ -475,7 +531,6 @@ export class EmDashRuntime {
475
531
  this.configuredPlugins = parts.configuredPlugins;
476
532
  this.sandboxedPlugins = parts.sandboxedPlugins;
477
533
  this.sandboxedPluginEntries = parts.sandboxedPluginEntries;
478
- this.schemaRegistry = new SchemaRegistry(parts.db);
479
534
  this._hooks = parts.hooks;
480
535
  this.enabledPlugins = parts.enabledPlugins;
481
536
  this.pluginStates = parts.pluginStates;
@@ -621,7 +676,9 @@ export class EmDashRuntime {
621
676
  // The old pipeline's contextFactoryOptions were built up incrementally
622
677
  // via setContextFactory calls during create(). We replay them here.
623
678
  if (this.email) {
624
- newPipeline.setContextFactory({ db: this.db, emailPipeline: this.email });
679
+ // db/getDb are already wired by createHookPipeline above (they live in
680
+ // pipelineFactoryOptions), so the merge only adds emailPipeline.
681
+ newPipeline.setContextFactory({ emailPipeline: this.email });
625
682
  }
626
683
  if (this.cronScheduler) {
627
684
  const scheduler = this.cronScheduler;
@@ -985,6 +1042,22 @@ export class EmDashRuntime {
985
1042
  // Initialize database (connects, runs migrations if needed)
986
1043
  const db = await phase("rt.db", "DB init + migrations", () => EmDashRuntime.getDatabase(deps));
987
1044
 
1045
+ // Resolver for the live connection, mirroring the `get db()` getter
1046
+ // below (which can't be used here — the runtime instance doesn't exist
1047
+ // yet). Long-lived subsystems built during create() (cron executor,
1048
+ // plugin context factory, media providers) capture this resolver rather
1049
+ // than the `db` snapshot, so a connection-backed adapter (Postgres over
1050
+ // Hyperdrive) serves their queries from the current request/event-scoped
1051
+ // connection in ALS instead of the per-isolate singleton — whose socket
1052
+ // belongs to an earlier request and would trip workerd's cross-request
1053
+ // I/O guard. Stateless adapters (D1, Node SQLite) set no ALS db on most
1054
+ // paths, so this falls back to the singleton: unchanged behavior.
1055
+ const resolveDb = (): Kysely<Database> => {
1056
+ const ctx = getRequestContext();
1057
+ // eslint-disable-next-line typescript/no-unsafe-type-assertion -- ALS db is typed unknown to avoid a circular import; middleware always sets a Kysely<Database>
1058
+ return (ctx?.db as Kysely<Database> | undefined) ?? db;
1059
+ };
1060
+
988
1061
  // Validate EMDASH_ENCRYPTION_KEY once here so a malformed value
989
1062
  // surfaces in startup logs instead of as request-time 500s. The key
990
1063
  // itself is not yet consumed (a follow-up PR adds plugin-secret
@@ -998,47 +1071,156 @@ export class EmDashRuntime {
998
1071
  // Initialize storage (sync)
999
1072
  const storage = EmDashRuntime.getStorage(deps);
1000
1073
 
1001
- // Fetch plugin states and site info concurrently — independent reads
1002
- // against different tables (_plugin_state vs options), so they share
1003
- // one round-trip window instead of paying two sequential ones. Each
1004
- // phase() wrapper still records that phase's own duration, and each
1005
- // body keeps its own non-fatal catch.
1006
1074
  let pluginStates: Map<string, string> = new Map();
1007
1075
  let siteInfo: { siteName?: string; siteUrl?: string; locale?: string } | undefined;
1008
- await Promise.all([
1009
- // Fetch plugin states from database
1076
+ // "Already set up" by default so a read failure (e.g. tables absent on a
1077
+ // pre-migration db) skips seeding rather than seeding a half-built db.
1078
+ let seedGate = { collectionCount: 1, setupDone: true };
1079
+
1080
+ // Seeding must only touch the configured singleton, never a borrowed
1081
+ // per-request db (playground / DO preview) or the loader-fallback db.
1082
+ const reqCtx = getRequestContext();
1083
+ const ownsConfiguredDb = !!deps.config.database && !(reqCtx?.dbIsIsolated && reqCtx.db);
1084
+
1085
+ // Run the init reads on a coalescing connection so the concurrent
1086
+ // same-turn reads flush as one batch() round trip. The singleton can't:
1087
+ // its plain SqliteAdapter reports supportsMultipleConnections=false, so
1088
+ // Kysely's connection mutex serializes concurrent reads into N round
1089
+ // trips. The connection is per-init and discarded — the long-lived
1090
+ // singleton must never coalesce or one request's reads could land in
1091
+ // another's batch. Backends without a coalescing dialect (Node/SQLite)
1092
+ // fall back to the singleton, where serialization costs nothing.
1093
+ let readDb = db;
1094
+ let readDbDisposable: Kysely<Database> | undefined;
1095
+ if (ownsConfiguredDb && deps.createCoalescingDialect && deps.config.database) {
1096
+ try {
1097
+ const dialect = deps.createCoalescingDialect(deps.config.database.config);
1098
+ if (dialect) {
1099
+ readDb = new Kysely<Database>({ dialect, log: kyselyLogOption() });
1100
+ readDbDisposable = readDb;
1101
+ }
1102
+ } catch {
1103
+ readDb = db;
1104
+ }
1105
+ }
1106
+ const optionsRepo = new OptionsRepository(readDb);
1107
+
1108
+ const readSiteInfo = async () => {
1109
+ const siteOpts = await optionsRepo.getMany<string>([
1110
+ "emdash:site_title",
1111
+ "emdash:site_url",
1112
+ "emdash:locale",
1113
+ ]);
1114
+ return {
1115
+ siteName: siteOpts.get("emdash:site_title") ?? undefined,
1116
+ siteUrl: siteOpts.get("emdash:site_url") ?? undefined,
1117
+ locale: siteOpts.get("emdash:locale") ?? undefined,
1118
+ };
1119
+ };
1120
+
1121
+ const coldStartReads: Array<Promise<void>> = [
1010
1122
  phase("rt.plugins", "Plugin states", async () => {
1011
1123
  try {
1012
- const states = await db
1124
+ const states = await readDb
1013
1125
  .selectFrom("_plugin_state")
1014
1126
  .select(["plugin_id", "status"])
1015
1127
  .execute();
1016
1128
  pluginStates = new Map(states.map((s) => [s.plugin_id, s.status]));
1017
1129
  } catch {
1018
- // Plugin state table may not exist yet
1130
+ // _plugin_state may not exist yet on a pre-migration db.
1019
1131
  }
1020
1132
  }),
1021
- // Load site info for plugin context extensions (1 batch query instead of 3)
1022
1133
  phase("rt.site", "Site info options", async () => {
1023
1134
  try {
1024
- const optionsRepo = new OptionsRepository(db);
1025
- const siteOpts = await optionsRepo.getMany<string>([
1026
- "emdash:site_title",
1027
- "emdash:site_url",
1028
- "emdash:locale",
1029
- ]);
1030
- siteInfo = {
1031
- siteName: siteOpts.get("emdash:site_title") ?? undefined,
1032
- siteUrl: siteOpts.get("emdash:site_url") ?? undefined,
1033
- locale: siteOpts.get("emdash:locale") ?? undefined,
1034
- };
1135
+ siteInfo = await readSiteInfo();
1035
1136
  } catch {
1036
- // Options table may not exist yet (pre-setup)
1137
+ // options may not exist yet on a pre-migration db.
1037
1138
  }
1038
1139
  }),
1039
- ]);
1140
+ ];
1141
+
1142
+ if (ownsConfiguredDb) {
1143
+ coldStartReads.push(
1144
+ phase("rt.seedcheck", "Auto-seed gate", async () => {
1145
+ try {
1146
+ const [collectionCount, setupOption] = await Promise.all([
1147
+ readDb
1148
+ .selectFrom("_emdash_collections")
1149
+ .select((eb) => eb.fn.countAll<number>().as("count"))
1150
+ .executeTakeFirstOrThrow(),
1151
+ readDb
1152
+ .selectFrom("options")
1153
+ .select("value")
1154
+ .where("name", "=", "emdash:setup_complete")
1155
+ .executeTakeFirst(),
1156
+ ]);
1157
+ const setupDone = (() => {
1158
+ try {
1159
+ return !!setupOption && JSON.parse(setupOption.value) === true;
1160
+ } catch {
1161
+ return false;
1162
+ }
1163
+ })();
1164
+ seedGate = { collectionCount: collectionCount.count, setupDone };
1165
+ } catch {
1166
+ // Leave the "already set up" default so a read failure never
1167
+ // triggers a seed onto a half-built db.
1168
+ }
1169
+ }),
1170
+ );
1171
+ }
1172
+
1173
+ await Promise.all(coldStartReads);
1174
+
1175
+ // Auto-seed the default schema for a first load that skipped the setup
1176
+ // wizard (the wizard and dev-bypass apply seeds explicitly). Run under a
1177
+ // per-isolate lock keyed by the configured db so a reclaimed-and-rerun
1178
+ // create() can't apply the seed a second time concurrently.
1179
+ if (seedGate.collectionCount === 0 && !seedGate.setupDone) {
1180
+ const seedKey = deps.config.database?.entrypoint ?? "default";
1181
+ const seedHolder = getSeedHolder();
1182
+ try {
1183
+ await initWithLock(
1184
+ seedHolder.lock,
1185
+ () => (seedHolder.done.has(seedKey) ? true : undefined),
1186
+ async () => {
1187
+ const { applySeed } = await import("./seed/apply.js");
1188
+ const { loadSeed } = await import("./seed/load.js");
1189
+ const { validateSeed } = await import("./seed/validate.js");
1190
+
1191
+ const seed = await loadSeed();
1192
+ const validation = validateSeed(seed);
1193
+ if (validation.valid) {
1194
+ await applySeed(db, seed, { onConflict: "skip" });
1195
+ console.log("Auto-seeded default collections");
1196
+ }
1197
+ seedHolder.done.add(seedKey);
1198
+ return true;
1199
+ },
1200
+ { deadlineMs: DB_INIT_DEADLINE_MS, anchor: (promise) => after(() => promise) },
1201
+ );
1202
+ // The site-info read ran before the seed wrote its defaults, so
1203
+ // refresh the snapshot the plugin context sees.
1204
+ try {
1205
+ siteInfo = await readSiteInfo();
1206
+ } catch {
1207
+ // Non-fatal — plugin context falls back to undefined fields.
1208
+ }
1209
+ } catch {
1210
+ // Non-fatal — a failed seed (e.g. missing seed module) leaves the
1211
+ // site un-seeded; a later request retries.
1212
+ }
1213
+ }
1214
+
1215
+ // The read connection is single-use; everything below uses the singleton.
1216
+ if (readDbDisposable) {
1217
+ try {
1218
+ await readDbDisposable.destroy();
1219
+ } catch {
1220
+ // Non-fatal — the underlying binding is shared and needs no teardown.
1221
+ }
1222
+ }
1040
1223
 
1041
- // Build set of enabled plugins
1042
1224
  const enabledPlugins = new Set<string>();
1043
1225
  for (const plugin of deps.plugins) {
1044
1226
  const status = pluginStates.get(plugin.id);
@@ -1154,9 +1336,15 @@ export class EmDashRuntime {
1154
1336
  // Filter to currently enabled plugins for the initial pipeline
1155
1337
  const enabledPluginList = allPipelinePlugins.filter((p) => enabledPlugins.has(p.id));
1156
1338
 
1157
- // Create hook pipeline
1339
+ // Create hook pipeline. getDb travels here (not just via the email
1340
+ // setContextFactory call below) so it survives rebuildHookPipeline(),
1341
+ // which reconstructs the factory from pipelineFactoryOptions. Without it,
1342
+ // toggling a plugin on an email-less deployment would silently revert
1343
+ // plugin contexts to the singleton db — re-breaking connection-backed
1344
+ // adapters. See #1622.
1158
1345
  const pipelineFactoryOptions = {
1159
1346
  db,
1347
+ getDb: resolveDb,
1160
1348
  storage: storage ?? undefined,
1161
1349
  siteInfo,
1162
1350
  };
@@ -1208,7 +1396,7 @@ export class EmDashRuntime {
1208
1396
  // Initialize media providers
1209
1397
  const mediaProviders = new Map<string, MediaProvider>();
1210
1398
  const mediaProviderEntries = deps.mediaProviderEntries ?? [];
1211
- const providerContext: MediaProviderContext = { db, storage };
1399
+ const providerContext: MediaProviderContext = { db, storage, getDb: resolveDb };
1212
1400
 
1213
1401
  for (const entry of mediaProviderEntries) {
1214
1402
  try {
@@ -1249,8 +1437,10 @@ export class EmDashRuntime {
1249
1437
  };
1250
1438
 
1251
1439
  // Wire email pipeline into context factory (independent of cron —
1252
- // must not be inside the cron try/catch or ctx.email breaks when cron fails)
1253
- pipeline.setContextFactory({ db, emailPipeline });
1440
+ // must not be inside the cron try/catch or ctx.email breaks when cron fails).
1441
+ // db/getDb were already set via pipelineFactoryOptions above; merge only
1442
+ // adds emailPipeline.
1443
+ pipeline.setContextFactory({ emailPipeline });
1254
1444
 
1255
1445
  let cronExecutor: CronExecutor | null = null;
1256
1446
  let cronScheduler: CronScheduler | null = null;
@@ -1262,7 +1452,7 @@ export class EmDashRuntime {
1262
1452
 
1263
1453
  await phase("rt.cron", "Cron init (recovery deferred post-response)", async () => {
1264
1454
  try {
1265
- cronExecutor = new CronExecutor(db, invokeCronHook);
1455
+ cronExecutor = new CronExecutor(resolveDb, invokeCronHook);
1266
1456
 
1267
1457
  // Recover stale locks from previous crashes. Pure bookkeeping
1268
1458
  // against the _emdash_cron_tasks table — no request needs the
@@ -1444,45 +1634,9 @@ export class EmDashRuntime {
1444
1634
  // cleanup-flag check costs an extra `options.get()` on every
1445
1635
  // isolate cold boot forever. Cheaper to leave it.
1446
1636
 
1447
- // Auto-seed schema if no collections exist and setup hasn't run.
1448
- // This covers first-load on sites that skip the setup wizard.
1449
- // Dev-bypass and the wizard apply seeds explicitly.
1450
- try {
1451
- const [collectionCount, setupOption] = await Promise.all([
1452
- db
1453
- .selectFrom("_emdash_collections")
1454
- .select((eb) => eb.fn.countAll<number>().as("count"))
1455
- .executeTakeFirstOrThrow(),
1456
- db
1457
- .selectFrom("options")
1458
- .select("value")
1459
- .where("name", "=", "emdash:setup_complete")
1460
- .executeTakeFirst(),
1461
- ]);
1462
-
1463
- const setupDone = (() => {
1464
- try {
1465
- return setupOption && JSON.parse(setupOption.value) === true;
1466
- } catch {
1467
- return false;
1468
- }
1469
- })();
1470
-
1471
- if (collectionCount.count === 0 && !setupDone) {
1472
- const { applySeed } = await import("./seed/apply.js");
1473
- const { loadSeed } = await import("./seed/load.js");
1474
- const { validateSeed } = await import("./seed/validate.js");
1475
-
1476
- const seed = await loadSeed();
1477
- const validation = validateSeed(seed);
1478
- if (validation.valid) {
1479
- await applySeed(db, seed, { onConflict: "skip" });
1480
- console.log("Auto-seeded default collections");
1481
- }
1482
- }
1483
- } catch {
1484
- // Tables may not exist yet. Non-fatal.
1485
- }
1637
+ // This returns a migrated but possibly unseeded db; create() runs
1638
+ // the seed gate and applies the seed, batched with its other init
1639
+ // reads.
1486
1640
 
1487
1641
  // Publish only while still the current owner: a reclaimed slow
1488
1642
  // init must not flip the cached Kysely identity back after the
@@ -2965,6 +3119,7 @@ export class EmDashRuntime {
2965
3119
  if (trustedPlugin && this.enabledPlugins.has(trustedPlugin.id)) {
2966
3120
  const routeRegistry = new PluginRouteRegistry({
2967
3121
  db: this.db,
3122
+ storage: this.storage ?? undefined,
2968
3123
  emailPipeline: this.email ?? undefined,
2969
3124
  trustedProxyHeaders: getTrustedProxyHeaders(this.config),
2970
3125
  });