emdash 0.17.2 → 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 (415) 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-B7GATEYo.mjs → api-BZ6bhjYs.mjs} +88 -16
  6. package/dist/api-BZ6bhjYs.mjs.map +1 -0
  7. package/dist/{apply-BrVqULFe.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 +414 -215
  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-CLTmOUyx.mjs → authorize-C_8t2KGa.mjs} +2 -2
  197. package/dist/{authorize-CLTmOUyx.mjs.map → authorize-C_8t2KGa.mjs.map} +1 -1
  198. package/dist/{byline-CAhk4FrG.mjs → byline-DUx48sJp.mjs} +6 -6
  199. package/dist/{byline-CAhk4FrG.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-CR5hGLMw.d.mts → byline-fields-DYXKDuNX.d.mts} +53 -29
  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-CbrD7STW.mjs → bylines-Cx5n-WqP.mjs} +3 -3
  209. package/dist/{bylines-CbrD7STW.mjs.map → bylines-Cx5n-WqP.mjs.map} +1 -1
  210. package/dist/{bylines-DCczH3AV.mjs → bylines-wurS258E.mjs} +50 -6
  211. package/dist/{bylines-DCczH3AV.mjs.map → bylines-wurS258E.mjs.map} +1 -1
  212. package/dist/{cache-DIHHyPkt.mjs → cache-B_HzASVT.mjs} +3 -3
  213. package/dist/{cache-DIHHyPkt.mjs.map → cache-B_HzASVT.mjs.map} +1 -1
  214. package/dist/{chunks-DnnHlRG3.mjs → chunks-BerYVuve.mjs} +2 -2
  215. package/dist/{chunks-DnnHlRG3.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-DkAfGX9E.mjs → comment-sqQxNpN3.mjs} +2 -2
  221. package/dist/{comment-DkAfGX9E.mjs.map → comment-sqQxNpN3.mjs.map} +1 -1
  222. package/dist/{comments-DLFnXs7J.mjs → comments-CJ0RZsYR.mjs} +3 -3
  223. package/dist/{comments-DLFnXs7J.mjs.map → comments-CJ0RZsYR.mjs.map} +1 -1
  224. package/dist/{content-C7aJ7keg.mjs → content-BIlVx-RX.mjs} +132 -43
  225. package/dist/content-BIlVx-RX.mjs.map +1 -0
  226. package/dist/{context-Ca0HkaIh.mjs → context-GG52SPgh.mjs} +10 -10
  227. package/dist/{context-Ca0HkaIh.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-BrfLIsX1.mjs → dashboard-2JgAMWxK.mjs} +4 -4
  231. package/dist/{dashboard-BrfLIsX1.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-Bk9s3Ism.mjs → error-RwM4dD35.mjs} +2 -2
  237. package/dist/{error-Bk9s3Ism.mjs.map → error-RwM4dD35.mjs.map} +1 -1
  238. package/dist/{fts-manager-XpDfbIKo.mjs → fts-manager-1RgHmopc.mjs} +2 -2
  239. package/dist/{fts-manager-XpDfbIKo.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-C8ciqSMJ.d.mts → index-FfiTQJq2.d.mts} +202 -20
  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-CF5oETkh.mjs → load-B84ohfBk.mjs} +2 -2
  247. package/dist/{load-CF5oETkh.mjs.map → load-B84ohfBk.mjs.map} +1 -1
  248. package/dist/{loader-BxyvbrZP.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-Cyz5BhSN.mjs → media-JOf3pNkw.mjs} +2 -2
  254. package/dist/{media-Cyz5BhSN.mjs.map → media-JOf3pNkw.mjs.map} +1 -1
  255. package/dist/{menus-PFp8FDuO.mjs → menus-DX4_E01q.mjs} +3 -3
  256. package/dist/{menus-PFp8FDuO.mjs.map → menus-DX4_E01q.mjs.map} +1 -1
  257. package/dist/{menus-CIdZ_Q6U.mjs → menus-Dp9xporj.mjs} +112 -16
  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-B-K21lvm.mjs → parse-CrGndy1A.mjs} +2 -2
  268. package/dist/{parse-B-K21lvm.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-Cc649nDl.mjs → query-BFQ029Ts.mjs} +21 -15
  274. package/dist/query-BFQ029Ts.mjs.map +1 -0
  275. package/dist/{rate-limit-BI1OdpQH.mjs → rate-limit-ClFFUga6.mjs} +2 -2
  276. package/dist/{rate-limit-BI1OdpQH.mjs.map → rate-limit-ClFFUga6.mjs.map} +1 -1
  277. package/dist/{redirect-C-FeA4j9.mjs → redirect-CRWIt8Zj.mjs} +3 -3
  278. package/dist/{redirect-C-FeA4j9.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-C1UgU9E0.mjs → redirects-OIu6vQ2i.mjs} +5 -5
  282. package/dist/{redirects-C1UgU9E0.mjs.map → redirects-OIu6vQ2i.mjs.map} +1 -1
  283. package/dist/{registry-C-T_PWgp.mjs → registry-brYh-rAT.mjs} +6 -6
  284. package/dist/{registry-C-T_PWgp.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-BiuUfx-V.mjs → runner--4wMWwKM.mjs} +224 -168
  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-BpCJh2lU.mjs → schema-CS7Eg5gh.mjs} +5 -5
  294. package/dist/{schema-BpCJh2lU.mjs.map → schema-CS7Eg5gh.mjs.map} +1 -1
  295. package/dist/{search-BrF7k0Ho.mjs → search-o-aQzHI1.mjs} +4 -4
  296. package/dist/{search-BrF7k0Ho.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-8DEa-dWt.mjs → sections-DhsZ0ns9.mjs} +3 -3
  300. package/dist/{sections-8DEa-dWt.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-CKr7pLfA.mjs → seo-B5e6y9Wk.mjs} +2 -2
  305. package/dist/{seo-CKr7pLfA.mjs.map → seo-B5e6y9Wk.mjs.map} +1 -1
  306. package/dist/{service-9P2cdyR_.mjs → service-DAxg8RPR.mjs} +2 -2
  307. package/dist/{service-9P2cdyR_.mjs.map → service-DAxg8RPR.mjs.map} +1 -1
  308. package/dist/{settings-Jro4YcUb.mjs → settings-B1p-gPUK.mjs} +5 -5
  309. package/dist/{settings-Jro4YcUb.mjs.map → settings-B1p-gPUK.mjs.map} +1 -1
  310. package/dist/{settings-DYVzINdn.mjs → settings-DIsbHTRE.mjs} +3 -3
  311. package/dist/{settings-DYVzINdn.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-CGD6y79Q.mjs → taxonomies-BEW7S5AI.mjs} +10 -8
  317. package/dist/taxonomies-BEW7S5AI.mjs.map +1 -0
  318. package/dist/{taxonomies-C0bVme_m.mjs → taxonomies-UusDXv3C.mjs} +4 -4
  319. package/dist/{taxonomies-C0bVme_m.mjs.map → taxonomies-UusDXv3C.mjs.map} +1 -1
  320. package/dist/{taxonomy-Db5xwphL.mjs → taxonomy-CdllE4oq.mjs} +3 -3
  321. package/dist/{taxonomy-Db5xwphL.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-CfyYQ7eY.mjs → types-BXSUSAjt.mjs} +16 -3
  327. package/dist/{types-CfyYQ7eY.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-tLdHUEXV.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-DWmnRg6E.mjs → validate-ZP9Dvg0P.mjs} +6 -3
  339. package/dist/validate-ZP9Dvg0P.mjs.map +1 -0
  340. package/dist/{validation-BQ_TP-On.mjs → validation-CE5i4q0c.mjs} +5 -5
  341. package/dist/{validation-BQ_TP-On.mjs.map → validation-CE5i4q0c.mjs.map} +1 -1
  342. package/dist/version-Dw0JXu45.mjs +7 -0
  343. package/dist/{version-CgcnMvqS.mjs.map → version-Dw0JXu45.mjs.map} +1 -1
  344. package/dist/{widgets-DzlINGI6.mjs → widgets-ClEnYQCH.mjs} +2 -2
  345. package/dist/{widgets-DzlINGI6.mjs.map → widgets-ClEnYQCH.mjs.map} +1 -1
  346. package/dist/{zod-generator-MMm56Prt.mjs → zod-generator-Djo_VHCt.mjs} +4 -3
  347. package/dist/zod-generator-Djo_VHCt.mjs.map +1 -0
  348. package/package.json +7 -7
  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/stream-end-metrics.ts +96 -0
  358. package/src/astro/middleware.ts +107 -31
  359. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  360. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +4 -2
  361. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +8 -4
  362. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +4 -2
  363. package/src/astro/routes/api/content/[collection]/[id].ts +4 -2
  364. package/src/astro/routes/api/content/[collection]/authors.ts +34 -0
  365. package/src/astro/types.ts +8 -1
  366. package/src/bylines/index.ts +57 -0
  367. package/src/cli/commands/export-seed.ts +28 -12
  368. package/src/components/EmDashImage.astro +23 -4
  369. package/src/components/Image.astro +20 -3
  370. package/src/database/migrations/043_content_references.ts +121 -0
  371. package/src/database/migrations/runner.ts +9 -2
  372. package/src/database/repositories/content.ts +225 -67
  373. package/src/database/repositories/index.ts +7 -0
  374. package/src/database/repositories/relation.ts +467 -0
  375. package/src/database/repositories/types.ts +31 -0
  376. package/src/database/repositories/user.ts +18 -0
  377. package/src/database/types.ts +34 -0
  378. package/src/emdash-runtime.ts +318 -168
  379. package/src/index.ts +8 -1
  380. package/src/loader.ts +67 -34
  381. package/src/media/responsive.ts +125 -0
  382. package/src/menus/index.ts +27 -9
  383. package/src/plugins/cron.ts +3 -2
  384. package/src/plugins/hooks.ts +35 -6
  385. package/src/plugins/index.ts +5 -0
  386. package/src/plugins/manager.ts +1 -0
  387. package/src/plugins/scheduler/node.ts +9 -2
  388. package/src/query.ts +32 -5
  389. package/src/scheduled-publish.ts +153 -0
  390. package/src/schema/zod-generator.ts +6 -2
  391. package/src/seed/apply.ts +16 -6
  392. package/src/seed/types.ts +9 -0
  393. package/src/seed/validate.ts +15 -0
  394. package/src/taxonomies/index.ts +13 -8
  395. package/src/utils/init-lock.ts +143 -0
  396. package/src/virtual-modules.d.ts +11 -0
  397. package/dist/api-B7GATEYo.mjs.map +0 -1
  398. package/dist/apply-BrVqULFe.mjs.map +0 -1
  399. package/dist/byline-fields-CR5hGLMw.d.mts.map +0 -1
  400. package/dist/content-C7aJ7keg.mjs.map +0 -1
  401. package/dist/cron-DZovZUnC.mjs.map +0 -1
  402. package/dist/index-C8ciqSMJ.d.mts.map +0 -1
  403. package/dist/loader-BxyvbrZP.mjs.map +0 -1
  404. package/dist/menus-CIdZ_Q6U.mjs.map +0 -1
  405. package/dist/query-Cc649nDl.mjs.map +0 -1
  406. package/dist/redirects-C0L9JUk4.mjs.map +0 -1
  407. package/dist/runner-BiuUfx-V.mjs.map +0 -1
  408. package/dist/taxonomies-CGD6y79Q.mjs.map +0 -1
  409. package/dist/types-i8_uzhMD.d.mts.map +0 -1
  410. package/dist/user-tLdHUEXV.mjs.map +0 -1
  411. package/dist/validate-DWmnRg6E.mjs.map +0 -1
  412. package/dist/validate-Dy6nkNls.d.mts.map +0 -1
  413. package/dist/version-CgcnMvqS.mjs +0 -7
  414. package/dist/zod-generator-MMm56Prt.mjs.map +0 -1
  415. package/src/plugins/scheduler/piggyback.ts +0 -71
@@ -1 +1 @@
1
- {"version":3,"file":"bylines-DCczH3AV.mjs","names":[],"sources":["../src/bylines/index.ts"],"sourcesContent":["/**\n * Runtime API for bylines\n *\n * Provides functions to query byline profiles and byline credits\n * associated with content entries. Follows the same pattern as\n * the taxonomies runtime API.\n *\n * i18n model (migration 040): byline rows are per-locale and share a\n * `translation_group`. Credits on `_emdash_content_bylines.byline_id` store\n * the translation_group, so a single credit spans every locale of a byline.\n *\n * Hydration is strict per locale: a credit at locale X renders iff a byline\n * row exists at locale X within the credited translation_group. There is no\n * read-time fallback. Mirrors `getEntryTerms` and the convention in PR #916.\n * Locale is passed in by callers — `query.ts` resolves it from the entry's\n * own `data.locale` for the runtime path.\n */\n\nimport { sql } from \"kysely\";\n\nimport { BylineRepository } from \"../database/repositories/byline.js\";\nimport type { BylineSummary, ContentBylineCredit } from \"../database/repositories/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { resolveLocaleChain } from \"../i18n/resolve.js\";\nimport { getDb } from \"../loader.js\";\nimport { requestCached } from \"../request-cache.js\";\nimport { isMissingTableError } from \"../utils/db-errors.js\";\n\n/**\n * No-op — kept for API compatibility.\n *\n * Used to invalidate a worker-lifetime \"has any byline?\" probe. That\n * probe added a query on every cold isolate to save one query on sites\n * with zero bylines (i.e. the wrong tradeoff), so we dropped it. The\n * batch byline join below returns an empty map for empty sites at the\n * same cost as the probe, without the pre-check.\n */\nexport function invalidateBylineCache(): void {\n\t// Intentionally empty.\n}\n\n/**\n * Get a byline by ID.\n *\n * @example\n * ```ts\n * import { getByline } from \"emdash\";\n *\n * const byline = await getByline(\"01HXYZ...\");\n * if (byline) {\n * console.log(byline.displayName);\n * }\n * ```\n */\nexport async function getByline(id: string): Promise<BylineSummary | null> {\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\treturn repo.findById(id);\n}\n\n/**\n * Get a byline by slug.\n *\n * Standalone identity lookup (e.g. rendering an author profile page). Walks\n * the configured locale fallback chain — same pattern as `getMenu` and\n * `getTerm`, see PR #916. Returns the first match found, walking\n * `[requestedLocale, ...fallbacks, defaultLocale]` in order.\n *\n * Note: this is intentionally different from credit hydration on a content\n * entry (`getEntryBylines`), which is strict per locale with no fallback.\n * The distinction: identity lookups answer \"give me this byline\", and\n * falling back to another locale's display name is acceptable. Credit\n * hydration answers \"what should render on this entry\", where falling back\n * silently surfaces a stale-locale name and contradicts editorial intent.\n *\n * @example\n * ```ts\n * import { getBylineBySlug } from \"emdash\";\n *\n * const byline = await getBylineBySlug(\"jane-doe\", { locale: \"de-de\" });\n * if (byline) {\n * console.log(byline.displayName);\n * }\n * ```\n */\nexport async function getBylineBySlug(\n\tslug: string,\n\toptions?: { locale?: string },\n): Promise<BylineSummary | null> {\n\tconst chain = resolveLocaleChain(options?.locale);\n\tconst cacheKey = `byline-by-slug:${slug}:${chain.length > 0 ? chain.join(\",\") : \"*\"}`;\n\treturn requestCached(cacheKey, async () => {\n\t\tconst db = await getDb();\n\t\tconst repo = new BylineRepository(db);\n\n\t\tif (chain.length === 0) {\n\t\t\t// No i18n or no resolved locale — fall back to the repo's\n\t\t\t// \"lowest-locale-code\" deterministic match.\n\t\t\treturn repo.findBySlug(slug);\n\t\t}\n\n\t\tfor (const locale of chain) {\n\t\t\tconst row = await repo.findBySlug(slug, { locale });\n\t\t\tif (row) return row;\n\t\t}\n\t\treturn null;\n\t});\n}\n\n/**\n * Get byline credits for a single content entry.\n *\n * Strict per locale (post-migration 040): a credit renders iff a byline row\n * exists at the requested locale within the credited translation_group.\n * Callers wanting fallback behaviour apply it themselves. When `locale` is\n * omitted, returns every locale variant of every credit on the entry —\n * useful for admin tooling, not for end-user rendering.\n *\n * Internal: not re-exported from the `emdash` package entry point. Every\n * entry returned by `getEmDashCollection` / `getEmDashEntry` already has\n * `data.bylines` populated by `hydrateEntryBylines` (which uses the batch\n * helper `getBylinesForEntries` directly). Site code should read those\n * fields rather than calling this function.\n */\nexport async function getEntryBylines(\n\tcollection: string,\n\tentryId: string,\n\toptions?: { locale?: string },\n): Promise<ContentBylineCredit[]> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\tconst localeOpt = options?.locale !== undefined ? { locale: options.locale } : undefined;\n\tconst explicit = await repo.getContentBylines(collection, entryId, localeOpt);\n\tif (explicit.length > 0) {\n\t\treturn explicit.map((c) => ({ ...c, source: \"explicit\" as const }));\n\t}\n\n\t// `primary_byline_id` is the explicit-credit sentinel: non-null\n\t// suppresses author fallback even when the credit doesn't resolve\n\t// at this locale.\n\tconst ctx = await getEntryContext(db, collection, entryId);\n\tif (ctx.primaryBylineId) return [];\n\n\tif (ctx.authorId) {\n\t\tconst fallback = await repo.findByUserId(ctx.authorId, localeOpt);\n\t\tif (fallback) {\n\t\t\treturn [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }];\n\t\t}\n\t}\n\n\treturn [];\n}\n\n/**\n * Entry reference for batch byline lookups. Passing `authorId`,\n * `primaryBylineId`, and `locale` in directly avoids a per-entry\n * `SELECT` against the content table during hydration.\n *\n * `primaryBylineId` is the explicit-credit sentinel — non-null suppresses\n * author fallback. `locale` drives the strict per-locale join.\n */\nexport interface BylineEntry {\n\tid: string;\n\tauthorId: string | null;\n\tprimaryBylineId?: string | null;\n\tlocale?: string | null;\n}\n\n/**\n * Batch-fetch byline credits for multiple content entries.\n *\n * Per-entry strict-locale hydration: entries are bucketed by `entry.locale`\n * and each bucket gets a single batched call to the strict-locale repo\n * method. Items with no `locale` field (legacy / single-locale installs)\n * share an unscoped bucket.\n *\n * Internal: consumed by `hydrateEntryBylines` in `query.ts` so that every\n * entry returned from `getEmDashCollection` / `getEmDashEntry` already has\n * `data.bylines` populated. Site code should rely on that eager hydration\n * rather than calling this directly -- this function is not re-exported\n * from the `emdash` package entry point.\n *\n * @param collection - The collection slug (e.g., \"posts\")\n * @param entries - Entry id + authorId + locale (each entry resolves at its own locale)\n * @returns Map from entry ID to array of byline credits\n */\nexport async function getBylinesForEntries(\n\tcollection: string,\n\tentries: BylineEntry[],\n): Promise<Map<string, ContentBylineCredit[]>> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst result = new Map<string, ContentBylineCredit[]>();\n\n\tfor (const { id } of entries) {\n\t\tresult.set(id, []);\n\t}\n\n\tif (entries.length === 0) {\n\t\treturn result;\n\t}\n\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\t// Bucket entries by locale so each bucket fires a single strict-locale\n\t// `getContentBylinesMany` call. Items with no locale field share a\n\t// bucket keyed by null (no `WHERE locale = ?` applied — legacy\n\t// pre-i18n shape).\n\tconst buckets = new Map<string | null, BylineEntry[]>();\n\tfor (const entry of entries) {\n\t\tconst key = entry.locale ?? null;\n\t\tconst bucket = buckets.get(key);\n\t\tif (bucket) bucket.push(entry);\n\t\telse buckets.set(key, [entry]);\n\t}\n\n\t// Sites with no bylines get an empty map back at the same cost as the\n\t// previous \"has any bylines\" probe, without the extra round-trip.\n\t// Pre-migration databases (bylines table missing) fall through to the\n\t// `isMissingTableError` catch below and return empty.\n\t//\n\t// Each bucket's `getContentBylinesMany` call uses `skipHydration: true`\n\t// so the per-bucket fetches return bylines with `customFields = {}`.\n\t// We then hydrate the union of returned bylines in a SINGLE batched\n\t// pass via `hydrateBylineCustomFields`. This keeps mixed-locale list\n\t// hydration at one batched group-shared query (and one batched\n\t// translatable query) per request, even when locale buckets reference\n\t// disjoint translation_groups — the strict reading of the Phase 3\n\t// query-count envelope.\n\tconst explicitByEntry = new Map<string, ContentBylineCredit[]>();\n\tconst entriesNeedingAuthorCheck: BylineEntry[] = [];\n\tconst hydrationTargets: BylineSummary[] = [];\n\tfor (const [locale, bucket] of buckets) {\n\t\tconst localeOpt = locale ? { locale, skipHydration: true } : { skipHydration: true };\n\t\tconst bucketIds = bucket.map((e) => e.id);\n\t\tlet bylinesMap;\n\t\ttry {\n\t\t\tbylinesMap = await repo.getContentBylinesMany(collection, bucketIds, localeOpt);\n\t\t} catch (error) {\n\t\t\tif (isMissingTableError(error)) return result;\n\t\t\tthrow error;\n\t\t}\n\t\tfor (const [id, list] of bylinesMap) {\n\t\t\texplicitByEntry.set(id, list);\n\t\t\tfor (const credit of list) hydrationTargets.push(credit.byline);\n\t\t}\n\n\t\tfor (const entry of bucket) {\n\t\t\tconst hasResolved = bylinesMap.has(entry.id) && bylinesMap.get(entry.id)!.length > 0;\n\t\t\tif (hasResolved) continue;\n\t\t\tif (entry.authorId) entriesNeedingAuthorCheck.push(entry);\n\t\t}\n\t}\n\n\t// Only entries without an explicit credit (primaryBylineId null) are\n\t// eligible for author fallback.\n\tconst fallbackByEntry = new Map<string, BylineSummary>();\n\tif (entriesNeedingAuthorCheck.length > 0) {\n\t\tconst authorBuckets = new Map<string | null, BylineEntry[]>();\n\t\tfor (const entry of entriesNeedingAuthorCheck) {\n\t\t\tif (entry.primaryBylineId) continue;\n\t\t\tconst key = entry.locale ?? null;\n\t\t\tconst bucket = authorBuckets.get(key);\n\t\t\tif (bucket) bucket.push(entry);\n\t\t\telse authorBuckets.set(key, [entry]);\n\t\t}\n\n\t\tfor (const [locale, bucket] of authorBuckets) {\n\t\t\tconst localeOpt: { locale?: string; skipHydration: true } = locale\n\t\t\t\t? { locale, skipHydration: true }\n\t\t\t\t: { skipHydration: true };\n\t\t\tconst authorIds = bucket.map((e) => e.authorId).filter((id): id is string => id !== null);\n\t\t\tconst uniqueAuthorIds = [...new Set(authorIds)];\n\t\t\tif (uniqueAuthorIds.length === 0) continue;\n\t\t\t// `skipHydration: true` returns bylines with `customFields = {}`\n\t\t\t// so the fallback path participates in the single batched\n\t\t\t// `hydrateBylineCustomFields` call below — keeping the query\n\t\t\t// envelope at \"+1 group-shared query per hydration pass\" even\n\t\t\t// when author bylines across locale buckets reference disjoint\n\t\t\t// translation_groups.\n\t\t\tconst authorBylineMap = await repo.findByUserIds(uniqueAuthorIds, localeOpt);\n\t\t\tfor (const entry of bucket) {\n\t\t\t\tif (!entry.authorId) continue;\n\t\t\t\tconst f = authorBylineMap.get(entry.authorId);\n\t\t\t\tif (f) {\n\t\t\t\t\tfallbackByEntry.set(entry.id, f);\n\t\t\t\t\thydrationTargets.push(f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Single batched hydration over every byline returned from both the\n\t// per-bucket explicit-credit fetches AND the per-bucket author-\n\t// fallback fetches. One translatable query + one group-shared query\n\t// for the whole pass, regardless of bucket count or whether\n\t// translation_groups overlap across locales.\n\tif (hydrationTargets.length > 0) {\n\t\tawait repo.hydrateBylineCustomFields(hydrationTargets);\n\t}\n\n\tfor (const { id } of entries) {\n\t\tconst explicit = explicitByEntry.get(id);\n\t\tif (explicit && explicit.length > 0) {\n\t\t\tresult.set(\n\t\t\t\tid,\n\t\t\t\texplicit.map((c) => ({ ...c, source: \"explicit\" as const })),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fallback = fallbackByEntry.get(id);\n\t\tif (fallback) {\n\t\t\tresult.set(id, [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }]);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/** Reads `author_id` + `primary_byline_id` for one entry in a single query. */\nasync function getEntryContext(\n\tdb: Awaited<ReturnType<typeof getDb>>,\n\tcollection: string,\n\tentryId: string,\n): Promise<{ authorId: string | null; primaryBylineId: string | null }> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst tableName = `ec_${collection}`;\n\n\tconst result = await sql<{\n\t\tauthor_id: string | null;\n\t\tprimary_byline_id: string | null;\n\t}>`\n\t\tSELECT author_id, primary_byline_id FROM ${sql.ref(tableName)}\n\t\tWHERE id = ${entryId}\n\t\tLIMIT 1\n\t`.execute(db);\n\n\tconst row = result.rows[0];\n\treturn {\n\t\tauthorId: row?.author_id ?? null,\n\t\tprimaryBylineId: row?.primary_byline_id ?? null,\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bylines-wurS258E.mjs","names":[],"sources":["../src/bylines/index.ts"],"sourcesContent":["/**\n * Runtime API for bylines\n *\n * Provides functions to query byline profiles and byline credits\n * associated with content entries. Follows the same pattern as\n * the taxonomies runtime API.\n *\n * i18n model (migration 040): byline rows are per-locale and share a\n * `translation_group`. Credits on `_emdash_content_bylines.byline_id` store\n * the translation_group, so a single credit spans every locale of a byline.\n *\n * Hydration is strict per locale: a credit at locale X renders iff a byline\n * row exists at locale X within the credited translation_group. There is no\n * read-time fallback. Mirrors `getEntryTerms` and the convention in PR #916.\n * Locale is passed in by callers — `query.ts` resolves it from the entry's\n * own `data.locale` for the runtime path.\n */\n\nimport { sql } from \"kysely\";\n\nimport { BylineRepository } from \"../database/repositories/byline.js\";\nimport type { BylineSummary, ContentBylineCredit } from \"../database/repositories/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { resolveLocaleChain } from \"../i18n/resolve.js\";\nimport { getDb } from \"../loader.js\";\nimport { requestCached } from \"../request-cache.js\";\nimport { isMissingTableError } from \"../utils/db-errors.js\";\n\n/**\n * No-op — kept for API compatibility.\n *\n * Used to invalidate a worker-lifetime \"has any byline?\" probe. That\n * probe added a query on every cold isolate to save one query on sites\n * with zero bylines (i.e. the wrong tradeoff), so we dropped it. The\n * batch byline join below returns an empty map for empty sites at the\n * same cost as the probe, without the pre-check.\n */\nexport function invalidateBylineCache(): void {\n\t// Intentionally empty.\n}\n\n/**\n * Get a byline by ID.\n *\n * @example\n * ```ts\n * import { getByline } from \"emdash\";\n *\n * const byline = await getByline(\"01HXYZ...\");\n * if (byline) {\n * console.log(byline.displayName);\n * }\n * ```\n */\nexport async function getByline(id: string): Promise<BylineSummary | null> {\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\treturn repo.findById(id);\n}\n\n/**\n * Get a byline by slug.\n *\n * Standalone identity lookup (e.g. rendering an author profile page). Walks\n * the configured locale fallback chain — same pattern as `getMenu` and\n * `getTerm`, see PR #916. Returns the first match found, walking\n * `[requestedLocale, ...fallbacks, defaultLocale]` in order.\n *\n * Note: this is intentionally different from credit hydration on a content\n * entry (`getEntryBylines`), which is strict per locale with no fallback.\n * The distinction: identity lookups answer \"give me this byline\", and\n * falling back to another locale's display name is acceptable. Credit\n * hydration answers \"what should render on this entry\", where falling back\n * silently surfaces a stale-locale name and contradicts editorial intent.\n *\n * @example\n * ```ts\n * import { getBylineBySlug } from \"emdash\";\n *\n * const byline = await getBylineBySlug(\"jane-doe\", { locale: \"de-de\" });\n * if (byline) {\n * console.log(byline.displayName);\n * }\n * ```\n */\nexport async function getBylineBySlug(\n\tslug: string,\n\toptions?: { locale?: string },\n): Promise<BylineSummary | null> {\n\tconst chain = resolveLocaleChain(options?.locale);\n\tconst cacheKey = `byline-by-slug:${slug}:${chain.length > 0 ? chain.join(\",\") : \"*\"}`;\n\treturn requestCached(cacheKey, async () => {\n\t\tconst db = await getDb();\n\t\tconst repo = new BylineRepository(db);\n\n\t\tif (chain.length === 0) {\n\t\t\t// No i18n or no resolved locale — fall back to the repo's\n\t\t\t// \"lowest-locale-code\" deterministic match.\n\t\t\treturn repo.findBySlug(slug);\n\t\t}\n\n\t\tfor (const locale of chain) {\n\t\t\tconst row = await repo.findBySlug(slug, { locale });\n\t\t\tif (row) return row;\n\t\t}\n\t\treturn null;\n\t});\n}\n\n/**\n * Get byline credits for a single content entry.\n *\n * Strict per locale (post-migration 040): a credit renders iff a byline row\n * exists at the requested locale within the credited translation_group.\n * Callers wanting fallback behaviour apply it themselves. When `locale` is\n * omitted, returns every locale variant of every credit on the entry —\n * useful for admin tooling, not for end-user rendering.\n *\n * Internal: not re-exported from the `emdash` package entry point. Every\n * entry returned by `getEmDashCollection` / `getEmDashEntry` already has\n * `data.bylines` populated by `hydrateEntryBylines` (which uses the batch\n * helper `getBylinesForEntries` directly). Site code should read those\n * fields rather than calling this function.\n */\nexport async function getEntryBylines(\n\tcollection: string,\n\tentryId: string,\n\toptions?: { locale?: string },\n): Promise<ContentBylineCredit[]> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\tconst localeOpt = options?.locale !== undefined ? { locale: options.locale } : undefined;\n\tconst explicit = await repo.getContentBylines(collection, entryId, localeOpt);\n\tif (explicit.length > 0) {\n\t\treturn explicit.map((c) => ({ ...c, source: \"explicit\" as const }));\n\t}\n\n\t// `primary_byline_id` is the explicit-credit sentinel: non-null\n\t// suppresses author fallback even when the credit doesn't resolve\n\t// at this locale.\n\tconst ctx = await getEntryContext(db, collection, entryId);\n\tif (ctx.primaryBylineId) return [];\n\n\tif (ctx.authorId) {\n\t\tconst fallback = await repo.findByUserId(ctx.authorId, localeOpt);\n\t\tif (fallback) {\n\t\t\treturn [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }];\n\t\t}\n\t}\n\n\treturn [];\n}\n\n/**\n * Entry reference for batch byline lookups. Passing `authorId`,\n * `primaryBylineId`, and `locale` in directly avoids a per-entry\n * `SELECT` against the content table during hydration.\n *\n * `primaryBylineId` is the explicit-credit sentinel — non-null suppresses\n * author fallback. `locale` drives the strict per-locale join.\n */\nexport interface BylineEntry {\n\tid: string;\n\tauthorId: string | null;\n\tprimaryBylineId?: string | null;\n\tlocale?: string | null;\n}\n\n/**\n * Batch-fetch byline credits for multiple content entries.\n *\n * Per-entry strict-locale hydration: entries are bucketed by `entry.locale`\n * and each bucket gets a single batched call to the strict-locale repo\n * method. Items with no `locale` field (legacy / single-locale installs)\n * share an unscoped bucket.\n *\n * Internal: consumed by `hydrateEntryBylines` in `query.ts` so that every\n * entry returned from `getEmDashCollection` / `getEmDashEntry` already has\n * `data.bylines` populated. Site code should rely on that eager hydration\n * rather than calling this directly -- this function is not re-exported\n * from the `emdash` package entry point.\n *\n * @param collection - The collection slug (e.g., \"posts\")\n * @param entries - Entry id + authorId + locale (each entry resolves at its own locale)\n * @returns Map from entry ID to array of byline credits\n */\nexport async function getBylinesForEntries(\n\tcollection: string,\n\tentries: BylineEntry[],\n): Promise<Map<string, ContentBylineCredit[]>> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst result = new Map<string, ContentBylineCredit[]>();\n\n\tfor (const { id } of entries) {\n\t\tresult.set(id, []);\n\t}\n\n\tif (entries.length === 0) {\n\t\treturn result;\n\t}\n\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\t// Bucket entries by locale so each bucket fires a single strict-locale\n\t// `getContentBylinesMany` call. Items with no locale field share a\n\t// bucket keyed by null (no `WHERE locale = ?` applied — legacy\n\t// pre-i18n shape).\n\tconst buckets = new Map<string | null, BylineEntry[]>();\n\tfor (const entry of entries) {\n\t\tconst key = entry.locale ?? null;\n\t\tconst bucket = buckets.get(key);\n\t\tif (bucket) bucket.push(entry);\n\t\telse buckets.set(key, [entry]);\n\t}\n\n\t// Sites with no bylines get an empty map back at the same cost as the\n\t// previous \"has any bylines\" probe, without the extra round-trip.\n\t// Pre-migration databases (bylines table missing) fall through to the\n\t// `isMissingTableError` catch below and return empty.\n\t//\n\t// Each bucket's `getContentBylinesMany` call uses `skipHydration: true`\n\t// so the per-bucket fetches return bylines with `customFields = {}`.\n\t// We then hydrate the union of returned bylines in a SINGLE batched\n\t// pass via `hydrateBylineCustomFields`. This keeps mixed-locale list\n\t// hydration at one batched group-shared query (and one batched\n\t// translatable query) per request, even when locale buckets reference\n\t// disjoint translation_groups — the strict reading of the Phase 3\n\t// query-count envelope.\n\tconst explicitByEntry = new Map<string, ContentBylineCredit[]>();\n\tconst entriesNeedingAuthorCheck: BylineEntry[] = [];\n\tconst hydrationTargets: BylineSummary[] = [];\n\tfor (const [locale, bucket] of buckets) {\n\t\tconst localeOpt = locale ? { locale, skipHydration: true } : { skipHydration: true };\n\t\tconst bucketIds = bucket.map((e) => e.id);\n\t\tlet bylinesMap;\n\t\ttry {\n\t\t\tbylinesMap = await repo.getContentBylinesMany(collection, bucketIds, localeOpt);\n\t\t} catch (error) {\n\t\t\tif (isMissingTableError(error)) return result;\n\t\t\tthrow error;\n\t\t}\n\t\tfor (const [id, list] of bylinesMap) {\n\t\t\texplicitByEntry.set(id, list);\n\t\t\tfor (const credit of list) hydrationTargets.push(credit.byline);\n\t\t}\n\n\t\tfor (const entry of bucket) {\n\t\t\tconst hasResolved = bylinesMap.has(entry.id) && bylinesMap.get(entry.id)!.length > 0;\n\t\t\tif (hasResolved) continue;\n\t\t\tif (entry.authorId) entriesNeedingAuthorCheck.push(entry);\n\t\t}\n\t}\n\n\t// Only entries without an explicit credit (primaryBylineId null) are\n\t// eligible for author fallback.\n\tconst fallbackByEntry = new Map<string, BylineSummary>();\n\tif (entriesNeedingAuthorCheck.length > 0) {\n\t\tconst authorBuckets = new Map<string | null, BylineEntry[]>();\n\t\tfor (const entry of entriesNeedingAuthorCheck) {\n\t\t\tif (entry.primaryBylineId) continue;\n\t\t\tconst key = entry.locale ?? null;\n\t\t\tconst bucket = authorBuckets.get(key);\n\t\t\tif (bucket) bucket.push(entry);\n\t\t\telse authorBuckets.set(key, [entry]);\n\t\t}\n\n\t\tfor (const [locale, bucket] of authorBuckets) {\n\t\t\tconst localeOpt: { locale?: string; skipHydration: true } = locale\n\t\t\t\t? { locale, skipHydration: true }\n\t\t\t\t: { skipHydration: true };\n\t\t\tconst authorIds = bucket.map((e) => e.authorId).filter((id): id is string => id !== null);\n\t\t\tconst uniqueAuthorIds = [...new Set(authorIds)];\n\t\t\tif (uniqueAuthorIds.length === 0) continue;\n\t\t\t// `skipHydration: true` returns bylines with `customFields = {}`\n\t\t\t// so the fallback path participates in the single batched\n\t\t\t// `hydrateBylineCustomFields` call below — keeping the query\n\t\t\t// envelope at \"+1 group-shared query per hydration pass\" even\n\t\t\t// when author bylines across locale buckets reference disjoint\n\t\t\t// translation_groups.\n\t\t\tconst authorBylineMap = await repo.findByUserIds(uniqueAuthorIds, localeOpt);\n\t\t\tfor (const entry of bucket) {\n\t\t\t\tif (!entry.authorId) continue;\n\t\t\t\tconst f = authorBylineMap.get(entry.authorId);\n\t\t\t\tif (f) {\n\t\t\t\t\tfallbackByEntry.set(entry.id, f);\n\t\t\t\t\thydrationTargets.push(f);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Single batched hydration over every byline returned from both the\n\t// per-bucket explicit-credit fetches AND the per-bucket author-\n\t// fallback fetches. One translatable query + one group-shared query\n\t// for the whole pass, regardless of bucket count or whether\n\t// translation_groups overlap across locales.\n\tif (hydrationTargets.length > 0) {\n\t\tawait repo.hydrateBylineCustomFields(hydrationTargets);\n\t}\n\n\tfor (const { id } of entries) {\n\t\tconst explicit = explicitByEntry.get(id);\n\t\tif (explicit && explicit.length > 0) {\n\t\t\tresult.set(\n\t\t\t\tid,\n\t\t\t\texplicit.map((c) => ({ ...c, source: \"explicit\" as const })),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fallback = fallbackByEntry.get(id);\n\t\tif (fallback) {\n\t\t\tresult.set(id, [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }]);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Get content entries credited to a byline, in any credit position.\n *\n * Unlike filtering on the content table's `primary_byline_id` column (which\n * only finds entries where the byline is the first/primary credit), this\n * matches every explicit credit recorded in `_emdash_content_bylines`, so\n * co-authored entries where the byline is a secondary credit are included.\n *\n * `byline` is matched against the byline's `translation_group` (the value\n * stored on credits since migration 040), so a single credit spans every\n * locale variant of the byline. Pass `byline.translationGroup ?? byline.id`\n * from `getByline` / `getBylineBySlug`. An array matches any of the given\n * bylines (OR).\n *\n * The result respects the active locale, status, ordering, and eager\n * hydration of `getEmDashCollection`.\n *\n * @example\n * ```ts\n * import { getBylineBySlug, getEntriesByByline } from \"emdash\";\n *\n * const byline = await getBylineBySlug(\"jane-doe\");\n * if (byline) {\n * const posts = await getEntriesByByline(\"posts\", byline.translationGroup ?? byline.id, {\n * orderBy: { published_at: \"desc\" },\n * });\n * }\n * ```\n *\n * @param collection - The collection slug (e.g. \"posts\")\n * @param byline - A byline translation group, or an array of them (OR)\n * @param options - Optional locale, ordering, status, and limit\n */\nexport async function getEntriesByByline(\n\tcollection: string,\n\tbyline: string | string[],\n\toptions: {\n\t\tlocale?: string;\n\t\torderBy?: Record<string, \"asc\" | \"desc\">;\n\t\tstatus?: \"draft\" | \"published\" | \"archived\";\n\t\tlimit?: number;\n\t} = {},\n): Promise<Array<{ id: string; data: Record<string, unknown> }>> {\n\tconst { getEmDashCollection } = await import(\"../query.js\");\n\n\tconst queryOptions: Record<string, unknown> = {\n\t\twhere: { byline },\n\t};\n\tif (options.locale !== undefined) queryOptions.locale = options.locale;\n\tif (options.orderBy !== undefined) queryOptions.orderBy = options.orderBy;\n\tif (options.status !== undefined) queryOptions.status = options.status;\n\tif (options.limit !== undefined) queryOptions.limit = options.limit;\n\n\tconst { entries } = await getEmDashCollection(collection, queryOptions);\n\treturn entries;\n}\n\n/** Reads `author_id` + `primary_byline_id` for one entry in a single query. */\nasync function getEntryContext(\n\tdb: Awaited<ReturnType<typeof getDb>>,\n\tcollection: string,\n\tentryId: string,\n): Promise<{ authorId: string | null; primaryBylineId: string | null }> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst tableName = `ec_${collection}`;\n\n\tconst result = await sql<{\n\t\tauthor_id: string | null;\n\t\tprimary_byline_id: string | null;\n\t}>`\n\t\tSELECT author_id, primary_byline_id FROM ${sql.ref(tableName)}\n\t\tWHERE id = ${entryId}\n\t\tLIMIT 1\n\t`.execute(db);\n\n\tconst row = result.rows[0];\n\treturn {\n\t\tauthorId: row?.author_id ?? null,\n\t\tprimaryBylineId: row?.primary_byline_id ?? null,\n\t};\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { i as __exportAll } from "./runner-BiuUfx-V.mjs";
2
- import { i as matchPattern, n as interpolateDestination, t as compilePattern } from "./patterns-CqG5Ya3i.mjs";
1
+ import { a as __exportAll } from "./runner--4wMWwKM.mjs";
2
+ import { i as matchPattern, n as interpolateDestination, t as compilePattern } from "./patterns-p-RBdTbM.mjs";
3
3
 
4
4
  //#region src/redirects/cache.ts
5
5
  var cache_exports = /* @__PURE__ */ __exportAll({
@@ -62,4 +62,4 @@ function matchCachedPatterns(rules, pathname) {
62
62
 
63
63
  //#endregion
64
64
  export { setCachedRedirects as a, matchCachedPatterns as i, getCachedRedirects as n, invalidateRedirectCache as r, cache_exports as t };
65
- //# sourceMappingURL=cache-DIHHyPkt.mjs.map
65
+ //# sourceMappingURL=cache-B_HzASVT.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache-DIHHyPkt.mjs","names":[],"sources":["../src/redirects/cache.ts"],"sourcesContent":["/**\n * Redirect rule cache.\n *\n * Module-level cache for enabled redirect rules. The middleware populates this\n * on first request; route handlers invalidate it on writes.\n *\n * Both exact-match and pattern rules are loaded from one query and cached\n * together: exact rules indexed by source path in a Map, pattern rules\n * pre-compiled into an array. A single warm request issues zero database\n * queries; a cold isolate issues one.\n *\n * This module deliberately has NO Astro imports so it can be safely imported\n * from handlers, seed, CLI, and tests without dragging in `astro:middleware`.\n */\n\nimport type { Redirect } from \"../database/repositories/redirect.js\";\nimport type { CompiledPattern } from \"./patterns.js\";\nimport { compilePattern, interpolateDestination, matchPattern } from \"./patterns.js\";\n\nexport interface CachedRedirectRule {\n\tredirect: Redirect;\n\tcompiled: CompiledPattern;\n}\n\nexport interface CachedRedirects {\n\t/** Exact-match rules indexed by source path (`source` -> `Redirect`). */\n\texact: Map<string, Redirect>;\n\t/** Pattern rules with their compiled regexes, preserving insertion order. */\n\tpatterns: CachedRedirectRule[];\n}\n\n/**\n * Cached enabled redirects.\n * null = not yet populated, object = cached.\n */\nlet cachedRedirects: CachedRedirects | null = null;\n\n/**\n * Invalidate the cached redirects (both exact and pattern).\n * Call when redirects are created, updated, or deleted.\n */\nexport function invalidateRedirectCache(): void {\n\tcachedRedirects = null;\n}\n\n/**\n * Get the cached redirects, or null if the cache is cold.\n */\nexport function getCachedRedirects(): CachedRedirects | null {\n\treturn cachedRedirects;\n}\n\n/**\n * Populate the cache from a list of enabled redirects (both exact and\n * pattern). The caller is responsible for passing only enabled rows — the\n * cache stores them as-is.\n */\nexport function setCachedRedirects(redirects: Redirect[]): CachedRedirects {\n\tconst exact = new Map<string, Redirect>();\n\tconst patterns: CachedRedirectRule[] = [];\n\tfor (const r of redirects) {\n\t\tif (r.isPattern) {\n\t\t\tpatterns.push({ redirect: r, compiled: compilePattern(r.source) });\n\t\t} else {\n\t\t\texact.set(r.source, r);\n\t\t}\n\t}\n\tcachedRedirects = { exact, patterns };\n\treturn cachedRedirects;\n}\n\n/**\n * Match a path against the cached pattern rules.\n * Returns the resolved destination and matching redirect, or null.\n */\nexport function matchCachedPatterns(\n\trules: CachedRedirectRule[],\n\tpathname: string,\n): { redirect: Redirect; destination: string } | null {\n\tfor (const { redirect, compiled } of rules) {\n\t\tconst params = matchPattern(compiled, pathname);\n\t\tif (params) {\n\t\t\tconst dest = interpolateDestination(redirect.destination, params);\n\t\t\treturn { redirect, destination: dest };\n\t\t}\n\t}\n\treturn null;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmCA,IAAI,kBAA0C;;;;;AAM9C,SAAgB,0BAAgC;AAC/C,mBAAkB;;;;;AAMnB,SAAgB,qBAA6C;AAC5D,QAAO;;;;;;;AAQR,SAAgB,mBAAmB,WAAwC;CAC1E,MAAM,wBAAQ,IAAI,KAAuB;CACzC,MAAM,WAAiC,EAAE;AACzC,MAAK,MAAM,KAAK,UACf,KAAI,EAAE,UACL,UAAS,KAAK;EAAE,UAAU;EAAG,UAAU,eAAe,EAAE,OAAO;EAAE,CAAC;KAElE,OAAM,IAAI,EAAE,QAAQ,EAAE;AAGxB,mBAAkB;EAAE;EAAO;EAAU;AACrC,QAAO;;;;;;AAOR,SAAgB,oBACf,OACA,UACqD;AACrD,MAAK,MAAM,EAAE,UAAU,cAAc,OAAO;EAC3C,MAAM,SAAS,aAAa,UAAU,SAAS;AAC/C,MAAI,OAEH,QAAO;GAAE;GAAU,aADN,uBAAuB,SAAS,aAAa,OAAO;GAC3B;;AAGxC,QAAO"}
1
+ {"version":3,"file":"cache-B_HzASVT.mjs","names":[],"sources":["../src/redirects/cache.ts"],"sourcesContent":["/**\n * Redirect rule cache.\n *\n * Module-level cache for enabled redirect rules. The middleware populates this\n * on first request; route handlers invalidate it on writes.\n *\n * Both exact-match and pattern rules are loaded from one query and cached\n * together: exact rules indexed by source path in a Map, pattern rules\n * pre-compiled into an array. A single warm request issues zero database\n * queries; a cold isolate issues one.\n *\n * This module deliberately has NO Astro imports so it can be safely imported\n * from handlers, seed, CLI, and tests without dragging in `astro:middleware`.\n */\n\nimport type { Redirect } from \"../database/repositories/redirect.js\";\nimport type { CompiledPattern } from \"./patterns.js\";\nimport { compilePattern, interpolateDestination, matchPattern } from \"./patterns.js\";\n\nexport interface CachedRedirectRule {\n\tredirect: Redirect;\n\tcompiled: CompiledPattern;\n}\n\nexport interface CachedRedirects {\n\t/** Exact-match rules indexed by source path (`source` -> `Redirect`). */\n\texact: Map<string, Redirect>;\n\t/** Pattern rules with their compiled regexes, preserving insertion order. */\n\tpatterns: CachedRedirectRule[];\n}\n\n/**\n * Cached enabled redirects.\n * null = not yet populated, object = cached.\n */\nlet cachedRedirects: CachedRedirects | null = null;\n\n/**\n * Invalidate the cached redirects (both exact and pattern).\n * Call when redirects are created, updated, or deleted.\n */\nexport function invalidateRedirectCache(): void {\n\tcachedRedirects = null;\n}\n\n/**\n * Get the cached redirects, or null if the cache is cold.\n */\nexport function getCachedRedirects(): CachedRedirects | null {\n\treturn cachedRedirects;\n}\n\n/**\n * Populate the cache from a list of enabled redirects (both exact and\n * pattern). The caller is responsible for passing only enabled rows — the\n * cache stores them as-is.\n */\nexport function setCachedRedirects(redirects: Redirect[]): CachedRedirects {\n\tconst exact = new Map<string, Redirect>();\n\tconst patterns: CachedRedirectRule[] = [];\n\tfor (const r of redirects) {\n\t\tif (r.isPattern) {\n\t\t\tpatterns.push({ redirect: r, compiled: compilePattern(r.source) });\n\t\t} else {\n\t\t\texact.set(r.source, r);\n\t\t}\n\t}\n\tcachedRedirects = { exact, patterns };\n\treturn cachedRedirects;\n}\n\n/**\n * Match a path against the cached pattern rules.\n * Returns the resolved destination and matching redirect, or null.\n */\nexport function matchCachedPatterns(\n\trules: CachedRedirectRule[],\n\tpathname: string,\n): { redirect: Redirect; destination: string } | null {\n\tfor (const { redirect, compiled } of rules) {\n\t\tconst params = matchPattern(compiled, pathname);\n\t\tif (params) {\n\t\t\tconst dest = interpolateDestination(redirect.destination, params);\n\t\t\treturn { redirect, destination: dest };\n\t\t}\n\t}\n\treturn null;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmCA,IAAI,kBAA0C;;;;;AAM9C,SAAgB,0BAAgC;AAC/C,mBAAkB;;;;;AAMnB,SAAgB,qBAA6C;AAC5D,QAAO;;;;;;;AAQR,SAAgB,mBAAmB,WAAwC;CAC1E,MAAM,wBAAQ,IAAI,KAAuB;CACzC,MAAM,WAAiC,EAAE;AACzC,MAAK,MAAM,KAAK,UACf,KAAI,EAAE,UACL,UAAS,KAAK;EAAE,UAAU;EAAG,UAAU,eAAe,EAAE,OAAO;EAAE,CAAC;KAElE,OAAM,IAAI,EAAE,QAAQ,EAAE;AAGxB,mBAAkB;EAAE;EAAO;EAAU;AACrC,QAAO;;;;;;AAOR,SAAgB,oBACf,OACA,UACqD;AACrD,MAAK,MAAM,EAAE,UAAU,cAAc,OAAO;EAC3C,MAAM,SAAS,aAAa,UAAU,SAAS;AAC/C,MAAI,OAEH,QAAO;GAAE;GAAU,aADN,uBAAuB,SAAS,aAAa,OAAO;GAC3B;;AAGxC,QAAO"}
@@ -1,4 +1,4 @@
1
- import { i as __exportAll } from "./runner-BiuUfx-V.mjs";
1
+ import { a as __exportAll } from "./runner--4wMWwKM.mjs";
2
2
 
3
3
  //#region src/utils/chunks.ts
4
4
  var chunks_exports = /* @__PURE__ */ __exportAll({
@@ -22,4 +22,4 @@ const SQL_BATCH_SIZE = 50;
22
22
 
23
23
  //#endregion
24
24
  export { chunks as n, chunks_exports as r, SQL_BATCH_SIZE as t };
25
- //# sourceMappingURL=chunks-DnnHlRG3.mjs.map
25
+ //# sourceMappingURL=chunks-BerYVuve.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chunks-DnnHlRG3.mjs","names":[],"sources":["../src/utils/chunks.ts"],"sourcesContent":["/**\n * Split an array into chunks of at most `size` elements.\n *\n * Used to keep SQL `IN (?, ?, …)` clauses within Cloudflare D1's\n * bound-parameter limit (~100 per statement).\n */\nexport function chunks<T>(arr: T[], size: number): T[][] {\n\tif (arr.length === 0) return [];\n\tconst result: T[][] = [];\n\tfor (let i = 0; i < arr.length; i += size) {\n\t\tresult.push(arr.slice(i, i + size));\n\t}\n\treturn result;\n}\n\n/** Conservative default chunk size for SQL IN clauses (well within D1's limit). */\nexport const SQL_BATCH_SIZE = 50;\n"],"mappings":";;;;;;;;;;;;;AAMA,SAAgB,OAAU,KAAU,MAAqB;AACxD,KAAI,IAAI,WAAW,EAAG,QAAO,EAAE;CAC/B,MAAM,SAAgB,EAAE;AACxB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,KACpC,QAAO,KAAK,IAAI,MAAM,GAAG,IAAI,KAAK,CAAC;AAEpC,QAAO;;;AAIR,MAAa,iBAAiB"}
1
+ {"version":3,"file":"chunks-BerYVuve.mjs","names":[],"sources":["../src/utils/chunks.ts"],"sourcesContent":["/**\n * Split an array into chunks of at most `size` elements.\n *\n * Used to keep SQL `IN (?, ?, …)` clauses within Cloudflare D1's\n * bound-parameter limit (~100 per statement).\n */\nexport function chunks<T>(arr: T[], size: number): T[][] {\n\tif (arr.length === 0) return [];\n\tconst result: T[][] = [];\n\tfor (let i = 0; i < arr.length; i += size) {\n\t\tresult.push(arr.slice(i, i + size));\n\t}\n\treturn result;\n}\n\n/** Conservative default chunk size for SQL IN clauses (well within D1's limit). */\nexport const SQL_BATCH_SIZE = 50;\n"],"mappings":";;;;;;;;;;;;;AAMA,SAAgB,OAAU,KAAU,MAAqB;AACxD,KAAI,IAAI,WAAW,EAAG,QAAO,EAAE;CAC/B,MAAM,SAAgB,EAAE;AACxB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,KACpC,QAAO,KAAK,IAAI,MAAM,GAAG,IAAI,KAAK,CAAC;AAEpC,QAAO;;;AAIR,MAAa,iBAAiB"}
@@ -1,33 +1,33 @@
1
1
  #!/usr/bin/env node
2
- import { i as __exportAll, r as runMigrations, t as getMigrationStatus } from "../runner-BiuUfx-V.mjs";
2
+ import { a as __exportAll, i as runMigrations, n as getMigrationStatus } from "../runner--4wMWwKM.mjs";
3
3
  import { t as EmDashDatabaseError } from "../errors-9P_FDrJ_.mjs";
4
4
  import { t as validateIdentifier } from "../validate-VPnKoIzW.mjs";
5
5
  import { c as listTablesLike } from "../dialect-helpers-DRI5pyY3.mjs";
6
- import { r as isI18nEnabled } from "../config-CVssduLe.mjs";
6
+ import { n as getI18nConfig, r as isI18nEnabled } from "../config-CVssduLe.mjs";
7
7
  import { n as slugify } from "../slugify-Cjh1ssOZ.mjs";
8
- import { t as ContentRepository } from "../content-C7aJ7keg.mjs";
8
+ import { t as ContentRepository } from "../content-BIlVx-RX.mjs";
9
9
  import { i as encodeBase64url } from "../base64-CqR-7kqF.mjs";
10
- import "../types-CfyYQ7eY.mjs";
11
- import { t as MediaRepository } from "../media-Cyz5BhSN.mjs";
12
- import { t as TaxonomyRepository } from "../taxonomy-Db5xwphL.mjs";
13
- import { t as OptionsRepository } from "../options-BL4X94qY.mjs";
14
- import "../redirect-C-FeA4j9.mjs";
15
- import "../request-cache-BYMs-BGX.mjs";
16
- import "../byline-registry-CxK5g559.mjs";
17
- import { t as BylineRepository } from "../byline-CAhk4FrG.mjs";
10
+ import "../types-BXSUSAjt.mjs";
11
+ import { t as MediaRepository } from "../media-JOf3pNkw.mjs";
12
+ import { t as TaxonomyRepository } from "../taxonomy-CdllE4oq.mjs";
13
+ import { t as OptionsRepository } from "../options-BPCVnesz.mjs";
14
+ import "../redirect-CRWIt8Zj.mjs";
15
+ import "../request-cache-D32LpnmI.mjs";
16
+ import "../byline-registry-CWP7I71B.mjs";
17
+ import { t as BylineRepository } from "../byline-DUx48sJp.mjs";
18
18
  import { n as isMissingTableError } from "../db-errors-CtzxKBxe.mjs";
19
- import "../fts-manager-XpDfbIKo.mjs";
20
- import { n as SchemaRegistry } from "../registry-C-T_PWgp.mjs";
19
+ import "../fts-manager-1RgHmopc.mjs";
20
+ import { n as SchemaRegistry } from "../registry-brYh-rAT.mjs";
21
21
  import { kyselyLogOption } from "../database/instrumentation.mjs";
22
- import "../loader-BxyvbrZP.mjs";
23
- import "../settings-Jro4YcUb.mjs";
22
+ import "../loader-CpZKpFz0.mjs";
23
+ import "../settings-B1p-gPUK.mjs";
24
24
  import { i as pluginManifestSchema } from "../manifest-schema-Cj-YrzrF.mjs";
25
25
  import { n as isDeprecatedCapability, t as CAPABILITY_RENAMES } from "../types-Cj2S6FuC.mjs";
26
26
  import "../ssrf-BsVGIE0Z.mjs";
27
27
  import "../ssrf-BvgVcfNQ.mjs";
28
- import { t as validateSeed } from "../validate-DWmnRg6E.mjs";
29
- import { t as applySeed } from "../apply-BrVqULFe.mjs";
30
- import { n as fingerprintKey, r as generateEncryptionKey, t as EmDashSecretsError } from "../secrets-YYbTgB1w.mjs";
28
+ import { t as validateSeed } from "../validate-ZP9Dvg0P.mjs";
29
+ import { t as applySeed } from "../apply-hQkKKBCf.mjs";
30
+ import { n as fingerprintKey, r as generateEncryptionKey, t as EmDashSecretsError } from "../secrets-C_ZtRos3.mjs";
31
31
  import { LocalStorage } from "../storage/local.mjs";
32
32
  import { o as convertDataForRead } from "../transport--Ck3RBin.mjs";
33
33
  import { createHeaderAwareFetch, customHeadersInterceptor, getCachedAccessToken, isAccessRedirect, resolveCustomHeaders, runCloudflaredLogin } from "../client/cf-access.mjs";
@@ -1250,7 +1250,8 @@ async function exportSeed(db, withContent) {
1250
1250
  };
1251
1251
  seed.settings = await exportSettings(db);
1252
1252
  seed.collections = await exportCollections(db);
1253
- const i18nEnabled = await detectI18nEnabled(db, seed.collections);
1253
+ const { i18nEnabled, defaultLocale } = await detectLocaleInfo(db, seed.collections);
1254
+ if (defaultLocale) seed.defaultLocale = defaultLocale;
1254
1255
  seed.taxonomies = await exportTaxonomies(db, i18nEnabled);
1255
1256
  seed.menus = await exportMenus(db, i18nEnabled);
1256
1257
  seed.widgetAreas = await exportWidgetAreas(db);
@@ -1306,7 +1307,7 @@ async function exportBylines(db) {
1306
1307
  };
1307
1308
  }
1308
1309
  /**
1309
- * Determine whether the export should emit locale-suffixed seed ids.
1310
+ * Determine locale-awareness and the data's default locale for the export.
1310
1311
  *
1311
1312
  * The runtime initializes the i18n config in middleware, but the CLI never does,
1312
1313
  * so `isI18nEnabled()` is always false under `emdash export-seed` (#1330). When
@@ -1317,28 +1318,40 @@ async function exportBylines(db) {
1317
1318
  * genuinely single-locale project from a multi-locale one. This keeps
1318
1319
  * single-locale exports on bare ids and gives multi-locale exports the
1319
1320
  * per-locale suffix they need to avoid duplicate seed ids.
1321
+ *
1322
+ * `defaultLocale` self-describes the single-locale case so a non-`en` default
1323
+ * survives the round-trip (#1421). When more than one locale is present every
1324
+ * row already carries its own `locale`, so no fallback is needed and we leave it
1325
+ * undefined rather than guess which locale is the "default" without the runtime
1326
+ * config.
1320
1327
  */
1321
- async function detectI18nEnabled(db, collections) {
1322
- if (isI18nEnabled()) return true;
1328
+ async function detectLocaleInfo(db, collections) {
1329
+ const config = getI18nConfig();
1330
+ if (isI18nEnabled() && config) return {
1331
+ i18nEnabled: true,
1332
+ defaultLocale: config.defaultLocale
1333
+ };
1323
1334
  const locales = /* @__PURE__ */ new Set();
1324
1335
  const collectDistinctLocales = async (tableRef) => {
1325
1336
  const result = await sql`
1326
1337
  SELECT DISTINCT locale FROM ${tableRef}
1327
1338
  `.execute(db);
1328
1339
  for (const row of result.rows) if (row.locale) locales.add(row.locale);
1329
- return locales.size > 1;
1330
1340
  };
1331
- if (await collectDistinctLocales(sql.ref("_emdash_taxonomy_defs"))) return true;
1332
- if (await collectDistinctLocales(sql.ref("_emdash_menus"))) return true;
1341
+ await collectDistinctLocales(sql.ref("_emdash_taxonomy_defs"));
1342
+ await collectDistinctLocales(sql.ref("_emdash_menus"));
1333
1343
  for (const collection of collections) {
1334
1344
  validateIdentifier(collection.slug, "collection slug");
1335
1345
  try {
1336
- if (await collectDistinctLocales(sql.ref(`ec_${collection.slug}`))) return true;
1346
+ await collectDistinctLocales(sql.ref(`ec_${collection.slug}`));
1337
1347
  } catch (error) {
1338
1348
  if (!isMissingTableError(error)) throw error;
1339
1349
  }
1340
1350
  }
1341
- return false;
1351
+ return {
1352
+ i18nEnabled: locales.size > 1,
1353
+ defaultLocale: locales.size === 1 ? [...locales][0] : void 0
1354
+ };
1342
1355
  }
1343
1356
  /**
1344
1357
  * Export site settings