emdash 0.18.0 → 0.19.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 (408) hide show
  1. package/dist/api/route-utils.d.mts +2 -2
  2. package/dist/api/route-utils.mjs +14 -14
  3. package/dist/api/schemas/index.d.mts +2 -2
  4. package/dist/api/schemas/index.mjs +3 -3
  5. package/dist/{api-Cs7DAACP.mjs → api-BZ6bhjYs.mjs} +88 -16
  6. package/dist/api-BZ6bhjYs.mjs.map +1 -0
  7. package/dist/{apply-BWMV4Zmw.mjs → apply-hQkKKBCf.mjs} +23 -23
  8. package/dist/apply-hQkKKBCf.mjs.map +1 -0
  9. package/dist/astro/index.d.mts +8 -8
  10. package/dist/astro/index.d.mts.map +1 -1
  11. package/dist/astro/index.mjs +113 -23
  12. package/dist/astro/index.mjs.map +1 -1
  13. package/dist/astro/middleware/auth.d.mts +7 -7
  14. package/dist/astro/middleware/auth.mjs +2 -2
  15. package/dist/astro/middleware/redirect.mjs +4 -4
  16. package/dist/astro/middleware/request-context.mjs +2 -2
  17. package/dist/astro/middleware.d.mts +26 -4
  18. package/dist/astro/middleware.d.mts.map +1 -1
  19. package/dist/astro/middleware.mjs +205 -173
  20. package/dist/astro/middleware.mjs.map +1 -1
  21. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  22. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  23. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +2 -2
  24. package/dist/astro/routes/api/admin/api-tokens/index.mjs +3 -3
  25. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +5 -5
  26. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
  27. package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
  28. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
  29. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +12 -12
  30. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +12 -12
  31. package/dist/astro/routes/api/admin/bylines/index.mjs +12 -12
  32. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
  33. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  34. package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
  35. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  36. package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
  37. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
  38. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
  39. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +3 -3
  40. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +3 -3
  41. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +31 -31
  42. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +31 -31
  43. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +30 -30
  44. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +30 -30
  45. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +30 -30
  46. package/dist/astro/routes/api/admin/plugins/index.mjs +30 -30
  47. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  48. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +30 -30
  49. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +30 -30
  50. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +30 -30
  51. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +30 -30
  52. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +31 -31
  53. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +30 -30
  54. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +31 -31
  55. package/dist/astro/routes/api/admin/plugins/updates.mjs +30 -30
  56. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +30 -30
  57. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  58. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +30 -30
  59. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
  60. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  61. package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
  62. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
  63. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  64. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  65. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  66. package/dist/astro/routes/api/auth/invite/complete.mjs +6 -6
  67. package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
  68. package/dist/astro/routes/api/auth/invite/register-options.mjs +6 -6
  69. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  70. package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
  71. package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
  72. package/dist/astro/routes/api/auth/me.mjs +6 -6
  73. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +2 -2
  74. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  75. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  76. package/dist/astro/routes/api/auth/passkey/options.mjs +7 -7
  77. package/dist/astro/routes/api/auth/passkey/register/options.mjs +6 -6
  78. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +6 -6
  79. package/dist/astro/routes/api/auth/passkey/verify.mjs +6 -6
  80. package/dist/astro/routes/api/auth/signup/complete.mjs +6 -6
  81. package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
  82. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  83. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
  84. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  85. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -5
  86. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  87. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  88. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  89. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +8 -8
  90. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +9 -8
  91. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  92. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  93. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  94. package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
  95. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +12 -10
  96. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  97. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +11 -11
  98. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  99. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -5
  100. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  101. package/dist/astro/routes/api/content/_collection_/_id_.mjs +9 -8
  102. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  103. package/dist/astro/routes/api/content/_collection_/authors.d.mts +8 -0
  104. package/dist/astro/routes/api/content/_collection_/authors.d.mts.map +1 -0
  105. package/dist/astro/routes/api/content/_collection_/authors.mjs +19 -0
  106. package/dist/astro/routes/api/content/_collection_/authors.mjs.map +1 -0
  107. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  108. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  109. package/dist/astro/routes/api/dashboard.mjs +7 -7
  110. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  111. package/dist/astro/routes/api/import/probe.d.mts +2 -2
  112. package/dist/astro/routes/api/import/probe.mjs +6 -6
  113. package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
  114. package/dist/astro/routes/api/import/wordpress/execute.d.mts +7 -7
  115. package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -9
  116. package/dist/astro/routes/api/import/wordpress/media.mjs +6 -6
  117. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  118. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
  119. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +6 -6
  120. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +9 -9
  121. package/dist/astro/routes/api/manifest.mjs +3 -3
  122. package/dist/astro/routes/api/mcp.mjs +28 -28
  123. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  124. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  125. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  126. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  127. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  128. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  129. package/dist/astro/routes/api/media/upload-url.mjs +6 -6
  130. package/dist/astro/routes/api/media.mjs +7 -7
  131. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
  132. package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
  133. package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
  134. package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
  135. package/dist/astro/routes/api/menus/_name_.mjs +7 -7
  136. package/dist/astro/routes/api/menus/index.mjs +7 -7
  137. package/dist/astro/routes/api/oauth/authorize.mjs +1 -1
  138. package/dist/astro/routes/api/oauth/device/authorize.mjs +4 -4
  139. package/dist/astro/routes/api/oauth/device/code.mjs +5 -5
  140. package/dist/astro/routes/api/oauth/device/token.mjs +5 -5
  141. package/dist/astro/routes/api/oauth/register.mjs +2 -2
  142. package/dist/astro/routes/api/oauth/token/refresh.mjs +4 -4
  143. package/dist/astro/routes/api/oauth/token/revoke.mjs +4 -4
  144. package/dist/astro/routes/api/oauth/token.mjs +4 -4
  145. package/dist/astro/routes/api/openapi.json.mjs +17 -3
  146. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  147. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +3 -3
  148. package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
  149. package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
  150. package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
  151. package/dist/astro/routes/api/redirects/index.mjs +10 -10
  152. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  153. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  154. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +30 -30
  155. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +30 -30
  156. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +30 -30
  157. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +30 -30
  158. package/dist/astro/routes/api/schema/collections/index.mjs +30 -30
  159. package/dist/astro/routes/api/schema/index.mjs +6 -6
  160. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +30 -30
  161. package/dist/astro/routes/api/schema/orphans/index.mjs +30 -30
  162. package/dist/astro/routes/api/search/enable.mjs +9 -9
  163. package/dist/astro/routes/api/search/index.mjs +8 -8
  164. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  165. package/dist/astro/routes/api/search/stats.mjs +6 -6
  166. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  167. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  168. package/dist/astro/routes/api/sections/index.mjs +8 -8
  169. package/dist/astro/routes/api/settings/email.mjs +5 -5
  170. package/dist/astro/routes/api/settings.mjs +12 -12
  171. package/dist/astro/routes/api/setup/admin-verify.mjs +6 -6
  172. package/dist/astro/routes/api/setup/admin.mjs +6 -6
  173. package/dist/astro/routes/api/setup/dev-bypass.mjs +18 -18
  174. package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
  175. package/dist/astro/routes/api/setup/index.mjs +21 -21
  176. package/dist/astro/routes/api/setup/status.mjs +3 -3
  177. package/dist/astro/routes/api/snapshot.mjs +5 -5
  178. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -11
  179. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -11
  180. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -11
  181. package/dist/astro/routes/api/taxonomies/index.mjs +11 -11
  182. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  183. package/dist/astro/routes/api/typegen.mjs +5 -5
  184. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  185. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  186. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
  187. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
  188. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  189. package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
  190. package/dist/astro/routes/api/widget-components.mjs +2 -2
  191. package/dist/astro/routes/robots.txt.mjs +6 -6
  192. package/dist/astro/routes/sitemap-_collection_.xml.mjs +6 -6
  193. package/dist/astro/routes/sitemap.xml.mjs +6 -6
  194. package/dist/astro/types.d.mts +15 -8
  195. package/dist/astro/types.d.mts.map +1 -1
  196. package/dist/{authorize-CotM4Yiu.mjs → authorize-C_8t2KGa.mjs} +2 -2
  197. package/dist/{authorize-CotM4Yiu.mjs.map → authorize-C_8t2KGa.mjs.map} +1 -1
  198. package/dist/{byline-CWQ9aSoz.mjs → byline-DUx48sJp.mjs} +6 -6
  199. package/dist/{byline-CWQ9aSoz.mjs.map → byline-DUx48sJp.mjs.map} +1 -1
  200. package/dist/{byline-fields-Dr-xcb6S.mjs → byline-fields-51kg6Vuv.mjs} +3 -3
  201. package/dist/{byline-fields-Dr-xcb6S.mjs.map → byline-fields-51kg6Vuv.mjs.map} +1 -1
  202. package/dist/{byline-fields-DC3Wkk-U.mjs → byline-fields-C_OsR-KF.mjs} +2 -2
  203. package/dist/{byline-fields-DC3Wkk-U.mjs.map → byline-fields-C_OsR-KF.mjs.map} +1 -1
  204. package/dist/{byline-fields-BNy7Ng1U.d.mts → byline-fields-DYXKDuNX.d.mts} +26 -2
  205. package/dist/byline-fields-DYXKDuNX.d.mts.map +1 -0
  206. package/dist/{byline-registry-CxK5g559.mjs → byline-registry-CWP7I71B.mjs} +3 -3
  207. package/dist/{byline-registry-CxK5g559.mjs.map → byline-registry-CWP7I71B.mjs.map} +1 -1
  208. package/dist/{bylines-LJMgENMI.mjs → bylines-Cx5n-WqP.mjs} +3 -3
  209. package/dist/{bylines-LJMgENMI.mjs.map → bylines-Cx5n-WqP.mjs.map} +1 -1
  210. package/dist/{bylines-BJSva1Un.mjs → bylines-wurS258E.mjs} +50 -6
  211. package/dist/{bylines-BJSva1Un.mjs.map → bylines-wurS258E.mjs.map} +1 -1
  212. package/dist/{cache-lZL7SgVb.mjs → cache-B_HzASVT.mjs} +3 -3
  213. package/dist/{cache-lZL7SgVb.mjs.map → cache-B_HzASVT.mjs.map} +1 -1
  214. package/dist/{chunks-BU-vP9Dh.mjs → chunks-BerYVuve.mjs} +2 -2
  215. package/dist/{chunks-BU-vP9Dh.mjs.map → chunks-BerYVuve.mjs.map} +1 -1
  216. package/dist/cli/index.mjs +40 -27
  217. package/dist/cli/index.mjs.map +1 -1
  218. package/dist/client/cf-access.d.mts +1 -1
  219. package/dist/client/index.d.mts +1 -1
  220. package/dist/{comment-C4jVbCM8.mjs → comment-sqQxNpN3.mjs} +2 -2
  221. package/dist/{comment-C4jVbCM8.mjs.map → comment-sqQxNpN3.mjs.map} +1 -1
  222. package/dist/{comments-BTAbC0Ek.mjs → comments-CJ0RZsYR.mjs} +3 -3
  223. package/dist/{comments-BTAbC0Ek.mjs.map → comments-CJ0RZsYR.mjs.map} +1 -1
  224. package/dist/{content-CyqOmOzm.mjs → content-BIlVx-RX.mjs} +132 -43
  225. package/dist/content-BIlVx-RX.mjs.map +1 -0
  226. package/dist/{context-DZ7bEh5-.mjs → context-GG52SPgh.mjs} +10 -10
  227. package/dist/{context-DZ7bEh5-.mjs.map → context-GG52SPgh.mjs.map} +1 -1
  228. package/dist/{cron-DZovZUnC.mjs → cron-BJ2ClIlj.mjs} +4 -3
  229. package/dist/cron-BJ2ClIlj.mjs.map +1 -0
  230. package/dist/{dashboard-B5WQpNTP.mjs → dashboard-2JgAMWxK.mjs} +4 -4
  231. package/dist/{dashboard-B5WQpNTP.mjs.map → dashboard-2JgAMWxK.mjs.map} +1 -1
  232. package/dist/db/index.d.mts +2 -2
  233. package/dist/db/index.mjs +1 -1
  234. package/dist/{device-flow-ptLrVINd.mjs → device-flow-s6_q3T7A.mjs} +2 -2
  235. package/dist/{device-flow-ptLrVINd.mjs.map → device-flow-s6_q3T7A.mjs.map} +1 -1
  236. package/dist/{error-DJOsMVSt.mjs → error-RwM4dD35.mjs} +2 -2
  237. package/dist/{error-DJOsMVSt.mjs.map → error-RwM4dD35.mjs.map} +1 -1
  238. package/dist/{fts-manager-DR1ERA0c.mjs → fts-manager-1RgHmopc.mjs} +2 -2
  239. package/dist/{fts-manager-DR1ERA0c.mjs.map → fts-manager-1RgHmopc.mjs.map} +1 -1
  240. package/dist/{index-D60_SzHG.d.mts → index-BpYeJO1E.d.mts} +2 -2
  241. package/dist/{index-D60_SzHG.d.mts.map → index-BpYeJO1E.d.mts.map} +1 -1
  242. package/dist/{index-CjKdMZ3U.d.mts → index-FfiTQJq2.d.mts} +199 -17
  243. package/dist/index-FfiTQJq2.d.mts.map +1 -0
  244. package/dist/index.d.mts +9 -9
  245. package/dist/index.mjs +43 -43
  246. package/dist/{load-6ZrRhepW.mjs → load-B84ohfBk.mjs} +2 -2
  247. package/dist/{load-6ZrRhepW.mjs.map → load-B84ohfBk.mjs.map} +1 -1
  248. package/dist/{loader-Dyx8dhFV.mjs → loader-CpZKpFz0.mjs} +32 -30
  249. package/dist/loader-CpZKpFz0.mjs.map +1 -0
  250. package/dist/media/index.mjs +1 -1
  251. package/dist/media/local-runtime.d.mts +7 -7
  252. package/dist/media/local-runtime.mjs +6 -6
  253. package/dist/{media-C-oovGCG.mjs → media-JOf3pNkw.mjs} +2 -2
  254. package/dist/{media-C-oovGCG.mjs.map → media-JOf3pNkw.mjs.map} +1 -1
  255. package/dist/{menus-DugoYwTX.mjs → menus-DX4_E01q.mjs} +3 -3
  256. package/dist/{menus-DugoYwTX.mjs.map → menus-DX4_E01q.mjs.map} +1 -1
  257. package/dist/{menus-BKkxXCmd.mjs → menus-Dp9xporj.mjs} +86 -9
  258. package/dist/menus-Dp9xporj.mjs.map +1 -0
  259. package/dist/{normalize-DVV8nbrL.mjs → normalize-CK5o04zr.mjs} +2 -2
  260. package/dist/{normalize-DVV8nbrL.mjs.map → normalize-CK5o04zr.mjs.map} +1 -1
  261. package/dist/{oauth-authorization-DvBAL75d.mjs → oauth-authorization-1aPAYjiC.mjs} +2 -2
  262. package/dist/{oauth-authorization-DvBAL75d.mjs.map → oauth-authorization-1aPAYjiC.mjs.map} +1 -1
  263. package/dist/{options-BL4X94qY.mjs → options-BPCVnesz.mjs} +1 -1
  264. package/dist/{options-BL4X94qY.mjs.map → options-BPCVnesz.mjs.map} +1 -1
  265. package/dist/{options-tb7DJROi.d.mts → options-D4MnavW_.d.mts} +3 -3
  266. package/dist/{options-tb7DJROi.d.mts.map → options-D4MnavW_.d.mts.map} +1 -1
  267. package/dist/{parse-BBkFmLVr.mjs → parse-CrGndy1A.mjs} +2 -2
  268. package/dist/{parse-BBkFmLVr.mjs.map → parse-CrGndy1A.mjs.map} +1 -1
  269. package/dist/{patterns-CqG5Ya3i.mjs → patterns-p-RBdTbM.mjs} +1 -1
  270. package/dist/{patterns-CqG5Ya3i.mjs.map → patterns-p-RBdTbM.mjs.map} +1 -1
  271. package/dist/plugin-utils.d.mts +7 -7
  272. package/dist/plugins/adapt-sandbox-entry.d.mts +7 -7
  273. package/dist/{query-Ctlq1aOk.mjs → query-BFQ029Ts.mjs} +21 -15
  274. package/dist/query-BFQ029Ts.mjs.map +1 -0
  275. package/dist/{rate-limit-CH6W6ikK.mjs → rate-limit-ClFFUga6.mjs} +2 -2
  276. package/dist/{rate-limit-CH6W6ikK.mjs.map → rate-limit-ClFFUga6.mjs.map} +1 -1
  277. package/dist/{redirect-C6tJA7tk.mjs → redirect-CRWIt8Zj.mjs} +3 -3
  278. package/dist/{redirect-C6tJA7tk.mjs.map → redirect-CRWIt8Zj.mjs.map} +1 -1
  279. package/dist/{redirects-C0L9JUk4.mjs → redirects-DEygMrRO.mjs} +25 -3
  280. package/dist/redirects-DEygMrRO.mjs.map +1 -0
  281. package/dist/{redirects-CacE9eQa.mjs → redirects-OIu6vQ2i.mjs} +5 -5
  282. package/dist/{redirects-CacE9eQa.mjs.map → redirects-OIu6vQ2i.mjs.map} +1 -1
  283. package/dist/{registry-CIDxZbhh.mjs → registry-brYh-rAT.mjs} +6 -6
  284. package/dist/{registry-CIDxZbhh.mjs.map → registry-brYh-rAT.mjs.map} +1 -1
  285. package/dist/{request-cache-BYMs-BGX.mjs → request-cache-D32LpnmI.mjs} +1 -1
  286. package/dist/{request-cache-BYMs-BGX.mjs.map → request-cache-D32LpnmI.mjs.map} +1 -1
  287. package/dist/{runner-pt6Wl-l-.mjs → runner--4wMWwKM.mjs} +217 -166
  288. package/dist/runner--4wMWwKM.mjs.map +1 -0
  289. package/dist/{runner-DM1yR5qd.d.mts → runner-BcRuXq_h.d.mts} +2 -2
  290. package/dist/{runner-DM1yR5qd.d.mts.map → runner-BcRuXq_h.d.mts.map} +1 -1
  291. package/dist/runtime.d.mts +7 -7
  292. package/dist/runtime.mjs +2 -2
  293. package/dist/{schema-B4tk0HAG.mjs → schema-CS7Eg5gh.mjs} +5 -5
  294. package/dist/{schema-B4tk0HAG.mjs.map → schema-CS7Eg5gh.mjs.map} +1 -1
  295. package/dist/{search-f-fNfwab.mjs → search-o-aQzHI1.mjs} +4 -4
  296. package/dist/{search-f-fNfwab.mjs.map → search-o-aQzHI1.mjs.map} +1 -1
  297. package/dist/{secrets-YYbTgB1w.mjs → secrets-C_ZtRos3.mjs} +2 -2
  298. package/dist/{secrets-YYbTgB1w.mjs.map → secrets-C_ZtRos3.mjs.map} +1 -1
  299. package/dist/{sections-biElLfT9.mjs → sections-DhsZ0ns9.mjs} +3 -3
  300. package/dist/{sections-biElLfT9.mjs.map → sections-DhsZ0ns9.mjs.map} +1 -1
  301. package/dist/seed/index.d.mts +2 -2
  302. package/dist/seed/index.mjs +16 -16
  303. package/dist/seo/index.d.mts +1 -1
  304. package/dist/{seo-BR39kvTF.mjs → seo-B5e6y9Wk.mjs} +2 -2
  305. package/dist/{seo-BR39kvTF.mjs.map → seo-B5e6y9Wk.mjs.map} +1 -1
  306. package/dist/{service-BhR2acnc.mjs → service-DAxg8RPR.mjs} +2 -2
  307. package/dist/{service-BhR2acnc.mjs.map → service-DAxg8RPR.mjs.map} +1 -1
  308. package/dist/{settings-b5zW1R1T.mjs → settings-B1p-gPUK.mjs} +5 -5
  309. package/dist/{settings-b5zW1R1T.mjs.map → settings-B1p-gPUK.mjs.map} +1 -1
  310. package/dist/{settings-D_NJvjgN.mjs → settings-DIsbHTRE.mjs} +3 -3
  311. package/dist/{settings-D_NJvjgN.mjs.map → settings-DIsbHTRE.mjs.map} +1 -1
  312. package/dist/{setup-complete-VoEZfasi.mjs → setup-complete-Yuv78yua.mjs} +2 -2
  313. package/dist/{setup-complete-VoEZfasi.mjs.map → setup-complete-Yuv78yua.mjs.map} +1 -1
  314. package/dist/{site-url-Cm8-sJy7.mjs → site-url-mEVmwIFi.mjs} +2 -2
  315. package/dist/{site-url-Cm8-sJy7.mjs.map → site-url-mEVmwIFi.mjs.map} +1 -1
  316. package/dist/{taxonomies-Crtzy4MT.mjs → taxonomies-BEW7S5AI.mjs} +7 -6
  317. package/dist/taxonomies-BEW7S5AI.mjs.map +1 -0
  318. package/dist/{taxonomies-Mhn9rjTQ.mjs → taxonomies-UusDXv3C.mjs} +4 -4
  319. package/dist/{taxonomies-Mhn9rjTQ.mjs.map → taxonomies-UusDXv3C.mjs.map} +1 -1
  320. package/dist/{taxonomy-DTZrIQpi.mjs → taxonomy-CdllE4oq.mjs} +3 -3
  321. package/dist/{taxonomy-DTZrIQpi.mjs.map → taxonomy-CdllE4oq.mjs.map} +1 -1
  322. package/dist/{transaction-NQj4VJ7Z.mjs → transaction-x2tJQ-A1.mjs} +1 -1
  323. package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-x2tJQ-A1.mjs.map} +1 -1
  324. package/dist/{transport-OnMNbsIA.d.mts → transport-BwQeeY2p.d.mts} +1 -1
  325. package/dist/{transport-OnMNbsIA.d.mts.map → transport-BwQeeY2p.d.mts.map} +1 -1
  326. package/dist/{types-K3MDsxpy.mjs → types-BXSUSAjt.mjs} +16 -3
  327. package/dist/{types-K3MDsxpy.mjs.map → types-BXSUSAjt.mjs.map} +1 -1
  328. package/dist/{types-D8bhH891.mjs → types-DZk_y-MU.mjs} +1 -1
  329. package/dist/{types-D8bhH891.mjs.map → types-DZk_y-MU.mjs.map} +1 -1
  330. package/dist/{types-DawhLFwy.d.mts → types-OT_Es5mp.d.mts} +26 -1
  331. package/dist/{types-DawhLFwy.d.mts.map → types-OT_Es5mp.d.mts.map} +1 -1
  332. package/dist/{types-i8_uzhMD.d.mts → types-WVmpZBJV.d.mts} +18 -3
  333. package/dist/types-WVmpZBJV.d.mts.map +1 -0
  334. package/dist/{user-DzEUl5zA.mjs → user-C0um7wrg.mjs} +18 -2
  335. package/dist/user-C0um7wrg.mjs.map +1 -0
  336. package/dist/{validate-Dy6nkNls.d.mts → validate-BPAHUSge.d.mts} +10 -2
  337. package/dist/validate-BPAHUSge.d.mts.map +1 -0
  338. package/dist/{validate-JCXcsqiY.mjs → validate-ZP9Dvg0P.mjs} +6 -3
  339. package/dist/validate-ZP9Dvg0P.mjs.map +1 -0
  340. package/dist/{validation-Bq-VyKJg.mjs → validation-CE5i4q0c.mjs} +5 -5
  341. package/dist/{validation-Bq-VyKJg.mjs.map → validation-CE5i4q0c.mjs.map} +1 -1
  342. package/dist/version-Dw0JXu45.mjs +7 -0
  343. package/dist/{version-CnS-Cr8A.mjs.map → version-Dw0JXu45.mjs.map} +1 -1
  344. package/dist/{widgets-Bap1eS1X.mjs → widgets-ClEnYQCH.mjs} +2 -2
  345. package/dist/{widgets-Bap1eS1X.mjs.map → widgets-ClEnYQCH.mjs.map} +1 -1
  346. package/dist/{zod-generator-BSDpkqSH.mjs → zod-generator-Djo_VHCt.mjs} +2 -2
  347. package/dist/{zod-generator-BSDpkqSH.mjs.map → zod-generator-Djo_VHCt.mjs.map} +1 -1
  348. package/package.json +5 -5
  349. package/src/api/handlers/content.ts +107 -8
  350. package/src/api/handlers/index.ts +2 -0
  351. package/src/api/openapi/document.ts +25 -0
  352. package/src/api/schemas/content.ts +33 -0
  353. package/src/astro/integration/index.ts +98 -0
  354. package/src/astro/integration/routes.ts +6 -0
  355. package/src/astro/integration/virtual-modules.ts +39 -0
  356. package/src/astro/integration/vite-config.ts +12 -0
  357. package/src/astro/middleware.ts +28 -0
  358. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  359. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +4 -2
  360. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +8 -4
  361. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +4 -2
  362. package/src/astro/routes/api/content/[collection]/[id].ts +4 -2
  363. package/src/astro/routes/api/content/[collection]/authors.ts +34 -0
  364. package/src/astro/types.ts +8 -1
  365. package/src/bylines/index.ts +57 -0
  366. package/src/cli/commands/export-seed.ts +28 -12
  367. package/src/components/EmDashImage.astro +22 -4
  368. package/src/components/Image.astro +20 -3
  369. package/src/database/migrations/043_content_references.ts +121 -0
  370. package/src/database/migrations/runner.ts +2 -0
  371. package/src/database/repositories/content.ts +225 -67
  372. package/src/database/repositories/index.ts +7 -0
  373. package/src/database/repositories/relation.ts +467 -0
  374. package/src/database/repositories/types.ts +31 -0
  375. package/src/database/repositories/user.ts +18 -0
  376. package/src/database/types.ts +34 -0
  377. package/src/emdash-runtime.ts +141 -42
  378. package/src/index.ts +8 -1
  379. package/src/loader.ts +67 -34
  380. package/src/media/responsive.ts +125 -0
  381. package/src/plugins/cron.ts +3 -2
  382. package/src/plugins/index.ts +5 -0
  383. package/src/plugins/scheduler/node.ts +9 -2
  384. package/src/query.ts +32 -5
  385. package/src/scheduled-publish.ts +153 -0
  386. package/src/seed/apply.ts +16 -6
  387. package/src/seed/types.ts +9 -0
  388. package/src/seed/validate.ts +15 -0
  389. package/src/taxonomies/index.ts +1 -0
  390. package/src/virtual-modules.d.ts +11 -0
  391. package/dist/api-Cs7DAACP.mjs.map +0 -1
  392. package/dist/apply-BWMV4Zmw.mjs.map +0 -1
  393. package/dist/byline-fields-BNy7Ng1U.d.mts.map +0 -1
  394. package/dist/content-CyqOmOzm.mjs.map +0 -1
  395. package/dist/cron-DZovZUnC.mjs.map +0 -1
  396. package/dist/index-CjKdMZ3U.d.mts.map +0 -1
  397. package/dist/loader-Dyx8dhFV.mjs.map +0 -1
  398. package/dist/menus-BKkxXCmd.mjs.map +0 -1
  399. package/dist/query-Ctlq1aOk.mjs.map +0 -1
  400. package/dist/redirects-C0L9JUk4.mjs.map +0 -1
  401. package/dist/runner-pt6Wl-l-.mjs.map +0 -1
  402. package/dist/taxonomies-Crtzy4MT.mjs.map +0 -1
  403. package/dist/types-i8_uzhMD.d.mts.map +0 -1
  404. package/dist/user-DzEUl5zA.mjs.map +0 -1
  405. package/dist/validate-Dy6nkNls.d.mts.map +0 -1
  406. package/dist/validate-JCXcsqiY.mjs.map +0 -1
  407. package/dist/version-CnS-Cr8A.mjs +0 -7
  408. package/src/plugins/scheduler/piggyback.ts +0 -71
package/src/query.ts CHANGED
@@ -101,13 +101,19 @@ export interface CollectionFilter {
101
101
  */
102
102
  cursor?: string;
103
103
  /**
104
- * Filter by field values, taxonomy terms, or ranges.
104
+ * Filter by field values, taxonomy terms, byline credits, or ranges.
105
105
  *
106
106
  * Taxonomy names are detected automatically and filtered via JOIN.
107
+ * The reserved `byline` key filters by byline credit (any credit, not
108
+ * just the primary one) via the `_emdash_content_bylines` junction
109
+ * table; its value is one or more byline translation groups. This
110
+ * matches co-authored entries, which `primary_byline_id` alone misses.
107
111
  * Other keys are treated as column filters on the content table.
108
112
  *
109
113
  * @example { category: 'news' } - Filter by taxonomy term
110
114
  * @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
115
+ * @example { byline: '01HXYZ...' } - Entries credited to a byline (any position)
116
+ * @example { byline: ['01HXYZ...', '01HABC...'] } - Credited to any of these bylines (OR)
111
117
  * @example { series: 'main' } - Exact match on a content field
112
118
  * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - Date range
113
119
  */
@@ -533,7 +539,9 @@ async function getEmDashCollectionUncached<T extends string, D = InferCollection
533
539
  // round-trip cost on remote databases (D1 replicas, etc.).
534
540
  await Promise.all([
535
541
  hydrateEntryBylines(type, entriesWithEdit),
536
- hydrateEntryTerms(type, entriesWithEdit),
542
+ // Hydrate terms in the same locale the content rows were resolved to,
543
+ // otherwise localized entries get default-locale taxonomy terms (#1441).
544
+ hydrateEntryTerms(type, entriesWithEdit, resolvedLocale),
537
545
  ]);
538
546
 
539
547
  return { entries: entriesWithEdit, nextCursor, cacheHint: cacheHint ?? {} };
@@ -611,7 +619,17 @@ export async function getEmDashEntry<T extends string, D = InferCollectionData<T
611
619
  wrapped: ContentEntry<D>,
612
620
  opts: { isPreview: boolean; fallbackLocale?: string; cacheHint: CacheHint },
613
621
  ): Promise<EntryResult<D>> {
614
- await Promise.all([hydrateEntryBylines(type, [wrapped]), hydrateEntryTerms(type, [wrapped])]);
622
+ // Hydrate terms in the entry's resolved locale (fallback-aware) so a
623
+ // localized entry never picks up default-locale taxonomy terms (#1441).
624
+ // When i18n is disabled we leave the locale unset to preserve the
625
+ // legacy "do not filter by locale" behaviour.
626
+ const termLocale = isI18nEnabled()
627
+ ? dataStr(entryData(wrapped), "locale") || undefined
628
+ : undefined;
629
+ await Promise.all([
630
+ hydrateEntryBylines(type, [wrapped]),
631
+ hydrateEntryTerms(type, [wrapped], termLocale),
632
+ ]);
615
633
  return {
616
634
  entry: wrapped,
617
635
  isPreview: opts.isPreview,
@@ -788,9 +806,18 @@ async function hydrateEntryBylines<D>(type: string, entries: ContentEntry<D>[]):
788
806
  * results and call getEntryTerms() per entry. With hydration, the list page
789
807
  * stays at a single round-trip for term data.
790
808
  *
809
+ * `locale` must be the locale the entries were resolved to. It is forwarded to
810
+ * `getAllTermsForEntries` so terms are returned in the entry's locale rather
811
+ * than falling back to the request-context / default locale (#1441). Pass
812
+ * `undefined` to keep the legacy "do not filter by locale" behaviour.
813
+ *
791
814
  * Fails silently if the taxonomy tables don't exist yet (pre-migration).
792
815
  */
793
- async function hydrateEntryTerms<D>(type: string, entries: ContentEntry<D>[]): Promise<void> {
816
+ async function hydrateEntryTerms<D>(
817
+ type: string,
818
+ entries: ContentEntry<D>[],
819
+ locale?: string,
820
+ ): Promise<void> {
794
821
  if (entries.length === 0) return;
795
822
 
796
823
  try {
@@ -799,7 +826,7 @@ async function hydrateEntryTerms<D>(type: string, entries: ContentEntry<D>[]): P
799
826
  const ids = entries.map((e) => dataStr(entryData(e), "id")).filter(Boolean);
800
827
  if (ids.length === 0) return;
801
828
 
802
- const termsMap = await getAllTermsForEntries(type, ids);
829
+ const termsMap = await getAllTermsForEntries(type, ids, { locale });
803
830
 
804
831
  for (const entry of entries) {
805
832
  const data = entryData(entry);
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Scheduled publishing sweep
3
+ *
4
+ * Promotes content whose scheduled publish time has passed. Driven by the
5
+ * platform scheduler alongside cron ticks and system cleanup — never by a
6
+ * request. On Node the cron scheduler's maintenance pass calls it; on
7
+ * Cloudflare the Worker's `scheduled()` handler does.
8
+ *
9
+ * Like `runSystemCleanup`, each collection sweep is independent and non-fatal:
10
+ * one collection failing must not stop the rest.
11
+ */
12
+
13
+ import type { Kysely } from "kysely";
14
+
15
+ import { handleContentPublish } from "./api/handlers/content.js";
16
+ import { ContentRepository } from "./database/repositories/content.js";
17
+ import type { Database } from "./database/types.js";
18
+ import { SchemaRegistry } from "./schema/registry.js";
19
+
20
+ /** A content item that was promoted to published by a sweep. */
21
+ export interface PublishedRef {
22
+ collection: string;
23
+ id: string;
24
+ }
25
+
26
+ /**
27
+ * Default cap on items promoted per collection in a single sweep. Bounds the
28
+ * publish/webhook fan-out of one tick so a large backlog can't exhaust a Worker
29
+ * invocation's CPU/subrequest budget; the remainder drains on later ticks.
30
+ */
31
+ export const SCHEDULED_PUBLISH_BATCH_LIMIT = 100;
32
+
33
+ /**
34
+ * Publishes a single content item. Mirrors the relevant subset of
35
+ * `handleContentPublish`'s return shape. Production callers pass
36
+ * `EmDashRuntime.handleContentPublish` so `content:afterPublish` hooks fire
37
+ * (search indexing, webhooks, syndication); the default falls back to the raw
38
+ * handler (no hooks) for callers that have only a `db`.
39
+ */
40
+ export type ScheduledPublishFn = (
41
+ collection: string,
42
+ id: string,
43
+ options: { publishedAt?: string; requireScheduledDue?: boolean },
44
+ ) => Promise<{ success: boolean; error?: { code?: string } }>;
45
+
46
+ export interface PublishDueContentOptions {
47
+ /**
48
+ * Publish callback. Production callers pass the runtime's
49
+ * `handleContentPublish` so `content:afterPublish` hooks fire (search
50
+ * indexing, webhooks, syndication). Defaults to the raw DB handler (no hooks).
51
+ */
52
+ publish?: ScheduledPublishFn;
53
+ /**
54
+ * Invoked after each collection's batch with the items promoted in that
55
+ * batch. Lets request-less callers (the Cloudflare `scheduled()` handler)
56
+ * purge edge-cache tags incrementally instead of only after the whole sweep,
57
+ * so a runtime killed mid-sweep strands at most one batch behind stale cache
58
+ * rather than everything published so far. Failures are logged, never fatal.
59
+ */
60
+ onPublished?: (refs: PublishedRef[]) => Promise<void>;
61
+ /**
62
+ * Maximum items promoted per collection per sweep. Defaults to
63
+ * `SCHEDULED_PUBLISH_BATCH_LIMIT`. Pass `0` (or a negative) for unbounded.
64
+ */
65
+ limit?: number;
66
+ }
67
+
68
+ /**
69
+ * Publish every content item whose `scheduled_at` is in the past.
70
+ *
71
+ * Iterates all collections, finds due items (`findReadyToPublish` returns both
72
+ * scheduled drafts and published entries with pending scheduled changes), and
73
+ * publishes each. `publish()` clears `scheduled_at`, so a second sweep is a
74
+ * no-op — safe to run on every tick.
75
+ *
76
+ * Bounded per collection by `limit` (default `SCHEDULED_PUBLISH_BATCH_LIMIT`):
77
+ * a large backlog drains across successive ticks rather than in one unbounded
78
+ * pass. After each collection's batch, `onPublished` (if given) is awaited so
79
+ * cache-tag invalidation happens incrementally, not just at the very end.
80
+ *
81
+ * Returns every item it promoted so request-less callers (the Cloudflare
82
+ * `scheduled()` handler) can also act on the full set.
83
+ */
84
+ export async function publishDueContent(
85
+ db: Kysely<Database>,
86
+ options: PublishDueContentOptions = {},
87
+ ): Promise<PublishedRef[]> {
88
+ const { publish, onPublished, limit = SCHEDULED_PUBLISH_BATCH_LIMIT } = options;
89
+ const published: PublishedRef[] = [];
90
+
91
+ let collections;
92
+ try {
93
+ collections = await new SchemaRegistry(db).listCollections();
94
+ } catch (error) {
95
+ console.error("[scheduled-publish] Failed to list collections:", error);
96
+ return published;
97
+ }
98
+
99
+ const repo = new ContentRepository(db);
100
+ const doPublish: ScheduledPublishFn =
101
+ publish ?? ((collection, id, opts) => handleContentPublish(db, collection, id, opts));
102
+ // 0 / negative means unbounded; findReadyToPublish treats that as "no LIMIT".
103
+ const batchLimit = limit > 0 ? limit : undefined;
104
+
105
+ for (const collection of collections) {
106
+ try {
107
+ const due = await repo.findReadyToPublish(collection.slug, batchLimit);
108
+ const batch: PublishedRef[] = [];
109
+ for (const item of due) {
110
+ // First publication of a scheduled draft should record the intended
111
+ // scheduled time, not the (later) sweep time. Items already published
112
+ // with pending draft changes keep their original published_at.
113
+ const publishedAt = item.publishedAt == null ? (item.scheduledAt ?? undefined) : undefined;
114
+ const result = await doPublish(collection.slug, item.id, {
115
+ publishedAt,
116
+ requireScheduledDue: true,
117
+ });
118
+ if (result.success) {
119
+ batch.push({ collection: collection.slug, id: item.id });
120
+ } else if (result.error?.code === "NOT_DUE") {
121
+ // Unscheduled or rescheduled between selection and publish — the
122
+ // editor changed their mind; skip quietly, not a failure.
123
+ } else {
124
+ console.error(
125
+ `[scheduled-publish] Failed to publish ${collection.slug}/${item.id}:`,
126
+ result.error,
127
+ );
128
+ }
129
+ }
130
+
131
+ if (batch.length > 0) {
132
+ published.push(...batch);
133
+ if (onPublished) {
134
+ // Purge this batch's cache tags before moving to the next
135
+ // collection, so a mid-sweep kill can't strand already-published
136
+ // content behind stale cache.
137
+ try {
138
+ await onPublished(batch);
139
+ } catch (error) {
140
+ console.error(
141
+ `[scheduled-publish] onPublished failed after "${collection.slug}" batch:`,
142
+ error,
143
+ );
144
+ }
145
+ }
146
+ }
147
+ } catch (error) {
148
+ console.error(`[scheduled-publish] Sweep failed for "${collection.slug}":`, error);
149
+ }
150
+ }
151
+
152
+ return published;
153
+ }
package/src/seed/apply.ts CHANGED
@@ -115,6 +115,13 @@ export async function applySeed(
115
115
  const seedIdMap = new Map<string, string>(); // seed id -> real entry id
116
116
  const seedBylineIdMap = new Map<string, string>(); // seed byline id -> real byline id
117
117
 
118
+ // Fallback locale for rows that omit an explicit `locale`. Prefer the runtime
119
+ // config (runtime-driven seeds), then the seed's self-described `defaultLocale`
120
+ // (CLI exports run outside the runtime), and only then `en`. Without the
121
+ // seed-carried default, a non-`en` single-locale project would be rewritten to
122
+ // `en` on apply (#1421).
123
+ const defaultLocale = getI18nConfig()?.defaultLocale ?? seed.defaultLocale ?? "en";
124
+
118
125
  // 1. Site settings
119
126
  if (seed.settings) {
120
127
  await setSiteSettings(seed.settings, db);
@@ -224,10 +231,9 @@ export async function applySeed(
224
231
  // seed-local id -> resolved info, used to wire `translationOf` refs.
225
232
  const defSeedIdMap = new Map<string, { id: string; translationGroup: string }>();
226
233
  const termSeedIdMap = new Map<string, string>();
227
- const fallbackLocale = getI18nConfig()?.defaultLocale ?? "en";
228
234
 
229
235
  for (const taxonomy of seed.taxonomies) {
230
- const defLocale = taxonomy.locale ?? fallbackLocale;
236
+ const defLocale = taxonomy.locale ?? defaultLocale;
231
237
 
232
238
  // (name, locale) is the UNIQUE key after migration 036.
233
239
  const existingDef = await db
@@ -418,8 +424,13 @@ export async function applySeed(
418
424
  // Create content entries
419
425
  for (const [collectionSlug, entries] of Object.entries(seed.content)) {
420
426
  for (const entry of entries) {
427
+ // Resolve the entry's locale up front so a non-`en` single-locale
428
+ // export (which omits `locale`) is filed under the project default
429
+ // rather than `en` (#1421).
430
+ const entryLocale = entry.locale ?? defaultLocale;
431
+
421
432
  // Check if entry exists (by slug + locale for locale-aware lookup)
422
- const existing = await contentRepo.findBySlug(collectionSlug, entry.slug, entry.locale);
433
+ const existing = await contentRepo.findBySlug(collectionSlug, entry.slug, entryLocale);
423
434
 
424
435
  if (existing) {
425
436
  if (onConflict === "error") {
@@ -515,7 +526,7 @@ export async function applySeed(
515
526
  slug: entry.slug,
516
527
  status,
517
528
  data: resolvedData,
518
- locale: entry.locale,
529
+ locale: entryLocale,
519
530
  translationOf,
520
531
  publishedAt: status === "published" ? new Date().toISOString() : null,
521
532
  });
@@ -545,10 +556,9 @@ export async function applySeed(
545
556
  const menuSeedIdMap = new Map<string, { id: string; translationGroup: string }>();
546
557
  // Shared across menus: translated items reference anchor items in sibling menus.
547
558
  const itemSeedIdMap = new Map<string, { id: string; translationGroup: string }>();
548
- const fallbackLocale = getI18nConfig()?.defaultLocale ?? "en";
549
559
 
550
560
  for (const menu of seed.menus) {
551
- const locale = menu.locale ?? fallbackLocale;
561
+ const locale = menu.locale ?? defaultLocale;
552
562
  let lookup = db
553
563
  .selectFrom("_emdash_menus")
554
564
  .selectAll()
package/src/seed/types.ts CHANGED
@@ -19,6 +19,15 @@ export interface SeedFile {
19
19
  /** Seed format version */
20
20
  version: "1";
21
21
 
22
+ /**
23
+ * Default locale for locale-bearing rows (menus, taxonomies, content) that
24
+ * omit an explicit `locale`. Lets a non-`en` single-locale project survive an
25
+ * `export-seed` → `seed` round-trip: `apply` runs outside the Astro runtime
26
+ * (no i18n config), so without this it would backfill the omitted locale as
27
+ * `en`. See #1421.
28
+ */
29
+ defaultLocale?: string;
30
+
22
31
  /** Metadata about the seed */
23
32
  meta?: {
24
33
  name?: string;
@@ -57,6 +57,21 @@ export function validateSeed(data: unknown): ValidationResult {
57
57
  errors.push(`Unsupported seed version: ${String(seed.version)}`);
58
58
  }
59
59
 
60
+ // defaultLocale backfills the locale of rows that omit one, so a blank or
61
+ // whitespace-padded value would silently write empty/invalid locales to the DB.
62
+ // Exported seeds never hit this, but it's part of the public schema now.
63
+ if (seed.defaultLocale !== undefined) {
64
+ if (
65
+ typeof seed.defaultLocale !== "string" ||
66
+ seed.defaultLocale.length === 0 ||
67
+ seed.defaultLocale !== seed.defaultLocale.trim()
68
+ ) {
69
+ errors.push(
70
+ "defaultLocale: must be a non-empty string with no leading or trailing whitespace",
71
+ );
72
+ }
73
+ }
74
+
60
75
  // Validate collections
61
76
  if (seed.collections) {
62
77
  if (!Array.isArray(seed.collections)) {
@@ -148,6 +148,7 @@ export async function getTaxonomyTerms(
148
148
  name: term.name,
149
149
  slug: term.slug,
150
150
  label: term.label,
151
+ description: term.data ? JSON.parse(term.data).description : undefined,
151
152
  children: [],
152
153
  count: counts.get(term.translation_group ?? term.id) ?? 0,
153
154
  locale: term.locale,
@@ -132,6 +132,17 @@ declare module "virtual:emdash/wait-until" {
132
132
  export const waitUntil: ((promise: Promise<unknown>) => void) | undefined;
133
133
  }
134
134
 
135
+ declare module "virtual:emdash/scheduler" {
136
+ import type { CreateSchedulerFn } from "./emdash-runtime.js";
137
+ /**
138
+ * Factory for the timer-based cron/maintenance heartbeat. A
139
+ * `NodeCronScheduler` factory on long-lived runtimes (Node/Bun); `null`
140
+ * under serverless adapters (e.g. Cloudflare) where an external Cron
141
+ * Trigger drives scheduled work instead.
142
+ */
143
+ export const createScheduler: CreateSchedulerFn | null;
144
+ }
145
+
135
146
  declare module "virtual:emdash/admin-registry" {
136
147
  /**
137
148
  * Plugin admin module registry.