emdash 0.18.0 → 0.20.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 (528) hide show
  1. package/dist/{adapters-C5AWLJSD.d.mts → adapters-BzIHV3sw.d.mts} +1 -1
  2. package/dist/{adapters-C5AWLJSD.d.mts.map → adapters-BzIHV3sw.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-CyYLEJkp.mjs → allowed-origins-B1u7Qnvg.mjs} +2 -2
  4. package/dist/{allowed-origins-CyYLEJkp.mjs.map → allowed-origins-B1u7Qnvg.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +15 -15
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +3 -3
  9. package/dist/{api-Cs7DAACP.mjs → api-DStv36ik.mjs} +123 -20
  10. package/dist/api-DStv36ik.mjs.map +1 -0
  11. package/dist/{api-tokens-VrXNiNvV.mjs → api-tokens-DPfhPu5V.mjs} +2 -2
  12. package/dist/{api-tokens-VrXNiNvV.mjs.map → api-tokens-DPfhPu5V.mjs.map} +1 -1
  13. package/dist/{apply-BWMV4Zmw.mjs → apply-Dr7snAMT.mjs} +23 -23
  14. package/dist/apply-Dr7snAMT.mjs.map +1 -0
  15. package/dist/astro/index.d.mts +10 -10
  16. package/dist/astro/index.d.mts.map +1 -1
  17. package/dist/astro/index.mjs +115 -25
  18. package/dist/astro/index.mjs.map +1 -1
  19. package/dist/astro/middleware/auth.d.mts +9 -9
  20. package/dist/astro/middleware/auth.mjs +6 -6
  21. package/dist/astro/middleware/redirect.mjs +4 -4
  22. package/dist/astro/middleware/request-context.mjs +2 -2
  23. package/dist/astro/middleware/setup.mjs +1 -1
  24. package/dist/astro/middleware.d.mts +26 -4
  25. package/dist/astro/middleware.d.mts.map +1 -1
  26. package/dist/astro/middleware.mjs +242 -259
  27. package/dist/astro/middleware.mjs.map +1 -1
  28. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  29. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  30. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  31. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  32. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +5 -5
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +8 -8
  34. package/dist/astro/routes/api/admin/byline-fields/index.mjs +8 -8
  35. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +8 -8
  36. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +12 -12
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +12 -12
  38. package/dist/astro/routes/api/admin/bylines/index.mjs +12 -12
  39. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +11 -11
  40. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  41. package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
  42. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  43. package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
  44. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
  45. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
  46. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  47. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  48. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +34 -34
  49. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +34 -34
  50. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +33 -33
  51. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +33 -33
  52. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +33 -33
  53. package/dist/astro/routes/api/admin/plugins/index.mjs +33 -33
  54. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  55. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +33 -33
  56. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +33 -33
  57. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +33 -33
  58. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +33 -33
  59. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +34 -34
  60. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +33 -33
  61. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +34 -34
  62. package/dist/astro/routes/api/admin/plugins/updates.mjs +33 -33
  63. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +33 -33
  64. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  65. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +33 -33
  66. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
  67. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  68. package/dist/astro/routes/api/admin/users/_id_/index.mjs +6 -6
  69. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
  70. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  71. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  72. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  73. package/dist/astro/routes/api/auth/invite/complete.mjs +10 -10
  74. package/dist/astro/routes/api/auth/invite/index.mjs +7 -7
  75. package/dist/astro/routes/api/auth/invite/register-options.mjs +9 -9
  76. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  77. package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
  78. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  79. package/dist/astro/routes/api/auth/me.mjs +6 -6
  80. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  81. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +4 -4
  82. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  83. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  84. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  85. package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
  86. package/dist/astro/routes/api/auth/passkey/register/options.mjs +9 -9
  87. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +10 -10
  88. package/dist/astro/routes/api/auth/passkey/verify.mjs +10 -10
  89. package/dist/astro/routes/api/auth/signup/complete.mjs +10 -10
  90. package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
  91. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  92. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
  93. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  94. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -5
  95. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs.map +1 -1
  96. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  97. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  98. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +8 -8
  99. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +9 -8
  100. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs.map +1 -1
  101. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  102. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  103. package/dist/astro/routes/api/content/_collection_/_id_/schedule.d.mts.map +1 -1
  104. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +12 -10
  105. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs.map +1 -1
  106. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +11 -11
  107. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  108. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -5
  109. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs.map +1 -1
  110. package/dist/astro/routes/api/content/_collection_/_id_.mjs +9 -8
  111. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  112. package/dist/astro/routes/api/content/_collection_/authors.d.mts +8 -0
  113. package/dist/astro/routes/api/content/_collection_/authors.d.mts.map +1 -0
  114. package/dist/astro/routes/api/content/_collection_/authors.mjs +19 -0
  115. package/dist/astro/routes/api/content/_collection_/authors.mjs.map +1 -0
  116. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  117. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  118. package/dist/astro/routes/api/dashboard.mjs +7 -7
  119. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  120. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  121. package/dist/astro/routes/api/import/probe.mjs +6 -6
  122. package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
  123. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  124. package/dist/astro/routes/api/import/wordpress/execute.mjs +9 -9
  125. package/dist/astro/routes/api/import/wordpress/media.mjs +6 -6
  126. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  127. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
  128. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  129. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +6 -6
  130. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  131. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +9 -9
  132. package/dist/astro/routes/api/manifest.mjs +4 -4
  133. package/dist/astro/routes/api/mcp.mjs +29 -29
  134. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  135. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  136. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  137. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  138. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  139. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  140. package/dist/astro/routes/api/media/upload-url.mjs +7 -7
  141. package/dist/astro/routes/api/media.mjs +8 -8
  142. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
  143. package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
  144. package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
  145. package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
  146. package/dist/astro/routes/api/menus/_name_.mjs +7 -7
  147. package/dist/astro/routes/api/menus/index.mjs +7 -7
  148. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  149. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  150. package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
  151. package/dist/astro/routes/api/oauth/device/token.mjs +7 -7
  152. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  153. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  154. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  155. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  156. package/dist/astro/routes/api/openapi.json.mjs +17 -3
  157. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  158. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  159. package/dist/astro/routes/api/redirects/404s/index.mjs +9 -9
  160. package/dist/astro/routes/api/redirects/404s/summary.mjs +9 -9
  161. package/dist/astro/routes/api/redirects/_id_.mjs +10 -10
  162. package/dist/astro/routes/api/redirects/index.mjs +10 -10
  163. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  164. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  165. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +33 -33
  166. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +33 -33
  167. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +33 -33
  168. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +33 -33
  169. package/dist/astro/routes/api/schema/collections/index.mjs +33 -33
  170. package/dist/astro/routes/api/schema/index.mjs +9 -14
  171. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  172. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +33 -33
  173. package/dist/astro/routes/api/schema/orphans/index.mjs +33 -33
  174. package/dist/astro/routes/api/search/enable.mjs +9 -9
  175. package/dist/astro/routes/api/search/index.mjs +8 -8
  176. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  177. package/dist/astro/routes/api/search/stats.mjs +6 -6
  178. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  179. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  180. package/dist/astro/routes/api/sections/index.mjs +8 -8
  181. package/dist/astro/routes/api/settings/email.mjs +5 -5
  182. package/dist/astro/routes/api/settings.mjs +12 -12
  183. package/dist/astro/routes/api/setup/admin-verify.mjs +11 -11
  184. package/dist/astro/routes/api/setup/admin.mjs +10 -10
  185. package/dist/astro/routes/api/setup/dev-bypass.mjs +23 -23
  186. package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
  187. package/dist/astro/routes/api/setup/index.mjs +23 -23
  188. package/dist/astro/routes/api/setup/status.mjs +4 -4
  189. package/dist/astro/routes/api/snapshot.mjs +6 -6
  190. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +11 -11
  191. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +11 -11
  192. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +11 -11
  193. package/dist/astro/routes/api/taxonomies/index.mjs +11 -11
  194. package/dist/astro/routes/api/themes/preview.mjs +6 -6
  195. package/dist/astro/routes/api/typegen.mjs +5 -5
  196. package/dist/astro/routes/api/well-known/auth.mjs +2 -2
  197. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  198. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  199. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  200. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +9 -8
  201. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
  202. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +9 -8
  203. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
  204. package/dist/astro/routes/api/widget-areas/_name_.mjs +6 -5
  205. package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
  206. package/dist/astro/routes/api/widget-areas/index.mjs +9 -8
  207. package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
  208. package/dist/astro/routes/api/widget-components.mjs +3 -3
  209. package/dist/astro/routes/robots.txt.mjs +7 -7
  210. package/dist/astro/routes/sitemap-_collection_.xml.d.mts.map +1 -1
  211. package/dist/astro/routes/sitemap-_collection_.xml.mjs +16 -9
  212. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  213. package/dist/astro/routes/sitemap.xml.mjs +8 -8
  214. package/dist/astro/types.d.mts +19 -12
  215. package/dist/astro/types.d.mts.map +1 -1
  216. package/dist/auth/providers/github.d.mts +1 -1
  217. package/dist/auth/providers/google.d.mts +1 -1
  218. package/dist/{authorize-CotM4Yiu.mjs → authorize-DsMSVSaY.mjs} +2 -2
  219. package/dist/{authorize-CotM4Yiu.mjs.map → authorize-DsMSVSaY.mjs.map} +1 -1
  220. package/dist/{byline-CWQ9aSoz.mjs → byline-DUx48sJp.mjs} +6 -6
  221. package/dist/{byline-CWQ9aSoz.mjs.map → byline-DUx48sJp.mjs.map} +1 -1
  222. package/dist/{byline-fields-DC3Wkk-U.mjs → byline-fields--WxSNS79.mjs} +2 -2
  223. package/dist/{byline-fields-DC3Wkk-U.mjs.map → byline-fields--WxSNS79.mjs.map} +1 -1
  224. package/dist/{byline-fields-Dr-xcb6S.mjs → byline-fields-8TMtkBnH.mjs} +3 -3
  225. package/dist/{byline-fields-Dr-xcb6S.mjs.map → byline-fields-8TMtkBnH.mjs.map} +1 -1
  226. package/dist/{byline-fields-BNy7Ng1U.d.mts → byline-fields-DbibsvTl.d.mts} +30 -2
  227. package/dist/byline-fields-DbibsvTl.d.mts.map +1 -0
  228. package/dist/{byline-registry-CxK5g559.mjs → byline-registry-CWP7I71B.mjs} +3 -3
  229. package/dist/{byline-registry-CxK5g559.mjs.map → byline-registry-CWP7I71B.mjs.map} +1 -1
  230. package/dist/{bylines-LJMgENMI.mjs → bylines-BdxWCnPL.mjs} +3 -3
  231. package/dist/{bylines-LJMgENMI.mjs.map → bylines-BdxWCnPL.mjs.map} +1 -1
  232. package/dist/{bylines-BJSva1Un.mjs → bylines-s8c2DXbH.mjs} +50 -6
  233. package/dist/{bylines-BJSva1Un.mjs.map → bylines-s8c2DXbH.mjs.map} +1 -1
  234. package/dist/{cache-lZL7SgVb.mjs → cache-B_HzASVT.mjs} +3 -3
  235. package/dist/{cache-lZL7SgVb.mjs.map → cache-B_HzASVT.mjs.map} +1 -1
  236. package/dist/{challenge-store-DGwuCc4R.mjs → challenge-store-DXX3rfdI.mjs} +1 -1
  237. package/dist/{challenge-store-DGwuCc4R.mjs.map → challenge-store-DXX3rfdI.mjs.map} +1 -1
  238. package/dist/{chunks-BU-vP9Dh.mjs → chunks-BerYVuve.mjs} +2 -2
  239. package/dist/{chunks-BU-vP9Dh.mjs.map → chunks-BerYVuve.mjs.map} +1 -1
  240. package/dist/cli/index.mjs +46 -32
  241. package/dist/cli/index.mjs.map +1 -1
  242. package/dist/client/cf-access.d.mts +1 -1
  243. package/dist/client/index.d.mts +1 -1
  244. package/dist/client/index.mjs +1 -1
  245. package/dist/{comment-C4jVbCM8.mjs → comment-sqQxNpN3.mjs} +2 -2
  246. package/dist/{comment-C4jVbCM8.mjs.map → comment-sqQxNpN3.mjs.map} +1 -1
  247. package/dist/{comments-BTAbC0Ek.mjs → comments-Vkivawyl.mjs} +3 -3
  248. package/dist/{comments-BTAbC0Ek.mjs.map → comments-Vkivawyl.mjs.map} +1 -1
  249. package/dist/{components-CTfpu3PZ.mjs → components-CK0cuUoH.mjs} +1 -1
  250. package/dist/{components-CTfpu3PZ.mjs.map → components-CK0cuUoH.mjs.map} +1 -1
  251. package/dist/{content-CyqOmOzm.mjs → content-BIlVx-RX.mjs} +132 -43
  252. package/dist/content-BIlVx-RX.mjs.map +1 -0
  253. package/dist/{context-DZ7bEh5-.mjs → context-Y7BRkWes.mjs} +10 -10
  254. package/dist/{context-DZ7bEh5-.mjs.map → context-Y7BRkWes.mjs.map} +1 -1
  255. package/dist/{cron-DZovZUnC.mjs → cron-BJ2ClIlj.mjs} +4 -3
  256. package/dist/cron-BJ2ClIlj.mjs.map +1 -0
  257. package/dist/{dashboard-B5WQpNTP.mjs → dashboard-2JgAMWxK.mjs} +4 -4
  258. package/dist/{dashboard-B5WQpNTP.mjs.map → dashboard-2JgAMWxK.mjs.map} +1 -1
  259. package/dist/database/instrumentation.d.mts +10 -1
  260. package/dist/database/instrumentation.d.mts.map +1 -1
  261. package/dist/database/instrumentation.mjs +13 -1
  262. package/dist/database/instrumentation.mjs.map +1 -1
  263. package/dist/db/index.d.mts +3 -3
  264. package/dist/db/index.mjs +1 -1
  265. package/dist/db/libsql.d.mts +1 -1
  266. package/dist/db/postgres.d.mts +1 -1
  267. package/dist/db/sqlite.d.mts +1 -1
  268. package/dist/{default-xLFNSsZ9.mjs → default-IlBaTFxM.mjs} +1 -1
  269. package/dist/{default-xLFNSsZ9.mjs.map → default-IlBaTFxM.mjs.map} +1 -1
  270. package/dist/{device-flow-ptLrVINd.mjs → device-flow-R23SIbQ2.mjs} +5 -5
  271. package/dist/{device-flow-ptLrVINd.mjs.map → device-flow-R23SIbQ2.mjs.map} +1 -1
  272. package/dist/{error-DJOsMVSt.mjs → error-RwM4dD35.mjs} +2 -2
  273. package/dist/{error-DJOsMVSt.mjs.map → error-RwM4dD35.mjs.map} +1 -1
  274. package/dist/{escape-bIyGoW5W.mjs → escape-Ds07EEyu.mjs} +1 -1
  275. package/dist/{escape-bIyGoW5W.mjs.map → escape-Ds07EEyu.mjs.map} +1 -1
  276. package/dist/{fts-manager-DR1ERA0c.mjs → fts-manager-1RgHmopc.mjs} +2 -2
  277. package/dist/{fts-manager-DR1ERA0c.mjs.map → fts-manager-1RgHmopc.mjs.map} +1 -1
  278. package/dist/{index-CjKdMZ3U.d.mts → index-B1keaX5Y.d.mts} +237 -24
  279. package/dist/index-B1keaX5Y.d.mts.map +1 -0
  280. package/dist/{index-D60_SzHG.d.mts → index-DR56od45.d.mts} +3 -3
  281. package/dist/{index-D60_SzHG.d.mts.map → index-DR56od45.d.mts.map} +1 -1
  282. package/dist/index.d.mts +17 -17
  283. package/dist/index.mjs +46 -46
  284. package/dist/{load-6ZrRhepW.mjs → load-BBetCvLC.mjs} +2 -2
  285. package/dist/{load-6ZrRhepW.mjs.map → load-BBetCvLC.mjs.map} +1 -1
  286. package/dist/{loader-Dyx8dhFV.mjs → loader-ZN1ll-d-.mjs} +36 -37
  287. package/dist/loader-ZN1ll-d-.mjs.map +1 -0
  288. package/dist/{manifest-schema-Cj-YrzrF.mjs → manifest-schema-BtwbL_vj.mjs} +55 -2
  289. package/dist/manifest-schema-BtwbL_vj.mjs.map +1 -0
  290. package/dist/media/index.d.mts +1 -1
  291. package/dist/media/index.mjs +1 -1
  292. package/dist/media/local-runtime.d.mts +11 -11
  293. package/dist/media/local-runtime.mjs +6 -6
  294. package/dist/{media-C-oovGCG.mjs → media-JOf3pNkw.mjs} +2 -2
  295. package/dist/{media-C-oovGCG.mjs.map → media-JOf3pNkw.mjs.map} +1 -1
  296. package/dist/{media-allowlist-CMcoYIjQ.mjs → media-allowlist-Dknq-OFY.mjs} +1 -1
  297. package/dist/{media-allowlist-CMcoYIjQ.mjs.map → media-allowlist-Dknq-OFY.mjs.map} +1 -1
  298. package/dist/media-url-VClf8glU.mjs +26 -0
  299. package/dist/media-url-VClf8glU.mjs.map +1 -0
  300. package/dist/{menus-DugoYwTX.mjs → menus-DX4_E01q.mjs} +3 -3
  301. package/dist/{menus-DugoYwTX.mjs.map → menus-DX4_E01q.mjs.map} +1 -1
  302. package/dist/{menus-BKkxXCmd.mjs → menus-DrQLusqj.mjs} +87 -37
  303. package/dist/menus-DrQLusqj.mjs.map +1 -0
  304. package/dist/{mode-BjlXswIw.mjs → mode-CO2vQHfq.mjs} +1 -1
  305. package/dist/{mode-BjlXswIw.mjs.map → mode-CO2vQHfq.mjs.map} +1 -1
  306. package/dist/{normalize-DVV8nbrL.mjs → normalize-CK5o04zr.mjs} +2 -2
  307. package/dist/{normalize-DVV8nbrL.mjs.map → normalize-CK5o04zr.mjs.map} +1 -1
  308. package/dist/{oauth-authorization-DvBAL75d.mjs → oauth-authorization-Bw4NdF_S.mjs} +5 -5
  309. package/dist/{oauth-authorization-DvBAL75d.mjs.map → oauth-authorization-Bw4NdF_S.mjs.map} +1 -1
  310. package/dist/{oauth-clients-8mPDStMv.mjs → oauth-clients-BGGFp57s.mjs} +1 -1
  311. package/dist/{oauth-clients-8mPDStMv.mjs.map → oauth-clients-BGGFp57s.mjs.map} +1 -1
  312. package/dist/{oauth-state-store-BJ7YtrfD.mjs → oauth-state-store-97x0xtN2.mjs} +1 -1
  313. package/dist/{oauth-state-store-BJ7YtrfD.mjs.map → oauth-state-store-97x0xtN2.mjs.map} +1 -1
  314. package/dist/{oauth-user-lookup-BdDSDvjF.mjs → oauth-user-lookup-B_vnZHKO.mjs} +1 -1
  315. package/dist/{oauth-user-lookup-BdDSDvjF.mjs.map → oauth-user-lookup-B_vnZHKO.mjs.map} +1 -1
  316. package/dist/{options-BL4X94qY.mjs → options-BPCVnesz.mjs} +1 -1
  317. package/dist/{options-BL4X94qY.mjs.map → options-BPCVnesz.mjs.map} +1 -1
  318. package/dist/{options-tb7DJROi.d.mts → options-DyYIYpPd.d.mts} +3 -3
  319. package/dist/{options-tb7DJROi.d.mts.map → options-DyYIYpPd.d.mts.map} +1 -1
  320. package/dist/page/index.d.mts +2 -2
  321. package/dist/{parse-BBkFmLVr.mjs → parse-CrGndy1A.mjs} +2 -2
  322. package/dist/{parse-BBkFmLVr.mjs.map → parse-CrGndy1A.mjs.map} +1 -1
  323. package/dist/{passkey-config-BDVM86Tj.mjs → passkey-config-C3QgnQnU.mjs} +1 -1
  324. package/dist/{passkey-config-BDVM86Tj.mjs.map → passkey-config-C3QgnQnU.mjs.map} +1 -1
  325. package/dist/{patterns-CqG5Ya3i.mjs → patterns-p-RBdTbM.mjs} +1 -1
  326. package/dist/{patterns-CqG5Ya3i.mjs.map → patterns-p-RBdTbM.mjs.map} +1 -1
  327. package/dist/{placeholder-B9lUUEmj.d.mts → placeholder-CVBv5z8k.d.mts} +1 -1
  328. package/dist/{placeholder-B9lUUEmj.d.mts.map → placeholder-CVBv5z8k.d.mts.map} +1 -1
  329. package/dist/plugin-types.d.mts +1 -1
  330. package/dist/plugin-utils.d.mts +9 -9
  331. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  332. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  333. package/dist/{public-url-egRHCy1m.mjs → public-url-BFVC2OTJ.mjs} +1 -1
  334. package/dist/{public-url-egRHCy1m.mjs.map → public-url-BFVC2OTJ.mjs.map} +1 -1
  335. package/dist/{query-Ctlq1aOk.mjs → query-CbUcI4Xk.mjs} +33 -17
  336. package/dist/query-CbUcI4Xk.mjs.map +1 -0
  337. package/dist/{rate-limit-CH6W6ikK.mjs → rate-limit-C7hjdkS5.mjs} +2 -2
  338. package/dist/{rate-limit-CH6W6ikK.mjs.map → rate-limit-C7hjdkS5.mjs.map} +1 -1
  339. package/dist/{redirect-Cw3JTlmj.mjs → redirect-B_q19j4v.mjs} +1 -1
  340. package/dist/{redirect-Cw3JTlmj.mjs.map → redirect-B_q19j4v.mjs.map} +1 -1
  341. package/dist/{redirect-C6tJA7tk.mjs → redirect-CRWIt8Zj.mjs} +3 -3
  342. package/dist/{redirect-C6tJA7tk.mjs.map → redirect-CRWIt8Zj.mjs.map} +1 -1
  343. package/dist/{redirects-C0L9JUk4.mjs → redirects-CCbCqCCd.mjs} +28 -4
  344. package/dist/redirects-CCbCqCCd.mjs.map +1 -0
  345. package/dist/{redirects-CacE9eQa.mjs → redirects-DxVoR7PI.mjs} +5 -5
  346. package/dist/{redirects-CacE9eQa.mjs.map → redirects-DxVoR7PI.mjs.map} +1 -1
  347. package/dist/{registry-CIDxZbhh.mjs → registry-brYh-rAT.mjs} +6 -6
  348. package/dist/{registry-CIDxZbhh.mjs.map → registry-brYh-rAT.mjs.map} +1 -1
  349. package/dist/{request-cache-BYMs-BGX.mjs → request-cache-D32LpnmI.mjs} +1 -1
  350. package/dist/{request-cache-BYMs-BGX.mjs.map → request-cache-D32LpnmI.mjs.map} +1 -1
  351. package/dist/request-context.d.mts +7 -0
  352. package/dist/request-context.d.mts.map +1 -1
  353. package/dist/request-context.mjs +2 -1
  354. package/dist/request-context.mjs.map +1 -1
  355. package/dist/{runner-pt6Wl-l-.mjs → runner--4wMWwKM.mjs} +217 -166
  356. package/dist/runner--4wMWwKM.mjs.map +1 -0
  357. package/dist/{runner-DM1yR5qd.d.mts → runner-DTdhuI9i.d.mts} +2 -2
  358. package/dist/{runner-DM1yR5qd.d.mts.map → runner-DTdhuI9i.d.mts.map} +1 -1
  359. package/dist/runtime.d.mts +10 -10
  360. package/dist/runtime.mjs +2 -2
  361. package/dist/{schema-B4tk0HAG.mjs → schema-C1E70ug_.mjs} +5 -5
  362. package/dist/{schema-B4tk0HAG.mjs.map → schema-C1E70ug_.mjs.map} +1 -1
  363. package/dist/{search-f-fNfwab.mjs → search-B3SGZw91.mjs} +4 -4
  364. package/dist/{search-f-fNfwab.mjs.map → search-B3SGZw91.mjs.map} +1 -1
  365. package/dist/{secrets-YYbTgB1w.mjs → secrets-ChPTmy9x.mjs} +2 -2
  366. package/dist/{secrets-YYbTgB1w.mjs.map → secrets-ChPTmy9x.mjs.map} +1 -1
  367. package/dist/{sections-biElLfT9.mjs → sections-D_lVzwRZ.mjs} +3 -3
  368. package/dist/{sections-biElLfT9.mjs.map → sections-D_lVzwRZ.mjs.map} +1 -1
  369. package/dist/seed/index.d.mts +2 -2
  370. package/dist/seed/index.mjs +17 -17
  371. package/dist/seo/index.d.mts +1 -1
  372. package/dist/seo/index.d.mts.map +1 -1
  373. package/dist/seo/index.mjs +3 -12
  374. package/dist/seo/index.mjs.map +1 -1
  375. package/dist/{seo-BR39kvTF.mjs → seo-B5e6y9Wk.mjs} +2 -2
  376. package/dist/{seo-BR39kvTF.mjs.map → seo-B5e6y9Wk.mjs.map} +1 -1
  377. package/dist/{seo-DfjLvu8i.mjs → seo-D_LPkOtu.mjs} +4 -3
  378. package/dist/seo-D_LPkOtu.mjs.map +1 -0
  379. package/dist/{service-BhR2acnc.mjs → service-ChDcsTBs.mjs} +3 -3
  380. package/dist/{service-BhR2acnc.mjs.map → service-ChDcsTBs.mjs.map} +1 -1
  381. package/dist/{settings-D_NJvjgN.mjs → settings-Cv47v9u8.mjs} +3 -3
  382. package/dist/{settings-D_NJvjgN.mjs.map → settings-Cv47v9u8.mjs.map} +1 -1
  383. package/dist/settings-DfxiWY_s.mjs +411 -0
  384. package/dist/settings-DfxiWY_s.mjs.map +1 -0
  385. package/dist/{setup-complete-VoEZfasi.mjs → setup-complete-yvPE4OsP.mjs} +2 -2
  386. package/dist/{setup-complete-VoEZfasi.mjs.map → setup-complete-yvPE4OsP.mjs.map} +1 -1
  387. package/dist/{setup-nonce-Bm0uKqmf.mjs → setup-nonce-C9aFzb94.mjs} +1 -1
  388. package/dist/{setup-nonce-Bm0uKqmf.mjs.map → setup-nonce-C9aFzb94.mjs.map} +1 -1
  389. package/dist/{site-url-Cm8-sJy7.mjs → site-url-CnHlmAs9.mjs} +2 -2
  390. package/dist/{site-url-Cm8-sJy7.mjs.map → site-url-CnHlmAs9.mjs.map} +1 -1
  391. package/dist/storage/local.d.mts +1 -1
  392. package/dist/storage/s3.d.mts +1 -1
  393. package/dist/{taxonomies-Mhn9rjTQ.mjs → taxonomies-BILwiyGk.mjs} +4 -4
  394. package/dist/{taxonomies-Mhn9rjTQ.mjs.map → taxonomies-BILwiyGk.mjs.map} +1 -1
  395. package/dist/{taxonomies-Crtzy4MT.mjs → taxonomies-BdAmbOwx.mjs} +50 -12
  396. package/dist/taxonomies-BdAmbOwx.mjs.map +1 -0
  397. package/dist/{taxonomy-DTZrIQpi.mjs → taxonomy-CdllE4oq.mjs} +3 -3
  398. package/dist/{taxonomy-DTZrIQpi.mjs.map → taxonomy-CdllE4oq.mjs.map} +1 -1
  399. package/dist/{transaction-NQj4VJ7Z.mjs → transaction-x2tJQ-A1.mjs} +1 -1
  400. package/dist/{transaction-NQj4VJ7Z.mjs.map → transaction-x2tJQ-A1.mjs.map} +1 -1
  401. package/dist/{transport-OnMNbsIA.d.mts → transport-B7PPP2CC.d.mts} +1 -1
  402. package/dist/{transport-OnMNbsIA.d.mts.map → transport-B7PPP2CC.d.mts.map} +1 -1
  403. package/dist/{transport--Ck3RBin.mjs → transport-CmpLD7W3.mjs} +1 -1
  404. package/dist/{transport--Ck3RBin.mjs.map → transport-CmpLD7W3.mjs.map} +1 -1
  405. package/dist/{types-DWnN7weG.d.mts → types-BFgrqwSk.d.mts} +1 -1
  406. package/dist/{types-DWnN7weG.d.mts.map → types-BFgrqwSk.d.mts.map} +1 -1
  407. package/dist/{types-Qa7-HJJC.d.mts → types-BH8-30hc.d.mts} +1 -1
  408. package/dist/{types-Qa7-HJJC.d.mts.map → types-BH8-30hc.d.mts.map} +1 -1
  409. package/dist/{types-DawhLFwy.d.mts → types-BPzXTV9x.d.mts} +26 -1
  410. package/dist/{types-DawhLFwy.d.mts.map → types-BPzXTV9x.d.mts.map} +1 -1
  411. package/dist/{types-DbCWhHet.d.mts → types-BUUVn1zr.d.mts} +2 -2
  412. package/dist/types-BUUVn1zr.d.mts.map +1 -0
  413. package/dist/{types-K3MDsxpy.mjs → types-BXSUSAjt.mjs} +16 -3
  414. package/dist/{types-K3MDsxpy.mjs.map → types-BXSUSAjt.mjs.map} +1 -1
  415. package/dist/{types-DMwSpvcw.d.mts → types-CPAPl93j.d.mts} +9 -3
  416. package/dist/{types-DMwSpvcw.d.mts.map → types-CPAPl93j.d.mts.map} +1 -1
  417. package/dist/types-CZI4E3qG.mjs +3 -0
  418. package/dist/{types-kwqCOUxj.d.mts → types-D4kUqbHh.d.mts} +1 -1
  419. package/dist/{types-kwqCOUxj.d.mts.map → types-D4kUqbHh.d.mts.map} +1 -1
  420. package/dist/{types-i8_uzhMD.d.mts → types-DTniiNto.d.mts} +19 -4
  421. package/dist/types-DTniiNto.d.mts.map +1 -0
  422. package/dist/{types-D8bhH891.mjs → types-DZk_y-MU.mjs} +1 -1
  423. package/dist/types-DZk_y-MU.mjs.map +1 -0
  424. package/dist/{types-DX6v9KzJ.d.mts → types-S15DXXNi.d.mts} +1 -1
  425. package/dist/{types-DX6v9KzJ.d.mts.map → types-S15DXXNi.d.mts.map} +1 -1
  426. package/dist/{user-DzEUl5zA.mjs → user-C0um7wrg.mjs} +18 -2
  427. package/dist/user-C0um7wrg.mjs.map +1 -0
  428. package/dist/{validate-JCXcsqiY.mjs → validate-Bz4vqcX1.mjs} +6 -3
  429. package/dist/validate-Bz4vqcX1.mjs.map +1 -0
  430. package/dist/{validate-Dy6nkNls.d.mts → validate-CNwkPWzz.d.mts} +13 -5
  431. package/dist/validate-CNwkPWzz.d.mts.map +1 -0
  432. package/dist/{validation-Bq-VyKJg.mjs → validation-DgGTJm3u.mjs} +5 -5
  433. package/dist/{validation-Bq-VyKJg.mjs.map → validation-DgGTJm3u.mjs.map} +1 -1
  434. package/dist/version-D-5txk2m.mjs +7 -0
  435. package/dist/{version-CnS-Cr8A.mjs.map → version-D-5txk2m.mjs.map} +1 -1
  436. package/dist/{widgets-Bap1eS1X.mjs → widgets-DZfmAbE4.mjs} +47 -44
  437. package/dist/widgets-DZfmAbE4.mjs.map +1 -0
  438. package/dist/{zod-generator-BSDpkqSH.mjs → zod-generator-Djo_VHCt.mjs} +2 -2
  439. package/dist/{zod-generator-BSDpkqSH.mjs.map → zod-generator-Djo_VHCt.mjs.map} +1 -1
  440. package/package.json +10 -10
  441. package/src/api/handlers/content.ts +107 -8
  442. package/src/api/handlers/index.ts +2 -0
  443. package/src/api/handlers/marketplace.ts +2 -5
  444. package/src/api/handlers/registry.ts +70 -0
  445. package/src/api/handlers/seo.ts +9 -1
  446. package/src/api/openapi/document.ts +25 -0
  447. package/src/api/schemas/content.ts +33 -0
  448. package/src/api/schemas/schema.ts +13 -1
  449. package/src/astro/integration/index.ts +98 -0
  450. package/src/astro/integration/routes.ts +6 -0
  451. package/src/astro/integration/virtual-modules.ts +39 -0
  452. package/src/astro/integration/vite-config.ts +12 -0
  453. package/src/astro/middleware.ts +48 -6
  454. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  455. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +4 -2
  456. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +8 -4
  457. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +4 -2
  458. package/src/astro/routes/api/content/[collection]/[id].ts +4 -2
  459. package/src/astro/routes/api/content/[collection]/authors.ts +34 -0
  460. package/src/astro/routes/api/schema/index.ts +7 -15
  461. package/src/astro/routes/sitemap-[collection].xml.ts +13 -2
  462. package/src/astro/types.ts +8 -1
  463. package/src/bylines/index.ts +57 -0
  464. package/src/cli/commands/bundle-utils.ts +2 -0
  465. package/src/cli/commands/export-seed.ts +28 -12
  466. package/src/cli/commands/secrets.ts +2 -2
  467. package/src/components/EmDashImage.astro +22 -4
  468. package/src/components/Image.astro +20 -3
  469. package/src/database/instrumentation.ts +13 -0
  470. package/src/database/migrations/043_content_references.ts +121 -0
  471. package/src/database/migrations/runner.ts +2 -0
  472. package/src/database/repositories/content.ts +225 -67
  473. package/src/database/repositories/index.ts +7 -0
  474. package/src/database/repositories/relation.ts +467 -0
  475. package/src/database/repositories/types.ts +31 -0
  476. package/src/database/repositories/user.ts +18 -0
  477. package/src/database/types.ts +34 -0
  478. package/src/emdash-runtime.ts +172 -67
  479. package/src/index.ts +8 -1
  480. package/src/loader.ts +81 -39
  481. package/src/media/responsive.ts +125 -0
  482. package/src/plugins/cron.ts +3 -2
  483. package/src/plugins/index.ts +5 -0
  484. package/src/plugins/manifest-schema.ts +75 -0
  485. package/src/plugins/marketplace.ts +2 -5
  486. package/src/plugins/scheduler/node.ts +9 -2
  487. package/src/plugins/types.ts +12 -0
  488. package/src/query.ts +45 -7
  489. package/src/request-context.ts +8 -0
  490. package/src/scheduled-publish.ts +153 -0
  491. package/src/schema/types.ts +11 -1
  492. package/src/seed/apply.ts +16 -6
  493. package/src/seed/types.ts +9 -0
  494. package/src/seed/validate.ts +15 -0
  495. package/src/seo/index.ts +2 -28
  496. package/src/seo/media-url.ts +32 -0
  497. package/src/settings/index.ts +32 -40
  498. package/src/taxonomies/index.ts +79 -12
  499. package/src/utils/isolate-cache.ts +189 -0
  500. package/src/virtual-modules.d.ts +11 -0
  501. package/src/widgets/index.ts +57 -54
  502. package/dist/api-Cs7DAACP.mjs.map +0 -1
  503. package/dist/apply-BWMV4Zmw.mjs.map +0 -1
  504. package/dist/byline-fields-BNy7Ng1U.d.mts.map +0 -1
  505. package/dist/content-CyqOmOzm.mjs.map +0 -1
  506. package/dist/cron-DZovZUnC.mjs.map +0 -1
  507. package/dist/index-CjKdMZ3U.d.mts.map +0 -1
  508. package/dist/loader-Dyx8dhFV.mjs.map +0 -1
  509. package/dist/manifest-schema-Cj-YrzrF.mjs.map +0 -1
  510. package/dist/menus-BKkxXCmd.mjs.map +0 -1
  511. package/dist/query-Ctlq1aOk.mjs.map +0 -1
  512. package/dist/redirects-C0L9JUk4.mjs.map +0 -1
  513. package/dist/runner-pt6Wl-l-.mjs.map +0 -1
  514. package/dist/seo-DfjLvu8i.mjs.map +0 -1
  515. package/dist/settings-b5zW1R1T.mjs +0 -235
  516. package/dist/settings-b5zW1R1T.mjs.map +0 -1
  517. package/dist/taxonomies-Crtzy4MT.mjs.map +0 -1
  518. package/dist/types-Cj2S6FuC.mjs +0 -3
  519. package/dist/types-D8bhH891.mjs.map +0 -1
  520. package/dist/types-DbCWhHet.d.mts.map +0 -1
  521. package/dist/types-i8_uzhMD.d.mts.map +0 -1
  522. package/dist/user-DzEUl5zA.mjs.map +0 -1
  523. package/dist/validate-Dy6nkNls.d.mts.map +0 -1
  524. package/dist/validate-JCXcsqiY.mjs.map +0 -1
  525. package/dist/version-CnS-Cr8A.mjs +0 -7
  526. package/dist/widgets-Bap1eS1X.mjs.map +0 -1
  527. package/src/plugins/scheduler/piggyback.ts +0 -71
  528. /package/dist/{api-tokens-B6VgoE6M.mjs → api-tokens-Oq39ba-Z.mjs} +0 -0
@@ -24,7 +24,10 @@ import { isSqlite } from "./database/dialect-helpers.js";
24
24
  import { kyselyLogOption } from "./database/instrumentation.js";
25
25
  import { MIGRATION_RACE_WAIT_MS, runMigrations } from "./database/migrations/runner.js";
26
26
  import { RevisionRepository } from "./database/repositories/revision.js";
27
- import type { ContentItem as ContentItemInternal } from "./database/repositories/types.js";
27
+ import type {
28
+ ContentItem as ContentItemInternal,
29
+ ContentDateField,
30
+ } from "./database/repositories/types.js";
28
31
  import { validateIdentifier } from "./database/validate.js";
29
32
  import { normalizeMediaValue } from "./media/normalize.js";
30
33
  import type { MediaProvider, MediaProviderCapabilities } from "./media/types.js";
@@ -42,6 +45,7 @@ import type {
42
45
  import type { FieldType } from "./schema/types.js";
43
46
  import { hashString } from "./utils/hash.js";
44
47
  import { createInitLock, type InitLock, initWithLock } from "./utils/init-lock.js";
48
+ import { createIsolateCache, isolateCachedAsync } from "./utils/isolate-cache.js";
45
49
  import { COMMIT, VERSION } from "./version.js";
46
50
 
47
51
  const LEADING_SLASH_PATTERN = /^\//;
@@ -115,6 +119,7 @@ import { validateEncryptionKeyAtStartup } from "./config/secrets.js";
115
119
  import { OptionsRepository } from "./database/repositories/options.js";
116
120
  import {
117
121
  handleContentList,
122
+ handleContentAuthors,
118
123
  handleContentGet,
119
124
  handleContentGetIncludingTrashed,
120
125
  handleContentCreate,
@@ -158,13 +163,12 @@ import {
158
163
  import { normalizeManifestRoute } from "./plugins/manifest-schema.js";
159
164
  import { extractRequestMeta, sanitizeHeadersForSandbox } from "./plugins/request-meta.js";
160
165
  import { PluginRouteRegistry, type RouteMeta } from "./plugins/routes.js";
161
- import { NodeCronScheduler } from "./plugins/scheduler/node.js";
162
- import { PiggybackScheduler } from "./plugins/scheduler/piggyback.js";
163
166
  import type { CronScheduler } from "./plugins/scheduler/types.js";
164
167
  import { PluginStateRepository } from "./plugins/state.js";
165
168
  import { normalizeRegistryConfig } from "./registry/config.js";
166
169
  import { requestCached } from "./request-cache.js";
167
170
  import { getRequestContext } from "./request-context.js";
171
+ import { publishDueContent, type PublishedRef } from "./scheduled-publish.js";
168
172
  import { FTSManager } from "./search/fts-manager.js";
169
173
  import { invalidateSiteSettingsCache } from "./settings/index.js";
170
174
 
@@ -237,6 +241,13 @@ export interface MediaProviderContext {
237
241
  storage: Storage | null;
238
242
  }
239
243
 
244
+ /**
245
+ * Builds the timer-based scheduler that drives cron ticks and maintenance.
246
+ * Injected via `virtual:emdash/scheduler` so the platform — not core — decides
247
+ * whether a long-lived heartbeat exists.
248
+ */
249
+ export type CreateSchedulerFn = (executor: CronExecutor) => CronScheduler;
250
+
240
251
  /**
241
252
  * Dependencies injected from virtual modules (middleware reads these)
242
253
  */
@@ -250,6 +261,16 @@ export interface RuntimeDependencies {
250
261
  sandboxEnabled: boolean;
251
262
  /** sandbox: false escape hatch - load sandboxed plugins in-process */
252
263
  sandboxBypassed?: boolean;
264
+ /**
265
+ * Factory for the timer-based cron/maintenance heartbeat. Supplied by the
266
+ * generated `virtual:emdash/scheduler` module: a `NodeCronScheduler` factory
267
+ * on long-lived runtimes (Node/Bun), or `null` on serverless adapters where
268
+ * an external driver (e.g. the Cloudflare Worker's `scheduled()` Cron
269
+ * Trigger) calls `runScheduledTasks()` instead. When absent or null, the
270
+ * runtime starts no scheduler. Keeping the platform decision in the
271
+ * integration means core has no adapter-specific runtime checks.
272
+ */
273
+ createScheduler?: CreateSchedulerFn | null;
253
274
  /** Media provider entries from virtual module */
254
275
  mediaProviderEntries?: MediaProviderEntry[];
255
276
  sandboxedPluginEntries: SandboxedPluginEntry[];
@@ -397,12 +418,12 @@ export class EmDashRuntime {
397
418
  private pluginStates: Map<string, string>;
398
419
 
399
420
  /**
400
- * Set to true after FTS indexes have been verified for this worker
401
- * lifetime so we don't re-scan on every admin request. See
402
- * ensureSearchHealthy().
421
+ * Isolate-lifetime guard so FTS indexes are verified at most once per
422
+ * worker rather than on every admin request. See ensureSearchHealthy().
423
+ * Uses the poison-immune isolate cache (never a shared awaitable promise)
424
+ * so a cancelled first caller can't wedge later ones.
403
425
  */
404
- private _searchHealthChecked = false;
405
- private _searchHealthPromise: Promise<void> | null = null;
426
+ private readonly _searchHealthCache = createIsolateCache<void>();
406
427
 
407
428
  /** Current hook pipeline. Use the `hooks` getter for external access. */
408
429
  get hooks(): HookPipeline {
@@ -479,14 +500,65 @@ export class EmDashRuntime {
479
500
  }
480
501
 
481
502
  /**
482
- * Tick the cron system from request context (piggyback mode).
483
- * Call this from middleware on each request to ensure cron tasks
484
- * execute even when no dedicated scheduler is available.
503
+ * Publish any content whose scheduled time has passed.
504
+ * Returns the items promoted so callers can invalidate their cache tags.
505
+ */
506
+ async publishScheduled(): Promise<PublishedRef[]> {
507
+ return publishDueContent(this.db, {
508
+ publish: (collection, id, options) => this.handleContentPublish(collection, id, options),
509
+ });
510
+ }
511
+
512
+ /**
513
+ * Run the full scheduled-maintenance batch: cron tasks, scheduled
514
+ * publishing, and system cleanup. For request-less drivers — the
515
+ * Cloudflare `scheduled()` handler invokes this from a Cron Trigger.
516
+ * (On Node the timer-based scheduler drives the same work itself.)
517
+ *
518
+ * Each step is independent and non-fatal. Returns the content promoted
519
+ * by the publishing sweep so the caller can purge edge-cache tags.
520
+ *
521
+ * `onPublished` (optional) is awaited after each collection's batch so a
522
+ * request-less driver can invalidate edge-cache tags incrementally rather
523
+ * than only after the whole sweep — bounding stale-cache exposure if the
524
+ * runtime is killed mid-sweep.
485
525
  */
486
- tickCron(): void {
487
- if (this.cronScheduler instanceof PiggybackScheduler) {
488
- this.cronScheduler.onRequest();
526
+ async runScheduledTasks(
527
+ options: {
528
+ onPublished?: (refs: PublishedRef[]) => Promise<void>;
529
+ } = {},
530
+ ): Promise<{ published: PublishedRef[] }> {
531
+ if (this.cronExecutor) {
532
+ try {
533
+ await this.cronExecutor.tick();
534
+ } catch (error) {
535
+ console.error("[cron] Tick failed:", error);
536
+ }
537
+ try {
538
+ await this.cronExecutor.recoverStaleLocks();
539
+ } catch (error) {
540
+ console.error("[cron] Stale lock recovery failed:", error);
541
+ }
542
+ }
543
+
544
+ let published: PublishedRef[] = [];
545
+ try {
546
+ // Route through the runtime wrapper so content:afterPublish hooks fire.
547
+ published = await publishDueContent(this.db, {
548
+ publish: (collection, id, opts) => this.handleContentPublish(collection, id, opts),
549
+ onPublished: options.onPublished,
550
+ });
551
+ } catch (error) {
552
+ console.error("[scheduled-publish] Sweep failed:", error);
489
553
  }
554
+
555
+ try {
556
+ await runSystemCleanup(this.db, this.storage ?? undefined);
557
+ } catch (error) {
558
+ console.error("[cleanup] System cleanup failed:", error);
559
+ }
560
+
561
+ return { published };
490
562
  }
491
563
 
492
564
  /**
@@ -1173,6 +1245,11 @@ export class EmDashRuntime {
1173
1245
 
1174
1246
  let cronExecutor: CronExecutor | null = null;
1175
1247
  let cronScheduler: CronScheduler | null = null;
1248
+ // Populated with the constructed runtime just before this method returns,
1249
+ // so the timer scheduler's cleanup can route scheduled publishing through
1250
+ // the runtime wrapper (firing content:afterPublish hooks). The first tick
1251
+ // is ≥1s out, well after the synchronous assignment below.
1252
+ const runtimeRef: { current: EmDashRuntime | null } = { current: null };
1176
1253
 
1177
1254
  await phase("rt.cron", "Cron init (recovery deferred post-response)", async () => {
1178
1255
  try {
@@ -1198,46 +1275,57 @@ export class EmDashRuntime {
1198
1275
  }
1199
1276
  });
1200
1277
 
1201
- // Detect platform and create appropriate scheduler.
1202
- // On Cloudflare Workers, setTimeout is available but unreliable for
1203
- // long durations use PiggybackScheduler as default.
1204
- // In Node/Bun, use NodeCronScheduler with real timers.
1205
- const isWorkersRuntime =
1206
- typeof globalThis.navigator !== "undefined" &&
1207
- globalThis.navigator.userAgent === "Cloudflare-Workers";
1208
-
1209
- if (isWorkersRuntime) {
1210
- cronScheduler = new PiggybackScheduler(cronExecutor);
1211
- } else {
1212
- cronScheduler = new NodeCronScheduler(cronExecutor);
1213
- }
1214
-
1215
- // Register system cleanup to run alongside each scheduler tick.
1216
- // Pass storage so cleanupPendingUploads can delete orphaned files.
1217
- cronScheduler.setSystemCleanup(async () => {
1218
- try {
1219
- await runSystemCleanup(db, storage ?? undefined);
1220
- } catch (error) {
1221
- // Non-fatal -- individual cleanup failures are already logged
1222
- // by runSystemCleanup. This catches unexpected errors.
1223
- console.error("[cleanup] System cleanup failed:", error);
1224
- }
1225
- });
1278
+ // The platform decides whether a long-lived timer heartbeat exists.
1279
+ // `createScheduler` is injected by the generated virtual:emdash/scheduler
1280
+ // module: a NodeCronScheduler factory on Node/Bun, or null on serverless
1281
+ // adapters (e.g. Cloudflare) where the Worker's `scheduled()` handler
1282
+ // drives runScheduledTasks() instead. No adapter check lives here.
1283
+ if (deps.createScheduler) {
1284
+ const scheduler = deps.createScheduler(cronExecutor);
1285
+ cronScheduler = scheduler;
1286
+
1287
+ // Run scheduled publishing and system cleanup alongside each tick.
1288
+ // Pass storage so cleanupPendingUploads can delete orphaned files.
1289
+ scheduler.setSystemCleanup(async () => {
1290
+ try {
1291
+ // Route through the runtime so content:afterPublish hooks fire.
1292
+ // Falls back to the raw handler if (improbably) the tick beats
1293
+ // the post-construction ref assignment.
1294
+ const runtime = runtimeRef.current;
1295
+ await publishDueContent(db, {
1296
+ publish: runtime
1297
+ ? (collection, id, options) =>
1298
+ runtime.handleContentPublish(collection, id, options)
1299
+ : undefined,
1300
+ });
1301
+ } catch (error) {
1302
+ console.error("[scheduled-publish] Sweep failed:", error);
1303
+ }
1304
+ try {
1305
+ await runSystemCleanup(db, storage ?? undefined);
1306
+ } catch (error) {
1307
+ // Non-fatal -- individual cleanup failures are already logged
1308
+ // by runSystemCleanup. This catches unexpected errors.
1309
+ console.error("[cleanup] System cleanup failed:", error);
1310
+ }
1311
+ });
1226
1312
 
1227
- // Add cron reschedule callback (merges with existing factory options)
1228
- pipeline.setContextFactory({
1229
- cronReschedule: () => cronScheduler?.reschedule(),
1230
- });
1313
+ // Add cron reschedule callback (merges with existing factory options)
1314
+ pipeline.setContextFactory({
1315
+ cronReschedule: () => cronScheduler?.reschedule(),
1316
+ });
1231
1317
 
1232
- // Start the scheduler
1233
- await cronScheduler.start();
1318
+ // start() is void on the timer scheduler but the interface
1319
+ // allows a promise (alarm-backed schedulers); we don't block on it.
1320
+ void scheduler.start();
1321
+ }
1234
1322
  } catch (error) {
1235
1323
  console.warn("[cron] Failed to initialize cron system:", error);
1236
1324
  // Non-fatal — CMS works without cron
1237
1325
  }
1238
1326
  });
1239
1327
 
1240
- return new EmDashRuntime({
1328
+ const runtime = new EmDashRuntime({
1241
1329
  db,
1242
1330
  storage,
1243
1331
  // Include bypassed sandboxed plugins in configuredPlugins so route
@@ -1260,6 +1348,10 @@ export class EmDashRuntime {
1260
1348
  runtimeDeps: deps,
1261
1349
  pipelineRef,
1262
1350
  });
1351
+ // Hand the constructed instance to the scheduler-cleanup closure so the
1352
+ // timer-driven sweep can fire publish hooks (see runtimeRef above).
1353
+ runtimeRef.current = runtime;
1354
+ return runtime;
1263
1355
  }
1264
1356
 
1265
1357
  /**
@@ -2137,27 +2229,32 @@ export class EmDashRuntime {
2137
2229
  * defend against FTS not existing yet (pre-setup).
2138
2230
  */
2139
2231
  async ensureSearchHealthy(): Promise<void> {
2140
- if (this._searchHealthChecked) return;
2141
- if (this._searchHealthPromise) return this._searchHealthPromise;
2142
- if (!isSqlite(this._db)) {
2143
- this._searchHealthChecked = true;
2144
- return;
2232
+ // Non-SQLite has no FTS to verify; the check is a cheap synchronous
2233
+ // branch, no need to cache it.
2234
+ if (!isSqlite(this._db)) return;
2235
+ try {
2236
+ await isolateCachedAsync(
2237
+ this._searchHealthCache,
2238
+ async () => {
2239
+ try {
2240
+ const ftsManager = new FTSManager(this._db);
2241
+ const repaired = await ftsManager.verifyAndRepairAll();
2242
+ if (repaired > 0) {
2243
+ console.log(`Repaired ${repaired} corrupted FTS index(es)`);
2244
+ }
2245
+ } catch {
2246
+ // FTS tables may not exist yet (pre-setup). Non-fatal — cache
2247
+ // the "checked" state regardless so we don't re-scan.
2248
+ }
2249
+ },
2250
+ { anchor: (promise) => after(() => promise), ownerTimeoutMs: 30_000 },
2251
+ );
2252
+ } catch {
2253
+ // This check is best-effort and must never fail the calling request.
2254
+ // The inner body already swallows verify errors; this guards the
2255
+ // outer failure modes (owner timeout, waiter give-up) so a slow FTS
2256
+ // scan degrades to "unverified", not a 500 on admin/search routes.
2145
2257
  }
2146
- this._searchHealthPromise = (async () => {
2147
- try {
2148
- const ftsManager = new FTSManager(this._db);
2149
- const repaired = await ftsManager.verifyAndRepairAll();
2150
- if (repaired > 0) {
2151
- console.log(`Repaired ${repaired} corrupted FTS index(es)`);
2152
- }
2153
- } catch {
2154
- // FTS tables may not exist yet (pre-setup). Non-fatal.
2155
- } finally {
2156
- this._searchHealthChecked = true;
2157
- this._searchHealthPromise = null;
2158
- }
2159
- })();
2160
- return this._searchHealthPromise;
2161
2258
  }
2162
2259
 
2163
2260
  // =========================================================================
@@ -2174,11 +2271,19 @@ export class EmDashRuntime {
2174
2271
  order?: "asc" | "desc";
2175
2272
  locale?: string;
2176
2273
  q?: string;
2274
+ authorId?: string;
2275
+ dateField?: ContentDateField;
2276
+ dateFrom?: string;
2277
+ dateTo?: string;
2177
2278
  },
2178
2279
  ) {
2179
2280
  return handleContentList(this.db, collection, params);
2180
2281
  }
2181
2282
 
2283
+ async handleContentAuthors(collection: string) {
2284
+ return handleContentAuthors(this.db, collection);
2285
+ }
2286
+
2182
2287
  async handleContentGet(collection: string, id: string, locale?: string) {
2183
2288
  const result = await handleContentGet(this.db, collection, id, locale);
2184
2289
  return this.hydrateDraftData(result);
@@ -2553,7 +2658,7 @@ export class EmDashRuntime {
2553
2658
  async handleContentPublish(
2554
2659
  collection: string,
2555
2660
  id: string,
2556
- options: { publishedAt?: string } = {},
2661
+ options: { publishedAt?: string; requireScheduledDue?: boolean } = {},
2557
2662
  ) {
2558
2663
  const result = await handleContentPublish(this.db, collection, id, options);
2559
2664
 
package/src/index.ts CHANGED
@@ -46,6 +46,7 @@ export type {
46
46
  // API handlers
47
47
  export {
48
48
  handleContentList,
49
+ handleContentAuthors,
49
50
  handleContentGet,
50
51
  handleContentGetIncludingTrashed,
51
52
  handleContentCreate,
@@ -201,6 +202,8 @@ export {
201
202
  PluginManager,
202
203
  createPluginManager,
203
204
  PluginRouteError,
205
+ // Scheduler (Node timer heartbeat — used by virtual:emdash/scheduler)
206
+ NodeCronScheduler,
204
207
  // Sandbox
205
208
  NoopSandboxRunner,
206
209
  SandboxNotAvailableError,
@@ -253,6 +256,10 @@ export type {
253
256
  CollectionCommentSettings,
254
257
  StoredComment,
255
258
 
259
+ // Scheduler types
260
+ CronScheduler,
261
+ SystemCleanupFn,
262
+
256
263
  // Sandbox runtime types
257
264
  SandboxRunner,
258
265
  SandboxedPluginInstance,
@@ -406,7 +413,7 @@ export type {
406
413
  } from "./menus/types.js";
407
414
 
408
415
  // Bylines
409
- export { getByline, getBylineBySlug } from "./bylines/index.js";
416
+ export { getByline, getBylineBySlug, getEntriesByByline } from "./bylines/index.js";
410
417
  export type { BylineSummary, ContentBylineCredit } from "./database/repositories/types.js";
411
418
 
412
419
  // Taxonomies
package/src/loader.ts CHANGED
@@ -540,12 +540,16 @@ export interface CollectionFilter {
540
540
  */
541
541
  cursor?: string;
542
542
  /**
543
- * Filter by field values, taxonomy terms, or ranges.
543
+ * Filter by field values, taxonomy terms, byline credits, or ranges.
544
544
  *
545
545
  * Taxonomy names are detected automatically and filtered via JOIN.
546
+ * The reserved `byline` key filters by byline credit (any credit, not
547
+ * just the primary one) via the `_emdash_content_bylines` junction
548
+ * table; its value is one or more byline translation groups.
546
549
  * Other keys are treated as column filters on the content table.
547
550
  *
548
551
  * @example { category: 'news' } - taxonomy term
552
+ * @example { byline: '01HXYZ...' } - entries credited to a byline (any position)
549
553
  * @example { series: 'main' } - exact match on a content field
550
554
  * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - date range
551
555
  */
@@ -673,13 +677,21 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
673
677
 
674
678
  // Build cursor condition if cursor is provided
675
679
  const cursorCondition = cursor ? buildCursorCondition(cursor, orderBy) : null;
676
- const cursorConditionPrefixed = cursor
677
- ? buildCursorCondition(cursor, orderBy, tableName)
678
- : null;
679
680
 
680
- // Separate taxonomy filters from field filters
681
+ // Separate taxonomy / byline filters from field filters
681
682
  let result: { rows: Record<string, unknown>[] };
682
- let taxonomyFilter: { name: string; slugs: string[] } | null = null;
683
+ // Taxonomy filters AND together: each entry constrains the base
684
+ // row to match at least one of its slugs *within that taxonomy*.
685
+ // Term slugs are unique only within a taxonomy, so every filter
686
+ // keeps its own `name` and emits its own `EXISTS` clause rather
687
+ // than pooling slugs into one `IN`.
688
+ const taxonomyFilters: { name: string; slugs: string[] }[] = [];
689
+ // A byline filter matches entries credited to any of the given
690
+ // byline translation groups via the `_emdash_content_bylines`
691
+ // junction table. `null` means no byline filter; an empty
692
+ // `groups` array means the filter was requested but matches
693
+ // nothing (short-circuited to an empty result below).
694
+ let bylineFilter: { groups: string[] } | null = null;
683
695
  const fieldFilters: Record<string, WhereValue> = {};
684
696
 
685
697
  if (where && Object.keys(where).length > 0) {
@@ -687,56 +699,51 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
687
699
 
688
700
  for (const [key, value] of Object.entries(where)) {
689
701
  if (value == null) continue;
690
- if (taxNames.has(key)) {
702
+ if (key === "byline") {
691
703
  if (isWhereRange(value)) {
692
704
  console.warn(
693
- `[emdash] where filter: range operators are not supported on taxonomy "${key}", ignored`,
705
+ `[emdash] where filter: range operators are not supported on "byline", ignored`,
694
706
  );
695
707
  continue;
696
708
  }
697
- if (taxonomyFilter) {
709
+ const groups = Array.isArray(value) ? value : [value];
710
+ bylineFilter = { groups };
711
+ } else if (taxNames.has(key)) {
712
+ if (isWhereRange(value)) {
698
713
  console.warn(
699
- `[emdash] where filter: only one taxonomy is supported per query, "${key}" ignored`,
714
+ `[emdash] where filter: range operators are not supported on taxonomy "${key}", ignored`,
700
715
  );
701
716
  continue;
702
717
  }
703
718
  const slugs = Array.isArray(value) ? value : [value];
704
- taxonomyFilter = { name: key, slugs };
719
+ taxonomyFilters.push({ name: key, slugs });
705
720
  } else {
706
721
  fieldFilters[key] = value;
707
722
  }
708
723
  }
709
724
  }
710
725
 
711
- if (taxonomyFilter) {
712
- const orderByClause = buildOrderByClause(orderBy, tableName);
713
- const statusCondition = buildStatusCondition(db, status, tableName);
714
- const localeCondition = locale
715
- ? sql`AND ${sql.ref(tableName)}.locale = ${locale}`
716
- : sql``;
717
- const cursorCond = cursorConditionPrefixed ? sql`AND ${cursorConditionPrefixed}` : sql``;
718
- const fieldConds = buildFieldConditions(fieldFilters, tableName);
719
- const fieldCondsSQL =
720
- fieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;
726
+ // A byline or taxonomy filter with no values matches nothing —
727
+ // short-circuit before building SQL (an empty `IN ()` is invalid
728
+ // SQL on both dialects).
729
+ if (
730
+ (bylineFilter && bylineFilter.groups.length === 0) ||
731
+ taxonomyFilters.some((f) => f.slugs.length === 0)
732
+ ) {
733
+ return { entries: [], cacheHint: { tags: [type] } };
734
+ }
721
735
 
722
- result = await sql<Record<string, unknown>>`
723
- SELECT DISTINCT ${sql.ref(tableName)}.* FROM ${sql.ref(tableName)}
724
- INNER JOIN content_taxonomies ct
725
- ON ct.collection = ${type}
726
- AND ct.entry_id = ${sql.ref(tableName)}.id
727
- INNER JOIN taxonomies t
728
- ON t.id = ct.taxonomy_id
729
- WHERE ${sql.ref(tableName)}.deleted_at IS NULL
730
- AND ${statusCondition}
731
- ${localeCondition}
732
- ${cursorCond}
733
- AND t.name = ${taxonomyFilter.name}
734
- AND t.slug IN (${sql.join(taxonomyFilter.slugs.map((s) => sql`${s}`))})
735
- ${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}
736
- ${orderByClause}
737
- ${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}
738
- `.execute(db);
739
- } else {
736
+ {
737
+ // Taxonomy and byline filters are applied as correlated
738
+ // `EXISTS` semi-joins rather than `INNER JOIN ... DISTINCT`.
739
+ // A join fan-out would force `SELECT DISTINCT table.*`, and
740
+ // Postgres cannot apply DISTINCT to a row containing a `json`
741
+ // column (no equality operator), so the join approach throws
742
+ // there. EXISTS matches "credited/tagged at least once"
743
+ // without duplicating rows, needs no DISTINCT, and works on
744
+ // both SQLite and Postgres. The base query stays a single-
745
+ // table `SELECT *`, so all field/status/locale/cursor/order
746
+ // conditions reference unprefixed columns as before.
740
747
  const orderByClause = buildOrderByClause(orderBy);
741
748
  const statusCondition = buildStatusCondition(db, status);
742
749
  const localeFilter = locale ? sql`AND locale = ${locale}` : sql``;
@@ -745,12 +752,47 @@ export function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFil
745
752
  const fieldCondsSQL =
746
753
  fieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;
747
754
 
755
+ // One `EXISTS` per taxonomy, AND'd together: an entry must be
756
+ // tagged with a matching term in *every* requested taxonomy.
757
+ // Each clause pins its own `t.name`, so slugs never pool
758
+ // across taxonomies (they're only unique within one).
759
+ const taxonomyCond =
760
+ taxonomyFilters.length > 0
761
+ ? sql`${sql.join(
762
+ taxonomyFilters.map(
763
+ (f) => sql`AND EXISTS (
764
+ SELECT 1 FROM content_taxonomies ct
765
+ INNER JOIN taxonomies t ON t.id = ct.taxonomy_id
766
+ WHERE ct.collection = ${type}
767
+ AND ct.entry_id = ${sql.ref(tableName)}.id
768
+ AND t.name = ${f.name}
769
+ AND t.slug IN (${sql.join(f.slugs.map((s) => sql`${s}`))})
770
+ )`,
771
+ ),
772
+ sql` `,
773
+ )}`
774
+ : sql``;
775
+
776
+ // `_emdash_content_bylines.byline_id` stores the byline's
777
+ // translation_group (migration 040), so a credit spans every
778
+ // locale variant of the byline and we match the group directly.
779
+ const bylineCond = bylineFilter
780
+ ? sql`AND EXISTS (
781
+ SELECT 1 FROM _emdash_content_bylines cb
782
+ WHERE cb.collection_slug = ${type}
783
+ AND cb.content_id = ${sql.ref(tableName)}.id
784
+ AND cb.byline_id IN (${sql.join(bylineFilter.groups.map((g) => sql`${g}`))})
785
+ )`
786
+ : sql``;
787
+
748
788
  result = await sql<Record<string, unknown>>`
749
789
  SELECT * FROM ${sql.ref(tableName)}
750
790
  WHERE deleted_at IS NULL
751
791
  AND ${statusCondition}
752
792
  ${localeFilter}
753
793
  ${cursorCond}
794
+ ${taxonomyCond}
795
+ ${bylineCond}
754
796
  ${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}
755
797
  ${orderByClause}
756
798
  ${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}