emdash 1.3.0 → 1.4.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 (970) hide show
  1. package/dist/{activation-Dim4YMM7.mjs → activation-CGlyigmg.mjs} +3 -3
  2. package/dist/{activation-Dim4YMM7.mjs.map → activation-CGlyigmg.mjs.map} +1 -1
  3. package/dist/{adapters-F_xorvWv.d.mts → adapters-D9a1PfqH.d.mts} +1 -1
  4. package/dist/{adapters-F_xorvWv.d.mts.map → adapters-D9a1PfqH.d.mts.map} +1 -1
  5. package/dist/{after-PcEvMY_6.mjs → after-32yNRvd2.mjs} +5 -2
  6. package/dist/{after-PcEvMY_6.mjs.map → after-32yNRvd2.mjs.map} +1 -1
  7. package/dist/api/route-utils.d.mts +4 -4
  8. package/dist/api/route-utils.mjs +50 -49
  9. package/dist/api/route-utils.mjs.map +1 -1
  10. package/dist/api/schemas/index.d.mts +1 -1
  11. package/dist/api/schemas/index.mjs +7 -7
  12. package/dist/{api-D-7BNHoz.mjs → api--PYoyeTo.mjs} +121 -48
  13. package/dist/api--PYoyeTo.mjs.map +1 -0
  14. package/dist/api-tokens-DqSlkDVI.mjs +9 -0
  15. package/dist/api-tokens-DqSlkDVI.mjs.map +1 -0
  16. package/dist/{api-tokens-Bx38ZCQp.mjs → api-tokens-GNCsIegW.mjs} +3 -3
  17. package/dist/{api-tokens-Bx38ZCQp.mjs.map → api-tokens-GNCsIegW.mjs.map} +1 -1
  18. package/dist/{apply-T7ATgzCh.mjs → apply-DVnupNeS.mjs} +149 -91
  19. package/dist/apply-DVnupNeS.mjs.map +1 -0
  20. package/dist/{approvals-D-m6wvGl.mjs → approvals-DTtYSB27.mjs} +2 -2
  21. package/dist/{approvals-D-m6wvGl.mjs.map → approvals-DTtYSB27.mjs.map} +1 -1
  22. package/dist/{artifacts-htGyfCSt.mjs → artifacts-Dvdp2KK-.mjs} +29 -13
  23. package/dist/artifacts-Dvdp2KK-.mjs.map +1 -0
  24. package/dist/astro/image-endpoint.mjs +12 -2
  25. package/dist/astro/image-endpoint.mjs.map +1 -1
  26. package/dist/astro/index.d.mts +15 -14
  27. package/dist/astro/index.d.mts.map +1 -1
  28. package/dist/astro/index.mjs +59 -8
  29. package/dist/astro/index.mjs.map +1 -1
  30. package/dist/astro/middleware/auth.d.mts +13 -12
  31. package/dist/astro/middleware/auth.d.mts.map +1 -1
  32. package/dist/astro/middleware/auth.mjs +10 -8
  33. package/dist/astro/middleware/auth.mjs.map +1 -1
  34. package/dist/astro/middleware/media-usage-write-fence.mjs +5 -5
  35. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  36. package/dist/astro/middleware/redirect.mjs +129 -49
  37. package/dist/astro/middleware/redirect.mjs.map +1 -1
  38. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  39. package/dist/astro/middleware/request-context.mjs +18 -9
  40. package/dist/astro/middleware/request-context.mjs.map +1 -1
  41. package/dist/astro/middleware.d.mts +13 -12
  42. package/dist/astro/middleware.d.mts.map +1 -1
  43. package/dist/astro/middleware.mjs +111 -101
  44. package/dist/astro/middleware.mjs.map +1 -1
  45. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +11 -11
  46. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +11 -11
  47. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +6 -6
  48. package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
  49. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +6 -6
  50. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +14 -14
  51. package/dist/astro/routes/api/admin/byline-fields/index.mjs +14 -14
  52. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +14 -14
  53. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +25 -25
  54. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +25 -25
  55. package/dist/astro/routes/api/admin/bylines/index.mjs +25 -25
  56. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +17 -17
  57. package/dist/astro/routes/api/admin/comments/_id_.mjs +8 -8
  58. package/dist/astro/routes/api/admin/comments/bulk.mjs +16 -16
  59. package/dist/astro/routes/api/admin/comments/counts.mjs +8 -8
  60. package/dist/astro/routes/api/admin/comments/index.mjs +16 -16
  61. package/dist/astro/routes/api/admin/core-update.mjs +6 -6
  62. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +5 -5
  63. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +4 -4
  64. package/dist/astro/routes/api/admin/media-usage/activation.mjs +18 -18
  65. package/dist/astro/routes/api/admin/media-usage/collection-deletions/index.mjs +19 -19
  66. package/dist/astro/routes/api/admin/media-usage/collection-deletions/retry.mjs +19 -19
  67. package/dist/astro/routes/api/admin/media-usage/progress.mjs +22 -21
  68. package/dist/astro/routes/api/admin/media-usage/progress.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/media-usage/repair.mjs +26 -25
  70. package/dist/astro/routes/api/admin/media-usage/repair.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/media-usage/work/index.mjs +19 -19
  72. package/dist/astro/routes/api/admin/media-usage/work/retry.mjs +19 -19
  73. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  74. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  75. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +7 -7
  76. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +7 -7
  77. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +66 -65
  78. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  79. package/dist/astro/routes/api/admin/plugins/_id_/mcp.mjs +5 -5
  80. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +66 -65
  81. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +66 -65
  83. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +73 -72
  85. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/index.mjs +66 -65
  87. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +4 -4
  89. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +66 -65
  90. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  91. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +73 -72
  92. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  93. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +66 -65
  94. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  95. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +66 -65
  96. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  97. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +74 -73
  98. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  99. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +4 -4
  100. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +68 -67
  101. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  102. package/dist/astro/routes/api/admin/plugins/registry/publisher-handle.mjs +4 -4
  103. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +67 -66
  104. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs.map +1 -1
  105. package/dist/astro/routes/api/admin/plugins/updates.mjs +66 -65
  106. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  107. package/dist/astro/routes/api/admin/scheduled-policy-rejections/_collection_/_id_.mjs +5 -5
  108. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +66 -65
  109. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  110. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +4 -4
  111. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +66 -65
  112. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  113. package/dist/astro/routes/api/admin/transfer/_...path_.mjs +3 -3
  114. package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +33 -32
  115. package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs.map +1 -1
  116. package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +33 -32
  117. package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs.map +1 -1
  118. package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +35 -34
  119. package/dist/astro/routes/api/admin/transfer/approvals/index.mjs.map +1 -1
  120. package/dist/astro/routes/api/admin/transfer/capabilities.mjs +35 -34
  121. package/dist/astro/routes/api/admin/transfer/capabilities.mjs.map +1 -1
  122. package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +35 -34
  123. package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs.map +1 -1
  124. package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +36 -35
  125. package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs.map +1 -1
  126. package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +36 -35
  127. package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs.map +1 -1
  128. package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +35 -34
  129. package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs.map +1 -1
  130. package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +36 -35
  131. package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs.map +1 -1
  132. package/dist/astro/routes/api/admin/transfer/exports/index.mjs +37 -36
  133. package/dist/astro/routes/api/admin/transfer/exports/index.mjs.map +1 -1
  134. package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +35 -34
  135. package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs.map +1 -1
  136. package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +35 -34
  137. package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs.map +1 -1
  138. package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +37 -36
  139. package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs.map +1 -1
  140. package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +35 -34
  141. package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs.map +1 -1
  142. package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +37 -36
  143. package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs.map +1 -1
  144. package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +35 -34
  145. package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs.map +1 -1
  146. package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +35 -34
  147. package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs.map +1 -1
  148. package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +37 -36
  149. package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs.map +1 -1
  150. package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +35 -34
  151. package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs.map +1 -1
  152. package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +35 -34
  153. package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs.map +1 -1
  154. package/dist/astro/routes/api/admin/transfer/imports/index.mjs +37 -36
  155. package/dist/astro/routes/api/admin/transfer/imports/index.mjs.map +1 -1
  156. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +4 -4
  157. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +3 -3
  158. package/dist/astro/routes/api/admin/users/_id_/index.mjs +12 -12
  159. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
  160. package/dist/astro/routes/api/admin/users/index.mjs +11 -11
  161. package/dist/astro/routes/api/auth/dev-bypass.mjs +3 -3
  162. package/dist/astro/routes/api/auth/handover.mjs +5 -5
  163. package/dist/astro/routes/api/auth/invite/accept.mjs +3 -3
  164. package/dist/astro/routes/api/auth/invite/complete.mjs +15 -15
  165. package/dist/astro/routes/api/auth/invite/index.mjs +12 -12
  166. package/dist/astro/routes/api/auth/invite/register-options.mjs +13 -13
  167. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  168. package/dist/astro/routes/api/auth/magic-link/send.mjs +14 -14
  169. package/dist/astro/routes/api/auth/magic-link/verify.mjs +13 -13
  170. package/dist/astro/routes/api/auth/me.mjs +12 -12
  171. package/dist/astro/routes/api/auth/mode.mjs +3 -3
  172. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +8 -8
  173. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +1 -1
  174. package/dist/astro/routes/api/auth/passkey/_id_.mjs +11 -11
  175. package/dist/astro/routes/api/auth/passkey/index.mjs +3 -3
  176. package/dist/astro/routes/api/auth/passkey/options.mjs +15 -15
  177. package/dist/astro/routes/api/auth/passkey/register/options.mjs +13 -13
  178. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +13 -13
  179. package/dist/astro/routes/api/auth/passkey/verify.mjs +15 -15
  180. package/dist/astro/routes/api/auth/signup/complete.mjs +15 -15
  181. package/dist/astro/routes/api/auth/signup/request.mjs +13 -13
  182. package/dist/astro/routes/api/auth/signup/verify.mjs +3 -3
  183. package/dist/astro/routes/api/calendar.mjs +12 -12
  184. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +12 -12
  185. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +17 -17
  186. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +4 -4
  187. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +15 -15
  188. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +4 -4
  189. package/dist/astro/routes/api/content/_collection_/_id_/lock.mjs +15 -15
  190. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +4 -4
  191. package/dist/astro/routes/api/content/_collection_/_id_/plugin-extensions/_pluginId_/_kind_/_extensionId_.mjs +9 -9
  192. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +29 -28
  193. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs.map +1 -1
  194. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +15 -15
  195. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs +34 -33
  196. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/children.mjs.map +1 -1
  197. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs +34 -33
  198. package/dist/astro/routes/api/content/_collection_/_id_/references/_relation_/parents.mjs.map +1 -1
  199. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +4 -4
  200. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +4 -4
  201. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +15 -15
  202. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -1
  203. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +35 -27
  204. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  205. package/dist/astro/routes/api/content/_collection_/_id_/translations.d.mts.map +1 -1
  206. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +8 -4
  207. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs.map +1 -1
  208. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +15 -15
  209. package/dist/astro/routes/api/content/_collection_/_id_.mjs +15 -15
  210. package/dist/astro/routes/api/content/_collection_/authors.mjs +4 -4
  211. package/dist/astro/routes/api/content/_collection_/index.mjs +12 -12
  212. package/dist/astro/routes/api/content/_collection_/trash.mjs +12 -12
  213. package/dist/astro/routes/api/dashboard.mjs +22 -16
  214. package/dist/astro/routes/api/dashboard.mjs.map +1 -1
  215. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  216. package/dist/astro/routes/api/dev/scheduled-tasks.mjs +97 -95
  217. package/dist/astro/routes/api/dev/scheduled-tasks.mjs.map +1 -1
  218. package/dist/astro/routes/api/health.mjs +4 -4
  219. package/dist/astro/routes/api/import/probe.d.mts +4 -3
  220. package/dist/astro/routes/api/import/probe.d.mts.map +1 -1
  221. package/dist/astro/routes/api/import/probe.mjs +27 -25
  222. package/dist/astro/routes/api/import/probe.mjs.map +1 -1
  223. package/dist/astro/routes/api/import/wordpress/analyze.d.mts +4 -3
  224. package/dist/astro/routes/api/import/wordpress/analyze.d.mts.map +1 -1
  225. package/dist/astro/routes/api/import/wordpress/analyze.mjs +7 -29
  226. package/dist/astro/routes/api/import/wordpress/analyze.mjs.map +1 -1
  227. package/dist/astro/routes/api/import/wordpress/execute.d.mts +14 -13
  228. package/dist/astro/routes/api/import/wordpress/execute.d.mts.map +1 -1
  229. package/dist/astro/routes/api/import/wordpress/execute.mjs +29 -29
  230. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  231. package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -12
  232. package/dist/astro/routes/api/import/wordpress/media.d.mts.map +1 -1
  233. package/dist/astro/routes/api/import/wordpress/media.mjs +14 -14
  234. package/dist/astro/routes/api/import/wordpress/prepare.mjs +19 -19
  235. package/dist/astro/routes/api/import/wordpress/prepare.mjs.map +1 -1
  236. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +14 -13
  237. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts.map +1 -1
  238. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +25 -24
  239. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs.map +1 -1
  240. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  241. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +27 -25
  242. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs.map +1 -1
  243. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +14 -13
  244. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts.map +1 -1
  245. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +39 -38
  246. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  247. package/dist/astro/routes/api/manifest.mjs +4 -4
  248. package/dist/astro/routes/api/mcp.mjs +99 -83
  249. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  250. package/dist/astro/routes/api/media/_id_/confirm.mjs +16 -16
  251. package/dist/astro/routes/api/media/_id_/replace.mjs +12 -12
  252. package/dist/astro/routes/api/media/_id_/upload.mjs +6 -6
  253. package/dist/astro/routes/api/media/_id_/usage.mjs +28 -27
  254. package/dist/astro/routes/api/media/_id_/usage.mjs.map +1 -1
  255. package/dist/astro/routes/api/media/_id_.mjs +26 -25
  256. package/dist/astro/routes/api/media/_id_.mjs.map +1 -1
  257. package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +5 -5
  258. package/dist/astro/routes/api/media/file/_...key_.d.mts.map +1 -1
  259. package/dist/astro/routes/api/media/file/_...key_.mjs +62 -8
  260. package/dist/astro/routes/api/media/file/_...key_.mjs.map +1 -1
  261. package/dist/astro/routes/api/media/folders/_id_.mjs +13 -13
  262. package/dist/astro/routes/api/media/folders/index.mjs +13 -13
  263. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +4 -4
  264. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +4 -4
  265. package/dist/astro/routes/api/media/providers/index.mjs +4 -4
  266. package/dist/astro/routes/api/media/upload-url.mjs +15 -15
  267. package/dist/astro/routes/api/media.mjs +30 -29
  268. package/dist/astro/routes/api/media.mjs.map +1 -1
  269. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +17 -15
  270. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs.map +1 -1
  271. package/dist/astro/routes/api/menus/_name_/items.mjs +17 -15
  272. package/dist/astro/routes/api/menus/_name_/items.mjs.map +1 -1
  273. package/dist/astro/routes/api/menus/_name_/reorder.mjs +17 -15
  274. package/dist/astro/routes/api/menus/_name_/reorder.mjs.map +1 -1
  275. package/dist/astro/routes/api/menus/_name_/translations.mjs +17 -15
  276. package/dist/astro/routes/api/menus/_name_/translations.mjs.map +1 -1
  277. package/dist/astro/routes/api/menus/_name_.mjs +17 -15
  278. package/dist/astro/routes/api/menus/_name_.mjs.map +1 -1
  279. package/dist/astro/routes/api/menus/index.mjs +17 -15
  280. package/dist/astro/routes/api/menus/index.mjs.map +1 -1
  281. package/dist/astro/routes/api/oauth/authorize.mjs +2 -2
  282. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  283. package/dist/astro/routes/api/oauth/device/code.mjs +8 -8
  284. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  285. package/dist/astro/routes/api/oauth/register.mjs +5 -5
  286. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  287. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  288. package/dist/astro/routes/api/oauth/token.d.mts.map +1 -1
  289. package/dist/astro/routes/api/oauth/token.mjs +7 -7
  290. package/dist/astro/routes/api/oauth/token.mjs.map +1 -1
  291. package/dist/astro/routes/api/openapi.json.mjs +12 -12
  292. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +9 -9
  293. package/dist/astro/routes/api/redirects/404s/index.mjs +20 -19
  294. package/dist/astro/routes/api/redirects/404s/index.mjs.map +1 -1
  295. package/dist/astro/routes/api/redirects/404s/summary.mjs +20 -19
  296. package/dist/astro/routes/api/redirects/404s/summary.mjs.map +1 -1
  297. package/dist/astro/routes/api/redirects/_id_.mjs +21 -20
  298. package/dist/astro/routes/api/redirects/_id_.mjs.map +1 -1
  299. package/dist/astro/routes/api/redirects/index.mjs +21 -20
  300. package/dist/astro/routes/api/redirects/index.mjs.map +1 -1
  301. package/dist/astro/routes/api/relations/_id_/index.mjs +34 -33
  302. package/dist/astro/routes/api/relations/_id_/index.mjs.map +1 -1
  303. package/dist/astro/routes/api/relations/index.mjs +34 -33
  304. package/dist/astro/routes/api/relations/index.mjs.map +1 -1
  305. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +4 -4
  306. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +15 -15
  307. package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +66 -65
  308. package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs.map +1 -1
  309. package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +66 -65
  310. package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs.map +1 -1
  311. package/dist/astro/routes/api/schema/block-types/index.mjs +66 -65
  312. package/dist/astro/routes/api/schema/block-types/index.mjs.map +1 -1
  313. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +66 -65
  314. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  315. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +66 -65
  316. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  317. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +66 -65
  318. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  319. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +66 -65
  320. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  321. package/dist/astro/routes/api/schema/collections/index.mjs +66 -65
  322. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  323. package/dist/astro/routes/api/schema/collections/reorder.mjs +66 -65
  324. package/dist/astro/routes/api/schema/collections/reorder.mjs.map +1 -1
  325. package/dist/astro/routes/api/schema/index.mjs +17 -16
  326. package/dist/astro/routes/api/schema/index.mjs.map +1 -1
  327. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +66 -65
  328. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  329. package/dist/astro/routes/api/schema/orphans/index.mjs +66 -65
  330. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  331. package/dist/astro/routes/api/search/enable.mjs +20 -18
  332. package/dist/astro/routes/api/search/enable.mjs.map +1 -1
  333. package/dist/astro/routes/api/search/index.mjs +19 -17
  334. package/dist/astro/routes/api/search/index.mjs.map +1 -1
  335. package/dist/astro/routes/api/search/rebuild.mjs +20 -18
  336. package/dist/astro/routes/api/search/rebuild.mjs.map +1 -1
  337. package/dist/astro/routes/api/search/stats.mjs +13 -11
  338. package/dist/astro/routes/api/search/stats.mjs.map +1 -1
  339. package/dist/astro/routes/api/search/suggest.mjs +19 -17
  340. package/dist/astro/routes/api/search/suggest.mjs.map +1 -1
  341. package/dist/astro/routes/api/sections/_slug_.mjs +19 -17
  342. package/dist/astro/routes/api/sections/_slug_.mjs.map +1 -1
  343. package/dist/astro/routes/api/sections/index.mjs +19 -17
  344. package/dist/astro/routes/api/sections/index.mjs.map +1 -1
  345. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +7 -7
  346. package/dist/astro/routes/api/settings/backups/archives/index.mjs +7 -7
  347. package/dist/astro/routes/api/settings/backups/export.mjs +7 -7
  348. package/dist/astro/routes/api/settings/backups/index.mjs +8 -8
  349. package/dist/astro/routes/api/settings/domain-notify.mjs +7 -7
  350. package/dist/astro/routes/api/settings/domain.mjs +19 -17
  351. package/dist/astro/routes/api/settings/domain.mjs.map +1 -1
  352. package/dist/astro/routes/api/settings/email.mjs +5 -5
  353. package/dist/astro/routes/api/settings.mjs +25 -23
  354. package/dist/astro/routes/api/settings.mjs.map +1 -1
  355. package/dist/astro/routes/api/setup/admin-verify.mjs +18 -18
  356. package/dist/astro/routes/api/setup/admin.mjs +14 -14
  357. package/dist/astro/routes/api/setup/dev-bypass.mjs +45 -44
  358. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  359. package/dist/astro/routes/api/setup/dev-reset.mjs +3 -3
  360. package/dist/astro/routes/api/setup/index.mjs +48 -47
  361. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  362. package/dist/astro/routes/api/setup/status.mjs +4 -4
  363. package/dist/astro/routes/api/site/domain-proof.mjs +17 -15
  364. package/dist/astro/routes/api/site/domain-proof.mjs.map +1 -1
  365. package/dist/astro/routes/api/snapshot.mjs +9 -9
  366. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs +25 -24
  367. package/dist/astro/routes/api/taxonomies/_name_/reorder.mjs.map +1 -1
  368. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +25 -24
  369. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs.map +1 -1
  370. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +25 -24
  371. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs.map +1 -1
  372. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +25 -24
  373. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs.map +1 -1
  374. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs +25 -24
  375. package/dist/astro/routes/api/taxonomies/_name_/translations.mjs.map +1 -1
  376. package/dist/astro/routes/api/taxonomies/_name_.mjs +25 -24
  377. package/dist/astro/routes/api/taxonomies/_name_.mjs.map +1 -1
  378. package/dist/astro/routes/api/taxonomies/bulk-tag.mjs +35 -34
  379. package/dist/astro/routes/api/taxonomies/bulk-tag.mjs.map +1 -1
  380. package/dist/astro/routes/api/taxonomies/index.mjs +25 -24
  381. package/dist/astro/routes/api/taxonomies/index.mjs.map +1 -1
  382. package/dist/astro/routes/api/themes/preview.mjs +6 -6
  383. package/dist/astro/routes/api/typegen.mjs +5 -5
  384. package/dist/astro/routes/api/visual-editing/action-token.mjs +5 -5
  385. package/dist/astro/routes/api/visual-editing/content/_collection_/_id_/publish.mjs +17 -17
  386. package/dist/astro/routes/api/visual-editing/toolbar-labels.mjs +3 -3
  387. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +1 -1
  388. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +1 -1
  389. package/dist/astro/routes/api/widget-areas/_name_/reorder.d.mts.map +1 -1
  390. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +24 -13
  391. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs.map +1 -1
  392. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.d.mts.map +1 -1
  393. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +22 -17
  394. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs.map +1 -1
  395. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +21 -17
  396. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs.map +1 -1
  397. package/dist/astro/routes/api/widget-areas/_name_.mjs +14 -10
  398. package/dist/astro/routes/api/widget-areas/_name_.mjs.map +1 -1
  399. package/dist/astro/routes/api/widget-areas/index.mjs +21 -17
  400. package/dist/astro/routes/api/widget-areas/index.mjs.map +1 -1
  401. package/dist/astro/routes/api/widget-components.mjs +3 -3
  402. package/dist/astro/routes/robots.txt.mjs +16 -14
  403. package/dist/astro/routes/robots.txt.mjs.map +1 -1
  404. package/dist/astro/routes/sitemap-_collection_.xml.mjs +18 -16
  405. package/dist/astro/routes/sitemap-_collection_.xml.mjs.map +1 -1
  406. package/dist/astro/routes/sitemap.xml.mjs +16 -14
  407. package/dist/astro/routes/sitemap.xml.mjs.map +1 -1
  408. package/dist/astro/types.d.mts +22 -20
  409. package/dist/astro/types.d.mts.map +1 -1
  410. package/dist/{audit-_gieLVGU.mjs → audit-B8XE-0UV.mjs} +2 -2
  411. package/dist/{audit-_gieLVGU.mjs.map → audit-B8XE-0UV.mjs.map} +1 -1
  412. package/dist/auth/providers/github.d.mts +1 -1
  413. package/dist/auth/providers/google.d.mts +1 -1
  414. package/dist/auth/providers/microsoft.d.mts +1 -1
  415. package/dist/{authorize-DPFBGbE6.mjs → authorize-NJgp8kLI.mjs} +2 -2
  416. package/dist/{authorize-DPFBGbE6.mjs.map → authorize-NJgp8kLI.mjs.map} +1 -1
  417. package/dist/{backup-3FgVxiDJ.mjs → backup-8rPSJ28a.mjs} +4 -4
  418. package/dist/{backup-3FgVxiDJ.mjs.map → backup-8rPSJ28a.mjs.map} +1 -1
  419. package/dist/{block-types-CYcG56JB.mjs → block-types-BbOrfnWs.mjs} +5 -5
  420. package/dist/{block-types-CYcG56JB.mjs.map → block-types-BbOrfnWs.mjs.map} +1 -1
  421. package/dist/{block-values-gCX4HBSl.mjs → block-values-Dg0-8PPS.mjs} +4 -4
  422. package/dist/{block-values-gCX4HBSl.mjs.map → block-values-Dg0-8PPS.mjs.map} +1 -1
  423. package/dist/{byline-BR1qhyiw.mjs → byline-DHJS-GGb.mjs} +123 -38
  424. package/dist/byline-DHJS-GGb.mjs.map +1 -0
  425. package/dist/{byline-fields-BLXZnX7N.mjs → byline-fields-CiR8FvvF.mjs} +3 -3
  426. package/dist/{byline-fields-BLXZnX7N.mjs.map → byline-fields-CiR8FvvF.mjs.map} +1 -1
  427. package/dist/{byline-fields-4ClDC88c.mjs → byline-fields-D6KYsEa7.mjs} +2 -2
  428. package/dist/{byline-fields-4ClDC88c.mjs.map → byline-fields-D6KYsEa7.mjs.map} +1 -1
  429. package/dist/{byline-registry-dvt4N3xV.mjs → byline-registry-BhzpO41z.mjs} +3 -3
  430. package/dist/{byline-registry-dvt4N3xV.mjs.map → byline-registry-BhzpO41z.mjs.map} +1 -1
  431. package/dist/{bylines-CVOvRUL7.mjs → bylines-Bsg5cH4S.mjs} +7 -7
  432. package/dist/bylines-Bsg5cH4S.mjs.map +1 -0
  433. package/dist/{bylines-DxOs9B7z.mjs → bylines-f_ZEc6Sn.mjs} +8 -8
  434. package/dist/{bylines-DxOs9B7z.mjs.map → bylines-f_ZEc6Sn.mjs.map} +1 -1
  435. package/dist/{cache-CEU9wo_h.mjs → cache-5DHbpEWu.mjs} +4 -4
  436. package/dist/{cache-CEU9wo_h.mjs.map → cache-5DHbpEWu.mjs.map} +1 -1
  437. package/dist/{capture-triggers-CT6dK9zd.mjs → capture-triggers-BezAvWcB.mjs} +2 -2
  438. package/dist/{capture-triggers-CT6dK9zd.mjs.map → capture-triggers-BezAvWcB.mjs.map} +1 -1
  439. package/dist/{challenge-store-C17BYx2-.mjs → challenge-store-B1C0V4b3.mjs} +1 -1
  440. package/dist/{challenge-store-C17BYx2-.mjs.map → challenge-store-B1C0V4b3.mjs.map} +1 -1
  441. package/dist/{chunks-xC4UD5-S.mjs → chunks-DiW8VMwz.mjs} +2 -2
  442. package/dist/{chunks-xC4UD5-S.mjs.map → chunks-DiW8VMwz.mjs.map} +1 -1
  443. package/dist/cli/index.mjs +53 -52
  444. package/dist/cli/index.mjs.map +1 -1
  445. package/dist/client/cf-access.d.mts +1 -1
  446. package/dist/client/index.d.mts +61 -61
  447. package/dist/client/index.d.mts.map +1 -1
  448. package/dist/client/index.mjs +3 -2
  449. package/dist/client/index.mjs.map +1 -1
  450. package/dist/{collection-slugs-cache-e09QeJQt.mjs → collection-slugs-cache-DIrLjqH-.mjs} +20 -14
  451. package/dist/collection-slugs-cache-DIrLjqH-.mjs.map +1 -0
  452. package/dist/{comment-UvIWDKcW.mjs → comment-DB74Zpa4.mjs} +18 -8
  453. package/dist/comment-DB74Zpa4.mjs.map +1 -0
  454. package/dist/{comment-reaction-dGp6_FRo.mjs → comment-reaction-BScxIWUn.mjs} +2 -2
  455. package/dist/{comment-reaction-dGp6_FRo.mjs.map → comment-reaction-BScxIWUn.mjs.map} +1 -1
  456. package/dist/{comments-pej-_BUO.mjs → comments-Cor_zKml.mjs} +3 -3
  457. package/dist/{comments-pej-_BUO.mjs.map → comments-Cor_zKml.mjs.map} +1 -1
  458. package/dist/config-Cs_AwWXI.mjs +106 -0
  459. package/dist/config-Cs_AwWXI.mjs.map +1 -0
  460. package/dist/{config-CFMojMFK.d.mts → config-D44_8G9J.d.mts} +3 -1
  461. package/dist/config-D44_8G9J.d.mts.map +1 -0
  462. package/dist/{config-Bsm_u_oE.d.mts → config-sDhZvkLR.d.mts} +56 -20
  463. package/dist/config-sDhZvkLR.d.mts.map +1 -0
  464. package/dist/{content-DQSRZTVw.mjs → content-BKHUVsE5.mjs} +67 -30
  465. package/dist/content-BKHUVsE5.mjs.map +1 -0
  466. package/dist/{content-list-query-CYKcY6Vi.d.mts → content-list-query-ByP4jRpZ.d.mts} +1 -1
  467. package/dist/{content-list-query-CYKcY6Vi.d.mts.map → content-list-query-ByP4jRpZ.d.mts.map} +1 -1
  468. package/dist/{content-policy-Dm32n9C6.mjs → content-policy-BmE0MPZY.mjs} +1 -1
  469. package/dist/{content-policy-Dm32n9C6.mjs.map → content-policy-BmE0MPZY.mjs.map} +1 -1
  470. package/dist/{content-repair-DNh5--x5.mjs → content-repair-Ukdxoq-R.mjs} +4 -4
  471. package/dist/{content-repair-DNh5--x5.mjs.map → content-repair-Ukdxoq-R.mjs.map} +1 -1
  472. package/dist/{context-BYptmCN0.mjs → context-CzjejcsE.mjs} +32 -33
  473. package/dist/context-CzjejcsE.mjs.map +1 -0
  474. package/dist/{credits-B9iORdWB.mjs → credits-BKREepht.mjs} +3 -3
  475. package/dist/{credits-B9iORdWB.mjs.map → credits-BKREepht.mjs.map} +1 -1
  476. package/dist/{dashboard-D0jcgBD7.mjs → dashboard-ynr1qJWM.mjs} +10 -9
  477. package/dist/dashboard-ynr1qJWM.mjs.map +1 -0
  478. package/dist/database/migration-lock.mjs +1 -1
  479. package/dist/db/index.d.mts +3 -3
  480. package/dist/db/index.mjs +3 -3
  481. package/dist/db/libsql-migrations.d.mts +1 -1
  482. package/dist/db/libsql-migrations.mjs +5 -5
  483. package/dist/db/libsql.d.mts +1 -1
  484. package/dist/db/postgres-migrations.d.mts +1 -1
  485. package/dist/db/postgres-migrations.mjs +5 -5
  486. package/dist/db/postgres.d.mts +1 -1
  487. package/dist/db/sqlite-migrations.d.mts +1 -1
  488. package/dist/db/sqlite-migrations.mjs +5 -5
  489. package/dist/db/sqlite.d.mts +1 -1
  490. package/dist/{db-errors-CBD5yMro.mjs → db-errors-unnO6yiZ.mjs} +12 -2
  491. package/dist/db-errors-unnO6yiZ.mjs.map +1 -0
  492. package/dist/deferred-tasks-wlMFJL95.d.mts +10 -0
  493. package/dist/deferred-tasks-wlMFJL95.d.mts.map +1 -0
  494. package/dist/{destination-r2zIAZ2S.mjs → destination-DR3IHjmy.mjs} +1 -1
  495. package/dist/{destination-r2zIAZ2S.mjs.map → destination-DR3IHjmy.mjs.map} +1 -1
  496. package/dist/{device-flow-BkFKBoAn.mjs → device-flow-D1U392GC.mjs} +3 -5
  497. package/dist/device-flow-D1U392GC.mjs.map +1 -0
  498. package/dist/{dialect-helpers-7_IqPdh9.mjs → dialect-helpers-B1XN2HGB.mjs} +10 -3
  499. package/dist/dialect-helpers-B1XN2HGB.mjs.map +1 -0
  500. package/dist/{direct-executor-Cbxzg4qe.mjs → direct-executor-Bs2g0ake.mjs} +4 -4
  501. package/dist/{direct-executor-Cbxzg4qe.mjs.map → direct-executor-Bs2g0ake.mjs.map} +1 -1
  502. package/dist/{dist-Cfu8mMBs.mjs → dist-BUmWMTbN.mjs} +1 -1
  503. package/dist/{dist-Cfu8mMBs.mjs.map → dist-BUmWMTbN.mjs.map} +1 -1
  504. package/dist/{email-locale-BJ8DjTzZ.mjs → email-locale-Bs3HFdnq.mjs} +1 -1
  505. package/dist/{email-locale-BJ8DjTzZ.mjs.map → email-locale-Bs3HFdnq.mjs.map} +1 -1
  506. package/dist/{emdash-runtime-DVi7vtXC.mjs → emdash-runtime-C8T-pZpS.mjs} +108 -62
  507. package/dist/emdash-runtime-C8T-pZpS.mjs.map +1 -0
  508. package/dist/{enrich-Duu4sV3a.mjs → enrich-DFlfnd3u.mjs} +3 -3
  509. package/dist/{enrich-Duu4sV3a.mjs.map → enrich-DFlfnd3u.mjs.map} +1 -1
  510. package/dist/{entry-lock-C7VX0NGK.d.mts → entry-lock-BulbgPBX.d.mts} +23 -23
  511. package/dist/{entry-lock-C7VX0NGK.d.mts.map → entry-lock-BulbgPBX.d.mts.map} +1 -1
  512. package/dist/{entry-lock-Df6-XhIu.mjs → entry-lock-CRVmruM0.mjs} +4 -4
  513. package/dist/{entry-lock-Df6-XhIu.mjs.map → entry-lock-CRVmruM0.mjs.map} +1 -1
  514. package/dist/{entry-lock-DLxCffFW.mjs → entry-lock-D-zJQ4q6.mjs} +3 -3
  515. package/dist/{entry-lock-DLxCffFW.mjs.map → entry-lock-D-zJQ4q6.mjs.map} +1 -1
  516. package/dist/{entry-locks-DJAqVweV.mjs → entry-locks-CJ9uhqg1.mjs} +2 -2
  517. package/dist/{entry-locks-DJAqVweV.mjs.map → entry-locks-CJ9uhqg1.mjs.map} +1 -1
  518. package/dist/{env-types-C3FCVBWe.mjs → env-types-BE3bCvfP.mjs} +5 -5
  519. package/dist/{env-types-C3FCVBWe.mjs.map → env-types-BE3bCvfP.mjs.map} +1 -1
  520. package/dist/{error-CVWeIOku.mjs → error-BCMgPxdn.mjs} +3 -3
  521. package/dist/{error-CVWeIOku.mjs.map → error-BCMgPxdn.mjs.map} +1 -1
  522. package/dist/{errors-BOYNdIo3.mjs → errors-8gJqv-XV.mjs} +15 -2
  523. package/dist/{errors-BOYNdIo3.mjs.map → errors-8gJqv-XV.mjs.map} +1 -1
  524. package/dist/{fence-C3MUitUN.mjs → fence-Dagicj14.mjs} +4 -4
  525. package/dist/{fence-C3MUitUN.mjs.map → fence-Dagicj14.mjs.map} +1 -1
  526. package/dist/{field-map-Bft9LKak.mjs → field-map-BSXdNGt5.mjs} +11 -10
  527. package/dist/field-map-BSXdNGt5.mjs.map +1 -0
  528. package/dist/{focal-point-JX8kcOTQ.mjs → focal-point-CgCcr1Ca.mjs} +1 -1
  529. package/dist/{focal-point-JX8kcOTQ.mjs.map → focal-point-CgCcr1Ca.mjs.map} +1 -1
  530. package/dist/{fts-manager-Beg3e4bI.mjs → fts-manager-6861qcwk.mjs} +68 -22
  531. package/dist/fts-manager-6861qcwk.mjs.map +1 -0
  532. package/dist/{gc-ByyAYiYE.mjs → gc-CNkXB3mE.mjs} +8 -8
  533. package/dist/{gc-ByyAYiYE.mjs.map → gc-CNkXB3mE.mjs.map} +1 -1
  534. package/dist/{hook-result-BrdLyOdI.d.mts → hook-result-f8t7hIuu.d.mts} +1 -1
  535. package/dist/{hook-result-BrdLyOdI.d.mts.map → hook-result-f8t7hIuu.d.mts.map} +1 -1
  536. package/dist/{hreflang-CY_F5OjF.d.mts → hreflang-8dUOJAPJ.d.mts} +2 -2
  537. package/dist/{hreflang-CY_F5OjF.d.mts.map → hreflang-8dUOJAPJ.d.mts.map} +1 -1
  538. package/dist/{hreflang-C8Jb-hrf.mjs → hreflang-BW5A4FLK.mjs} +8 -8
  539. package/dist/{hreflang-C8Jb-hrf.mjs.map → hreflang-BW5A4FLK.mjs.map} +1 -1
  540. package/dist/{http-route-dispatch-CyeW6iPv.mjs → http-route-dispatch-rXKvTNm9.mjs} +5 -5
  541. package/dist/{http-route-dispatch-CyeW6iPv.mjs.map → http-route-dispatch-rXKvTNm9.mjs.map} +1 -1
  542. package/dist/{identity-Cael5uTT.mjs → identity-CPRRSovU.mjs} +3 -3
  543. package/dist/{identity-Cael5uTT.mjs.map → identity-CPRRSovU.mjs.map} +1 -1
  544. package/dist/{import-BUXjdZUn.mjs → import-yVbfPyfd.mjs} +5 -5
  545. package/dist/{import-BUXjdZUn.mjs.map → import-yVbfPyfd.mjs.map} +1 -1
  546. package/dist/index-VM7Fzxwe.d.mts +260 -0
  547. package/dist/index-VM7Fzxwe.d.mts.map +1 -0
  548. package/dist/index.d.mts +25 -24
  549. package/dist/index.mjs +89 -88
  550. package/dist/{install-finalization-3JX5qQEA.mjs → install-finalization-RU6VrHOX.mjs} +1 -1
  551. package/dist/{install-finalization-3JX5qQEA.mjs.map → install-finalization-RU6VrHOX.mjs.map} +1 -1
  552. package/dist/{json-recordset-BUjxhr77.mjs → json-recordset-D0WhN2UA.mjs} +2 -2
  553. package/dist/{json-recordset-BUjxhr77.mjs.map → json-recordset-D0WhN2UA.mjs.map} +1 -1
  554. package/dist/{lifecycle-7vUJeFRe.mjs → lifecycle-B8d7Rdqx.mjs} +1 -1
  555. package/dist/{lifecycle-7vUJeFRe.mjs.map → lifecycle-B8d7Rdqx.mjs.map} +1 -1
  556. package/dist/{load-CdAG9wz-.mjs → load-D4xtzm6h.mjs} +2 -2
  557. package/dist/{load-CdAG9wz-.mjs.map → load-D4xtzm6h.mjs.map} +1 -1
  558. package/dist/{loader-CswroUbe.mjs → loader-DhnedqY4.mjs} +199 -101
  559. package/dist/loader-DhnedqY4.mjs.map +1 -0
  560. package/dist/{loops-uA4iTOzd.mjs → loops-B2YS-Zzr.mjs} +2 -2
  561. package/dist/{loops-uA4iTOzd.mjs.map → loops-B2YS-Zzr.mjs.map} +1 -1
  562. package/dist/{manifest-builder-B8zjuH3f.mjs → manifest-builder-g1FLviel.mjs} +10 -3
  563. package/dist/manifest-builder-g1FLviel.mjs.map +1 -0
  564. package/dist/media/image-endpoint.d.mts +3 -2
  565. package/dist/media/image-endpoint.d.mts.map +1 -1
  566. package/dist/media/image-endpoint.mjs +17 -8
  567. package/dist/media/image-endpoint.mjs.map +1 -1
  568. package/dist/media/index.d.mts +1 -1
  569. package/dist/media/index.mjs +7 -6
  570. package/dist/media/index.mjs.map +1 -1
  571. package/dist/media/local-runtime.d.mts +15 -14
  572. package/dist/media/local-runtime.d.mts.map +1 -1
  573. package/dist/media/local-runtime.mjs +20 -15
  574. package/dist/media/local-runtime.mjs.map +1 -1
  575. package/dist/{media-1WC65OCB.mjs → media-BR4_t-Wd.mjs} +3 -3
  576. package/dist/{media-1WC65OCB.mjs.map → media-BR4_t-Wd.mjs.map} +1 -1
  577. package/dist/{media--dJRU6i2.mjs → media-CikS-q6E.mjs} +4 -4
  578. package/dist/{media--dJRU6i2.mjs.map → media-CikS-q6E.mjs.map} +1 -1
  579. package/dist/{media-Bws9f18T.mjs → media-DepNLhPq.mjs} +14 -4
  580. package/dist/media-DepNLhPq.mjs.map +1 -0
  581. package/dist/{media-allowlist-BJB7MFx6.mjs → media-allowlist-BMBLqyWh.mjs} +2 -2
  582. package/dist/{media-allowlist-BJB7MFx6.mjs.map → media-allowlist-BMBLqyWh.mjs.map} +1 -1
  583. package/dist/{media-folders-Dn3C16B8.mjs → media-folders-CI0Wydfo.mjs} +2 -2
  584. package/dist/{media-folders-Dn3C16B8.mjs.map → media-folders-CI0Wydfo.mjs.map} +1 -1
  585. package/dist/{media-usage-CF0WVcLO.mjs → media-usage-X1_20MY-.mjs} +8 -8
  586. package/dist/{media-usage-CF0WVcLO.mjs.map → media-usage-X1_20MY-.mjs.map} +1 -1
  587. package/dist/{media-usage-activation-C9HwVw5w.mjs → media-usage-activation-bWusy3M2.mjs} +3 -3
  588. package/dist/{media-usage-activation-C9HwVw5w.mjs.map → media-usage-activation-bWusy3M2.mjs.map} +1 -1
  589. package/dist/{media-usage-work-m3AWTmmC.mjs → media-usage-work-B2RaoJIa.mjs} +4 -4
  590. package/dist/{media-usage-work-m3AWTmmC.mjs.map → media-usage-work-B2RaoJIa.mjs.map} +1 -1
  591. package/dist/{media-usage-work-CkLa5-nc.mjs → media-usage-work-BCK2J-v_.mjs} +7 -7
  592. package/dist/{media-usage-work-CkLa5-nc.mjs.map → media-usage-work-BCK2J-v_.mjs.map} +1 -1
  593. package/dist/{menus-BCVSSp1z.mjs → menus-B0Qqv_cS.mjs} +176 -92
  594. package/dist/menus-B0Qqv_cS.mjs.map +1 -0
  595. package/dist/{menus-Cl4kwdt7.mjs → menus-oypxT1pI.mjs} +134 -53
  596. package/dist/menus-oypxT1pI.mjs.map +1 -0
  597. package/dist/{menus-BSzwObhV.mjs → menus-uEAxWAm1.mjs} +3 -3
  598. package/dist/{menus-BSzwObhV.mjs.map → menus-uEAxWAm1.mjs.map} +1 -1
  599. package/dist/migrations/index.d.mts +1 -1
  600. package/dist/migrations/index.mjs +5 -5
  601. package/dist/{mime-B5M9R53H.mjs → mime-D1We9jUx.mjs} +1 -1
  602. package/dist/{mime-B5M9R53H.mjs.map → mime-D1We9jUx.mjs.map} +1 -1
  603. package/dist/{normalize-BuWa0lvd.mjs → normalize-Cx-bNwhP.mjs} +41 -12
  604. package/dist/normalize-Cx-bNwhP.mjs.map +1 -0
  605. package/dist/{oauth-authorization-TpEJrYB7.mjs → oauth-authorization-CPLgBrdo.mjs} +19 -6
  606. package/dist/oauth-authorization-CPLgBrdo.mjs.map +1 -0
  607. package/dist/{oauth-state-store-CHMn_mwc.mjs → oauth-state-store-BndCfRum.mjs} +1 -1
  608. package/dist/{oauth-state-store-CHMn_mwc.mjs.map → oauth-state-store-BndCfRum.mjs.map} +1 -1
  609. package/dist/object-cache/memory.d.mts +1 -1
  610. package/dist/{object-cache-Bo6DGaC9.mjs → object-cache-DmKr09La.mjs} +21 -4
  611. package/dist/{object-cache-Bo6DGaC9.mjs.map → object-cache-DmKr09La.mjs.map} +1 -1
  612. package/dist/{options-DJWaq3Ie.d.mts → options-BUUgroHg.d.mts} +3 -3
  613. package/dist/{options-DJWaq3Ie.d.mts.map → options-BUUgroHg.d.mts.map} +1 -1
  614. package/dist/page/index.d.mts +2 -2
  615. package/dist/page/index.mjs +16 -14
  616. package/dist/page/index.mjs.map +1 -1
  617. package/dist/{parse-DgQ2NABT.mjs → parse-B_b6gZxG.mjs} +2 -2
  618. package/dist/{parse-DgQ2NABT.mjs.map → parse-B_b6gZxG.mjs.map} +1 -1
  619. package/dist/{parse-CWHOFc6z.d.mts → parse-Dndx1QmN.d.mts} +3 -3
  620. package/dist/{parse-CWHOFc6z.d.mts.map → parse-Dndx1QmN.d.mts.map} +1 -1
  621. package/dist/{passkey-config-D0kdzEao.mjs → passkey-config-D2Lua5__.mjs} +1 -1
  622. package/dist/{passkey-config-D0kdzEao.mjs.map → passkey-config-D2Lua5__.mjs.map} +1 -1
  623. package/dist/{patterns-CMNnYCgf.mjs → patterns-CryGz_EV.mjs} +1 -1
  624. package/dist/{patterns-CMNnYCgf.mjs.map → patterns-CryGz_EV.mjs.map} +1 -1
  625. package/dist/{placeholder-D41vk11_.d.mts → placeholder-CSKu5OkD.d.mts} +9 -1
  626. package/dist/placeholder-CSKu5OkD.d.mts.map +1 -0
  627. package/dist/plugin-test-runtime.d.mts +17 -15
  628. package/dist/plugin-test-runtime.d.mts.map +1 -1
  629. package/dist/plugin-test-runtime.mjs +99 -98
  630. package/dist/plugin-types.d.mts +2 -2
  631. package/dist/plugin-utils.d.mts +13 -12
  632. package/dist/plugin-utils.d.mts.map +1 -1
  633. package/dist/plugins/adapt-sandbox-entry.d.mts +13 -12
  634. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  635. package/dist/plugins/host.d.mts +5 -5
  636. package/dist/plugins/host.mjs +48 -47
  637. package/dist/{policy-DLQ--Hnm.mjs → policy-BPugqmeV.mjs} +13 -5
  638. package/dist/policy-BPugqmeV.mjs.map +1 -0
  639. package/dist/{protocol-79kUO7jP.d.mts → protocol-PoAfD_9W.d.mts} +2 -2
  640. package/dist/{protocol-79kUO7jP.d.mts.map → protocol-PoAfD_9W.d.mts.map} +1 -1
  641. package/dist/{public-plugin-api-routes-BuAMJ8nN.mjs → public-plugin-api-routes-CMljrTby.mjs} +9 -9
  642. package/dist/{public-plugin-api-routes-BuAMJ8nN.mjs.map → public-plugin-api-routes-CMljrTby.mjs.map} +1 -1
  643. package/dist/{public-submission-Di3TsgzX.mjs → public-submission-ayqoyee4.mjs} +10 -10
  644. package/dist/{public-submission-Di3TsgzX.mjs.map → public-submission-ayqoyee4.mjs.map} +1 -1
  645. package/dist/query-BFHjCzSh.mjs +37 -0
  646. package/dist/query-BFHjCzSh.mjs.map +1 -0
  647. package/dist/{query-CpnRlBh8.mjs → query-D62NntCZ.mjs} +55 -65
  648. package/dist/query-D62NntCZ.mjs.map +1 -0
  649. package/dist/{query-haKvLAWl.mjs → query-LmPY2y0C.mjs} +5 -5
  650. package/dist/{query-haKvLAWl.mjs.map → query-LmPY2y0C.mjs.map} +1 -1
  651. package/dist/{rate-limit-Xp4d0NBY.mjs → rate-limit-C04Llsoc.mjs} +3 -3
  652. package/dist/{rate-limit-Xp4d0NBY.mjs.map → rate-limit-C04Llsoc.mjs.map} +1 -1
  653. package/dist/{redirect-DiS_3mA4.mjs → redirect-DjLdw427.mjs} +6 -6
  654. package/dist/{redirect-DiS_3mA4.mjs.map → redirect-DjLdw427.mjs.map} +1 -1
  655. package/dist/{redirect-paths-CNYq7w80.mjs → redirect-paths-DOaVBp6E.mjs} +1 -1
  656. package/dist/{redirect-paths-CNYq7w80.mjs.map → redirect-paths-DOaVBp6E.mjs.map} +1 -1
  657. package/dist/{redirects-BHpy-VsZ.mjs → redirects-Cpq1catN.mjs} +6 -6
  658. package/dist/{redirects-BHpy-VsZ.mjs.map → redirects-Cpq1catN.mjs.map} +1 -1
  659. package/dist/{redirects-BEVSRMa2.mjs → redirects-CyvvZrCJ.mjs} +2 -2
  660. package/dist/{redirects-BEVSRMa2.mjs.map → redirects-CyvvZrCJ.mjs.map} +1 -1
  661. package/dist/{registry-TUVaid9Z.mjs → registry-B0-O575m.mjs} +25 -20
  662. package/dist/registry-B0-O575m.mjs.map +1 -0
  663. package/dist/{relations-CA_QuMTU.mjs → relations-WIOojTL4.mjs} +24 -11
  664. package/dist/relations-WIOojTL4.mjs.map +1 -0
  665. package/dist/{request-cache-C4CIo5ad.mjs → request-cache-5z2WzWmh.mjs} +1 -1
  666. package/dist/{request-cache-C4CIo5ad.mjs.map → request-cache-5z2WzWmh.mjs.map} +1 -1
  667. package/dist/request-context.d.mts +12 -1
  668. package/dist/request-context.d.mts.map +1 -1
  669. package/dist/request-context.mjs.map +1 -1
  670. package/dist/{resolve-DwNM-CXl.mjs → resolve-BNnm8EkB.mjs} +14 -13
  671. package/dist/{resolve-DwNM-CXl.mjs.map → resolve-BNnm8EkB.mjs.map} +1 -1
  672. package/dist/{resolve-D-kqyKns.mjs → resolve-DdNXBJSr.mjs} +4 -4
  673. package/dist/resolve-DdNXBJSr.mjs.map +1 -0
  674. package/dist/{revision-BVp8S0e_.mjs → revision-Dx7Uth1X.mjs} +5 -5
  675. package/dist/{revision-BVp8S0e_.mjs.map → revision-Dx7Uth1X.mjs.map} +1 -1
  676. package/dist/{routes-BerZFrvV.mjs → routes-avqgc-8r.mjs} +3 -3
  677. package/dist/{routes-BerZFrvV.mjs.map → routes-avqgc-8r.mjs.map} +1 -1
  678. package/dist/{runner-C5NeAkBQ.mjs → runner-Bkkfk4O8.mjs} +78 -4
  679. package/dist/runner-Bkkfk4O8.mjs.map +1 -0
  680. package/dist/{runner-BObHz5FC.d.mts → runner-Dfgp6-S_.d.mts} +7 -2
  681. package/dist/runner-Dfgp6-S_.d.mts.map +1 -0
  682. package/dist/runtime.d.mts +14 -13
  683. package/dist/runtime.d.mts.map +1 -1
  684. package/dist/runtime.mjs +8 -6
  685. package/dist/runtime.mjs.map +1 -1
  686. package/dist/schema/project-env-types.mjs +43 -42
  687. package/dist/schema/project-env-types.mjs.map +1 -1
  688. package/dist/{schema-DJRfvM_o.mjs → schema-B-3rntlX.mjs} +11 -11
  689. package/dist/{schema-DJRfvM_o.mjs.map → schema-B-3rntlX.mjs.map} +1 -1
  690. package/dist/{schema-C4OBuv6Z.mjs → schema-BqBlUZtb.mjs} +4 -4
  691. package/dist/{schema-C4OBuv6Z.mjs.map → schema-BqBlUZtb.mjs.map} +1 -1
  692. package/dist/{scopes-BU03K7Uo.mjs → scopes-DNaY7Ey0.mjs} +3 -3
  693. package/dist/{scopes-BU03K7Uo.mjs.map → scopes-DNaY7Ey0.mjs.map} +1 -1
  694. package/dist/{search-DfVzks89.mjs → search-BPWTnpnD.mjs} +32 -32
  695. package/dist/search-BPWTnpnD.mjs.map +1 -0
  696. package/dist/{secrets-Cc_O3Kp-.mjs → secrets-Dswzrz3k.mjs} +2 -2
  697. package/dist/{secrets-Cc_O3Kp-.mjs.map → secrets-Dswzrz3k.mjs.map} +1 -1
  698. package/dist/{sections-BMy4JVUz.mjs → sections-rSao6rBG.mjs} +3 -3
  699. package/dist/{sections-BMy4JVUz.mjs.map → sections-rSao6rBG.mjs.map} +1 -1
  700. package/dist/seed/index.d.mts +2 -2
  701. package/dist/seed/index.mjs +42 -41
  702. package/dist/seo/index.d.mts +3 -3
  703. package/dist/seo/index.mjs +30 -28
  704. package/dist/seo/index.mjs.map +1 -1
  705. package/dist/{seo-VZYOEy8f.mjs → seo-B_H_pqOd.mjs} +3 -3
  706. package/dist/{seo-VZYOEy8f.mjs.map → seo-B_H_pqOd.mjs.map} +1 -1
  707. package/dist/{service-Bo_usgSk.mjs → service-DpiUQVpp.mjs} +2 -2
  708. package/dist/{service-Bo_usgSk.mjs.map → service-DpiUQVpp.mjs.map} +1 -1
  709. package/dist/{session-user-DlpPdf8L.mjs → session-user-DiE4JKPP.mjs} +4 -4
  710. package/dist/{session-user-DlpPdf8L.mjs.map → session-user-DiE4JKPP.mjs.map} +1 -1
  711. package/dist/{settings-DS914jjE.mjs → settings--XlUdUaI.mjs} +3 -3
  712. package/dist/{settings-DS914jjE.mjs.map → settings--XlUdUaI.mjs.map} +1 -1
  713. package/dist/{settings-CWb84sDm.mjs → settings-D932YP2-.mjs} +111 -44
  714. package/dist/settings-D932YP2-.mjs.map +1 -0
  715. package/dist/{setup-complete-BuNxAUiN.mjs → setup-complete-qsJYWutC.mjs} +2 -2
  716. package/dist/{setup-complete-BuNxAUiN.mjs.map → setup-complete-qsJYWutC.mjs.map} +1 -1
  717. package/dist/{setup-nonce-BnEAX0iy.mjs → setup-nonce-CBFgUFXw.mjs} +1 -1
  718. package/dist/{setup-nonce-BnEAX0iy.mjs.map → setup-nonce-CBFgUFXw.mjs.map} +1 -1
  719. package/dist/{site-domain-Bq5j5bVg.mjs → site-domain-oRGS_JfA.mjs} +2 -2
  720. package/dist/{site-domain-Bq5j5bVg.mjs.map → site-domain-oRGS_JfA.mjs.map} +1 -1
  721. package/dist/{sitemap-name-BTg2NJJv.mjs → sitemap-name-B8QP8wud.mjs} +1 -1
  722. package/dist/{sitemap-name-BTg2NJJv.mjs.map → sitemap-name-B8QP8wud.mjs.map} +1 -1
  723. package/dist/{slugify-bu2-jKia.mjs → slugify-BDEG9pLk.mjs} +1 -1
  724. package/dist/{slugify-bu2-jKia.mjs.map → slugify-BDEG9pLk.mjs.map} +1 -1
  725. package/dist/{snapshot-DYsG4uOq.mjs → snapshot-BjaXDZQ5.mjs} +2 -2
  726. package/dist/{snapshot-DYsG4uOq.mjs.map → snapshot-BjaXDZQ5.mjs.map} +1 -1
  727. package/dist/{stage-D8DWgPcO.mjs → stage-CZQnXM_G.mjs} +3 -3
  728. package/dist/{stage-D8DWgPcO.mjs.map → stage-CZQnXM_G.mjs.map} +1 -1
  729. package/dist/{staged-CD_imitH.mjs → staged-ByBmPFtX.mjs} +3 -3
  730. package/dist/{staged-CD_imitH.mjs.map → staged-ByBmPFtX.mjs.map} +1 -1
  731. package/dist/storage/local.d.mts +1 -1
  732. package/dist/storage/s3.d.mts +1 -1
  733. package/dist/{storage-query-DRyu3bSU.d.mts → storage-query-BFp06Y0s.d.mts} +22 -10
  734. package/dist/storage-query-BFp06Y0s.d.mts.map +1 -0
  735. package/dist/{taxonomies-Dd9JJv_a.mjs → taxonomies-5SR76j11.mjs} +15 -17
  736. package/dist/taxonomies-5SR76j11.mjs.map +1 -0
  737. package/dist/{taxonomies-ChnU7Mc8.mjs → taxonomies-B__VmCKQ.mjs} +64 -58
  738. package/dist/taxonomies-B__VmCKQ.mjs.map +1 -0
  739. package/dist/{taxonomy-C_C_LBAU.mjs → taxonomy-CMI5fczd.mjs} +30 -17
  740. package/dist/taxonomy-CMI5fczd.mjs.map +1 -0
  741. package/dist/{transaction-BVYIo_yu.mjs → transaction-CkoQ5wqQ.mjs} +1 -1
  742. package/dist/{transaction-BVYIo_yu.mjs.map → transaction-CkoQ5wqQ.mjs.map} +1 -1
  743. package/dist/{transfer-WmWiR3xf.mjs → transfer-BbKfufJ4.mjs} +2 -2
  744. package/dist/{transfer-WmWiR3xf.mjs.map → transfer-BbKfufJ4.mjs.map} +1 -1
  745. package/dist/{transfer-ClH6w6BV.mjs → transfer-DTGblAj2.mjs} +71 -34
  746. package/dist/{transfer-ClH6w6BV.mjs.map → transfer-DTGblAj2.mjs.map} +1 -1
  747. package/dist/{transfer-download--ofRj9Cw.mjs → transfer-download-D9LQEDX0.mjs} +1 -1
  748. package/dist/{transfer-download--ofRj9Cw.mjs.map → transfer-download-D9LQEDX0.mjs.map} +1 -1
  749. package/dist/{transport-DxiXnbXk.d.mts → transport-Dm5QzpT_.d.mts} +1 -1
  750. package/dist/{transport-DxiXnbXk.d.mts.map → transport-Dm5QzpT_.d.mts.map} +1 -1
  751. package/dist/{transport-BjbqNiPI.mjs → transport-Dzpn5b3i.mjs} +4 -3
  752. package/dist/transport-Dzpn5b3i.mjs.map +1 -0
  753. package/dist/{turnstile-CJwvsOqw.mjs → turnstile-Cs2wfkJG.mjs} +1 -1
  754. package/dist/{turnstile-CJwvsOqw.mjs.map → turnstile-Cs2wfkJG.mjs.map} +1 -1
  755. package/dist/{types-BA3ey2QH.d.mts → types-BAsCk5KU.d.mts} +1 -1
  756. package/dist/{types-BA3ey2QH.d.mts.map → types-BAsCk5KU.d.mts.map} +1 -1
  757. package/dist/{types-RLgeIpnF.d.mts → types-BuvSwT9Y.d.mts} +8 -7
  758. package/dist/{types-RLgeIpnF.d.mts.map → types-BuvSwT9Y.d.mts.map} +1 -1
  759. package/dist/{types-CNB-dj6F.d.mts → types-C4KT3Md2.d.mts} +10 -6
  760. package/dist/types-C4KT3Md2.d.mts.map +1 -0
  761. package/dist/{types-DvqVxZXa.d.mts → types-CVXHwIBB.d.mts} +1 -1
  762. package/dist/{types-DvqVxZXa.d.mts.map → types-CVXHwIBB.d.mts.map} +1 -1
  763. package/dist/{types-BGmQ0uXs.mjs → types-C_asjp1J.mjs} +1 -1
  764. package/dist/types-C_asjp1J.mjs.map +1 -0
  765. package/dist/{types-DHO7Pd25.d.mts → types-CadaL_k8.d.mts} +1 -1
  766. package/dist/{types-DHO7Pd25.d.mts.map → types-CadaL_k8.d.mts.map} +1 -1
  767. package/dist/{types-QoPHm-2w.d.mts → types-CjftrmZR.d.mts} +3 -3
  768. package/dist/{types-QoPHm-2w.d.mts.map → types-CjftrmZR.d.mts.map} +1 -1
  769. package/dist/{types-DCFavOii.d.mts → types-DKwRUA-x.d.mts} +1 -1
  770. package/dist/{types-DCFavOii.d.mts.map → types-DKwRUA-x.d.mts.map} +1 -1
  771. package/dist/{types-D2NEXtgB.mjs → types-DwhEvIVb.mjs} +8 -2
  772. package/dist/types-DwhEvIVb.mjs.map +1 -0
  773. package/dist/{types-Bwpzb5o6.d.mts → types-GwAyS5SH.d.mts} +1 -1
  774. package/dist/{types-Bwpzb5o6.d.mts.map → types-GwAyS5SH.d.mts.map} +1 -1
  775. package/dist/{types-slSqujQL.d.mts → types-uU2YNYSt.d.mts} +6 -1
  776. package/dist/types-uU2YNYSt.d.mts.map +1 -0
  777. package/dist/{update-check-BxNg9T6N.mjs → update-check-ABBJgg6M.mjs} +4 -4
  778. package/dist/{update-check-BxNg9T6N.mjs.map → update-check-ABBJgg6M.mjs.map} +1 -1
  779. package/dist/{url-Dn3IStq8.mjs → url-DTfGDJhI.mjs} +1 -1
  780. package/dist/{url-Dn3IStq8.mjs.map → url-DTfGDJhI.mjs.map} +1 -1
  781. package/dist/{user-BlCTKVAm.mjs → user-By8SzQxS.mjs} +3 -3
  782. package/dist/{user-BlCTKVAm.mjs.map → user-By8SzQxS.mjs.map} +1 -1
  783. package/dist/{utils-TPt7w2cS.mjs → utils-D5uOi6WS.mjs} +13 -5
  784. package/dist/utils-D5uOi6WS.mjs.map +1 -0
  785. package/dist/{index-BB9sVisO.d.mts → utils-Szp4iBQB.d.mts} +9 -256
  786. package/dist/utils-Szp4iBQB.d.mts.map +1 -0
  787. package/dist/{validate-emKxGC5F.d.mts → validate-DDvxy6qG.d.mts} +8 -8
  788. package/dist/{validate-emKxGC5F.d.mts.map → validate-DDvxy6qG.d.mts.map} +1 -1
  789. package/dist/{validate-DxYhJQA-.mjs → validate-Dz-TIOFB.mjs} +7 -7
  790. package/dist/{validate-DxYhJQA-.mjs.map → validate-Dz-TIOFB.mjs.map} +1 -1
  791. package/dist/{validation-Ckq4vsVg.mjs → validation-Fc9ZSUS_.mjs} +17 -16
  792. package/dist/{validation-Ckq4vsVg.mjs.map → validation-Fc9ZSUS_.mjs.map} +1 -1
  793. package/dist/version-Bu6Nlbb5.mjs +7 -0
  794. package/dist/{version-DHmGpcch.mjs.map → version-Bu6Nlbb5.mjs.map} +1 -1
  795. package/dist/version-DqB7LIO7.mjs +49 -0
  796. package/dist/version-DqB7LIO7.mjs.map +1 -0
  797. package/dist/{widgets-DA5XmvVC.mjs → widgets-BUx_Mf2q.mjs} +18 -5
  798. package/dist/widgets-BUx_Mf2q.mjs.map +1 -0
  799. package/dist/{wxr-taxonomies-RgRG0d5e.mjs → wxr-taxonomies-DbJtWrWM.mjs} +7 -6
  800. package/dist/wxr-taxonomies-DbJtWrWM.mjs.map +1 -0
  801. package/dist/{wxr-taxonomies-CrMonejI.d.mts → wxr-taxonomies-Dy2i2ON3.d.mts} +1 -1
  802. package/dist/wxr-taxonomies-Dy2i2ON3.d.mts.map +1 -0
  803. package/dist/{zod-generator-D0JKy94C.mjs → zod-generator--nlM0930.mjs} +5 -4
  804. package/dist/zod-generator--nlM0930.mjs.map +1 -0
  805. package/package.json +5 -5
  806. package/src/api/handlers/bulk-tag.ts +11 -3
  807. package/src/api/handlers/bylines.ts +6 -2
  808. package/src/api/handlers/content.ts +154 -23
  809. package/src/api/handlers/dashboard.ts +13 -6
  810. package/src/api/handlers/device-flow.ts +1 -3
  811. package/src/api/handlers/menus.ts +27 -13
  812. package/src/api/handlers/oauth-authorization.ts +1 -3
  813. package/src/api/handlers/relations.ts +15 -1
  814. package/src/api/handlers/taxonomies.ts +27 -17
  815. package/src/astro/image-endpoint.ts +23 -2
  816. package/src/astro/integration/admin-nav.ts +52 -0
  817. package/src/astro/integration/index.ts +7 -0
  818. package/src/astro/integration/runtime.ts +14 -0
  819. package/src/astro/integration/shims/use-sync-external-store-with-selector.js +2 -0
  820. package/src/astro/integration/shims/use-sync-external-store.js +4 -1
  821. package/src/astro/integration/vite-config.ts +16 -8
  822. package/src/astro/middleware/auth.ts +9 -2
  823. package/src/astro/middleware/redirect.ts +158 -63
  824. package/src/astro/middleware/request-context.ts +1 -0
  825. package/src/astro/middleware.ts +17 -4
  826. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +4 -1
  827. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +14 -1
  828. package/src/astro/routes/api/dashboard.ts +2 -0
  829. package/src/astro/routes/api/import/wordpress/analyze.ts +5 -29
  830. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -3
  831. package/src/astro/routes/api/media/file/[...key].ts +31 -7
  832. package/src/astro/routes/api/oauth/token.ts +5 -1
  833. package/src/astro/routes/api/widget-areas/[name]/reorder.ts +7 -1
  834. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +3 -1
  835. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +2 -1
  836. package/src/astro/routes/api/widget-areas/[name].ts +2 -1
  837. package/src/astro/routes/api/widget-areas/index.ts +2 -1
  838. package/src/astro/types.ts +4 -3
  839. package/src/auth/api-tokens.ts +3 -0
  840. package/src/auth/types.ts +6 -0
  841. package/src/cleanup.ts +44 -0
  842. package/src/cli/commands/export-seed.ts +6 -4
  843. package/src/cli/commands/login.ts +2 -4
  844. package/src/client/index.ts +1 -0
  845. package/src/client/transport.ts +11 -7
  846. package/src/components/EmDashImage.astro +14 -2
  847. package/src/components/InlinePortableTextEditor.tsx +4 -1
  848. package/src/components/inline-bubble-menu.tsx +109 -95
  849. package/src/components/inline-image.tsx +54 -48
  850. package/src/database/dialect-helpers.ts +10 -3
  851. package/src/database/migrations/content-sized.ts +82 -0
  852. package/src/database/migrations/policy.ts +28 -2
  853. package/src/database/migrations/runner.ts +48 -0
  854. package/src/database/repositories/byline.ts +95 -31
  855. package/src/database/repositories/comment.ts +17 -7
  856. package/src/database/repositories/content.ts +96 -23
  857. package/src/database/repositories/media.ts +17 -0
  858. package/src/database/repositories/menu.ts +236 -139
  859. package/src/database/repositories/taxonomy-def.ts +9 -2
  860. package/src/database/repositories/taxonomy.ts +47 -14
  861. package/src/database/repositories/types.ts +14 -3
  862. package/src/database/types.ts +1 -1
  863. package/src/emdash-runtime.ts +60 -17
  864. package/src/fields/image.ts +1 -0
  865. package/src/i18n/config.ts +58 -10
  866. package/src/i18n/normalize.ts +16 -2
  867. package/src/i18n/query.ts +47 -0
  868. package/src/i18n/resolve.ts +8 -3
  869. package/src/import/utils.ts +15 -2
  870. package/src/import/wxr-taxonomies.ts +3 -2
  871. package/src/index.ts +1 -0
  872. package/src/loader.ts +183 -114
  873. package/src/mcp/server.ts +28 -1
  874. package/src/media/caption.ts +30 -0
  875. package/src/media/content-disposition.ts +56 -0
  876. package/src/media/image-endpoint.ts +13 -6
  877. package/src/media/local-runtime.ts +3 -0
  878. package/src/media/normalize.ts +17 -8
  879. package/src/media/responsive.ts +12 -2
  880. package/src/media/types.ts +16 -3
  881. package/src/media/usage/content-fields.ts +2 -1
  882. package/src/menus/index.ts +158 -36
  883. package/src/migrations/manifest.ts +1 -0
  884. package/src/object-cache/index.ts +22 -0
  885. package/src/plugin-test-runtime.ts +1 -0
  886. package/src/plugins/byline-access.ts +3 -1
  887. package/src/plugins/context.ts +1 -2
  888. package/src/plugins/storage-indexes.ts +7 -3
  889. package/src/query.ts +67 -53
  890. package/src/redirects/artifacts.ts +39 -5
  891. package/src/references/field-map.ts +6 -4
  892. package/src/request-context.ts +8 -0
  893. package/src/schema/collection-slugs-cache.ts +31 -17
  894. package/src/schema/registry.ts +9 -0
  895. package/src/schema/types.ts +7 -6
  896. package/src/schema/zod-generator.ts +2 -1
  897. package/src/search/fts-manager.ts +103 -31
  898. package/src/search/query.ts +31 -64
  899. package/src/seed/apply.ts +221 -109
  900. package/src/seed/types.ts +6 -4
  901. package/src/settings/index.ts +135 -35
  902. package/src/settings/version.ts +54 -0
  903. package/src/taxonomies/index.ts +99 -85
  904. package/src/taxonomies/term-counts.ts +2 -1
  905. package/src/transfer/import/advance.ts +12 -1
  906. package/src/transfer/import/scaffold.ts +7 -1
  907. package/src/transfer/import/stages.ts +53 -2
  908. package/src/utils/db-errors.ts +15 -0
  909. package/src/utils/revalidating-cache.ts +85 -0
  910. package/src/virtual-modules.d.ts +1 -0
  911. package/src/visual-editing/toolbar.ts +7 -2
  912. package/src/widgets/index.ts +27 -13
  913. package/dist/api-D-7BNHoz.mjs.map +0 -1
  914. package/dist/api-tokens-CdP49zVF.mjs +0 -3
  915. package/dist/apply-T7ATgzCh.mjs.map +0 -1
  916. package/dist/artifacts-htGyfCSt.mjs.map +0 -1
  917. package/dist/byline-BR1qhyiw.mjs.map +0 -1
  918. package/dist/bylines-CVOvRUL7.mjs.map +0 -1
  919. package/dist/collection-slugs-cache-e09QeJQt.mjs.map +0 -1
  920. package/dist/comment-UvIWDKcW.mjs.map +0 -1
  921. package/dist/config-Bsm_u_oE.d.mts.map +0 -1
  922. package/dist/config-CFMojMFK.d.mts.map +0 -1
  923. package/dist/config-CvmjJcVw.mjs +0 -73
  924. package/dist/config-CvmjJcVw.mjs.map +0 -1
  925. package/dist/content-DQSRZTVw.mjs.map +0 -1
  926. package/dist/context-BYptmCN0.mjs.map +0 -1
  927. package/dist/dashboard-D0jcgBD7.mjs.map +0 -1
  928. package/dist/db-errors-CBD5yMro.mjs.map +0 -1
  929. package/dist/deferred-tasks-ZvUECSzI.d.mts +0 -9
  930. package/dist/deferred-tasks-ZvUECSzI.d.mts.map +0 -1
  931. package/dist/device-flow-BkFKBoAn.mjs.map +0 -1
  932. package/dist/dialect-helpers-7_IqPdh9.mjs.map +0 -1
  933. package/dist/emdash-runtime-DVi7vtXC.mjs.map +0 -1
  934. package/dist/field-defs-cache-Dez5iWJJ.mjs +0 -77
  935. package/dist/field-defs-cache-Dez5iWJJ.mjs.map +0 -1
  936. package/dist/field-map-Bft9LKak.mjs.map +0 -1
  937. package/dist/fts-manager-Beg3e4bI.mjs.map +0 -1
  938. package/dist/index-BB9sVisO.d.mts.map +0 -1
  939. package/dist/loader-CswroUbe.mjs.map +0 -1
  940. package/dist/manifest-builder-B8zjuH3f.mjs.map +0 -1
  941. package/dist/media-Bws9f18T.mjs.map +0 -1
  942. package/dist/menus-BCVSSp1z.mjs.map +0 -1
  943. package/dist/menus-Cl4kwdt7.mjs.map +0 -1
  944. package/dist/normalize-BuWa0lvd.mjs.map +0 -1
  945. package/dist/oauth-authorization-TpEJrYB7.mjs.map +0 -1
  946. package/dist/placeholder-D41vk11_.d.mts.map +0 -1
  947. package/dist/policy-DLQ--Hnm.mjs.map +0 -1
  948. package/dist/query-CpnRlBh8.mjs.map +0 -1
  949. package/dist/registry-TUVaid9Z.mjs.map +0 -1
  950. package/dist/relations-CA_QuMTU.mjs.map +0 -1
  951. package/dist/resolve-D-kqyKns.mjs.map +0 -1
  952. package/dist/runner-BObHz5FC.d.mts.map +0 -1
  953. package/dist/runner-C5NeAkBQ.mjs.map +0 -1
  954. package/dist/search-DfVzks89.mjs.map +0 -1
  955. package/dist/settings-CWb84sDm.mjs.map +0 -1
  956. package/dist/storage-query-DRyu3bSU.d.mts.map +0 -1
  957. package/dist/taxonomies-ChnU7Mc8.mjs.map +0 -1
  958. package/dist/taxonomies-Dd9JJv_a.mjs.map +0 -1
  959. package/dist/taxonomy-C_C_LBAU.mjs.map +0 -1
  960. package/dist/transport-BjbqNiPI.mjs.map +0 -1
  961. package/dist/types-BGmQ0uXs.mjs.map +0 -1
  962. package/dist/types-CNB-dj6F.d.mts.map +0 -1
  963. package/dist/types-D2NEXtgB.mjs.map +0 -1
  964. package/dist/types-slSqujQL.d.mts.map +0 -1
  965. package/dist/utils-TPt7w2cS.mjs.map +0 -1
  966. package/dist/version-DHmGpcch.mjs +0 -7
  967. package/dist/widgets-DA5XmvVC.mjs.map +0 -1
  968. package/dist/wxr-taxonomies-CrMonejI.d.mts.map +0 -1
  969. package/dist/wxr-taxonomies-RgRG0d5e.mjs.map +0 -1
  970. package/dist/zod-generator-D0JKy94C.mjs.map +0 -1
@@ -1,77 +0,0 @@
1
- import { d as __exportAll } from "./runner-C5NeAkBQ.mjs";
2
- import { t as after } from "./after-PcEvMY_6.mjs";
3
- import { getRequestContext } from "./request-context.mjs";
4
- import { n as initWithLock, t as createInitLock } from "./init-lock-BGmew3r1.mjs";
5
- import { r as requestCached } from "./request-cache-C4CIo5ad.mjs";
6
- import { n as BylineSchemaRegistry } from "./byline-registry-dvt4N3xV.mjs";
7
-
8
- //#region src/bylines/field-defs-cache.ts
9
- var field_defs_cache_exports = /* @__PURE__ */ __exportAll({ getBylineFieldDefs: () => getBylineFieldDefs });
10
- const HOLDER_KEY = Symbol.for("emdash:byline-field-defs");
11
- const g = globalThis;
12
- const holder = g[HOLDER_KEY] ?? (() => {
13
- const h = {
14
- value: null,
15
- hasValue: false,
16
- cachedVersion: -1,
17
- lock: createInitLock()
18
- };
19
- g[HOLDER_KEY] = h;
20
- return h;
21
- })();
22
- const REQUEST_CACHE_KEY_VERSION = "byline-fields-version";
23
- const REQUEST_CACHE_KEY_DEFS_PREFIX = "byline-field-defs:";
24
- /**
25
- * Reclaim window for the single-flight lock: if an owner holds it past
26
- * this without publishing (e.g. its request was cancelled and the
27
- * anchored fetch hasn't completed yet), the next reader reclaims and
28
- * refetches. `listFields` is a single fast SELECT, so this only needs to
29
- * cover a genuinely slow/stranded query. Mutable solely so tests can
30
- * shorten it; production never changes it.
31
- */
32
- let reclaimDeadlineMs = 1e4;
33
- /**
34
- * Read the persisted `options.byline_fields_version` counter. Cached for
35
- * the duration of the current request via `requestCached`. Returns `0`
36
- * when the row is missing (matches `BylineSchemaRegistry.getVersion`).
37
- */
38
- async function getBylineFieldsVersion(db) {
39
- return requestCached(REQUEST_CACHE_KEY_VERSION, () => new BylineSchemaRegistry(db).getVersion());
40
- }
41
- /**
42
- * Resolve registered byline custom-field definitions. Two-tier cache:
43
- * per-request via `requestCached`, then per-isolate via the global
44
- * holder.
45
- *
46
- * The global holder is bypassed for isolated requests (playground / DO
47
- * preview, which point at a divergent schema) and for dirty versions
48
- * (odd counter — see `BylineSchemaRegistry`'s class JSDoc — indicates
49
- * an in-flight or crashed mutation). Both bypass paths still hit the
50
- * per-request cache, so a single render dedupes within itself.
51
- *
52
- * Always returns an array. Empty = no custom fields registered.
53
- */
54
- async function getBylineFieldDefs(db) {
55
- const isolated = getRequestContext()?.dbIsIsolated === true;
56
- const version = await getBylineFieldsVersion(db);
57
- const dirty = version % 2 !== 0;
58
- return requestCached(`${REQUEST_CACHE_KEY_DEFS_PREFIX}${version}`, async () => {
59
- if (isolated || dirty) return new BylineSchemaRegistry(db).listFields();
60
- return initWithLock(holder.lock, () => holder.hasValue && holder.cachedVersion === version ? holder.value : null, (isCurrentClaim) => (async () => {
61
- const defs = await new BylineSchemaRegistry(db).listFields();
62
- if (isCurrentClaim() && version >= holder.cachedVersion) {
63
- holder.value = defs;
64
- holder.hasValue = true;
65
- holder.cachedVersion = version;
66
- }
67
- return defs;
68
- })(), {
69
- deadlineMs: reclaimDeadlineMs,
70
- anchor: (promise) => after(() => promise)
71
- });
72
- });
73
- }
74
-
75
- //#endregion
76
- export { getBylineFieldDefs as n, field_defs_cache_exports as t };
77
- //# sourceMappingURL=field-defs-cache-Dez5iWJJ.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"field-defs-cache-Dez5iWJJ.mjs","names":[],"sources":["../src/bylines/field-defs-cache.ts"],"sourcesContent":["/**\n * Byline field-definitions cache\n *\n * Discussion #1174 / Phase 3. Two-tier cache for the byline custom-field\n * registry, mirroring the `settings/index.ts` pattern.\n *\n * **Tier 1 — per-isolate (globalThis).** Field definitions change rarely\n * but are read on every byline hydration (admin pages, content rendering,\n * API responses). Caching at the isolate level drops the SELECT-from-\n * `_emdash_byline_fields` from once-per-hydration to once-per-isolate-\n * after-bump. The cache holds the resolved *value* behind a reclaimable\n * single-flight lock (see `utils/single-flight-cache.ts`), never an\n * in-flight promise: concurrent cold-isolate readers coalesce onto one\n * query by polling the published value, so a reader whose request is\n * cancelled mid-query can never strand later byline hydrations on the\n * isolate (the workerd never-settling-promise hazard that produced 524s).\n *\n * Stored on globalThis under `Symbol.for(\"emdash:byline-field-defs\")` so\n * Vite SSR chunk duplication can't produce two independent caches (same\n * pattern as `request-cache.ts` and `request-context.ts`).\n *\n * **Tier 2 — per-request.** Wraps both the version read and the defs\n * fetch in `requestCached` so a single page render that hits byline\n * hydration multiple times (e.g. list view + individual byline lookups\n * in a sidebar) pays at most one version read and one defs fetch in\n * total. The defs cache key includes the version, so a (highly\n * unlikely) mid-request bump still produces a self-consistent view —\n * the second call sees a different key and refetches.\n *\n * **Invalidation.** `options.byline_fields_version` is bumped by every\n * `BylineSchemaRegistry` mutation (Phase 2). Each isolate independently\n * reads the persisted version on the next request and compares against\n * its cached version; mismatch triggers a refetch and overwrite. Other\n * isolates see the change within one request after the bump propagates.\n *\n * **Isolated databases bypass the global cache.** Playground and DO\n * preview sessions set `requestContext.dbIsIsolated = true`, signalling\n * the per-request `db` points at an isolated schema that may diverge\n * from the singleton. Schema-derived caches keyed by the singleton's\n * version would silently leak the singleton's defs into the isolated\n * request. We follow the `loader.ts:74` `getTaxonomyNames` precedent:\n * skip both reading from and writing to the global holder when the\n * request is isolated. The per-request cache (`requestCached`) is keyed\n * by the WeakMap'd `EmDashRequestContext`, so it can't cross-pollinate\n * between requests — it stays in play even for isolated DBs.\n *\n * **Why a versioned cache and not a TTL?** The version counter gives\n * deterministic invalidation without the staleness window a TTL would\n * impose. Field-definition changes need to be visible to the next\n * request, not eventually. The cost is one cheap `options` read per\n * request — cheaper than the field-defs fetch it replaces, and cheaper\n * than maintaining a TTL state machine.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { after } from \"../after.js\";\nimport type { Database } from \"../database/types.js\";\nimport { requestCached } from \"../request-cache.js\";\nimport { getRequestContext } from \"../request-context.js\";\nimport { BylineSchemaRegistry } from \"../schema/byline-registry.js\";\nimport type { BylineFieldDefinition } from \"../schema/types.js\";\nimport { createInitLock, type InitLock, initWithLock } from \"../utils/init-lock.js\";\n\ninterface FieldDefsHolder {\n\t/** Last resolved defs, valid only when `hasValue` is true. */\n\tvalue: BylineFieldDefinition[] | null;\n\t/** Presence flag, separate from `value` so an empty-array result still caches. */\n\thasValue: boolean;\n\t/** Persisted-version value that `value` was fetched against. */\n\tcachedVersion: number;\n\t/** Reclaimable single-flight lock so a cancelled owner can't wedge readers. */\n\tlock: InitLock;\n}\n\nconst HOLDER_KEY = Symbol.for(\"emdash:byline-field-defs\");\nconst g = globalThis as Record<symbol, unknown>;\nconst holder: FieldDefsHolder =\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see request-cache.ts)\n\t(g[HOLDER_KEY] as FieldDefsHolder | undefined) ??\n\t(() => {\n\t\tconst h: FieldDefsHolder = {\n\t\t\tvalue: null,\n\t\t\thasValue: false,\n\t\t\tcachedVersion: -1,\n\t\t\tlock: createInitLock(),\n\t\t};\n\t\tg[HOLDER_KEY] = h;\n\t\treturn h;\n\t})();\n\nconst REQUEST_CACHE_KEY_VERSION = \"byline-fields-version\";\nconst REQUEST_CACHE_KEY_DEFS_PREFIX = \"byline-field-defs:\";\n\n/**\n * Reclaim window for the single-flight lock: if an owner holds it past\n * this without publishing (e.g. its request was cancelled and the\n * anchored fetch hasn't completed yet), the next reader reclaims and\n * refetches. `listFields` is a single fast SELECT, so this only needs to\n * cover a genuinely slow/stranded query. Mutable solely so tests can\n * shorten it; production never changes it.\n */\nlet reclaimDeadlineMs = 10_000;\n\n/**\n * Read the persisted `options.byline_fields_version` counter. Cached for\n * the duration of the current request via `requestCached`. Returns `0`\n * when the row is missing (matches `BylineSchemaRegistry.getVersion`).\n */\nasync function getBylineFieldsVersion(db: Kysely<Database>): Promise<number> {\n\treturn requestCached(REQUEST_CACHE_KEY_VERSION, () => new BylineSchemaRegistry(db).getVersion());\n}\n\n/**\n * Resolve registered byline custom-field definitions. Two-tier cache:\n * per-request via `requestCached`, then per-isolate via the global\n * holder.\n *\n * The global holder is bypassed for isolated requests (playground / DO\n * preview, which point at a divergent schema) and for dirty versions\n * (odd counter — see `BylineSchemaRegistry`'s class JSDoc — indicates\n * an in-flight or crashed mutation). Both bypass paths still hit the\n * per-request cache, so a single render dedupes within itself.\n *\n * Always returns an array. Empty = no custom fields registered.\n */\nexport async function getBylineFieldDefs(db: Kysely<Database>): Promise<BylineFieldDefinition[]> {\n\tconst isolated = getRequestContext()?.dbIsIsolated === true;\n\tconst version = await getBylineFieldsVersion(db);\n\tconst dirty = version % 2 !== 0;\n\treturn requestCached(`${REQUEST_CACHE_KEY_DEFS_PREFIX}${version}`, async () => {\n\t\tif (isolated || dirty) {\n\t\t\treturn new BylineSchemaRegistry(db).listFields();\n\t\t}\n\t\t// Per-isolate single-flight cache keyed on the persisted version.\n\t\t// Coalesce concurrent cold readers via the lock and read the\n\t\t// published value; never await another request's in-flight promise\n\t\t// (a cancelled owner would otherwise strand every later byline\n\t\t// hydration on the isolate). The fetch is anchored so a cancelled\n\t\t// originator still drives it to completion and populates the cache.\n\t\treturn initWithLock<BylineFieldDefinition[]>(\n\t\t\tholder.lock,\n\t\t\t() => (holder.hasValue && holder.cachedVersion === version ? holder.value : null),\n\t\t\t(isCurrentClaim) =>\n\t\t\t\t(async () => {\n\t\t\t\t\tconst defs = await new BylineSchemaRegistry(db).listFields();\n\t\t\t\t\t// Publish only while still the current claim, and never\n\t\t\t\t\t// regress over a newer version a concurrent reader stored.\n\t\t\t\t\tif (isCurrentClaim() && version >= holder.cachedVersion) {\n\t\t\t\t\t\tholder.value = defs;\n\t\t\t\t\t\tholder.hasValue = true;\n\t\t\t\t\t\tholder.cachedVersion = version;\n\t\t\t\t\t}\n\t\t\t\t\treturn defs;\n\t\t\t\t})(),\n\t\t\t{ deadlineMs: reclaimDeadlineMs, anchor: (promise) => after(() => promise) },\n\t\t);\n\t});\n}\n\n/**\n * Test/internal helper: clear the per-isolate cache. Useful for unit\n * tests that mutate the registry directly and need to force a refetch\n * without going through the full version-bump path.\n *\n * Production code paths should rely on the version counter for\n * invalidation — calling this from a write path would bypass the\n * coordination that lets other isolates see the change.\n */\nexport function resetBylineFieldDefsCacheForTests(): void {\n\tholder.value = null;\n\tholder.hasValue = false;\n\tholder.cachedVersion = -1;\n\tholder.lock.ownerStartedAt = null;\n\tholder.lock.generation = 0;\n\treclaimDeadlineMs = 10_000;\n}\n\n/**\n * Test-only: shorten the single-flight reclaim window so a \"stranded\n * owner\" scenario can be exercised without waiting out the production\n * deadline. Reset by `resetBylineFieldDefsCacheForTests`.\n *\n * @internal\n */\nexport function setBylineFieldDefsReclaimDeadlineForTests(ms: number): void {\n\treclaimDeadlineMs = ms;\n}\n"],"mappings":";;;;;;;;;AA2EA,MAAM,aAAa,OAAO,IAAI,2BAA2B;AACzD,MAAM,IAAI;AACV,MAAM,SAEJ,EAAE,sBACI;CACN,MAAM,IAAqB;EAC1B,OAAO;EACP,UAAU;EACV,eAAe;EACf,MAAM,gBAAgB;EACtB;AACD,GAAE,cAAc;AAChB,QAAO;IACJ;AAEL,MAAM,4BAA4B;AAClC,MAAM,gCAAgC;;;;;;;;;AAUtC,IAAI,oBAAoB;;;;;;AAOxB,eAAe,uBAAuB,IAAuC;AAC5E,QAAO,cAAc,iCAAiC,IAAI,qBAAqB,GAAG,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;AAgBjG,eAAsB,mBAAmB,IAAwD;CAChG,MAAM,WAAW,mBAAmB,EAAE,iBAAiB;CACvD,MAAM,UAAU,MAAM,uBAAuB,GAAG;CAChD,MAAM,QAAQ,UAAU,MAAM;AAC9B,QAAO,cAAc,GAAG,gCAAgC,WAAW,YAAY;AAC9E,MAAI,YAAY,MACf,QAAO,IAAI,qBAAqB,GAAG,CAAC,YAAY;AAQjD,SAAO,aACN,OAAO,YACA,OAAO,YAAY,OAAO,kBAAkB,UAAU,OAAO,QAAQ,OAC3E,oBACC,YAAY;GACZ,MAAM,OAAO,MAAM,IAAI,qBAAqB,GAAG,CAAC,YAAY;AAG5D,OAAI,gBAAgB,IAAI,WAAW,OAAO,eAAe;AACxD,WAAO,QAAQ;AACf,WAAO,WAAW;AAClB,WAAO,gBAAgB;;AAExB,UAAO;MACJ,EACL;GAAE,YAAY;GAAmB,SAAS,YAAY,YAAY,QAAQ;GAAE,CAC5E;GACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"field-map-Bft9LKak.mjs","names":[],"sources":["../src/references/field-map.ts"],"sourcesContent":["/**\n * The reference fields a collection carries, for the public query path.\n *\n * `referenceFieldConstraints` (api/handlers) answers the write question — how\n * many entries may a field select, and is it required. Rendering asks a\n * different one: which collection do I load, and which end of the relation am I\n * standing on. Both read the same rows; keeping them apart keeps the render\n * path off the relation table, which the constraints map has to read for its\n * limits.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport { jsonExtractExpr } from \"../database/dialect-helpers.js\";\nimport type { Database } from \"../database/types.js\";\nimport { getDb } from \"../loader.js\";\nimport { cachedQuery, CacheNamespace } from \"../object-cache/index.js\";\nimport { requestCached } from \"../request-cache.js\";\nimport { isMissingTableError } from \"../utils/db-errors.js\";\n\n/** One reference field, as a render needs it. */\nexport interface ReferenceFieldBinding {\n\t/** Field slug — the key a caller names a selection under. */\n\tslug: string;\n\t/** Relation slug the field binds to. */\n\trelation: string;\n\t/**\n\t * The relation's id, read in the same statement as the binding. Rendering\n\t * pages the link table by id, so carrying it here is what keeps a field's\n\t * cost at one link read rather than a slug lookup and then the read.\n\t */\n\trelationId: string;\n\t/** Which end of the relation this field's own collection sits on. */\n\tside: \"parent\" | \"child\";\n\t/** The collection at the other end. */\n\ttargetCollection: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nasync function loadBindings(\n\tdb: Kysely<Database>,\n\tcollection: string,\n): Promise<ReferenceFieldBinding[]> {\n\t// The relation's id joins in here rather than being looked up per field at\n\t// render time: the field stores a slug, but the link table is keyed by id.\n\tconst relationSlug = jsonExtractExpr(db, \"validation\", \"relation\");\n\tlet rows: { slug: string; validation: string | null; relation_id: string | null }[];\n\ttry {\n\t\tconst result = await sql<{\n\t\t\tslug: string;\n\t\t\tvalidation: string | null;\n\t\t\trelation_id: string | null;\n\t\t}>`\n\t\t\tSELECT f.slug AS slug, f.validation AS validation, r.id AS relation_id\n\t\t\tFROM ${sql.ref(\"_emdash_fields\")} AS f\n\t\t\tINNER JOIN ${sql.ref(\"_emdash_collections\")} AS c ON c.id = f.collection_id\n\t\t\tLEFT JOIN ${sql.ref(\"_emdash_relations\")} AS r ON r.slug = ${sql.raw(relationSlug)}\n\t\t\tWHERE c.slug = ${collection} AND f.type = 'reference'\n\t\t`.execute(db);\n\t\trows = result.rows;\n\t} catch (error) {\n\t\tif (isMissingTableError(error)) return [];\n\t\tthrow error;\n\t}\n\n\tconst bindings: ReferenceFieldBinding[] = [];\n\tfor (const row of rows) {\n\t\tif (!row.validation) continue;\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(row.validation);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isRecord(parsed)) continue;\n\t\tconst { relation, targetCollection } = parsed;\n\t\t// A field with neither is unbound: it keeps its own column, and its value\n\t\t// is already in `data`. There is nothing to resolve. Nor is there when the\n\t\t// named relation is gone — the join leaves no id to page by.\n\t\tif (typeof relation !== \"string\" || typeof targetCollection !== \"string\") continue;\n\t\tif (!row.relation_id) continue;\n\t\tbindings.push({\n\t\t\tslug: row.slug,\n\t\t\trelation,\n\t\t\trelationId: row.relation_id,\n\t\t\ttargetCollection,\n\t\t\tside: parsed.relationSide === \"child\" ? \"child\" : \"parent\",\n\t\t});\n\t}\n\treturn bindings;\n}\n\n/**\n * Every bound reference field on `collection`, by field slug.\n *\n * Cached twice over: once per request, and once in the schema object-cache\n * namespace, which a schema edit already bumps. A render that asks for\n * references therefore pays for this lookup at most once per isolate between\n * schema changes, and a render that asks for none never issues it.\n */\nexport function getReferenceFieldMap(\n\tcollection: string,\n): Promise<Map<string, ReferenceFieldBinding>> {\n\treturn requestCached(`reference-field-map:${collection}`, async () => {\n\t\tconst bindings = await cachedQuery({\n\t\t\tnamespace: CacheNamespace.SCHEMA,\n\t\t\tkey: `reference-field-map:${collection}`,\n\t\t\tload: async () => loadBindings(await getDb(), collection),\n\t\t});\n\t\treturn new Map(bindings.map((binding) => [binding.slug, binding]));\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsCA,SAAS,SAAS,OAAkD;AACnE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,eAAe,aACd,IACA,YACmC;CAGnC,MAAM,eAAe,gBAAgB,IAAI,cAAc,WAAW;CAClE,IAAI;AACJ,KAAI;AAYH,UAXe,MAAM,GAInB;;UAEM,IAAI,IAAI,iBAAiB,CAAC;gBACpB,IAAI,IAAI,sBAAsB,CAAC;eAChC,IAAI,IAAI,oBAAoB,CAAC,oBAAoB,IAAI,IAAI,aAAa,CAAC;oBAClE,WAAW;IAC3B,QAAQ,GAAG,EACC;UACN,OAAO;AACf,MAAI,oBAAoB,MAAM,CAAE,QAAO,EAAE;AACzC,QAAM;;CAGP,MAAM,WAAoC,EAAE;AAC5C,MAAK,MAAM,OAAO,MAAM;AACvB,MAAI,CAAC,IAAI,WAAY;EACrB,IAAI;AACJ,MAAI;AACH,YAAS,KAAK,MAAM,IAAI,WAAW;UAC5B;AACP;;AAED,MAAI,CAAC,SAAS,OAAO,CAAE;EACvB,MAAM,EAAE,UAAU,qBAAqB;AAIvC,MAAI,OAAO,aAAa,YAAY,OAAO,qBAAqB,SAAU;AAC1E,MAAI,CAAC,IAAI,YAAa;AACtB,WAAS,KAAK;GACb,MAAM,IAAI;GACV;GACA,YAAY,IAAI;GAChB;GACA,MAAM,OAAO,iBAAiB,UAAU,UAAU;GAClD,CAAC;;AAEH,QAAO;;;;;;;;;;AAWR,SAAgB,qBACf,YAC8C;AAC9C,QAAO,cAAc,uBAAuB,cAAc,YAAY;EACrE,MAAM,WAAW,MAAM,YAAY;GAClC,WAAW,eAAe;GAC1B,KAAK,uBAAuB;GAC5B,MAAM,YAAY,aAAa,MAAM,OAAO,EAAE,WAAW;GACzD,CAAC;AACF,SAAO,IAAI,IAAI,SAAS,KAAK,YAAY,CAAC,QAAQ,MAAM,QAAQ,CAAC,CAAC;GACjE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fts-manager-Beg3e4bI.mjs","names":["dialectTableExists"],"sources":["../src/search/fts-manager.ts"],"sourcesContent":["/**\n * FTS5 Manager\n *\n * Manages FTS5 virtual tables and triggers for search indexing.\n */\n\nimport type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite, tableExists as dialectTableExists } from \"../database/dialect-helpers.js\";\nimport type { Database } from \"../database/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { SEARCH_TOKENIZERS } from \"./types.js\";\nimport type { SearchConfig, SearchTokenizer } from \"./types.js\";\n\nconst DEFAULT_SEARCH_TOKENIZER: SearchTokenizer = \"porter unicode61\";\n\nfunction isSearchTokenizer(value: unknown): value is SearchTokenizer {\n\treturn SEARCH_TOKENIZERS.some((tokenizer) => tokenizer === value);\n}\n\nfunction resolveSearchTokenizer(tokenize?: SearchTokenizer): SearchTokenizer {\n\tif (tokenize === undefined) return DEFAULT_SEARCH_TOKENIZER;\n\tif (!isSearchTokenizer(tokenize)) {\n\t\tthrow new Error(`Unsupported FTS5 tokenizer: \"${String(tokenize)}\"`);\n\t}\n\treturn tokenize;\n}\n\n/**\n * FTS5 Manager\n *\n * Handles creation, deletion, and management of FTS5 virtual tables\n * for full-text search on content collections.\n */\nexport class FTSManager {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Validate a collection slug and its searchable field names.\n\t * Must be called before any raw SQL interpolation.\n\t */\n\tprivate validateInputs(collectionSlug: string, searchableFields?: string[]): void {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\tif (searchableFields) {\n\t\t\tfor (const field of searchableFields) {\n\t\t\t\tvalidateIdentifier(field, \"searchable field name\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the FTS table name for a collection\n\t * Uses _emdash_ prefix to clearly mark as internal/system table\n\t */\n\tgetFtsTableName(collectionSlug: string): string {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\treturn `_emdash_fts_${collectionSlug}`;\n\t}\n\n\t/**\n\t * Get the content table name for a collection\n\t */\n\tgetContentTableName(collectionSlug: string): string {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\treturn `ec_${collectionSlug}`;\n\t}\n\n\t/**\n\t * Check if an FTS table exists for a collection\n\t */\n\tasync ftsTableExists(collectionSlug: string): Promise<boolean> {\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\treturn dialectTableExists(this.db, ftsTable);\n\t}\n\n\t/**\n\t * Create an FTS5 virtual table for a collection.\n\t * FTS5 is SQLite-only; on other dialects this is a no-op.\n\t *\n\t * @param collectionSlug - The collection slug\n\t * @param searchableFields - Array of field names to index\n\t * @param weights - Optional field weights for ranking\n\t * @param tokenize - Optional FTS5 tokenizer configuration\n\t */\n\tasync createFtsTable(\n\t\tcollectionSlug: string,\n\t\tsearchableFields: string[],\n\t\t_weights?: Record<string, number>,\n\t\ttokenize?: SearchTokenizer,\n\t): Promise<void> {\n\t\tconst tokenizer = resolveSearchTokenizer(tokenize);\n\t\tif (!isSqlite(this.db)) return;\n\t\tthis.validateInputs(collectionSlug, searchableFields);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\n\t\t// Build the column list for FTS5\n\t\t// id and locale are UNINDEXED (used for joining/filtering, not searched)\n\t\tconst columns = [\"id UNINDEXED\", \"locale UNINDEXED\", ...searchableFields].join(\", \");\n\n\t\t// Create the FTS5 virtual table. The table stores its own copy of the\n\t\t// indexed values (no `content=` option): Portable Text fields are\n\t\t// indexed as extracted plain text — see searchValueExpr — which cannot\n\t\t// mirror the raw JSON in the ec_* column, and external-content FTS5\n\t\t// requires the index to exactly mirror the backing table's values\n\t\t// (snippet() reads them, and the 'delete' command must be fed the\n\t\t// inserted values or the index corrupts — see migration 039's history).\n\t\t// Storing the extracted text also makes snippet() return prose.\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE VIRTUAL TABLE IF NOT EXISTS \"${ftsTable}\" USING fts5(\n\t\t\t\t${columns},\n\t\t\t\ttokenize='${tokenizer}'\n\t\t\t)\n\t\t`)\n\t\t\t.execute(this.db);\n\n\t\t// Create triggers for automatic sync\n\t\tawait this.createTriggers(collectionSlug, searchableFields);\n\t}\n\n\t/**\n\t * SQL expression producing the indexed value for one searchable field.\n\t *\n\t * Portable Text fields are stored as JSON; indexing the raw JSON pollutes\n\t * the index with structural tokens (`_type`, style values like `normal`,\n\t * `_key` ULIDs) and makes snippets show JSON fragments. Extract the prose\n\t * instead: every JSON string under a `text`, `alt`, `caption`, or `code`\n\t * key (span text, image alt/caption, code blocks). This is a superset of\n\t * `extractPlainText` in text-extraction.ts, which walks only known block\n\t * shapes — the SQL variant takes those keys at any depth, so search and\n\t * the extractPlainText consumers (vectorize/ai-search) can see different\n\t * text for the same document. Only JSON documents\n\t * (arrays/objects) are extracted; legacy rows holding a bare string or a\n\t * JSON scalar (`Some title`, `2024`) are indexed as-is. Extraction must\n\t * live in SQL because the sync triggers cannot call into JS.\n\t *\n\t * `ref` must be a validated column reference (`NEW.x`, `OLD.x`, `\"x\"`).\n\t */\n\tprivate searchValueExpr(ref: string, fieldType: string | undefined): string {\n\t\tif (fieldType !== \"portableText\") return ref;\n\t\treturn (\n\t\t\t`CASE WHEN ${ref} IS NULL THEN NULL ` +\n\t\t\t`WHEN json_valid(${ref}) AND json_type(${ref}) IN ('array', 'object') THEN (` +\n\t\t\t`SELECT group_concat(j.value, ' ') FROM json_tree(${ref}) AS j ` +\n\t\t\t`WHERE j.key IN ('text', 'alt', 'caption', 'code') AND j.type = 'text') ` +\n\t\t\t`ELSE ${ref} END`\n\t\t);\n\t}\n\n\t/**\n\t * Field type per slug for a collection, for choosing the indexed-value\n\t * expression. Fields missing from the schema fall back to raw indexing.\n\t */\n\tprivate async getFieldTypes(collectionSlug: string): Promise<Map<string, string>> {\n\t\tconst collection = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.executeTakeFirst();\n\t\tif (!collection) return new Map();\n\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.select([\"slug\", \"type\"])\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.execute();\n\t\treturn new Map(rows.map((r) => [r.slug, r.type]));\n\t}\n\n\t/**\n\t * Create triggers to keep FTS table in sync with content table.\n\t *\n\t * The insert and update triggers only add rows to the FTS index when\n\t * `deleted_at IS NULL`. This keeps soft-deleted content out of the\n\t * search index and ensures the FTS row count matches the non-deleted\n\t * content count (which `verifyAndRepairIndex` relies on).\n\t *\n\t * The FTS table stores its own values (no `content=` option), so removal\n\t * is a plain `DELETE FROM fts WHERE rowid = OLD.rowid` — a harmless no-op\n\t * for rows that were never indexed (soft-deleted content). The\n\t * external-content `'delete'`-command choreography and its corruption\n\t * modes (migration 039) do not apply to self-contained tables.\n\t *\n\t * `INSERT OR REPLACE` keeps the insert path idempotent: re-running a\n\t * populate (search repair runs per isolate, so two isolates can race) converges\n\t * on one index row per content row instead of failing on the rowid\n\t * constraint.\n\t *\n\t * The trigger SQL emitted here MUST stay in lock-step with migration\n\t * `064_fts_plain_text.ts`. If this changes again, add a new migration\n\t * rather than editing shipped ones — migrations are forward-only.\n\t */\n\tprivate async createTriggers(collectionSlug: string, searchableFields: string[]): Promise<void> {\n\t\tthis.validateInputs(collectionSlug, searchableFields);\n\t\tif (searchableFields.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot create FTS triggers for collection \"${collectionSlug}\": no searchable fields. ` +\n\t\t\t\t\t`Mark at least one field as searchable before enabling search.`,\n\t\t\t);\n\t\t}\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\t\tconst fieldTypes = await this.getFieldTypes(collectionSlug);\n\t\tconst fieldList = searchableFields.join(\", \");\n\t\tconst newValueList = searchableFields\n\t\t\t.map((f) => this.searchValueExpr(`NEW.${f}`, fieldTypes.get(f)))\n\t\t\t.join(\", \");\n\n\t\t// Insert trigger - only index non-deleted content\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_insert\"\n\t\t\tAFTER INSERT ON \"${contentTable}\"\n\t\t\tWHEN NEW.deleted_at IS NULL\n\t\t\tBEGIN\n\t\t\t\tINSERT OR REPLACE INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\t\tVALUES (NEW.rowid, NEW.id, NEW.locale, ${newValueList});\n\t\t\tEND\n\t\t`)\n\t\t\t.execute(this.db);\n\n\t\t// Update trigger - drop the old index row, re-insert when the row is\n\t\t// still visible. Trash (deleted_at set) ends at DELETE only; restore\n\t\t// ends at DELETE (no-op) + re-insert.\n\t\t//\n\t\t// The WHEN guard compares raw column values (null-safe IS NOT) so the\n\t\t// trigger fires only when an indexed value, the row's locale, or its\n\t\t// trash state actually changed. Without it every UPDATE re-tokenizes\n\t\t// the whole document — metadata-only saves (status flips, scheduling,\n\t\t// version bumps) and the publish path's rewrite-identical-values\n\t\t// UPDATEs dominate save CPU and WAL volume. deleted_at must stay in\n\t\t// the guard or trash/restore stop syncing the index.\n\t\tconst changedCondition = [\"deleted_at\", \"locale\", ...searchableFields]\n\t\t\t.map((f) => `OLD.${f} IS NOT NEW.${f}`)\n\t\t\t.join(\" OR \");\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_update\"\n\t\t\tAFTER UPDATE ON \"${contentTable}\"\n\t\t\tWHEN ${changedCondition}\n\t\t\tBEGIN\n\t\t\t\tDELETE FROM \"${ftsTable}\" WHERE rowid = OLD.rowid;\n\t\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\t\tSELECT NEW.rowid, NEW.id, NEW.locale, ${newValueList}\n\t\t\t\tWHERE NEW.deleted_at IS NULL;\n\t\t\tEND\n\t\t`)\n\t\t\t.execute(this.db);\n\n\t\t// Delete trigger\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_delete\"\n\t\t\tAFTER DELETE ON \"${contentTable}\"\n\t\t\tBEGIN\n\t\t\t\tDELETE FROM \"${ftsTable}\" WHERE rowid = OLD.rowid;\n\t\t\tEND\n\t\t`)\n\t\t\t.execute(this.db);\n\t}\n\n\t/**\n\t * Drop triggers for a collection\n\t */\n\tprivate async dropTriggers(collectionSlug: string): Promise<void> {\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\n\t\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_insert\"`).execute(this.db);\n\t\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_update\"`).execute(this.db);\n\t\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_delete\"`).execute(this.db);\n\t}\n\n\t/**\n\t * Drop the FTS table and triggers for a collection\n\t */\n\tasync dropFtsTable(collectionSlug: string): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\n\t\t// Drop triggers first\n\t\tawait this.dropTriggers(collectionSlug);\n\n\t\t// Drop the FTS table\n\t\tawait sql.raw(`DROP TABLE IF EXISTS \"${ftsTable}\"`).execute(this.db);\n\t}\n\n\t/**\n\t * Rebuild the FTS index for a collection\n\t *\n\t * This is useful after bulk imports or if the index gets out of sync.\n\t */\n\tasync rebuildIndex(\n\t\tcollectionSlug: string,\n\t\tsearchableFields: string[],\n\t\tweights?: Record<string, number>,\n\t\ttokenize?: SearchTokenizer,\n\t): Promise<void> {\n\t\tresolveSearchTokenizer(tokenize);\n\t\tif (!isSqlite(this.db)) return;\n\t\t// Drop existing table and triggers\n\t\tawait this.dropFtsTable(collectionSlug);\n\n\t\t// Recreate table and triggers\n\t\tawait this.createFtsTable(collectionSlug, searchableFields, weights, tokenize);\n\n\t\t// Populate from existing content\n\t\tawait this.populateFromContent(collectionSlug, searchableFields);\n\t}\n\n\t/**\n\t * Populate the FTS table from existing content.\n\t *\n\t * `INSERT OR REPLACE` so a concurrent double-populate (search repair runs\n\t * per isolate) converges instead of failing on the rowid constraint.\n\t */\n\tasync populateFromContent(collectionSlug: string, searchableFields: string[]): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tthis.validateInputs(collectionSlug, searchableFields);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\t\tconst fieldTypes = await this.getFieldTypes(collectionSlug);\n\t\tconst fieldList = searchableFields.join(\", \");\n\t\t// Table-qualified references: json_tree exposes columns named\n\t\t// key/value/type/path/..., and inside the extraction subquery a bare\n\t\t// column reference binds to those instead of the ec_* column.\n\t\tconst valueList = searchableFields\n\t\t\t.map((f) => this.searchValueExpr(`\"${contentTable}\".\"${f}\"`, fieldTypes.get(f)))\n\t\t\t.join(\", \");\n\n\t\t// Insert all existing content into FTS table\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tINSERT OR REPLACE INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\tSELECT rowid, id, locale, ${valueList} FROM \"${contentTable}\"\n\t\t\tWHERE deleted_at IS NULL\n\t\t`)\n\t\t\t.execute(this.db);\n\t}\n\n\t/**\n\t * Index up to `limit` content rows with `rowid > afterRowid`, in rowid\n\t * order, so a large collection can be populated across several requests.\n\t * Returns the last rowid covered, or null when no rows remain. Returns\n\t * null on dialects without FTS5.\n\t */\n\tasync populateRange(\n\t\tcollectionSlug: string,\n\t\tsearchableFields: string[],\n\t\tafterRowid: number,\n\t\tlimit: number,\n\t): Promise<number | null> {\n\t\tif (!isSqlite(this.db)) return null;\n\t\tthis.validateInputs(collectionSlug, searchableFields);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\t\tconst range = await sql<{ last: number | null }>`\n\t\t\tSELECT MAX(rowid) AS last FROM (\n\t\t\t\tSELECT rowid FROM ${sql.ref(contentTable)}\n\t\t\t\tWHERE rowid > ${afterRowid}\n\t\t\t\tORDER BY rowid\n\t\t\t\tLIMIT ${limit}\n\t\t\t)\n\t\t`.execute(this.db);\n\t\tconst last = range.rows[0]?.last ?? null;\n\t\tif (last === null) return null;\n\n\t\tconst fieldTypes = await this.getFieldTypes(collectionSlug);\n\t\tconst fieldList = searchableFields.join(\", \");\n\t\tconst valueList = searchableFields\n\t\t\t.map((f) => this.searchValueExpr(`\"${contentTable}\".\"${f}\"`, fieldTypes.get(f)))\n\t\t\t.join(\", \");\n\t\tawait sql`\n\t\t\tINSERT OR REPLACE INTO ${sql.ref(ftsTable)}(rowid, id, locale, ${sql.raw(fieldList)})\n\t\t\tSELECT rowid, id, locale, ${sql.raw(valueList)} FROM ${sql.ref(contentTable)}\n\t\t\tWHERE deleted_at IS NULL AND rowid > ${afterRowid} AND rowid <= ${last}\n\t\t`.execute(this.db);\n\t\treturn Number(last);\n\t}\n\n\t/**\n\t * Get the search configuration for a collection\n\t */\n\tasync getSearchConfig(collectionSlug: string): Promise<SearchConfig | null> {\n\t\tconst result = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select([\"search_config\", \"title_field\"])\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!result?.search_config) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(result.search_config);\n\t\t\tif (\n\t\t\t\ttypeof parsed !== \"object\" ||\n\t\t\t\tparsed === null ||\n\t\t\t\t!(\"enabled\" in parsed) ||\n\t\t\t\ttypeof parsed.enabled !== \"boolean\"\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst config: SearchConfig = { enabled: parsed.enabled };\n\t\t\tif (result.title_field) config.titleField = result.title_field;\n\t\t\tif (\"weights\" in parsed && typeof parsed.weights === \"object\" && parsed.weights !== null) {\n\t\t\t\t// weights is a JSON-parsed object — safe to treat as Record<string, number>\n\t\t\t\tconst weights: Record<string, number> = {};\n\t\t\t\tfor (const [k, v] of Object.entries(parsed.weights)) {\n\t\t\t\t\tif (typeof v === \"number\") {\n\t\t\t\t\t\tweights[k] = v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconfig.weights = weights;\n\t\t\t}\n\t\t\tif (\"tokenize\" in parsed) {\n\t\t\t\tif (!isSearchTokenizer(parsed.tokenize)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tconfig.tokenize = parsed.tokenize;\n\t\t\t}\n\t\t\treturn config;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Update the search configuration for a collection\n\t */\n\tasync setSearchConfig(collectionSlug: string, config: SearchConfig): Promise<void> {\n\t\tif (config.tokenize !== undefined) {\n\t\t\tresolveSearchTokenizer(config.tokenize);\n\t\t}\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_collections\")\n\t\t\t.set({ search_config: JSON.stringify(config) })\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Get searchable fields for a collection\n\t */\n\tasync getSearchableFields(collectionSlug: string): Promise<string[]> {\n\t\tconst collection = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!collection) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst fields = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.select(\"slug\")\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.where(\"searchable\", \"=\", 1)\n\t\t\t.execute();\n\n\t\treturn fields.map((f) => f.slug);\n\t}\n\n\t/**\n\t * Whether a collection has a user-defined `title` field.\n\t *\n\t * `title` is not a system column on `ec_*` tables -- it exists only when a\n\t * collection defines a field with slug `title`. Search and suggestion SQL\n\t * that selects `c.title` must check this first; otherwise collections\n\t * without a title field raise \"no such column: c.title\".\n\t */\n\tasync hasTitleColumn(collectionSlug: string): Promise<boolean> {\n\t\tconst withTitle = await this.getCollectionsWithTitleColumn([collectionSlug]);\n\t\treturn withTitle.has(collectionSlug);\n\t}\n\n\t/**\n\t * Bulk variant of `hasTitleColumn()`: which of the given collections have\n\t * a user-defined `title` field. One query instead of one `hasTitleColumn`\n\t * round-trip pair per collection -- callers that check this once per\n\t * collection in a loop (multi-collection search, suggestions) should use\n\t * this instead (AGENTS.md: \"one query beats two\").\n\t */\n\tasync getCollectionsWithTitleColumn(collectionSlugs: string[]): Promise<Set<string>> {\n\t\tif (collectionSlugs.length === 0) return new Set();\n\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_fields as f\")\n\t\t\t.innerJoin(\"_emdash_collections as c\", \"c.id\", \"f.collection_id\")\n\t\t\t.select([\"c.slug as collection_slug\"])\n\t\t\t.where(\"f.slug\", \"=\", \"title\")\n\t\t\t.execute();\n\n\t\tconst withTitle = new Set(rows.map((r) => r.collection_slug));\n\t\treturn new Set(collectionSlugs.filter((slug) => withTitle.has(slug)));\n\t}\n\n\t/**\n\t * Enable search for a collection.\n\t *\n\t * Uses rebuildIndex to ensure a clean state -- drop any existing FTS\n\t * table/triggers, recreate them, and populate from content. This avoids\n\t * duplicate rows when triggers have already populated the index (e.g.\n\t * during seeding where content is inserted before search is enabled).\n\t */\n\tasync enableSearch(\n\t\tcollectionSlug: string,\n\t\toptions?: { weights?: Record<string, number>; tokenize?: SearchTokenizer },\n\t): Promise<void> {\n\t\tif (options?.tokenize !== undefined) {\n\t\t\tresolveSearchTokenizer(options.tokenize);\n\t\t}\n\t\tif (!isSqlite(this.db)) {\n\t\t\tthrow new Error(\"Full-text search is only available with SQLite databases\");\n\t\t}\n\t\t// Get searchable fields\n\t\tconst searchableFields = await this.getSearchableFields(collectionSlug);\n\n\t\tif (searchableFields.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`No searchable fields defined for collection \"${collectionSlug}\". ` +\n\t\t\t\t\t`Mark at least one field as searchable before enabling search.`,\n\t\t\t);\n\t\t}\n\n\t\tconst existing = await this.getSearchConfig(collectionSlug);\n\t\tconst weights = options?.weights ?? existing?.weights;\n\t\tconst tokenize = options?.tokenize ?? existing?.tokenize;\n\n\t\t// Rebuild from scratch to ensure clean state (no duplicate rows)\n\t\tawait this.rebuildIndex(collectionSlug, searchableFields, weights, tokenize);\n\n\t\t// Update search config\n\t\tawait this.setSearchConfig(collectionSlug, {\n\t\t\tenabled: true,\n\t\t\tweights,\n\t\t\ttokenize,\n\t\t});\n\t}\n\n\t/**\n\t * Disable search for a collection\n\t *\n\t * Drops the FTS table and triggers.\n\t */\n\tasync disableSearch(collectionSlug: string): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tawait this.dropFtsTable(collectionSlug);\n\t\tconst existing = await this.getSearchConfig(collectionSlug);\n\t\tawait this.setSearchConfig(collectionSlug, {\n\t\t\tenabled: false,\n\t\t\tweights: existing?.weights,\n\t\t\ttokenize: existing?.tokenize,\n\t\t});\n\t}\n\n\t/**\n\t * Get index statistics for a collection\n\t */\n\tasync getIndexStats(\n\t\tcollectionSlug: string,\n\t): Promise<{ indexed: number; lastRebuilt?: string } | null> {\n\t\tif (!isSqlite(this.db)) return null;\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst ftsDocsizeTable = `${ftsTable}_docsize`;\n\n\t\t// Check if table exists\n\t\tif (!(await this.ftsTableExists(collectionSlug))) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Count indexed rows\n\t\tconst result = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM \"${sql.raw(ftsDocsizeTable)}\"\n\t\t`.execute(this.db);\n\n\t\treturn {\n\t\t\tindexed: result.rows[0]?.count ?? 0,\n\t\t};\n\t}\n\n\t/**\n\t * Verify FTS index integrity and rebuild if drift is detected.\n\t *\n\t * Cheap belt-and-braces check, run lazily on the first search request\n\t * per isolate. The expensive cases (corrupted indexes from pre-fix\n\t * EmDash versions, broken legacy triggers) are handled at boot time by\n\t * migration `039_fix_fts5_triggers`, not here. This routine sticks to:\n\t *\n\t * 1. FTS table missing while config says search is enabled -> rebuild.\n\t * 2. Row count mismatch between content table and FTS docsize -> rebuild.\n\t *\n\t * Returns true if the index was rebuilt, false if it was healthy.\n\t */\n\tasync verifyAndRepairIndex(collectionSlug: string): Promise<boolean> {\n\t\tif (!isSqlite(this.db)) return false;\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst ftsDocsizeTable = `${ftsTable}_docsize`;\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\t\tconst fields = await this.getSearchableFields(collectionSlug);\n\t\tconst config = await this.getSearchConfig(collectionSlug);\n\n\t\tif (!(await this.ftsTableExists(collectionSlug))) {\n\t\t\tif (!config?.enabled || fields.length === 0) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconsole.warn(`FTS index for \"${collectionSlug}\" is missing. Rebuilding.`);\n\t\t\tawait this.rebuildIndex(collectionSlug, fields, config.weights, config.tokenize);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Row count parity check against the docsize shadow table, which\n\t\t// tracks rows actually present in the full-text index.\n\t\tconst contentCount = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(contentTable)}\n\t\t\tWHERE deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst ftsCount = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM \"${sql.raw(ftsDocsizeTable)}\"\n\t\t`.execute(this.db);\n\n\t\tconst contentRows = contentCount.rows[0]?.count ?? 0;\n\t\tconst ftsRows = ftsCount.rows[0]?.count ?? 0;\n\n\t\tif (contentRows !== ftsRows) {\n\t\t\tconsole.warn(\n\t\t\t\t`FTS index for \"${collectionSlug}\" has ${ftsRows} rows but content table has ${contentRows}. Rebuilding.`,\n\t\t\t);\n\t\t\tif (fields.length > 0) {\n\t\t\t\tawait this.rebuildIndex(collectionSlug, fields, config?.weights, config?.tokenize);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Verify and repair FTS indexes for all search-enabled collections.\n\t *\n\t * Intended to run at startup to auto-heal any corruption from\n\t * previous process crashes.\n\t */\n\tasync verifyAndRepairAll(): Promise<number> {\n\t\tif (!isSqlite(this.db)) return 0;\n\n\t\tconst collections = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select(\"slug\")\n\t\t\t.where(\"search_config\", \"is not\", null)\n\t\t\t.execute();\n\n\t\tlet repaired = 0;\n\t\tfor (const { slug } of collections) {\n\t\t\tconst config = await this.getSearchConfig(slug);\n\t\t\tif (!config?.enabled) continue;\n\n\t\t\ttry {\n\t\t\t\tconst wasRepaired = await this.verifyAndRepairIndex(slug);\n\t\t\t\tif (wasRepaired) repaired++;\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`Failed to verify/repair FTS index for \"${slug}\":`, error);\n\t\t\t}\n\t\t}\n\n\t\treturn repaired;\n\t}\n}\n"],"mappings":";;;;;;;;AAeA,MAAM,2BAA4C;AAElD,SAAS,kBAAkB,OAA0C;AACpE,QAAO,kBAAkB,MAAM,cAAc,cAAc,MAAM;;AAGlE,SAAS,uBAAuB,UAA6C;AAC5E,KAAI,aAAa,OAAW,QAAO;AACnC,KAAI,CAAC,kBAAkB,SAAS,CAC/B,OAAM,IAAI,MAAM,gCAAgC,OAAO,SAAS,CAAC,GAAG;AAErE,QAAO;;;;;;;;AASR,IAAa,aAAb,MAAwB;CACvB,YAAY,AAAQ,IAAsB;EAAtB;;;;;;CAMpB,AAAQ,eAAe,gBAAwB,kBAAmC;AACjF,qBAAmB,gBAAgB,kBAAkB;AACrD,MAAI,iBACH,MAAK,MAAM,SAAS,iBACnB,oBAAmB,OAAO,wBAAwB;;;;;;CASrD,gBAAgB,gBAAgC;AAC/C,qBAAmB,gBAAgB,kBAAkB;AACrD,SAAO,eAAe;;;;;CAMvB,oBAAoB,gBAAgC;AACnD,qBAAmB,gBAAgB,kBAAkB;AACrD,SAAO,MAAM;;;;;CAMd,MAAM,eAAe,gBAA0C;EAC9D,MAAM,WAAW,KAAK,gBAAgB,eAAe;AACrD,SAAOA,YAAmB,KAAK,IAAI,SAAS;;;;;;;;;;;CAY7C,MAAM,eACL,gBACA,kBACA,UACA,UACgB;EAChB,MAAM,YAAY,uBAAuB,SAAS;AAClD,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE;AACxB,OAAK,eAAe,gBAAgB,iBAAiB;EACrD,MAAM,WAAW,KAAK,gBAAgB,eAAe;EAIrD,MAAM,UAAU;GAAC;GAAgB;GAAoB,GAAG;GAAiB,CAAC,KAAK,KAAK;AAUpF,QAAM,IACJ,IAAI;yCACiC,SAAS;MAC5C,QAAQ;gBACE,UAAU;;IAEtB,CACA,QAAQ,KAAK,GAAG;AAGlB,QAAM,KAAK,eAAe,gBAAgB,iBAAiB;;;;;;;;;;;;;;;;;;;;CAqB5D,AAAQ,gBAAgB,KAAa,WAAuC;AAC3E,MAAI,cAAc,eAAgB,QAAO;AACzC,SACC,aAAa,IAAI,qCACE,IAAI,kBAAkB,IAAI,kFACO,IAAI,qFAEhD,IAAI;;;;;;CAQd,MAAc,cAAc,gBAAsD;EACjF,MAAM,aAAa,MAAM,KAAK,GAC5B,WAAW,sBAAsB,CACjC,OAAO,KAAK,CACZ,MAAM,QAAQ,KAAK,eAAe,CAClC,kBAAkB;AACpB,MAAI,CAAC,WAAY,wBAAO,IAAI,KAAK;EAEjC,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,iBAAiB,CAC5B,OAAO,CAAC,QAAQ,OAAO,CAAC,CACxB,MAAM,iBAAiB,KAAK,WAAW,GAAG,CAC1C,SAAS;AACX,SAAO,IAAI,IAAI,KAAK,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;CA0BlD,MAAc,eAAe,gBAAwB,kBAA2C;AAC/F,OAAK,eAAe,gBAAgB,iBAAiB;AACrD,MAAI,iBAAiB,WAAW,EAC/B,OAAM,IAAI,MACT,8CAA8C,eAAe,wFAE7D;EAEF,MAAM,WAAW,KAAK,gBAAgB,eAAe;EACrD,MAAM,eAAe,KAAK,oBAAoB,eAAe;EAC7D,MAAM,aAAa,MAAM,KAAK,cAAc,eAAe;EAC3D,MAAM,YAAY,iBAAiB,KAAK,KAAK;EAC7C,MAAM,eAAe,iBACnB,KAAK,MAAM,KAAK,gBAAgB,OAAO,KAAK,WAAW,IAAI,EAAE,CAAC,CAAC,CAC/D,KAAK,KAAK;AAGZ,QAAM,IACJ,IAAI;mCAC2B,SAAS;sBACtB,aAAa;;;8BAGL,SAAS,uBAAuB,UAAU;6CAC3B,aAAa;;IAEtD,CACA,QAAQ,KAAK,GAAG;EAalB,MAAM,mBAAmB;GAAC;GAAc;GAAU,GAAG;GAAiB,CACpE,KAAK,MAAM,OAAO,EAAE,cAAc,IAAI,CACtC,KAAK,OAAO;AACd,QAAM,IACJ,IAAI;mCAC2B,SAAS;sBACtB,aAAa;UACzB,iBAAiB;;mBAER,SAAS;mBACT,SAAS,uBAAuB,UAAU;4CACjB,aAAa;;;IAGrD,CACA,QAAQ,KAAK,GAAG;AAGlB,QAAM,IACJ,IAAI;mCAC2B,SAAS;sBACtB,aAAa;;mBAEhB,SAAS;;IAExB,CACA,QAAQ,KAAK,GAAG;;;;;CAMnB,MAAc,aAAa,gBAAuC;AACjE,OAAK,eAAe,eAAe;EACnC,MAAM,WAAW,KAAK,gBAAgB,eAAe;AAErD,QAAM,IAAI,IAAI,2BAA2B,SAAS,UAAU,CAAC,QAAQ,KAAK,GAAG;AAC7E,QAAM,IAAI,IAAI,2BAA2B,SAAS,UAAU,CAAC,QAAQ,KAAK,GAAG;AAC7E,QAAM,IAAI,IAAI,2BAA2B,SAAS,UAAU,CAAC,QAAQ,KAAK,GAAG;;;;;CAM9E,MAAM,aAAa,gBAAuC;AACzD,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE;AACxB,OAAK,eAAe,eAAe;EACnC,MAAM,WAAW,KAAK,gBAAgB,eAAe;AAGrD,QAAM,KAAK,aAAa,eAAe;AAGvC,QAAM,IAAI,IAAI,yBAAyB,SAAS,GAAG,CAAC,QAAQ,KAAK,GAAG;;;;;;;CAQrE,MAAM,aACL,gBACA,kBACA,SACA,UACgB;AAChB,yBAAuB,SAAS;AAChC,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE;AAExB,QAAM,KAAK,aAAa,eAAe;AAGvC,QAAM,KAAK,eAAe,gBAAgB,kBAAkB,SAAS,SAAS;AAG9E,QAAM,KAAK,oBAAoB,gBAAgB,iBAAiB;;;;;;;;CASjE,MAAM,oBAAoB,gBAAwB,kBAA2C;AAC5F,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE;AACxB,OAAK,eAAe,gBAAgB,iBAAiB;EACrD,MAAM,WAAW,KAAK,gBAAgB,eAAe;EACrD,MAAM,eAAe,KAAK,oBAAoB,eAAe;EAC7D,MAAM,aAAa,MAAM,KAAK,cAAc,eAAe;EAC3D,MAAM,YAAY,iBAAiB,KAAK,KAAK;EAI7C,MAAM,YAAY,iBAChB,KAAK,MAAM,KAAK,gBAAgB,IAAI,aAAa,KAAK,EAAE,IAAI,WAAW,IAAI,EAAE,CAAC,CAAC,CAC/E,KAAK,KAAK;AAGZ,QAAM,IACJ,IAAI;6BACqB,SAAS,uBAAuB,UAAU;+BACxC,UAAU,SAAS,aAAa;;IAE3D,CACA,QAAQ,KAAK,GAAG;;;;;;;;CASnB,MAAM,cACL,gBACA,kBACA,YACA,OACyB;AACzB,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE,QAAO;AAC/B,OAAK,eAAe,gBAAgB,iBAAiB;EACrD,MAAM,WAAW,KAAK,gBAAgB,eAAe;EACrD,MAAM,eAAe,KAAK,oBAAoB,eAAe;EAS7D,MAAM,QARQ,MAAM,GAA4B;;wBAE1B,IAAI,IAAI,aAAa,CAAC;oBAC1B,WAAW;;YAEnB,MAAM;;IAEd,QAAQ,KAAK,GAAG,EACC,KAAK,IAAI,QAAQ;AACpC,MAAI,SAAS,KAAM,QAAO;EAE1B,MAAM,aAAa,MAAM,KAAK,cAAc,eAAe;EAC3D,MAAM,YAAY,iBAAiB,KAAK,KAAK;EAC7C,MAAM,YAAY,iBAChB,KAAK,MAAM,KAAK,gBAAgB,IAAI,aAAa,KAAK,EAAE,IAAI,WAAW,IAAI,EAAE,CAAC,CAAC,CAC/E,KAAK,KAAK;AACZ,QAAM,GAAG;4BACiB,IAAI,IAAI,SAAS,CAAC,sBAAsB,IAAI,IAAI,UAAU,CAAC;+BACxD,IAAI,IAAI,UAAU,CAAC,QAAQ,IAAI,IAAI,aAAa,CAAC;0CACtC,WAAW,gBAAgB,KAAK;IACtE,QAAQ,KAAK,GAAG;AAClB,SAAO,OAAO,KAAK;;;;;CAMpB,MAAM,gBAAgB,gBAAsD;EAC3E,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,sBAAsB,CACjC,OAAO,CAAC,iBAAiB,cAAc,CAAC,CACxC,MAAM,QAAQ,KAAK,eAAe,CAClC,kBAAkB;AAEpB,MAAI,CAAC,QAAQ,cACZ,QAAO;AAGR,MAAI;GACH,MAAM,SAAkB,KAAK,MAAM,OAAO,cAAc;AACxD,OACC,OAAO,WAAW,YAClB,WAAW,QACX,EAAE,aAAa,WACf,OAAO,OAAO,YAAY,UAE1B,QAAO;GAER,MAAM,SAAuB,EAAE,SAAS,OAAO,SAAS;AACxD,OAAI,OAAO,YAAa,QAAO,aAAa,OAAO;AACnD,OAAI,aAAa,UAAU,OAAO,OAAO,YAAY,YAAY,OAAO,YAAY,MAAM;IAEzF,MAAM,UAAkC,EAAE;AAC1C,SAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAAO,QAAQ,CAClD,KAAI,OAAO,MAAM,SAChB,SAAQ,KAAK;AAGf,WAAO,UAAU;;AAElB,OAAI,cAAc,QAAQ;AACzB,QAAI,CAAC,kBAAkB,OAAO,SAAS,CACtC,QAAO;AAER,WAAO,WAAW,OAAO;;AAE1B,UAAO;UACA;AACP,UAAO;;;;;;CAOT,MAAM,gBAAgB,gBAAwB,QAAqC;AAClF,MAAI,OAAO,aAAa,OACvB,wBAAuB,OAAO,SAAS;AAExC,QAAM,KAAK,GACT,YAAY,sBAAsB,CAClC,IAAI,EAAE,eAAe,KAAK,UAAU,OAAO,EAAE,CAAC,CAC9C,MAAM,QAAQ,KAAK,eAAe,CAClC,SAAS;;;;;CAMZ,MAAM,oBAAoB,gBAA2C;EACpE,MAAM,aAAa,MAAM,KAAK,GAC5B,WAAW,sBAAsB,CACjC,OAAO,KAAK,CACZ,MAAM,QAAQ,KAAK,eAAe,CAClC,kBAAkB;AAEpB,MAAI,CAAC,WACJ,QAAO,EAAE;AAUV,UAPe,MAAM,KAAK,GACxB,WAAW,iBAAiB,CAC5B,OAAO,OAAO,CACd,MAAM,iBAAiB,KAAK,WAAW,GAAG,CAC1C,MAAM,cAAc,KAAK,EAAE,CAC3B,SAAS,EAEG,KAAK,MAAM,EAAE,KAAK;;;;;;;;;;CAWjC,MAAM,eAAe,gBAA0C;AAE9D,UADkB,MAAM,KAAK,8BAA8B,CAAC,eAAe,CAAC,EAC3D,IAAI,eAAe;;;;;;;;;CAUrC,MAAM,8BAA8B,iBAAiD;AACpF,MAAI,gBAAgB,WAAW,EAAG,wBAAO,IAAI,KAAK;EAElD,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,sBAAsB,CACjC,UAAU,4BAA4B,QAAQ,kBAAkB,CAChE,OAAO,CAAC,4BAA4B,CAAC,CACrC,MAAM,UAAU,KAAK,QAAQ,CAC7B,SAAS;EAEX,MAAM,YAAY,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,gBAAgB,CAAC;AAC7D,SAAO,IAAI,IAAI,gBAAgB,QAAQ,SAAS,UAAU,IAAI,KAAK,CAAC,CAAC;;;;;;;;;;CAWtE,MAAM,aACL,gBACA,SACgB;AAChB,MAAI,SAAS,aAAa,OACzB,wBAAuB,QAAQ,SAAS;AAEzC,MAAI,CAAC,SAAS,KAAK,GAAG,CACrB,OAAM,IAAI,MAAM,2DAA2D;EAG5E,MAAM,mBAAmB,MAAM,KAAK,oBAAoB,eAAe;AAEvE,MAAI,iBAAiB,WAAW,EAC/B,OAAM,IAAI,MACT,gDAAgD,eAAe,kEAE/D;EAGF,MAAM,WAAW,MAAM,KAAK,gBAAgB,eAAe;EAC3D,MAAM,UAAU,SAAS,WAAW,UAAU;EAC9C,MAAM,WAAW,SAAS,YAAY,UAAU;AAGhD,QAAM,KAAK,aAAa,gBAAgB,kBAAkB,SAAS,SAAS;AAG5E,QAAM,KAAK,gBAAgB,gBAAgB;GAC1C,SAAS;GACT;GACA;GACA,CAAC;;;;;;;CAQH,MAAM,cAAc,gBAAuC;AAC1D,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE;AACxB,QAAM,KAAK,aAAa,eAAe;EACvC,MAAM,WAAW,MAAM,KAAK,gBAAgB,eAAe;AAC3D,QAAM,KAAK,gBAAgB,gBAAgB;GAC1C,SAAS;GACT,SAAS,UAAU;GACnB,UAAU,UAAU;GACpB,CAAC;;;;;CAMH,MAAM,cACL,gBAC4D;AAC5D,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE,QAAO;AAC/B,OAAK,eAAe,eAAe;EAEnC,MAAM,kBAAkB,GADP,KAAK,gBAAgB,eAAe,CACjB;AAGpC,MAAI,CAAE,MAAM,KAAK,eAAe,eAAe,CAC9C,QAAO;AAQR,SAAO,EACN,UALc,MAAM,GAAsB;oCACT,IAAI,IAAI,gBAAgB,CAAC;IACzD,QAAQ,KAAK,GAAG,EAGD,KAAK,IAAI,SAAS,GAClC;;;;;;;;;;;;;;;CAgBF,MAAM,qBAAqB,gBAA0C;AACpE,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE,QAAO;AAC/B,OAAK,eAAe,eAAe;EAEnC,MAAM,kBAAkB,GADP,KAAK,gBAAgB,eAAe,CACjB;EACpC,MAAM,eAAe,KAAK,oBAAoB,eAAe;EAC7D,MAAM,SAAS,MAAM,KAAK,oBAAoB,eAAe;EAC7D,MAAM,SAAS,MAAM,KAAK,gBAAgB,eAAe;AAEzD,MAAI,CAAE,MAAM,KAAK,eAAe,eAAe,EAAG;AACjD,OAAI,CAAC,QAAQ,WAAW,OAAO,WAAW,EACzC,QAAO;AAGR,WAAQ,KAAK,kBAAkB,eAAe,2BAA2B;AACzE,SAAM,KAAK,aAAa,gBAAgB,QAAQ,OAAO,SAAS,OAAO,SAAS;AAChF,UAAO;;EAKR,MAAM,eAAe,MAAM,GAAsB;mCAChB,IAAI,IAAI,aAAa,CAAC;;IAErD,QAAQ,KAAK,GAAG;EAElB,MAAM,WAAW,MAAM,GAAsB;oCACX,IAAI,IAAI,gBAAgB,CAAC;IACzD,QAAQ,KAAK,GAAG;EAElB,MAAM,cAAc,aAAa,KAAK,IAAI,SAAS;EACnD,MAAM,UAAU,SAAS,KAAK,IAAI,SAAS;AAE3C,MAAI,gBAAgB,SAAS;AAC5B,WAAQ,KACP,kBAAkB,eAAe,QAAQ,QAAQ,8BAA8B,YAAY,eAC3F;AACD,OAAI,OAAO,SAAS,EACnB,OAAM,KAAK,aAAa,gBAAgB,QAAQ,QAAQ,SAAS,QAAQ,SAAS;AAEnF,UAAO;;AAGR,SAAO;;;;;;;;CASR,MAAM,qBAAsC;AAC3C,MAAI,CAAC,SAAS,KAAK,GAAG,CAAE,QAAO;EAE/B,MAAM,cAAc,MAAM,KAAK,GAC7B,WAAW,sBAAsB,CACjC,OAAO,OAAO,CACd,MAAM,iBAAiB,UAAU,KAAK,CACtC,SAAS;EAEX,IAAI,WAAW;AACf,OAAK,MAAM,EAAE,UAAU,aAAa;AAEnC,OAAI,EADW,MAAM,KAAK,gBAAgB,KAAK,GAClC,QAAS;AAEtB,OAAI;AAEH,QADoB,MAAM,KAAK,qBAAqB,KAAK,CACxC;YACT,OAAO;AACf,YAAQ,MAAM,0CAA0C,KAAK,KAAK,MAAM;;;AAI1E,SAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-BB9sVisO.d.mts","names":[],"sources":["../src/database/repositories/byline.ts","../src/utils/slugify.ts","../src/cli/wxr/parser.ts","../src/import/sections.ts","../src/import/registry.ts","../src/import/sources/wxr.ts","../src/import/sources/wordpress-rest.ts","../src/import/sources/wordpress-plugin.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"loader-CswroUbe.mjs","names":[],"sources":["../src/database/repositories/taxonomy-def.ts","../src/page/seo-panel.ts","../src/loader.ts"],"sourcesContent":["import { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../types.js\";\n\n/**\n * A taxonomy's structure: the same in every locale. Stored once in\n * `_emdash_taxonomy_def_groups`, keyed by name, and copied onto each locale's\n * `_emdash_taxonomy_defs` row for code that reads it directly, such as the plugin\n * sandbox bridges.\n */\nexport interface TaxonomyStructure {\n\thierarchical: boolean;\n\tcollections: string[];\n}\n\n/**\n * Select definition rows (aliased `d`) with their taxonomy's structure.\n * Qualify columns in `where` and `orderBy`: `id` and `name` exist on both tables.\n *\n * A row that has no group yet, because code without the group table wrote it\n * during a rolling deploy, reads its own copy.\n */\nexport function selectTaxonomyDefs(db: Kysely<Database>) {\n\treturn db\n\t\t.selectFrom(\"_emdash_taxonomy_defs as d\")\n\t\t.leftJoin(\"_emdash_taxonomy_def_groups as g\", \"g.name\", \"d.name\")\n\t\t.select([\n\t\t\t\"d.id\",\n\t\t\t\"d.name\",\n\t\t\t\"d.label\",\n\t\t\t\"d.label_singular\",\n\t\t\t\"d.created_at\",\n\t\t\t\"d.locale\",\n\t\t\t\"d.translation_group\",\n\t\t\tsql<number>`coalesce(g.hierarchical, d.hierarchical)`.as(\"hierarchical\"),\n\t\t\tsql<string | null>`coalesce(g.collections, d.collections)`.as(\"collections\"),\n\t\t]);\n}\n\n/**\n * The taxonomy's group id and structure, or null when no locale defines `name`.\n * A group whose definitions are all gone counts as deleted.\n */\nexport async function findTaxonomyStructure(\n\tdb: Kysely<Database>,\n\tname: string,\n): Promise<(TaxonomyStructure & { id: string }) | null> {\n\tconst row = await selectTaxonomyDefs(db)\n\t\t.where(\"d.name\", \"=\", name)\n\t\t.orderBy(\"d.id\", \"asc\")\n\t\t.executeTakeFirst();\n\tif (!row) return null;\n\treturn {\n\t\tid: row.translation_group ?? row.id,\n\t\thierarchical: row.hierarchical === 1,\n\t\tcollections: parseTaxonomyCollections(row.collections),\n\t};\n}\n\n/**\n * Write a taxonomy's structure for every locale and return its group id.\n *\n * Creates the group with `groupId` and `structure` when the name has none. An\n * existing group changes only the fields in `overwrite`, so a caller holding an\n * older read of the other field does not write it back. Every definition row of\n * the name is then linked to the group and copies its values, including rows\n * written without it.\n */\nexport async function saveTaxonomyStructure(\n\tdb: Kysely<Database>,\n\tname: string,\n\tgroupId: string,\n\tstructure: TaxonomyStructure,\n\toverwrite: Partial<TaxonomyStructure> = structure,\n): Promise<string> {\n\tconst changes: { hierarchical?: number; collections?: string } = {};\n\tif (overwrite.hierarchical !== undefined) changes.hierarchical = overwrite.hierarchical ? 1 : 0;\n\tif (overwrite.collections !== undefined) {\n\t\tchanges.collections = JSON.stringify([...new Set(overwrite.collections)]);\n\t}\n\tconst saved = await db\n\t\t.insertInto(\"_emdash_taxonomy_def_groups\")\n\t\t.values({\n\t\t\tid: groupId,\n\t\t\tname,\n\t\t\thierarchical: structure.hierarchical ? 1 : 0,\n\t\t\tcollections: JSON.stringify([...new Set(structure.collections)]),\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\tObject.keys(changes).length > 0\n\t\t\t\t? oc.column(\"name\").doUpdateSet(changes)\n\t\t\t\t: oc.column(\"name\").doNothing(),\n\t\t)\n\t\t.returning([\"id\", \"hierarchical\", \"collections\"])\n\t\t.executeTakeFirst();\n\tconst group =\n\t\tsaved ??\n\t\t(await db\n\t\t\t.selectFrom(\"_emdash_taxonomy_def_groups\")\n\t\t\t.select([\"id\", \"hierarchical\", \"collections\"])\n\t\t\t.where(\"name\", \"=\", name)\n\t\t\t.executeTakeFirstOrThrow());\n\tawait db\n\t\t.updateTable(\"_emdash_taxonomy_defs\")\n\t\t.set({\n\t\t\thierarchical: group.hierarchical,\n\t\t\tcollections: group.collections,\n\t\t\ttranslation_group: group.id,\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n\treturn group.id;\n}\n\n/** Parse a stored `collections` value, skipping anything that isn't a string list. */\nexport function parseTaxonomyCollections(value: string | null): string[] {\n\tif (!value) return [];\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(value);\n\t} catch {\n\t\treturn [];\n\t}\n\tif (!Array.isArray(parsed)) return [];\n\treturn [...new Set(parsed.filter((entry): entry is string => typeof entry === \"string\"))];\n}\n","/**\n * Request-scoped hand-off of SEO panel data from the entry query to the\n * render components.\n *\n * The loader's single-entry path already folds the `_emdash_seo` row into\n * the entry query as a JSON subselect, so the panel data is in hand when an\n * entry is fetched — it primes this cache, and `<EmDashHead>` (plus the body\n * fragment components) pick the data up with a plain map read. No code path\n * here ever queries the database.\n *\n * Kept as a leaf module (request-cache only) so the loader and the query\n * layer can prime without importing the page-context machinery, which pulls\n * in site settings and would create an import cycle back into the loader.\n */\n\nimport type { ContentSeo } from \"../database/repositories/types.js\";\nimport { peekRequestCache, setRequestCacheEntry } from \"../request-cache.js\";\n\nfunction seoPanelCacheKey(collection: string, id: string): string {\n\treturn `seo-panel:${collection}:${id}`;\n}\n\n/**\n * Prime the request-scoped SEO panel cache for a content entry.\n *\n * Called wherever an entry's folded SEO data materializes: the loader's\n * single-entry path (fresh query) and the object-cache revive path in\n * `getEmDashEntry` (warm hit, where the loader never runs). No-ops outside\n * a request context; never overwrites an already-primed value.\n */\nexport function primeSeoPanel(collection: string, id: string, seo: ContentSeo): void {\n\tsetRequestCacheEntry(seoPanelCacheKey(collection, id), seo);\n}\n\n/**\n * Read the SEO panel data primed for a content entry in this request.\n *\n * Returns `null` when nothing was primed — either the entry has no SEO\n * row, or it was not fetched through an EmDash loader in this request\n * (e.g. prerendered pages, or a hand-rolled query). Callers treat null as\n * \"no overlay\"; this never falls back to a database lookup, so the\n * logged-out hot path gains zero queries.\n */\nexport async function peekSeoPanel(collection: string, id: string): Promise<ContentSeo | null> {\n\tconst primed = peekRequestCache<ContentSeo>(seoPanelCacheKey(collection, id));\n\treturn primed ? await primed : null;\n}\n","/**\n * Astro Live Collections loader for EmDash\n *\n * This loader implements the Astro LiveLoader interface to fetch content\n * at runtime from the database, enabling live editing without rebuilds.\n *\n * Architecture:\n * - Single `_emdash` Astro collection handles all content types\n * - Dialect comes from virtual module (configured in astro.config.mjs)\n * - Each content type maps to its own database table: ec_posts, ec_products, etc.\n * - `getEmDashCollection()` / `getEmDashEntry()` wrap Astro's live collection API\n */\n\nimport type { LiveLoader } from \"astro/loaders\";\nimport { Kysely, type RawBuilder, sql, type Dialect } from \"kysely\";\n\nimport { buildStatusCondition, isPostgres } from \"./database/dialect-helpers.js\";\nimport { kyselyLogOption } from \"./database/instrumentation.js\";\nimport { jsonTextValues } from \"./database/json-recordset.js\";\nimport { selectTaxonomyDefs } from \"./database/repositories/taxonomy-def.js\";\nimport { decodeCursor, encodeCursor, InvalidCursorError } from \"./database/repositories/types.js\";\nimport { validateIdentifier } from \"./database/validate.js\";\nimport { getI18nConfig } from \"./i18n/config.js\";\nimport type { Database } from \"./index.js\";\nimport { primeSeoPanel } from \"./page/seo-panel.js\";\nimport { getRequestContext } from \"./request-context.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"./utils/chunks.js\";\nimport { isMissingColumnError, isMissingTableError } from \"./utils/db-errors.js\";\n\nconst FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * SEO columns folded into the single-entry query as a single JSON column\n * (`_emdash_seo` in the result set), then expanded onto the row under these\n * aliases for `extractSeo()`. Surfacing SEO as one aggregated column keeps the\n * result-set width bounded regardless of how many fields the collection has,\n * which matters for D1: a flat `LEFT JOIN _emdash_seo` adds 5 alias columns to\n * every row and pushes wide collections (common after WordPress / ACF imports)\n * past D1's per-result-set column limit, surfacing as a silent null entry.\n * One JSON column is one column, so the join stays safe at any schema width.\n *\n * The aliases mirror the strategy used by `foldedHydrationSelects` for byline\n * and taxonomy hydration: aggregate in SQL, expand in JS. SEO is 1:1 with\n * content, so the subquery uses `json_object` (not the array aggregator).\n *\n * The `_emdash_` prefix on the aliases guarantees they can never collide with\n * a content field. Field slugs must match `/^[a-z][a-z0-9_]*$/`, so a user can\n * legitimately define a `seo_title` field; surfacing the SEO column under its\n * bare name would shadow that field in the result set and drop the user's\n * value. The prefix (illegal as a leading slug char) sidesteps this entirely.\n */\nconst SEO_COLUMN_ALIASES: Record<string, string> = {\n\tseo_title: \"_emdash_seo_title\",\n\tseo_description: \"_emdash_seo_description\",\n\tseo_image: \"_emdash_seo_image\",\n\tseo_canonical: \"_emdash_seo_canonical\",\n\tseo_no_index: \"_emdash_seo_no_index\",\n};\n\n/** Aliased SEO result keys — excluded from generic field mapping. */\nconst SEO_ALIAS_COLUMNS = Object.values(SEO_COLUMN_ALIASES);\n\n/** Folded SEO JSON column name in the result set (expanded onto aliases in JS). */\nconst SEO_FOLDED_COLUMN = \"_emdash_seo\";\n\n/** Folded boolean field slugs used to restore SQLite integer values. */\nconst BOOLEAN_FIELDS_FOLDED_COLUMN = \"_emdash_boolean_fields\";\n\n/** Rank of a row among its translation group's variants, in {@link loadEntriesByGroups}. */\nconst VARIANT_RANK_COLUMN = \"_emdash_variant_rank\";\n\n/**\n * System columns excluded from entry.data\n * Note: slug is intentionally NOT excluded - it's useful as data.slug in templates\n */\nconst SYSTEM_COLUMNS = new Set([\n\t\"id\",\n\t// \"slug\" - kept in data for template access\n\t\"status\",\n\t\"author_id\",\n\t\"primary_byline_id\",\n\t\"created_at\",\n\t\"updated_at\",\n\t\"published_at\",\n\t\"scheduled_at\",\n\t\"deleted_at\",\n\t\"version\",\n\t\"live_revision_id\",\n\t\"draft_revision_id\",\n\t\"locale\",\n\t\"translation_group\",\n\t// Aliased SEO columns expanded from the folded _emdash_seo JSON column on\n\t// the single-entry path. Surfaced as a nested data.seo object (see\n\t// extractSeo), never as flat fields. The aliases are _emdash_-prefixed so\n\t// they can't shadow a user field named e.g. `seo_title`.\n\t...SEO_ALIAS_COLUMNS,\n\t// Folded hydration JSON columns (see foldedHydrationSelects and\n\t// foldedSeoSelect) — surfaced via the FOLDED_* markers or expanded onto\n\t// SEO_ALIAS_COLUMNS, never as flat fields.\n\t\"_emdash_terms\",\n\t\"_emdash_bylines\",\n\t\"_emdash_bylines_exist\",\n\tSEO_FOLDED_COLUMN,\n\tBOOLEAN_FIELDS_FOLDED_COLUMN,\n\tVARIANT_RANK_COLUMN,\n]);\n\n/** Markers for byline/taxonomy hydration folded into the content query. */\nexport const FOLDED_TERMS = Symbol.for(\"emdash:foldedTerms\");\nexport const FOLDED_BYLINES = Symbol.for(\"emdash:foldedBylines\");\n/**\n * Marker for whether `_emdash_bylines` has any rows at all (`false` = table\n * empty). Lets byline hydration trust an empty fold instead of re-checking\n * via the byline query path on sites that never use bylines.\n */\nexport const FOLDED_BYLINES_EXIST = Symbol.for(\"emdash:foldedBylinesExist\");\n\n/**\n * Correlated JSON-array subqueries that fold taxonomy-term and byline hydration\n * into the content query, removing the two separate hydration round trips per\n * fetch. `outer` is the content table's alias/name; each subquery correlates on\n * `<outer>.id`, so the base query stays one row per entry (no join fan-out, no\n * duplicated content payload). Order is NOT applied in the aggregate (it differs\n * across dialects) — the consumer sorts terms by label and credits by sortOrder.\n *\n * Dialect-specific aggregation: SQLite `json_group_array`/`json_object` returns\n * a JSON *string*; Postgres `json_agg`/`json_build_object` (coalesced to `[]`)\n * returns parsed JSON. {@link stashFolded} handles both.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any Kysely instance\nfunction foldedHydrationSelects(db: Kysely<any>, type: string, outer: string) {\n\tconst o = sql.ref(outer);\n\tconst pg = isPostgres(db);\n\tconst obj = (pairs: string) =>\n\t\tpg ? sql.raw(`json_build_object(${pairs})`) : sql.raw(`json_object(${pairs})`);\n\tconst agg = (inner: RawBuilder<unknown>) =>\n\t\tpg ? sql`coalesce(json_agg(${inner}), '[]'::json)` : sql`json_group_array(${inner})`;\n\n\t// Pin the byline join order on SQLite (#1722). Taxonomy hydration uses\n\t// LEFT JOINs below, whose order is already fixed by SQL semantics. SQLite\n\t// honours `CROSS JOIN` ordering, forcing the byline subquery to drive from\n\t// its pivot by content reference and probe by translation_group. Postgres\n\t// keeps statistics and rejects `CROSS JOIN … ON`, so it stays a plain JOIN.\n\tconst foldJoin = pg ? sql`JOIN` : sql`CROSS JOIN`;\n\n\tconst termObj = obj(\n\t\t\"'id', coalesce(exact_term.id, default_term.id), 'name', coalesce(exact_term.name, default_term.name), 'slug', coalesce(exact_term.slug, default_term.slug), 'label', coalesce(exact_term.label, default_term.label), 'parent_id', coalesce(exact_term.parent_id, default_term.parent_id), 'locale', coalesce(exact_term.locale, default_term.locale), 'translation_group', coalesce(exact_term.translation_group, default_term.translation_group)\",\n\t);\n\tconst defaultLocale = getI18nConfig()?.defaultLocale ?? \"en\";\n\tconst selectedTermId = sql`coalesce(exact_term.id, default_term.id)`;\n\tconst termAgg = pg\n\t\t? sql`coalesce(json_agg(${termObj}) FILTER (WHERE ${selectedTermId} IS NOT NULL), '[]'::json)`\n\t\t: sql`json_group_array(${termObj}) FILTER (WHERE ${selectedTermId} IS NOT NULL)`;\n\tconst terms = sql`(SELECT ${termAgg} FROM ${sql.ref(\"content_taxonomies\")} AS ct LEFT JOIN ${sql.ref(\"taxonomies\")} AS exact_term ON exact_term.translation_group = ct.taxonomy_id AND exact_term.locale = ${o}.locale LEFT JOIN ${sql.ref(\"taxonomies\")} AS default_term ON default_term.translation_group = ct.taxonomy_id AND default_term.locale = ${defaultLocale} WHERE ct.collection = ${type} AND ct.entry_id = ${o}.translation_group) AS ${sql.ref(\"_emdash_terms\")}`;\n\n\tconst bylineInner = obj(\n\t\t\"'id', b.id, 'slug', b.slug, 'displayName', b.display_name, 'bio', b.bio, 'avatarMediaId', b.avatar_media_id, 'avatarStorageKey', m.storage_key, 'avatarAlt', m.alt, 'avatarBlurhash', m.blurhash, 'avatarDominantColor', m.dominant_color, 'websiteUrl', b.website_url, 'userId', b.user_id, 'isGuest', b.is_guest, 'createdAt', b.created_at, 'updatedAt', b.updated_at, 'locale', b.locale, 'translationGroup', b.translation_group\",\n\t);\n\tconst creditObj = pg\n\t\t? sql.raw(\n\t\t\t\t\"json_build_object('roleLabel', cb.role_label, 'sortOrder', cb.sort_order, 'byline', \",\n\t\t\t)\n\t\t: sql.raw(\"json_object('roleLabel', cb.role_label, 'sortOrder', cb.sort_order, 'byline', \");\n\tconst credit = sql`${creditObj}${bylineInner})`;\n\tconst bylines = sql`(SELECT ${agg(credit)} FROM ${sql.ref(\"_emdash_content_bylines\")} AS cb ${foldJoin} ${sql.ref(\"_emdash_bylines\")} AS b ON b.translation_group = cb.byline_id LEFT JOIN ${sql.ref(\"media\")} AS m ON m.id = b.avatar_media_id WHERE cb.collection_slug = ${type} AND cb.content_id = ${o}.id AND b.locale = ${o}.locale) AS ${sql.ref(\"_emdash_bylines\")}`;\n\t// Uncorrelated existence probe (evaluated once per statement, not per row):\n\t// 1 when `_emdash_bylines` has any row, NULL when empty. An empty table\n\t// means an empty fold is authoritative — no credit in any locale, no\n\t// author-fallback byline — so hydration can skip the byline query path.\n\tconst bylinesExist = sql`(SELECT 1 FROM ${sql.ref(\"_emdash_bylines\")} LIMIT 1) AS ${sql.ref(\"_emdash_bylines_exist\")}`;\n\treturn { terms, bylines, bylinesExist };\n}\n\n/**\n * Correlated JSON-object subquery that folds per-entry SEO into the content\n * query without widening the result set: 1 row of `_emdash_seo` becomes 1 JSON\n * column rather than 5 flat columns. The JSON column is expanded onto the row\n * via {@link expandFoldedSeo} after the query runs, preserving the alias keys\n * that {@link extractSeo} reads. Missing SEO row (no entry in `_emdash_seo`)\n * yields NULL, which {@link expandFoldedSeo} treats as \"no SEO\" - identical to\n * the prior LEFT JOIN miss behavior.\n *\n * Dialect-specific aggregation mirrors {@link foldedHydrationSelects}: SQLite\n * `json_object` returns a JSON *string*, Postgres `json_build_object` returns\n * parsed JSON; both branches are handled in expansion.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any Kysely instance\nfunction foldedSeoSelect(db: Kysely<any>, type: string, outer: string) {\n\tconst o = sql.ref(outer);\n\tconst pg = isPostgres(db);\n\t// Use raw column names (not aliases) as JSON keys: the JSON is expanded back\n\t// onto SEO_COLUMN_ALIASES in JS, and keeping the keys matched to the\n\t// underlying columns makes the SQL readable and the expansion 1-to-1.\n\tconst pairs =\n\t\t\"'seo_title', s.seo_title, 'seo_description', s.seo_description, 'seo_image', s.seo_image, 'seo_canonical', s.seo_canonical, 'seo_no_index', s.seo_no_index\";\n\tconst obj = pg ? sql.raw(`json_build_object(${pairs})`) : sql.raw(`json_object(${pairs})`);\n\treturn sql`(SELECT ${obj} FROM ${sql.ref(\"_emdash_seo\")} AS s WHERE s.collection = ${type} AND s.content_id = ${o}.id LIMIT 1) AS ${sql.ref(SEO_FOLDED_COLUMN)}`;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any Kysely instance\nfunction foldedBooleanFieldsSelect(db: Kysely<any>, type: string) {\n\tconst aggregate = isPostgres(db)\n\t\t? sql`coalesce(json_agg(f.slug), '[]'::json)`\n\t\t: sql`json_group_array(f.slug)`;\n\treturn sql`(\n\t\tSELECT ${aggregate}\n\t\tFROM ${sql.ref(\"_emdash_fields\")} AS f\n\t\tINNER JOIN ${sql.ref(\"_emdash_collections\")} AS c ON c.id = f.collection_id\n\t\tWHERE c.slug = ${type} AND f.type = ${\"boolean\"}\n\t) AS ${sql.ref(BOOLEAN_FIELDS_FOLDED_COLUMN)}`;\n}\n\n/**\n * Expand the folded `_emdash_seo` JSON column onto the row using SEO_COLUMN_ALIASES,\n * so {@link extractSeo} reads it transparently. SQLite returns a JSON string\n * (parse it); Postgres returns already-parsed JSON. Missing/malformed/null is\n * a no-op: {@link extractSeo} returns null when the aliases are absent.\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction expandFoldedSeo(row: Record<string, unknown>): void {\n\tconst raw = row[SEO_FOLDED_COLUMN];\n\tdelete row[SEO_FOLDED_COLUMN];\n\tlet parsed: Record<string, unknown> | null = null;\n\tif (typeof raw === \"string\") {\n\t\ttry {\n\t\t\tconst candidate: unknown = JSON.parse(raw);\n\t\t\tif (isPlainObject(candidate)) parsed = candidate;\n\t\t} catch {\n\t\t\treturn; // malformed JSON: leave the row without SEO aliases (extractSeo returns null)\n\t\t}\n\t} else if (isPlainObject(raw)) {\n\t\tparsed = raw;\n\t}\n\tif (!parsed) return;\n\tfor (const [col, alias] of Object.entries(SEO_COLUMN_ALIASES)) {\n\t\trow[alias] = parsed[col] ?? null;\n\t}\n}\n\nexport function creditsFromFoldedBylines(folded: unknown[]) {\n\treturn folded\n\t\t.map((raw) => {\n\t\t\tconst credit = isPlainObject(raw) ? raw : {};\n\t\t\tconst byline = isPlainObject(credit.byline) ? credit.byline : {};\n\t\t\treturn {\n\t\t\t\troleLabel: typeof credit.roleLabel === \"string\" ? credit.roleLabel : null,\n\t\t\t\tsortOrder: Number(credit.sortOrder ?? 0),\n\t\t\t\tsource: \"explicit\" as const,\n\t\t\t\tbyline: {\n\t\t\t\t\t...byline,\n\t\t\t\t\tisGuest: Boolean(byline.isGuest),\n\t\t\t\t\t// Folded rows omit custom-field values.\n\t\t\t\t\tcustomFields: {},\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.toSorted((a, b) => a.sortOrder - b.sortOrder);\n}\n\n/**\n * Stash folded hydration JSON (non-enumerable) for the query.ts fast paths.\n * SQLite returns a JSON string (parse it); Postgres returns already-parsed JSON.\n */\nfunction stashFolded(data: Record<string, unknown>, row: Record<string, unknown>): void {\n\tfor (const [col, sym] of [\n\t\t[\"_emdash_terms\", FOLDED_TERMS],\n\t\t[\"_emdash_bylines\", FOLDED_BYLINES],\n\t] as const) {\n\t\tconst raw = row[col];\n\t\tlet value: unknown;\n\t\tif (typeof raw === \"string\") {\n\t\t\ttry {\n\t\t\t\tvalue = JSON.parse(raw);\n\t\t\t} catch {\n\t\t\t\tcontinue; // malformed: fall back to the query path\n\t\t\t}\n\t\t} else if (Array.isArray(raw)) {\n\t\t\tvalue = raw; // Postgres json/jsonb already parsed by the driver\n\t\t} else {\n\t\t\tcontinue;\n\t\t}\n\t\tObject.defineProperty(data, sym, { value, enumerable: false, configurable: true });\n\t}\n\t// Existence probe: 1 = table has rows, NULL = empty (both dialects). A row\n\t// without the column (e.g. a cached snapshot) leaves the marker unset,\n\t// which hydration treats as \"unknown\" and falls back conservatively.\n\tif (\"_emdash_bylines_exist\" in row) {\n\t\tObject.defineProperty(data, FOLDED_BYLINES_EXIST, {\n\t\t\tvalue: row[\"_emdash_bylines_exist\"] != null,\n\t\t\tenumerable: false,\n\t\t\tconfigurable: true,\n\t\t});\n\t}\n\n\tconst foldedBylines = Reflect.get(data, FOLDED_BYLINES);\n\tif (!Array.isArray(foldedBylines)) return;\n\tconst credits = creditsFromFoldedBylines(foldedBylines);\n\tdata.bylines = credits;\n\tdata.byline = credits[0]?.byline ?? null;\n}\n\n/** Resolved SEO shape attached to `entry.data.seo`. Mirrors `ContentSeo`. */\ninterface EntrySeo {\n\ttitle: string | null;\n\tdescription: string | null;\n\timage: string | null;\n\tcanonical: string | null;\n\tnoIndex: boolean;\n}\n\n/**\n * Build a `data.seo` object from the joined `_emdash_seo` columns on a row.\n *\n * Returns `null` when no SEO row exists (LEFT JOIN miss → `seo_no_index` is\n * NULL, since the column is `NOT NULL DEFAULT 0` whenever a row is present).\n * Returning null keeps the `seo` key off entries that have none, so\n * `getSeoMeta()` falls back to its defaults exactly as before.\n */\nfunction extractSeo(row: Record<string, unknown>): EntrySeo | null {\n\tconst noIndex = row[SEO_COLUMN_ALIASES.seo_no_index];\n\tif (noIndex === null || noIndex === undefined) return null;\n\tconst title = row[SEO_COLUMN_ALIASES.seo_title];\n\tconst description = row[SEO_COLUMN_ALIASES.seo_description];\n\tconst image = row[SEO_COLUMN_ALIASES.seo_image];\n\tconst canonical = row[SEO_COLUMN_ALIASES.seo_canonical];\n\treturn {\n\t\ttitle: typeof title === \"string\" ? title : null,\n\t\tdescription: typeof description === \"string\" ? description : null,\n\t\timage: typeof image === \"string\" ? image : null,\n\t\tcanonical: typeof canonical === \"string\" ? canonical : null,\n\t\tnoIndex: noIndex === 1,\n\t};\n}\n\n/**\n * Get the table name for a collection type\n */\nfunction getTableName(type: string): string {\n\tvalidateIdentifier(type, \"collection type\");\n\treturn `ec_${type}`;\n}\n\n/**\n * Cache for taxonomy names by collection (only used for the primary database).\n * Stored on globalThis so Vite SSR chunk duplication cannot create independent\n * caches. Skipped when a per-request DB override is active (e.g. preview mode)\n * because the override DB may have different taxonomies.\n */\ninterface TaxonomyNamesHolder {\n\tcache: Map<string, Set<string>> | null;\n}\n\nconst TAXONOMY_NAMES_CACHE_KEY = Symbol.for(\"emdash:taxonomy-names\");\nconst taxonomyNamesStore = globalThis as Record<symbol, unknown>;\nconst taxonomyNamesHolder: TaxonomyNamesHolder =\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis singleton pattern (see taxonomies/index.ts)\n\t(taxonomyNamesStore[TAXONOMY_NAMES_CACHE_KEY] as TaxonomyNamesHolder | undefined) ??\n\t(() => {\n\t\tconst holder: TaxonomyNamesHolder = { cache: null };\n\t\ttaxonomyNamesStore[TAXONOMY_NAMES_CACHE_KEY] = holder;\n\t\treturn holder;\n\t})();\n\nfunction setTaxonomyNamesCache(cache: Map<string, Set<string>> | null): void {\n\ttaxonomyNamesHolder.cache = cache;\n}\n\n/**\n * Get taxonomy names attached to a collection (cached for the primary DB,\n * bypassed only when the per-request DB is an isolated instance — playground /\n * DO preview). Plain D1 Sessions routing shares schema with the singleton, so\n * the isolate-wide cache stays valid.\n */\nasync function getTaxonomyNames(db: Kysely<Database>, collection: string): Promise<Set<string>> {\n\tconst hasIsolatedDb = getRequestContext()?.dbIsIsolated === true;\n\n\tif (!hasIsolatedDb && taxonomyNamesHolder.cache) {\n\t\treturn taxonomyNamesHolder.cache.get(collection) ?? new Set();\n\t}\n\n\ttry {\n\t\tconst defs = await selectTaxonomyDefs(db).execute();\n\t\tconst namesByCollection = new Map<string, Set<string>>();\n\t\tfor (const def of defs) {\n\t\t\tlet collections: unknown;\n\t\t\ttry {\n\t\t\t\tcollections = JSON.parse(def.collections ?? \"[]\");\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!Array.isArray(collections)) continue;\n\t\t\tfor (const attachedCollection of collections) {\n\t\t\t\tif (typeof attachedCollection !== \"string\") continue;\n\t\t\t\tconst names = namesByCollection.get(attachedCollection) ?? new Set<string>();\n\t\t\t\tnames.add(def.name);\n\t\t\t\tnamesByCollection.set(attachedCollection, names);\n\t\t\t}\n\t\t}\n\t\tif (!hasIsolatedDb) {\n\t\t\tsetTaxonomyNamesCache(namesByCollection);\n\t\t}\n\t\treturn namesByCollection.get(collection) ?? new Set();\n\t} catch (error) {\n\t\tif (!isMissingTableError(error) && !isMissingColumnError(error)) throw error;\n\n\t\tconst empty = new Set<string>();\n\t\tif (!hasIsolatedDb) {\n\t\t\tsetTaxonomyNamesCache(new Map());\n\t\t}\n\t\treturn empty;\n\t}\n}\n\n/**\n * Reset the isolate-wide taxonomy-names cache.\n *\n * Called from `invalidateTaxonomyDefsCache()` so that creating or seeding a\n * taxonomy definition is reflected within the current isolate instead of\n * waiting for the isolate to recycle. Keeps this cache consistent with the\n * isolate-wide taxonomy-defs cache in `taxonomies/index.ts`.\n */\nexport function resetTaxonomyNamesCache(): void {\n\tsetTaxonomyNamesCache(null);\n}\n\n/**\n * System columns to include in data (mapped to camelCase where needed)\n */\nconst INCLUDE_IN_DATA: Record<string, string> = {\n\tid: \"id\",\n\tstatus: \"status\",\n\tauthor_id: \"authorId\",\n\tprimary_byline_id: \"primaryBylineId\",\n\tcreated_at: \"createdAt\",\n\tupdated_at: \"updatedAt\",\n\tpublished_at: \"publishedAt\",\n\tscheduled_at: \"scheduledAt\",\n\tdraft_revision_id: \"draftRevisionId\",\n\tlive_revision_id: \"liveRevisionId\",\n\tlocale: \"locale\",\n\ttranslation_group: \"translationGroup\",\n};\n\n/** System date columns that should be converted to Date objects */\nconst DATE_COLUMNS = new Set([\"created_at\", \"updated_at\", \"published_at\", \"scheduled_at\"]);\n\n/**\n * Hidden, symbol-keyed property on each mapped data record carrying raw DB\n * values: the string of every date column and, in a collection load, the\n * primary sort column's value. Lets cursor encoders downstream reproduce the\n * loader's exact `nextCursor` from an entry, whose `data` leaves some columns\n * out, parses text that looks like JSON, and holds dates as `Date` objects,\n * which lose precision for stored values that aren't already\n * ISO-with-milliseconds (e.g. `2026-01-01T00:00:00Z` becomes\n * `2026-01-01T00:00:00.000Z`).\n */\nexport const CURSOR_RAW_VALUES: unique symbol = Symbol(\"emdash:cursorRawValues\");\n\nconst LOCAL_MEDIA_FILE_PREFIX = \"/_emdash/api/media/file/\";\nconst URL_SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z\\d+\\-.]*:/;\n\n/** Safely extract a string value from a record, returning fallback if not a string */\nfunction rowStr(row: Record<string, unknown>, key: string, fallback = \"\"): string {\n\tconst val = row[key];\n\treturn typeof val === \"string\" ? val : fallback;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isBareMediaKey(src: string): boolean {\n\treturn !src.startsWith(\"/\") && !URL_SCHEME_PATTERN.test(src);\n}\n\nfunction normalizeLocalMediaValue(value: unknown): unknown {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(normalizeLocalMediaValue);\n\t}\n\n\tif (!isRecord(value)) {\n\t\treturn value;\n\t}\n\n\tconst normalized: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(value)) {\n\t\tnormalized[key] = normalizeLocalMediaValue(child);\n\t}\n\n\tif (\n\t\tnormalized.provider === \"local\" &&\n\t\ttypeof normalized.src === \"string\" &&\n\t\tnormalized.src.length > 0\n\t) {\n\t\tconst src = normalized.src;\n\t\tif (src.startsWith(LOCAL_MEDIA_FILE_PREFIX)) {\n\t\t\tconst id = src.slice(LOCAL_MEDIA_FILE_PREFIX.length);\n\t\t\tif (!normalized.id && id) {\n\t\t\t\tnormalized.id = id;\n\t\t\t}\n\t\t} else if (isBareMediaKey(src)) {\n\t\t\tif (!normalized.id) {\n\t\t\t\tnormalized.id = src;\n\t\t\t}\n\t\t\tnormalized.src = `${LOCAL_MEDIA_FILE_PREFIX}${src}`;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n/**\n * Map a database row to entry data\n * Extracts content fields (non-system columns) and parses JSON where needed.\n * System columns needed for templates (id, status, dates) are included with camelCase names.\n */\nfunction mapRowToData(\n\trow: Record<string, unknown>,\n\tbooleanFields: ReadonlySet<string>,\n\tsortColumn?: string,\n): Record<string, unknown> {\n\tconst data: Record<string, unknown> = {};\n\tconst rawValues: Record<string, SortCursorValue> = {};\n\n\tfor (const [key, value] of Object.entries(row)) {\n\t\t// Include certain system columns (mapped to camelCase where needed)\n\t\tif (key in INCLUDE_IN_DATA) {\n\t\t\t// Convert date columns from ISO strings to Date objects\n\t\t\tif (DATE_COLUMNS.has(key)) {\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\trawValues[key] = value;\n\t\t\t\t\tdata[INCLUDE_IN_DATA[key]] = new Date(value);\n\t\t\t\t} else {\n\t\t\t\t\tdata[INCLUDE_IN_DATA[key]] = null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdata[INCLUDE_IN_DATA[key]] = value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (SYSTEM_COLUMNS.has(key)) continue;\n\n\t\tif (booleanFields.has(key) && (typeof value === \"boolean\" || value === 0 || value === 1)) {\n\t\t\tdata[key] = Boolean(value);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Try to parse JSON strings (for portableText, json fields, etc.)\n\t\tif (typeof value === \"string\") {\n\t\t\ttry {\n\t\t\t\t// Only parse if it looks like JSON (starts with { or [)\n\t\t\t\tif (value.startsWith(\"{\") || value.startsWith(\"[\")) {\n\t\t\t\t\tdata[key] = normalizeLocalMediaValue(JSON.parse(value));\n\t\t\t\t} else {\n\t\t\t\t\tdata[key] = value;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tdata[key] = value;\n\t\t\t}\n\t\t} else {\n\t\t\tdata[key] = value;\n\t\t}\n\t}\n\n\tstashSortValue(data, row, sortColumn, rawValues);\n\n\treturn data;\n}\n\n/**\n * Keep the row's raw sort value on `data` (non-enumerable) so the next-page\n * cursor is encoded from the same value the keyset query compares against.\n */\nfunction stashSortValue(\n\tdata: Record<string, unknown>,\n\trow: Record<string, unknown>,\n\tsortColumn: string | undefined,\n\trawValues: Record<string, SortCursorValue> = {},\n): void {\n\tif (sortColumn !== undefined && sortColumn in row) {\n\t\trawValues[sortColumn] = sortCursorValue(row[sortColumn]);\n\t}\n\tObject.defineProperty(data, CURSOR_RAW_VALUES, {\n\t\tvalue: rawValues,\n\t\tenumerable: false,\n\t\tconfigurable: false,\n\t\twritable: false,\n\t});\n}\n\n/**\n * Fetch the draft revision snapshots for the rows a collection read should\n * serve as drafts, keyed by content row ID. One query per `SQL_BATCH_SIZE`\n * revisions; nothing runs unless `scope` is set.\n */\nasync function loadDraftRevisions(\n\tdb: Kysely<Database>,\n\trows: Record<string, unknown>[],\n\tscope: DraftRevisionScope | undefined,\n): Promise<Map<string, Record<string, unknown>>> {\n\tconst drafts = new Map<string, Record<string, unknown>>();\n\tif (!scope) return drafts;\n\tconst wanted = new Map<string, string>();\n\tfor (const row of rows) {\n\t\tconst draftId = rowStr(row, \"draft_revision_id\");\n\t\tif (!draftId) continue;\n\t\tif (\n\t\t\tscope !== \"all\" &&\n\t\t\tscope.id !== rowStr(row, \"id\") &&\n\t\t\tscope.id !== rowStr(row, \"slug\") &&\n\t\t\tscope.id !== entryIdForRow(row)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\twanted.set(draftId, rowStr(row, \"id\"));\n\t}\n\tfor (const ids of chunks([...wanted.keys()], SQL_BATCH_SIZE)) {\n\t\tconst result = await sql<{ id: string; data: string }>`\n\t\t\tSELECT id, data FROM revisions WHERE id IN (${sql.join(ids)})\n\t\t`.execute(db);\n\t\tfor (const revision of result.rows) {\n\t\t\tconst rowId = wanted.get(revision.id);\n\t\t\tif (rowId) drafts.set(rowId, JSON.parse(revision.data));\n\t\t}\n\t}\n\treturn drafts;\n}\n\n/**\n * Build an entry whose content fields come from a revision snapshot, keeping\n * the system metadata of the content table row.\n */\nfunction revisionEntry(\n\trow: Record<string, unknown>,\n\tparsed: Record<string, unknown>,\n\tbooleanFields: ReturnType<typeof parseFoldedBooleanFields>,\n\tsortColumn?: string,\n) {\n\tconst systemData: Record<string, unknown> = {};\n\tfor (const [key, mappedKey] of Object.entries(INCLUDE_IN_DATA)) {\n\t\tif (key in row) {\n\t\t\tif (DATE_COLUMNS.has(key)) {\n\t\t\t\tsystemData[mappedKey] = typeof row[key] === \"string\" ? new Date(row[key]) : null;\n\t\t\t} else {\n\t\t\t\tsystemData[mappedKey] = row[key];\n\t\t\t}\n\t\t}\n\t}\n\t// Use slug from revision metadata if present, else from content table\n\tconst slug = typeof parsed._slug === \"string\" ? parsed._slug : rowStr(row, \"slug\");\n\tconst revSlug = slug || rowStr(row, \"id\");\n\tconst i18nConfig = virtualConfig?.i18n;\n\tconst i18nEnabled = i18nConfig && i18nConfig.locales.length > 1;\n\tconst revLocale = rowStr(row, \"locale\");\n\tconst shouldPrefixRev =\n\t\ti18nEnabled &&\n\t\trevLocale !== \"\" &&\n\t\t(revLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\tconst data: Record<string, unknown> = {\n\t\t...systemData,\n\t\tslug,\n\t\t...mapRevisionData(parsed, booleanFields),\n\t};\n\tstashSortValue(data, row, sortColumn);\n\treturn {\n\t\tid: shouldPrefixRev ? `${revLocale}/${revSlug}` : revSlug,\n\t\tslug,\n\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\tdata,\n\t\tcacheHint: {\n\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t},\n\t};\n}\n\n/**\n * The entry id Astro addresses a row by: its slug, prefixed with the locale\n * whenever i18n routing would prefix the URL. Shared by every path that builds\n * a loader entry so a referenced entry carries the same id it would have been\n * loaded under directly.\n */\nfunction entryIdForRow(row: Record<string, unknown>): string {\n\tconst i18nConfig = virtualConfig?.i18n;\n\tconst slug = rowStr(row, \"slug\") || rowStr(row, \"id\");\n\tconst locale = rowStr(row, \"locale\");\n\tconst shouldPrefix =\n\t\ti18nConfig &&\n\t\ti18nConfig.locales.length > 1 &&\n\t\tlocale !== \"\" &&\n\t\t(locale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\treturn shouldPrefix ? `${locale}/${slug}` : slug;\n}\n\n/** A loader entry as {@link emdashLoader} builds one, before the query layer wraps it. */\nexport interface LoadedEntry {\n\tid: string;\n\tslug: string;\n\tstatus: string;\n\tdata: Record<string, unknown>;\n\tcacheHint: { tags: string[]; lastModified?: Date };\n}\n\n/**\n * Load one locale variant of each translation group, in one query per\n * `SQL_BATCH_SIZE` chunk of groups.\n *\n * A group's variant is the first of `localeChain` it has, or else its lowest\n * locale code: a reference names a translation group, so a target that exists\n * only outside the chain is still a real reference. Groups with no surviving\n * variant are absent from the result.\n *\n * The rows go through the same {@link mapRowToData} as a direct entry load, so\n * a referenced entry's `data` carries the same dates, booleans and normalized\n * media values a caller would get from `getEmDashEntry`. Bylines and taxonomy\n * terms are not hydrated; each would cost a correlated subquery per row.\n */\nexport async function loadEntriesByGroups(\n\ttype: string,\n\ttranslationGroups: string[],\n\toptions: { publishedOnly?: boolean; localeChain?: readonly string[] } = {},\n): Promise<LoadedEntry[]> {\n\tif (translationGroups.length === 0) return [];\n\tconst db = await getDb();\n\tconst tableName = getTableName(type);\n\tconst statusFilter = options.publishedOnly ? sql`AND status = ${\"published\"}` : sql``;\n\tconst booleanFieldsSelect = foldedBooleanFieldsSelect(db, type);\n\tconst localeChain = options.localeChain ?? [];\n\tconst chainPosition =\n\t\tlocaleChain.length > 0\n\t\t\t? sql`CASE locale ${sql.join(\n\t\t\t\t\tlocaleChain.map((locale, index) => sql`WHEN ${locale} THEN ${sql.lit(index)}`),\n\t\t\t\t\tsql` `,\n\t\t\t\t)} ELSE ${sql.lit(localeChain.length)} END,`\n\t\t\t: sql``;\n\n\tconst entries: LoadedEntry[] = [];\n\ttry {\n\t\tfor (const chunk of chunks(translationGroups, SQL_BATCH_SIZE)) {\n\t\t\tconst result = await sql<Record<string, unknown>>`\n\t\t\t\tSELECT * FROM (\n\t\t\t\t\tSELECT *, ${booleanFieldsSelect},\n\t\t\t\t\t\tROW_NUMBER() OVER (\n\t\t\t\t\t\t\tPARTITION BY translation_group ORDER BY ${chainPosition} locale ASC\n\t\t\t\t\t\t) AS ${sql.ref(VARIANT_RANK_COLUMN)}\n\t\t\t\t\tFROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE translation_group IN (${sql.join(chunk.map((group) => sql`${group}`))})\n\t\t\t\t\tAND deleted_at IS NULL\n\t\t\t\t\t${statusFilter}\n\t\t\t\t) AS variants\n\t\t\t\tWHERE ${sql.ref(VARIANT_RANK_COLUMN)} = 1\n\t\t\t\tORDER BY translation_group ASC\n\t\t\t`.execute(db);\n\t\t\tconst booleanFields = parseFoldedBooleanFields(result.rows[0]);\n\t\t\tfor (const row of result.rows) {\n\t\t\t\tentries.push({\n\t\t\t\t\tid: entryIdForRow(row),\n\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\tdata: mapRowToData(row, booleanFields),\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (isMissingTableError(error)) return [];\n\t\tthrow error;\n\t}\n\treturn entries;\n}\n\nfunction parseFoldedBooleanFields(row: Record<string, unknown> | undefined): Set<string> {\n\tconst raw = row?.[BOOLEAN_FIELDS_FOLDED_COLUMN];\n\tlet values: unknown;\n\tif (typeof raw === \"string\") {\n\t\ttry {\n\t\t\tvalues = JSON.parse(raw);\n\t\t} catch {\n\t\t\treturn new Set();\n\t\t}\n\t} else {\n\t\tvalues = raw;\n\t}\n\n\tif (!Array.isArray(values)) return new Set();\n\treturn new Set(values.filter((value): value is string => typeof value === \"string\"));\n}\n\n/**\n * Map revision data (already-parsed JSON object) to entry data.\n * Strips _-prefixed metadata keys (e.g. _slug) used internally by revisions.\n */\nfunction mapRevisionData(\n\tdata: Record<string, unknown>,\n\tbooleanFields: ReadonlySet<string>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (key.startsWith(\"_\")) continue; // revision metadata\n\t\tif (booleanFields.has(key) && (typeof value === \"boolean\" || value === 0 || value === 1)) {\n\t\t\tresult[key] = Boolean(value);\n\t\t\tcontinue;\n\t\t}\n\t\tresult[key] = normalizeLocalMediaValue(value);\n\t}\n\treturn result;\n}\n\n// Virtual module imports are lazy-loaded to avoid errors when importing\n// emdash outside of Astro/Vite context (e.g., in astro.config.mjs)\nlet virtualConfig:\n\t| {\n\t\t\tdatabase?: { config: unknown };\n\t\t\ti18n?: { defaultLocale: string; locales: string[]; prefixDefaultLocale?: boolean } | null;\n\t }\n\t| undefined;\nlet virtualCreateDialect: ((config: unknown) => Dialect) | undefined;\n\nasync function loadVirtualConfig() {\n\tif (virtualConfig === undefined) {\n\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t// @ts-ignore - virtual module\n\t\tconst configModule = await import(\"virtual:emdash/config\");\n\t\tvirtualConfig = configModule.default;\n\t}\n}\n\nasync function loadVirtualModules() {\n\tawait loadVirtualConfig();\n\tif (virtualCreateDialect === undefined) {\n\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t// @ts-ignore - virtual module\n\t\tconst dialectModule = await import(\"virtual:emdash/dialect\");\n\t\tvirtualCreateDialect = dialectModule.createDialect;\n\t\t// dialectType is no longer needed here — dialect detection is\n\t\t// done via the db adapter instance in dialect-helpers.ts\n\t}\n}\n\n/**\n * Entry data type - generic object\n */\nexport type EntryData = Record<string, unknown>;\n\n/**\n * Sort direction\n */\nexport type SortDirection = \"asc\" | \"desc\";\n\n/**\n * Order by specification - field name to direction\n * @example { created_at: \"desc\" } - Sort by created_at descending\n * @example { title: \"asc\" } - Sort by title ascending\n */\nexport type OrderBySpec = Record<string, SortDirection>;\n\n/**\n * Resolved primary sort field and direction (used for cursor pagination).\n */\ninterface PrimarySort {\n\tfield: string;\n\tdirection: SortDirection;\n}\n\n/**\n * Get the primary sort field from an orderBy spec (first valid field, or default).\n */\nfunction getPrimarySort(orderBy: OrderBySpec | undefined, tablePrefix?: string): PrimarySort {\n\tif (orderBy) {\n\t\tfor (const [field, direction] of Object.entries(orderBy)) {\n\t\t\tif (FIELD_NAME_PATTERN.test(field)) {\n\t\t\t\tconst fullField = tablePrefix ? `${tablePrefix}.${field}` : field;\n\t\t\t\treturn { field: fullField, direction };\n\t\t\t}\n\t\t}\n\t}\n\tconst defaultField = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\treturn { field: defaultField, direction: \"desc\" };\n}\n\n/**\n * Build ORDER BY clause from orderBy spec\n * Validates field names to prevent SQL injection (alphanumeric + underscore only)\n * Supports multiple sort fields in object key order\n */\nfunction buildOrderByClause(\n\torderBy: OrderBySpec | undefined,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\t// Default to created_at DESC\n\tif (!orderBy || Object.keys(orderBy).length === 0) {\n\t\tconst field = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\t\treturn sql`ORDER BY ${sql.ref(field)} DESC, ${sql.ref(tablePrefix ? `${tablePrefix}.id` : \"id\")} DESC`;\n\t}\n\n\tconst sortParts: ReturnType<typeof sql>[] = [];\n\n\tfor (const [field, direction] of Object.entries(orderBy)) {\n\t\t// Validate field name (alphanumeric + underscore only)\n\t\tif (!FIELD_NAME_PATTERN.test(field)) {\n\t\t\tcontinue; // Skip invalid field names\n\t\t}\n\n\t\tconst fullField = tablePrefix ? `${tablePrefix}.${field}` : field;\n\t\tconst dir = direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\t\tsortParts.push(sql`${sql.ref(fullField)} ${dir}`);\n\t}\n\n\t// If no valid sort fields, fall back to default\n\tif (sortParts.length === 0) {\n\t\tconst defaultField = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\t\treturn sql`ORDER BY ${sql.ref(defaultField)} DESC, ${sql.ref(tablePrefix ? `${tablePrefix}.id` : \"id\")} DESC`;\n\t}\n\n\t// Add id as tiebreaker to ensure stable cursor ordering\n\tconst primary = getPrimarySort(orderBy, tablePrefix);\n\tconst idField = tablePrefix ? `${tablePrefix}.id` : \"id\";\n\tconst idDir = primary.direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\tsortParts.push(sql`${sql.ref(idField)} ${idDir}`);\n\n\treturn sql`ORDER BY ${sql.join(sortParts, sql`, `)}`;\n}\n\n/**\n * Sort columns every row has a value for. Their cursors keep the plain\n * `{ orderValue, id }` shape; any other sort column can hold NULL.\n */\nconst NON_NULL_SORT_COLUMNS = new Set([\"id\", \"created_at\", \"updated_at\", \"status\", \"locale\"]);\n\ntype SortCursorValue = string | number | null;\n\ninterface SortCursorPayload {\n\tversion: 1;\n\tfield: string;\n\tvalue: SortCursorValue;\n}\n\nfunction sortCursorValue(value: unknown): SortCursorValue {\n\tif (typeof value === \"string\" || typeof value === \"number\") return value;\n\tif (typeof value === \"boolean\") return value ? 1 : 0;\n\tif (value instanceof Date) return value.toISOString();\n\treturn null;\n}\n\n/**\n * Encode the cursor for the page after the row whose primary sort column\n * `field` holds `value`.\n *\n * @internal shared with query.ts, which re-encodes cursors from entries.\n */\nexport function encodeSortCursor(field: string, value: unknown, id: string): string {\n\tconst cursorValue = sortCursorValue(value);\n\tif (NON_NULL_SORT_COLUMNS.has(field)) {\n\t\treturn encodeCursor(cursorValue === null ? \"\" : String(cursorValue), id);\n\t}\n\tconst payload: SortCursorPayload = { version: 1, field, value: cursorValue };\n\treturn encodeCursor(JSON.stringify(payload), id);\n}\n\nfunction decodeSortCursor(cursor: string, field: string): { value: SortCursorValue; id: string } {\n\tconst { orderValue, id } = decodeCursor(cursor);\n\tif (NON_NULL_SORT_COLUMNS.has(field)) return { value: orderValue, id };\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = JSON.parse(orderValue);\n\t} catch {\n\t\tpayload = undefined;\n\t}\n\t// A plain `{ orderValue, id }` cursor, which nullable columns were paged\n\t// with before and which wrote a NULL as \"\".\n\tif (payload === null || typeof payload !== \"object\") {\n\t\treturn { value: orderValue === \"\" ? null : orderValue, id };\n\t}\n\tconst candidate = payload as Partial<SortCursorPayload>;\n\tconst { value } = candidate;\n\tif (\n\t\tcandidate.version !== 1 ||\n\t\tcandidate.field !== field ||\n\t\t(value !== null && typeof value !== \"string\" && typeof value !== \"number\")\n\t) {\n\t\tthrow new InvalidCursorError(cursor);\n\t}\n\treturn { value, id };\n}\n\n/**\n * Keyset condition for the rows after `cursor`, ordered by `sort` then `id`\n * in `direction`. The ORDER BY keeps each dialect's own NULL position, lowest\n * on SQLite and highest on Postgres, so the condition follows it.\n *\n * Throws `InvalidCursorError` if the cursor is malformed; callers should\n * let this propagate so users see a real error rather than silently\n * falling back to the first page.\n */\nfunction sortCursorCondition(\n\tdb: Kysely<Database>,\n\tcursor: string,\n\tcolumn: string,\n\tdirection: SortDirection,\n\tsort: RawBuilder<unknown>,\n\tid: RawBuilder<unknown>,\n): ReturnType<typeof sql> {\n\tconst { value, id: cursorId } = decodeSortCursor(cursor, column);\n\tconst cmp = direction === \"asc\" ? sql.raw(\">\") : sql.raw(\"<\");\n\tconst nullsFirst = (direction === \"asc\") !== isPostgres(db);\n\tif (value === null) {\n\t\treturn nullsFirst\n\t\t\t? sql`(${sort} IS NOT NULL OR ${id} ${cmp} ${cursorId})`\n\t\t\t: sql`(${sort} IS NULL AND ${id} ${cmp} ${cursorId})`;\n\t}\n\tconst past = sql`${sort} ${cmp} ${value} OR (${sort} = ${value} AND ${id} ${cmp} ${cursorId})`;\n\treturn nullsFirst || NON_NULL_SORT_COLUMNS.has(column)\n\t\t? sql`(${past})`\n\t\t: sql`(${past} OR ${sort} IS NULL)`;\n}\n\n/**\n * Build a cursor WHERE condition for keyset pagination.\n * Uses the primary sort field + id as tiebreaker for stable ordering.\n */\nfunction buildCursorCondition(\n\tdb: Kysely<Database>,\n\tcursor: string,\n\torderBy: OrderBySpec | undefined,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\tconst primary = getPrimarySort(orderBy);\n\tconst ref = (column: string) => sql.ref(tablePrefix ? `${tablePrefix}.${column}` : column);\n\treturn sortCursorCondition(\n\t\tdb,\n\t\tcursor,\n\t\tprimary.field,\n\t\tprimary.direction,\n\t\tref(primary.field),\n\t\tref(\"id\"),\n\t);\n}\n\n/** Type guard: is the where value a range object (not a string or array)? */\nfunction isWhereRange(value: WhereValue): value is WhereRange {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * Keys a `where` or `orderBy` can name that belong to the table rather than to\n * a field. `slug` is one of them; {@link SYSTEM_COLUMNS} leaves it out because\n * it is kept in `entry.data` for templates.\n */\nconst SYSTEM_QUERY_KEYS: ReadonlySet<string> = new Set([...SYSTEM_COLUMNS, \"slug\"]);\n\n/**\n * The first of `keys` that names a reference field bound to a relation, or\n * undefined.\n *\n * Such a field has no column: a `WHERE` on it fails with \"no such column\", which\n * the catch below reads as an empty collection, and a field bound after its\n * column existed answers from values it stopped writing. Both read to a template\n * as \"nothing matched\", so the key has to be caught before the query is built.\n *\n * System columns are answered without a lookup, and the lookup itself is cached\n * per request and in the schema object-cache namespace, so a render that filters\n * by an ordinary field pays for this at most once between schema changes, and a\n * render that filters by nothing never pays at all.\n */\nasync function findStoragelessQueryKey(\n\tcollection: string,\n\tkeys: string[],\n): Promise<string | undefined> {\n\tconst candidates = keys.filter((key) => !SYSTEM_QUERY_KEYS.has(key));\n\tif (candidates.length === 0) return undefined;\n\tconst { getReferenceFieldMap } = await import(\"./references/field-map.js\");\n\tconst bound = await getReferenceFieldMap(collection);\n\treturn candidates.find((key) => bound.has(key));\n}\n\n/**\n * A boolean field owns an INTEGER column (`FIELD_TYPE_TO_COLUMN`) and its\n * values are written as 0/1, so binding a native `true` against one is a type\n * error on PostgreSQL. SQLite accepts the boolean and compares it as 1, which\n * is why filtering by a boolean field only ever broke on one dialect.\n */\nfunction bindableFilterValue(value: unknown): unknown {\n\treturn typeof value === \"boolean\" ? (value ? 1 : 0) : value;\n}\n\n/**\n * Build AND conditions for non-taxonomy field filters.\n * Returns an array of sql fragments; empty if no field filters apply.\n * Field names are validated against FIELD_NAME_PATTERN to prevent injection.\n *\n * D1 allows 100 bound parameters per statement, and an array filter binds one\n * per value. So when the arrays in `fields` hold more than `SQL_BATCH_SIZE`\n * values between them, the longest arrays are bound as a single JSON parameter\n * each (`IN (SELECT value FROM json_each(?))`, or `jsonb_array_elements_text`\n * on PostgreSQL) until the rest fit. The statement stays one query, so\n * ordering, cursors, limit and offset stay in the database. Values bound that\n * way compare as text.\n */\nfunction buildFieldConditions(\n\tdb: Kysely<Database>,\n\tfields: Record<string, WhereValue>,\n\ttablePrefix?: string,\n): ReturnType<typeof sql>[] {\n\tconst conditions: ReturnType<typeof sql>[] = [];\n\n\tconst arrayLengths = Object.entries(fields)\n\t\t.filter((entry): entry is [string, string[]] => Array.isArray(entry[1]))\n\t\t.map(([key, value]) => [key, value.length] as const)\n\t\t.toSorted((a, b) => b[1] - a[1]);\n\tlet inlineValues = arrayLengths.reduce((sum, [, length]) => sum + length, 0);\n\tconst asJson = new Set<string>();\n\tfor (const [key, length] of arrayLengths) {\n\t\tif (inlineValues <= SQL_BATCH_SIZE) break;\n\t\tasJson.add(key);\n\t\tinlineValues -= length;\n\t}\n\n\tfor (const [key, value] of Object.entries(fields)) {\n\t\tif (!FIELD_NAME_PATTERN.test(key)) {\n\t\t\tconsole.warn(`[emdash] where filter: invalid field name \"${key}\" ignored`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (value == null) continue;\n\t\tconst ref = tablePrefix ? sql.ref(`${tablePrefix}.${key}`) : sql.ref(key);\n\n\t\tif (isWhereRange(value)) {\n\t\t\tconst { gt, gte, lt, lte } = value;\n\t\t\tif (gt === undefined && gte === undefined && lt === undefined && lte === undefined) {\n\t\t\t\t// An object with no bound (for example `{ in: [...] }`) would add no\n\t\t\t\t// condition, and the query would return unfiltered rows.\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[emdash] where filter: \"${key}\" is an object with none of gt/gte/lt/lte and was ignored (use an array for IN)`,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (gt !== undefined) conditions.push(sql`${ref} > ${bindableFilterValue(gt)}`);\n\t\t\tif (gte !== undefined) conditions.push(sql`${ref} >= ${bindableFilterValue(gte)}`);\n\t\t\tif (lt !== undefined) conditions.push(sql`${ref} < ${bindableFilterValue(lt)}`);\n\t\t\tif (lte !== undefined) conditions.push(sql`${ref} <= ${bindableFilterValue(lte)}`);\n\t\t} else if (Array.isArray(value)) {\n\t\t\tif (value.length === 0) continue;\n\t\t\tif (asJson.has(key)) {\n\t\t\t\tconst values = value.map((v) => String(bindableFilterValue(v)));\n\t\t\t\tconditions.push(sql`${ref} IN (${jsonTextValues(db, values)})`);\n\t\t\t} else {\n\t\t\t\tconditions.push(\n\t\t\t\t\tsql`${ref} IN (${sql.join(value.map((v) => sql`${bindableFilterValue(v)}`))})`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tconditions.push(sql`${ref} = ${bindableFilterValue(value)}`);\n\t\t}\n\t}\n\n\treturn conditions;\n}\n\n/**\n * Pivot rows from which a term counts as large. Seeking the pivot reads every\n * assignment of the term; walking `ec_*` in sort order reads about\n * `collection size / term size` rows per match. The walk wins only for large\n * terms, and the size probe reads at most this many pivot index entries.\n *\n * The walk estimate assumes the term's entries are spread over the sort order\n * and the requested locale. A term clustered in time, a deep page or a narrow\n * byline filter makes the walk read up to the whole collection; the seek would\n * still read every assignment of the term.\n */\nexport const LARGE_TERM_ASSIGNMENTS = 200;\n\n/** A single `published_at`/`created_at` sort, which an `ec_*` index serves in order. */\nfunction isIndexedPivotSort(orderBy: OrderBySpec | undefined): boolean {\n\tconst validSortKeys = orderBy\n\t\t? Object.keys(orderBy).filter((k) => FIELD_NAME_PATTERN.test(k))\n\t\t: [];\n\tconst primary = getPrimarySort(orderBy);\n\treturn (\n\t\tvalidSortKeys.length <= 1 &&\n\t\t(primary.field === \"published_at\" || primary.field === \"created_at\")\n\t);\n}\n\n/**\n * Resolve a taxonomy filter (`name` + one or more `slug`s, optionally scoped to\n * `locale`) to the set of `translation_group`s the pivot stores in\n * `content_taxonomies.taxonomy_id`. Exact terms only — no subtree expansion.\n *\n * Mirrors the meaning of the old EXISTS join (`t.name = ? AND t.slug IN (?)\n * [AND t.locale = ?]`): a pivot row matches when its group has a term with that\n * name/slug in the active locale. Resolving to explicit values (rather than an\n * `IN (subquery)`) keeps the single-term case a plain equality on the pivot\n * index, which is what gives the clean early-`LIMIT` seek.\n *\n * With `probeCollection`, `large` reports whether a resolved term has at least\n * {@link LARGE_TERM_ASSIGNMENTS} pivot rows in that collection. The capped\n * probe rides in this query; a query of its own would add a round trip to\n * every listing.\n */\nasync function resolveTermGroups(\n\tdb: Kysely<Database>,\n\tname: string,\n\tslugs: string[],\n\tlocale: string | undefined,\n\tprobeCollection?: string,\n): Promise<{ groups: string[]; large: boolean }> {\n\tlet query = db\n\t\t.selectFrom(\"taxonomies\")\n\t\t.select(\"translation_group\")\n\t\t.distinct()\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"slug\", \"in\", slugs)\n\t\t.$if(probeCollection !== undefined, (qb) =>\n\t\t\tqb.select((eb) =>\n\t\t\t\teb\n\t\t\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t\t\t.select(sql<number>`1`.as(\"hit\"))\n\t\t\t\t\t.where(\"content_taxonomies.collection\", \"=\", probeCollection!)\n\t\t\t\t\t.whereRef(\"content_taxonomies.taxonomy_id\", \"=\", \"taxonomies.translation_group\")\n\t\t\t\t\t.limit(1)\n\t\t\t\t\t.offset(LARGE_TERM_ASSIGNMENTS - 1)\n\t\t\t\t\t.as(\"large\"),\n\t\t\t),\n\t\t);\n\tif (locale) query = query.where(\"locale\", \"=\", locale);\n\tconst rows = await query.execute();\n\tconst groups = new Set<string>();\n\tlet large = false;\n\tfor (const row of rows) {\n\t\tif (row.translation_group) groups.add(row.translation_group);\n\t\tif (row.large != null) large = true;\n\t}\n\treturn { groups: [...groups], large };\n}\n\n/** Equality (single) or `IN` (multiple) condition on a pivot group column. */\nfunction pivotGroupCondition(ref: string, groups: string[]): ReturnType<typeof sql> {\n\tif (groups.length === 1) return sql`${sql.ref(ref)} = ${groups[0]}`;\n\treturn sql`${sql.ref(ref)} IN (${sql.join(groups.map((g) => sql`${g}`))})`;\n}\n\n/** LIMIT/OFFSET fragment matching the loader's single-table variant. */\nfunction buildPivotLimitOffset(\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any Kysely instance\n\tdb: Kysely<any>,\n\tfetchLimit: number | undefined,\n\toffset: number | undefined,\n): ReturnType<typeof sql> {\n\tif (fetchLimit != null && offset != null) return sql`LIMIT ${fetchLimit} OFFSET ${offset}`;\n\tif (fetchLimit != null) return sql`LIMIT ${fetchLimit}`;\n\tif (offset != null) {\n\t\treturn isPostgres(db) ? sql`OFFSET ${offset}` : sql`LIMIT -1 OFFSET ${offset}`;\n\t}\n\treturn sql``;\n}\n\n/**\n * Options for {@link buildTaxonomyPivotQuery}.\n *\n * Parameterized on the `deletedIsNull` predicate and `status` condition so the\n * same builder serves the public live path (`deleted_at IS NULL` + published)\n * and, without any schema change, an admin trash (`deleted_at IS NOT\n * NULL`) or all-statuses shape. Admin wiring is out of scope today; the\n * parameters exist so `ContentRepository` can adopt this if it gains taxonomy\n * filtering.\n */\nexport interface TaxonomyPivotQueryOptions {\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any Kysely instance\n\tdb: Kysely<any>;\n\t/** Collection slug (pivot `collection` value). */\n\tcollection: string;\n\t/** Content table name (`ec_<collection>`). */\n\ttableName: string;\n\t/**\n\t * Resolved translation_group sets, one per taxonomy filter. The first drives\n\t * the pivot seek; each additional set becomes a residual `EXISTS` (AND across\n\t * taxonomies). Multiple groups within a set are OR'd (dedup via GROUP BY).\n\t */\n\tgroupSets: string[][];\n\torderBy: OrderBySpec | undefined;\n\tcursor: string | undefined;\n\tlocale: string | undefined;\n\t/**\n\t * Status shape. A concrete value (`published`/`draft`/…) applies the same\n\t * condition `buildStatusCondition` produces (public: published only).\n\t * `undefined` drops the status filter entirely — the admin all-statuses shape.\n\t */\n\tstatus: string | undefined;\n\t/** `true` → `deleted_at IS NULL` (live); `false` → `IS NOT NULL` (trash). */\n\tdeletedIsNull: boolean;\n\t/** Byline translation_groups for an AND'd byline filter, or `null`. */\n\tbylineGroups: string[] | null;\n\tfetchLimit: number | undefined;\n\toffset: number | undefined;\n\t/**\n\t * SQLite only: walk `ec_*` in sort order and probe the pivot per row until\n\t * `LIMIT` rows match, instead of seeking the term and sorting its candidates.\n\t * Set it only for a single large term (see {@link LARGE_TERM_ASSIGNMENTS})\n\t * under an indexed sort with a `LIMIT`; any other shape makes the walk read\n\t * most of the collection.\n\t */\n\tdriveFromContent?: boolean;\n}\n\n/**\n * Build the pivot-driven taxonomy listing query (#1834).\n *\n * Joins the term pivot to content translations through their shared\n * translation_group. Content columns remain authoritative for locale,\n * visibility, sorting, and cursor predicates.\n *\n * Two shapes:\n * - **Indexed sort** (`published_at`/`created_at`, single sort field): the\n * `LIMIT` lives in `picked`, which either sorts the term's candidates or,\n * with `driveFromContent`, walks the `ec_*` sort index and stops at `LIMIT`.\n * - **Temp-sort** (`updated_at` or any other field, or multi-field sort): no\n * pivot sort index applies, so `picked` collects the tagged candidate set and\n * the outer query sorts the joined rows. Bounded to tagged rows — no\n * `ec_*` full scan — but no early-`LIMIT`.\n */\nexport function buildTaxonomyPivotQuery(\n\topts: TaxonomyPivotQueryOptions,\n): ReturnType<typeof sql<Record<string, unknown>>> {\n\tconst {\n\t\tdb,\n\t\tcollection,\n\t\ttableName,\n\t\tgroupSets,\n\t\torderBy,\n\t\tcursor,\n\t\tlocale,\n\t\tstatus,\n\t\tdeletedIsNull,\n\t\tbylineGroups,\n\t\tfetchLimit,\n\t\toffset,\n\t\tdriveFromContent = false,\n\t} = opts;\n\n\tconst primary = getPrimarySort(orderBy);\n\tconst isIndexedSort = isIndexedPivotSort(orderBy);\n\tconst dir = primary.direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\n\tconst firstGroups = groupSets[0] ?? [];\n\tconst restGroups = groupSets.slice(1);\n\tconst multiGroup = firstGroups.length > 1;\n\n\t// Multi-term AND: one residual pivot-PK EXISTS per additional taxonomy.\n\tconst residual =\n\t\trestGroups.length > 0\n\t\t\t? sql`${sql.join(\n\t\t\t\t\trestGroups.map(\n\t\t\t\t\t\t(g) => sql`AND EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM content_taxonomies ct2\n\t\t\t\t\t\tWHERE ct2.collection = ${collection}\n\t\t\t\t\t\t\tAND ct2.entry_id = ct.entry_id\n\t\t\t\t\t\t\tAND ${pivotGroupCondition(\"ct2.taxonomy_id\", g)}\n\t\t\t\t\t)`,\n\t\t\t\t\t),\n\t\t\t\t\tsql` `,\n\t\t\t\t)}`\n\t\t\t: sql``;\n\n\t// Byline assignments remain keyed to a locale-specific content row.\n\tconst bylineCt = bylineGroups\n\t\t? sql`AND EXISTS (\n\t\t\t\tSELECT 1 FROM _emdash_content_bylines cb\n\t\t\t\tWHERE cb.collection_slug = ${collection}\n\t\t\t\t\tAND cb.content_id = r.id\n\t\t\t\t\tAND cb.byline_id IN (${sql.join(bylineGroups.map((g) => sql`${g}`))})\n\t\t\t)`\n\t\t: sql``;\n\n\tconst firstGroupCond = pivotGroupCondition(\"ct.taxonomy_id\", firstGroups);\n\t// `CROSS JOIN` keeps the pivot as the outer table. A plain `JOIN` lets the\n\t// planner walk the `(deleted_at, <sort> DESC, id DESC)` index on `ec_*`\n\t// whatever the term's size, which reads most of the collection for a\n\t// small term. Postgres rejects `CROSS JOIN … ON`, so it always gets the\n\t// plain `JOIN`.\n\t//\n\t// The temp-sort branch keeps the pin. Its `picked` collects every tagged\n\t// entry with no `LIMIT`, so starting from `ec_*` can never stop early, and\n\t// D1 does start there when `ANALYZE` has underestimated\n\t// `deleted_at IS NULL` (a trash with many distinct deletion times): it\n\t// walks the collection's `(deleted_at, status)` index and probes the pivot\n\t// once per published row.\n\tconst pivotContentJoin = isPostgres(db) || driveFromContent ? sql`JOIN` : sql`CROSS JOIN`;\n\tconst {\n\t\tterms: termsSelect,\n\t\tbylines: bylinesSelect,\n\t\tbylinesExist: bylinesExistSelect,\n\t} = foldedHydrationSelects(db, collection, \"r\");\n\tconst booleanFieldsSelect = foldedBooleanFieldsSelect(db, collection);\n\n\t// Authoritative re-check on the joined `ec_*` row.\n\tconst deletedR = deletedIsNull ? sql`r.deleted_at IS NULL` : sql`r.deleted_at IS NOT NULL`;\n\tconst statusR = status !== undefined ? sql`AND ${buildStatusCondition(db, status, \"r\")}` : sql``;\n\tconst localeR = locale ? sql`AND r.locale = ${locale}` : sql``;\n\n\tif (isIndexedSort) {\n\t\tconst sortRef = sql.ref(`r.${primary.field}`);\n\t\tconst sortval = multiGroup ? sql`MAX(${sortRef})` : sortRef;\n\t\tconst groupByClause = multiGroup ? sql`GROUP BY r.id` : sql``;\n\n\t\tlet cursorClause = sql``;\n\t\tlet havingClause = sql``;\n\t\tif (cursor) {\n\t\t\tconst cond = sortCursorCondition(\n\t\t\t\tdb,\n\t\t\t\tcursor,\n\t\t\t\tprimary.field,\n\t\t\t\tprimary.direction,\n\t\t\t\tsortval,\n\t\t\t\tsql.ref(\"r.id\"),\n\t\t\t);\n\t\t\t// A GROUP BY makes `sortval` an aggregate → cursor goes in HAVING.\n\t\t\tif (multiGroup) havingClause = sql`HAVING ${cond}`;\n\t\t\telse cursorClause = sql`AND ${cond}`;\n\t\t}\n\n\t\tconst limitClause = buildPivotLimitOffset(db, fetchLimit, offset);\n\n\t\treturn sql<Record<string, unknown>>`\n\t\t\tWITH picked AS (\n\t\t\t\tSELECT r.id AS entry_id, ${sortval} AS sortval\n\t\t\t\tFROM content_taxonomies ct\n\t\t\t\t${pivotContentJoin} ${sql.ref(tableName)} AS r ON r.translation_group = ct.entry_id\n\t\t\t\tWHERE ct.collection = ${collection}\n\t\t\t\t\tAND ${firstGroupCond}\n\t\t\t\t\tAND ${deletedR}\n\t\t\t\t\t${statusR}\n\t\t\t\t\t${localeR}\n\t\t\t\t\t${residual}\n\t\t\t\t\t${bylineCt}\n\t\t\t\t\t${cursorClause}\n\t\t\t\t${groupByClause}\n\t\t\t\t${havingClause}\n\t\t\t\tORDER BY sortval ${dir}, r.id ${dir}\n\t\t\t\t${limitClause}\n\t\t\t)\n\t\t\tSELECT r.*, ${termsSelect}, ${bylinesSelect}, ${bylinesExistSelect}, ${booleanFieldsSelect}\n\t\t\tFROM picked JOIN ${sql.ref(tableName)} AS r ON r.id = picked.entry_id\n\t\t\tWHERE ${deletedR} ${statusR} ${localeR}\n\t\t\tORDER BY picked.sortval ${dir}, picked.entry_id ${dir}\n\t\t`;\n\t}\n\n\t// Temp-sort path: seek the term via the pivot, sort the joined candidate set.\n\tconst orderByClause = buildOrderByClause(orderBy, \"r\");\n\tconst cursorCond = cursor ? sql`AND ${buildCursorCondition(db, cursor, orderBy, \"r\")}` : sql``;\n\tconst limitClause = buildPivotLimitOffset(db, fetchLimit, offset);\n\treturn sql<Record<string, unknown>>`\n\t\tWITH picked AS (\n\t\t\tSELECT DISTINCT r.id AS entry_id\n\t\t\tFROM content_taxonomies ct\n\t\t\t${pivotContentJoin} ${sql.ref(tableName)} AS r ON r.translation_group = ct.entry_id\n\t\t\tWHERE ct.collection = ${collection}\n\t\t\t\tAND ${firstGroupCond}\n\t\t\t\tAND ${deletedR}\n\t\t\t\t${statusR}\n\t\t\t\t${localeR}\n\t\t\t\t${residual}\n\t\t\t\t${bylineCt}\n\t\t)\n\t\tSELECT r.*, ${termsSelect}, ${bylinesSelect}, ${bylinesExistSelect}, ${booleanFieldsSelect}\n\t\tFROM picked JOIN ${sql.ref(tableName)} AS r ON r.id = picked.entry_id\n\t\tWHERE ${deletedR} ${statusR} ${localeR}\n\t\t\t${cursorCond}\n\t\t${orderByClause}\n\t\t${limitClause}\n\t`;\n}\n\n/**\n * Range filter for comparison operators on field values.\n * Values are compared as strings in the database. This works correctly for\n * ISO 8601 dates (e.g. \"2024-01-01T00:00:00Z\") because lexicographic ordering\n * matches chronological ordering. Ensure date values use a consistent format.\n */\nexport interface WhereRange {\n\tgt?: string;\n\tgte?: string;\n\tlt?: string;\n\tlte?: string;\n}\n\n/**\n * A where clause value: exact match, multi-value match, or range comparison.\n */\nexport type WhereValue = string | string[] | WhereRange;\n\n/**\n * Fields shared by every collection filter, independent of pagination mode.\n *\n * Cursor and offset pagination are mutually exclusive, so they live on the\n * `CursorCollectionFilter` / `OffsetCollectionFilter` variants rather than\n * here. Use the {@link CollectionFilter} union for any value that may be\n * either.\n */\nexport interface CollectionFilterBase {\n\ttype: string;\n\tstatus?: \"draft\" | \"published\" | \"archived\";\n\tlimit?: number;\n\t/**\n\t * Filter by field values, taxonomy terms, byline credits, or ranges.\n\t *\n\t * Taxonomy names are detected automatically and filtered via JOIN.\n\t * The reserved `byline` key filters by byline credit (any credit, not\n\t * just the primary one) via the `_emdash_content_bylines` junction\n\t * table; its value is one or more byline translation groups.\n\t * Other keys are treated as column filters on the content table.\n\t *\n\t * @example { category: 'news' } - taxonomy term\n\t * @example { byline: '01HXYZ...' } - entries credited to a byline (any position)\n\t * @example { series: 'main' } - exact match on a content field\n\t * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - date range\n\t */\n\twhere?: Record<string, WhereValue>;\n\t/**\n\t * Order results by field(s)\n\t * @default { created_at: \"desc\" }\n\t */\n\torderBy?: OrderBySpec;\n\t/**\n\t * Filter by locale (e.g. 'en', 'fr').\n\t * When set, only returns content in this locale.\n\t */\n\tlocale?: string;\n}\n\n/** Keyset-paginated collection filter. Cannot also carry an `offset`. */\nexport interface CursorCollectionFilter extends CollectionFilterBase {\n\t/**\n\t * Opaque cursor for keyset pagination.\n\t * Pass the `nextCursor` value from a previous result to fetch the next page.\n\t */\n\tcursor?: string;\n\toffset?: never;\n}\n\n/** Offset-paginated collection filter. Cannot also carry a `cursor`. */\nexport interface OffsetCollectionFilter extends CollectionFilterBase {\n\t/**\n\t * Skip this many rows before returning results (offset pagination).\n\t * Use with `limit` for numbered archive routes (`/page/2`):\n\t * `offset = (page - 1) * perPage`. Ignored unless it is a positive\n\t * integer.\n\t */\n\toffset?: number;\n\tcursor?: never;\n}\n\n/**\n * Filter for loadCollection - type is required.\n *\n * A union of the cursor and offset pagination variants: supplying both\n * `cursor` and `offset` is a compile-time error, since they are mutually\n * exclusive ways to express \"the next page\" (cursor wins at runtime).\n */\nexport type CollectionFilter = CursorCollectionFilter | OffsetCollectionFilter;\n\n/**\n * Which entries a collection read serves from their draft revision: `\"all\"`\n * (edit mode) or one entry's ID or slug (a preview token, scoped to that\n * entry). Set by `getEmDashCollection` from the request context; not part of\n * the public filter.\n */\ntype DraftRevisionScope = \"all\" | { id: string };\n\ntype LoaderCollectionFilter = CollectionFilter & { draftRevisions?: DraftRevisionScope };\n\n/**\n * Filter for loadEntry - type and id are required\n */\nexport interface EntryFilter {\n\ttype: string;\n\tid: string;\n\t/**\n\t * When set, fetch content data from this revision instead of the content table.\n\t * Used by preview mode to serve draft revision data.\n\t */\n\trevisionId?: string;\n\t/**\n\t * Locale to scope slug lookup. Only affects slug resolution;\n\t * IDs are globally unique and always resolve regardless of locale.\n\t */\n\tlocale?: string;\n}\n\n// Cached database instance (shared across calls)\nlet dbInstance: Kysely<Database> | null = null;\n\n/**\n * Get the database instance. Used by query wrapper functions and middleware.\n *\n * Checks the ALS request context first — if a per-request DB override is set\n * (e.g. by DO preview middleware), it takes precedence over the module-level\n * cached instance. This allows preview mode to route queries to an isolated\n * Durable Object database without modifying any calling code.\n *\n * Initializes the default database on first call using config from virtual module.\n */\nexport async function getDb(): Promise<Kysely<Database>> {\n\t// Entry IDs depend on the i18n config, so it must be loaded on the\n\t// request-scoped path too, not only when the default database is opened.\n\tawait loadVirtualConfig();\n\t// Per-request DB override via ALS (normal mode)\n\tconst ctx = getRequestContext();\n\tif (ctx?.db) {\n\t\treturn ctx.db as Kysely<Database>; // eslint-disable-line typescript/no-unsafe-type-assertion -- db is typed as unknown in RequestContext to avoid circular deps\n\t}\n\n\tif (!dbInstance) {\n\t\tawait loadVirtualModules();\n\t\tif (!virtualConfig?.database || typeof virtualCreateDialect !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"EmDash database not configured. Add database config to emdash() in astro.config.mjs\",\n\t\t\t);\n\t\t}\n\t\tconst dialect = virtualCreateDialect(virtualConfig.database.config);\n\t\tdbInstance = new Kysely<Database>({ dialect, log: kyselyLogOption() });\n\t}\n\treturn dbInstance;\n}\n\n/** @internal Date projection for published archive entries. */\nexport async function loadPublishedDates(type: string, locale?: string) {\n\tconst tableName = getTableName(type);\n\tconst db = await getDb();\n\tconst result = await sql<{ published_at: string | null; updated_at: string | null }>`\n\t\tSELECT published_at, updated_at FROM ${sql.ref(tableName)}\n\t\tWHERE deleted_at IS NULL\n\t\tAND ${buildStatusCondition(db, \"published\")}\n\t\t${locale ? sql`AND locale = ${locale}` : sql``}\n\t\tORDER BY published_at DESC, id DESC\n\t`.execute(db);\n\treturn result.rows;\n}\n\n/**\n * Create an EmDash Live Collections loader\n *\n * This loader handles ALL content types in a single Astro collection.\n * Use `getEmDashCollection()` and `getEmDashEntry()` to query\n * specific content types.\n *\n * Database is configured in astro.config.mjs via the emdash() integration.\n *\n * @example\n * ```ts\n * // src/live.config.ts\n * import { defineLiveCollection } from \"astro:content\";\n * import { emdashLoader } from \"emdash\";\n *\n * export const collections = {\n * emdash: defineLiveCollection({\n * loader: emdashLoader(),\n * }),\n * };\n * ```\n */\nexport function emdashLoader(): LiveLoader<EntryData, EntryFilter, LoaderCollectionFilter> {\n\treturn {\n\t\tname: \"emdash\",\n\n\t\t/**\n\t\t * Load all entries for a content type\n\t\t */\n\t\tasync loadCollection({ filter }) {\n\t\t\ttry {\n\t\t\t\t// Get DB instance (initializes on first use)\n\t\t\t\tconst db = await getDb();\n\n\t\t\t\t// Type filter is required\n\t\t\t\tconst type = filter?.type;\n\t\t\t\tif (!type) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\"type filter is required. Use getEmDashCollection() instead of getLiveCollection() directly.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Query the per-collection table (ec_posts, ec_products, etc.)\n\t\t\t\tconst tableName = getTableName(type);\n\n\t\t\t\t// Build query with dynamic table name\n\t\t\t\tconst status = filter?.status || \"published\";\n\t\t\t\tconst limit = filter?.limit;\n\t\t\t\tconst cursor = filter?.cursor;\n\t\t\t\tconst where = filter?.where;\n\t\t\t\tconst orderBy = filter?.orderBy;\n\t\t\t\tconst locale = filter?.locale;\n\n\t\t\t\t// Cursor pagination: over-fetch by 1 to detect next page\n\t\t\t\tconst fetchLimit = limit ? limit + 1 : undefined;\n\n\t\t\t\t// Offset pagination (numbered archive routes). Keyset (cursor)\n\t\t\t\t// and offset are mutually exclusive ways to express \"the next\n\t\t\t\t// page\" — when both are supplied, cursor wins and offset is\n\t\t\t\t// dropped so the two don't stack into a double skip. Only a\n\t\t\t\t// positive integer applies; 0 / negative / fractional are no-ops.\n\t\t\t\tconst rawOffset = cursor ? undefined : filter?.offset;\n\t\t\t\tconst offset =\n\t\t\t\t\ttypeof rawOffset === \"number\" && Number.isInteger(rawOffset) && rawOffset > 0\n\t\t\t\t\t\t? rawOffset\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\t// Build cursor condition if cursor is provided\n\t\t\t\tconst cursorCondition = cursor ? buildCursorCondition(db, cursor, orderBy) : null;\n\n\t\t\t\t// Separate taxonomy / byline filters from field filters\n\t\t\t\tlet result: { rows: Record<string, unknown>[] };\n\t\t\t\t// Taxonomy filters AND together: each entry constrains the base\n\t\t\t\t// row to match at least one of its slugs *within that taxonomy*.\n\t\t\t\t// Term slugs are unique only within a taxonomy, so every filter\n\t\t\t\t// keeps its own `name` and emits its own `EXISTS` clause rather\n\t\t\t\t// than pooling slugs into one `IN`.\n\t\t\t\tconst taxonomyFilters: { name: string; slugs: string[] }[] = [];\n\t\t\t\t// A byline filter matches entries credited to any of the given\n\t\t\t\t// byline translation groups via the `_emdash_content_bylines`\n\t\t\t\t// junction table. `null` means no byline filter; an empty\n\t\t\t\t// `groups` array means the filter was requested but matches\n\t\t\t\t// nothing (short-circuited to an empty result below).\n\t\t\t\tlet bylineFilter: { groups: string[] } | null = null;\n\t\t\t\tconst fieldFilters: Record<string, WhereValue> = {};\n\n\t\t\t\tif (where && Object.keys(where).length > 0) {\n\t\t\t\t\tconst taxNames = await getTaxonomyNames(db, type);\n\n\t\t\t\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\t\t\t\tif (value == null) continue;\n\t\t\t\t\t\tif (key === \"byline\") {\n\t\t\t\t\t\t\tif (isWhereRange(value)) {\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`[emdash] where filter: range operators are not supported on \"byline\", ignored`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst groups = Array.isArray(value) ? value : [value];\n\t\t\t\t\t\t\tbylineFilter = { groups };\n\t\t\t\t\t\t} else if (taxNames.has(key)) {\n\t\t\t\t\t\t\tif (isWhereRange(value)) {\n\t\t\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\t\t`[emdash] where filter: range operators are not supported on taxonomy \"${key}\", ignored`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst slugs = Array.isArray(value) ? value : [value];\n\t\t\t\t\t\t\ttaxonomyFilters.push({ name: key, slugs });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfieldFilters[key] = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst storagelessKey = await findStoragelessQueryKey(type, [\n\t\t\t\t\t...Object.keys(fieldFilters),\n\t\t\t\t\t...Object.keys(orderBy ?? {}),\n\t\t\t\t]);\n\t\t\t\tif (storagelessKey) {\n\t\t\t\t\tconst message = `Cannot filter or sort \"${type}\" by \"${storagelessKey}\": it is a reference field bound to a relation, and its links are not stored on the entry. Read them with getEmDashEntry(..., { references }) or getEmDashReferences().`;\n\t\t\t\t\t// Warned as well as returned, the way the missing-column catch\n\t\t\t\t\t// below warns: a template that renders `entries` without reading\n\t\t\t\t\t// `error` would otherwise see the same empty list this replaced.\n\t\t\t\t\tconsole.warn(`[emdash] where filter: ${message}`);\n\t\t\t\t\treturn { error: new Error(message) };\n\t\t\t\t}\n\n\t\t\t\t// A byline or taxonomy filter with no values matches nothing —\n\t\t\t\t// short-circuit before building SQL (an empty `IN ()` is invalid\n\t\t\t\t// SQL on both dialects).\n\t\t\t\tif (\n\t\t\t\t\t(bylineFilter && bylineFilter.groups.length === 0) ||\n\t\t\t\t\ttaxonomyFilters.some((f) => f.slugs.length === 0)\n\t\t\t\t) {\n\t\t\t\t\treturn { entries: [], cacheHint: { tags: [type] } };\n\t\t\t\t}\n\n\t\t\t\tif (taxonomyFilters.length > 0 && Object.keys(fieldFilters).length === 0) {\n\t\t\t\t\t// Pivot-drive fast path (#1834): seek the matching entries on the\n\t\t\t\t\t// denormalized `content_taxonomies` pivot instead of scanning the\n\t\t\t\t\t// whole collection and probing a taxonomy EXISTS per row. Only the\n\t\t\t\t\t// taxonomy path is restructured — a taxonomy filter combined with a\n\t\t\t\t\t// content-field filter falls through to the single-table shape\n\t\t\t\t\t// below (field predicates live on `ec_*`, not the pivot). A byline\n\t\t\t\t\t// filter rides along inside the pivot CTE (see the builder).\n\t\t\t\t\tconst groupSets: string[][] = [];\n\n\t\t\t\t\t// Walking `ec_*` fills a page quickly only for one large term group\n\t\t\t\t\t// under an indexed sort with a `LIMIT`. With a second taxonomy or\n\t\t\t\t\t// several groups it reads far more rows than the pivot seek, so\n\t\t\t\t\t// only a single slug of a single taxonomy pays for the size probe.\n\t\t\t\t\tconst probeCollection =\n\t\t\t\t\t\t!isPostgres(db) &&\n\t\t\t\t\t\ttaxonomyFilters.length === 1 &&\n\t\t\t\t\t\ttaxonomyFilters[0]?.slugs.length === 1 &&\n\t\t\t\t\t\tfetchLimit != null &&\n\t\t\t\t\t\tisIndexedPivotSort(orderBy)\n\t\t\t\t\t\t\t? type\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\tlet driveFromContent = false;\n\t\t\t\t\tfor (const taxFilter of taxonomyFilters) {\n\t\t\t\t\t\tconst { groups, large } = await resolveTermGroups(\n\t\t\t\t\t\t\tdb,\n\t\t\t\t\t\t\ttaxFilter.name,\n\t\t\t\t\t\t\ttaxFilter.slugs,\n\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\tprobeCollection,\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// A slug that resolves to no term matches nothing; since taxonomy\n\t\t\t\t\t\t// filters AND together, one empty set empties the whole result.\n\t\t\t\t\t\tif (groups.length === 0) {\n\t\t\t\t\t\t\treturn { entries: [], cacheHint: { tags: [type] } };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgroupSets.push(groups);\n\t\t\t\t\t\tdriveFromContent = large && groups.length === 1;\n\t\t\t\t\t}\n\n\t\t\t\t\tresult = await buildTaxonomyPivotQuery({\n\t\t\t\t\t\tdb,\n\t\t\t\t\t\tcollection: type,\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\tgroupSets,\n\t\t\t\t\t\torderBy,\n\t\t\t\t\t\tcursor,\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t// Public listings only ever want live content.\n\t\t\t\t\t\tdeletedIsNull: true,\n\t\t\t\t\t\tbylineGroups: bylineFilter ? bylineFilter.groups : null,\n\t\t\t\t\t\tfetchLimit,\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tdriveFromContent,\n\t\t\t\t\t}).execute(db);\n\t\t\t\t} else {\n\t\t\t\t\t// Taxonomy and byline filters are applied as correlated\n\t\t\t\t\t// `EXISTS` semi-joins rather than `INNER JOIN ... DISTINCT`.\n\t\t\t\t\t// A join fan-out would force `SELECT DISTINCT table.*`, and\n\t\t\t\t\t// Postgres cannot apply DISTINCT to a row containing a `json`\n\t\t\t\t\t// column (no equality operator), so the join approach throws\n\t\t\t\t\t// there. EXISTS matches \"credited/tagged at least once\"\n\t\t\t\t\t// without duplicating rows, needs no DISTINCT, and works on\n\t\t\t\t\t// both SQLite and Postgres. The base query stays a single-\n\t\t\t\t\t// table `SELECT *`, so all field/status/locale/cursor/order\n\t\t\t\t\t// conditions reference unprefixed columns as before.\n\t\t\t\t\tconst orderByClause = buildOrderByClause(orderBy);\n\t\t\t\t\tconst statusCondition = buildStatusCondition(db, status);\n\t\t\t\t\tconst localeFilter = locale ? sql`AND locale = ${locale}` : sql``;\n\t\t\t\t\tconst cursorCond = cursorCondition ? sql`AND ${cursorCondition}` : sql``;\n\t\t\t\t\tconst fieldConds = buildFieldConditions(db, fieldFilters);\n\t\t\t\t\tconst fieldCondsSQL =\n\t\t\t\t\t\tfieldConds.length > 0 ? sql`${sql.join(fieldConds, sql` AND `)}` : null;\n\n\t\t\t\t\t// One `EXISTS` per taxonomy, AND'd together: an entry must be\n\t\t\t\t\t// tagged with a matching term in *every* requested taxonomy.\n\t\t\t\t\t// Each clause pins its own `t.name`, so slugs never pool\n\t\t\t\t\t// across taxonomies (they're only unique within one).\n\t\t\t\t\tconst taxonomyCond =\n\t\t\t\t\t\ttaxonomyFilters.length > 0\n\t\t\t\t\t\t\t? sql`${sql.join(\n\t\t\t\t\t\t\t\t\ttaxonomyFilters.map(\n\t\t\t\t\t\t\t\t\t\t(f) => sql`AND EXISTS (\n\t\t\t\t\t\t\tSELECT 1 FROM content_taxonomies ct\n\t\t\t\t\t\t\tINNER JOIN taxonomies t ON t.translation_group = ct.taxonomy_id\n\t\t\t\t\t\t\tWHERE ct.collection = ${type}\n\t\t\t\t\t\t\t\tAND ct.entry_id = ${sql.ref(tableName)}.translation_group\n\t\t\t\t\t\t\t\tAND t.name = ${f.name}\n\t\t\t\t\t\t\t\tAND t.slug IN (${sql.join(f.slugs.map((s) => sql`${s}`))})\n\t\t\t\t\t\t\t${locale ? sql`AND t.locale = ${locale}` : sql``}\n\t\t\t\t\t\t)`,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tsql` `,\n\t\t\t\t\t\t\t\t)}`\n\t\t\t\t\t\t\t: sql``;\n\n\t\t\t\t\t// `_emdash_content_bylines.byline_id` stores the byline's\n\t\t\t\t\t// translation_group (migration 040), so a credit spans every\n\t\t\t\t\t// locale variant of the byline and we match the group directly.\n\t\t\t\t\tconst bylineCond = bylineFilter\n\t\t\t\t\t\t? sql`AND EXISTS (\n\t\t\t\t\t\t\tSELECT 1 FROM _emdash_content_bylines cb\n\t\t\t\t\t\t\tWHERE cb.collection_slug = ${type}\n\t\t\t\t\t\t\t\tAND cb.content_id = ${sql.ref(tableName)}.id\n\t\t\t\t\t\t\t\tAND cb.byline_id IN (${sql.join(bylineFilter.groups.map((g) => sql`${g}`))})\n\t\t\t\t\t\t)`\n\t\t\t\t\t\t: sql``;\n\n\t\t\t\t\t// Fold byline + taxonomy hydration into the list query.\n\t\t\t\t\tconst {\n\t\t\t\t\t\tterms: termsSelect,\n\t\t\t\t\t\tbylines: bylinesSelect,\n\t\t\t\t\t\tbylinesExist: bylinesExistSelect,\n\t\t\t\t\t} = foldedHydrationSelects(db, type, tableName);\n\t\t\t\t\tconst booleanFieldsSelect = foldedBooleanFieldsSelect(db, type);\n\n\t\t\t\t\t// LIMIT/OFFSET clause. SQLite only accepts OFFSET when a\n\t\t\t\t\t// LIMIT is present, so a bare offset uses `LIMIT -1`\n\t\t\t\t\t// (unbounded); Postgres takes a standalone OFFSET.\n\t\t\t\t\tlet limitOffsetClause = sql``;\n\t\t\t\t\tif (fetchLimit != null && offset != null) {\n\t\t\t\t\t\tlimitOffsetClause = sql`LIMIT ${fetchLimit} OFFSET ${offset}`;\n\t\t\t\t\t} else if (fetchLimit != null) {\n\t\t\t\t\t\tlimitOffsetClause = sql`LIMIT ${fetchLimit}`;\n\t\t\t\t\t} else if (offset != null) {\n\t\t\t\t\t\tlimitOffsetClause = isPostgres(db)\n\t\t\t\t\t\t\t? sql`OFFSET ${offset}`\n\t\t\t\t\t\t\t: sql`LIMIT -1 OFFSET ${offset}`;\n\t\t\t\t\t}\n\t\t\t\t\tresult = await sql<Record<string, unknown>>`\n\t\t\t\t\t\tSELECT *, ${termsSelect}, ${bylinesSelect}, ${bylinesExistSelect}, ${booleanFieldsSelect} FROM ${sql.ref(tableName)}\n\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\tAND ${statusCondition}\n\t\t\t\t\t\t${localeFilter}\n\t\t\t\t\t\t${cursorCond}\n\t\t\t\t\t\t${taxonomyCond}\n\t\t\t\t\t\t${bylineCond}\n\t\t\t\t\t\t${fieldCondsSQL ? sql`AND ${fieldCondsSQL}` : sql``}\n\t\t\t\t\t\t${orderByClause}\n\t\t\t\t\t\t${limitOffsetClause}\n\t\t\t\t\t`.execute(db);\n\t\t\t\t}\n\n\t\t\t\t// Detect whether there are more results (over-fetched by 1)\n\t\t\t\tconst hasMore = limit ? result.rows.length > limit : false;\n\t\t\t\tconst rows = hasMore ? result.rows.slice(0, limit) : result.rows;\n\n\t\t\t\tconst primary = getPrimarySort(orderBy);\n\t\t\t\t// Strip table prefix from field name for row lookup\n\t\t\t\tconst sortColumn = primary.field.includes(\".\")\n\t\t\t\t\t? primary.field.split(\".\").pop()!\n\t\t\t\t\t: primary.field;\n\n\t\t\t\t// Map rows to entries\n\t\t\t\tconst booleanFields = parseFoldedBooleanFields(rows[0]);\n\t\t\t\tconst drafts = await loadDraftRevisions(db, rows, filter?.draftRevisions);\n\t\t\t\tconst entries = rows.map((row) => {\n\t\t\t\t\tconst draft = drafts.get(rowStr(row, \"id\"));\n\t\t\t\t\tif (draft) {\n\t\t\t\t\t\tconst revEntry = revisionEntry(row, draft, booleanFields, sortColumn);\n\t\t\t\t\t\tstashFolded(revEntry.data, row);\n\t\t\t\t\t\treturn revEntry;\n\t\t\t\t\t}\n\t\t\t\t\tconst id = entryIdForRow(row);\n\t\t\t\t\tconst data = mapRowToData(row, booleanFields, sortColumn);\n\t\t\t\t\tstashFolded(data, row);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\t\tdata,\n\t\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\t// Encode nextCursor from the last row if there are more results\n\t\t\t\tlet nextCursor: string | undefined;\n\t\t\t\tif (hasMore && rows.length > 0) {\n\t\t\t\t\tconst lastRow = rows.at(-1)!;\n\t\t\t\t\tnextCursor = encodeSortCursor(sortColumn, lastRow[sortColumn], String(lastRow.id));\n\t\t\t\t}\n\n\t\t\t\t// Collection-level cache hint uses the most recent updated_at\n\t\t\t\tlet collectionLastModified: Date | undefined;\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\tif (row.updated_at) {\n\t\t\t\t\t\tconst d = new Date(rowStr(row, \"updated_at\"));\n\t\t\t\t\t\tif (!collectionLastModified || d > collectionLastModified) {\n\t\t\t\t\t\t\tcollectionLastModified = d;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tentries,\n\t\t\t\t\tnextCursor,\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [type],\n\t\t\t\t\t\tlastModified: collectionLastModified,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\t// Handle missing table/column gracefully - return empty collection.\n\t\t\t\t// Missing table happens before migrations have run.\n\t\t\t\t// Missing column happens when a where filter references a non-existent field.\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tif (isMissingTableError(error) || isMissingColumnError(error)) {\n\t\t\t\t\tif (isMissingColumnError(error)) {\n\t\t\t\t\t\tconsole.warn(`[emdash] where filter: ${message}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn { entries: [] };\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\terror: new Error(`Failed to load collection: ${message}`),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load a single entry by type and ID/slug\n\t\t *\n\t\t * When filter.revisionId is set (preview mode), the entry's data\n\t\t * comes from the revisions table instead of the content table columns.\n\t\t */\n\t\tasync loadEntry({ filter }) {\n\t\t\ttry {\n\t\t\t\t// Get DB instance\n\t\t\t\tconst db = await getDb();\n\n\t\t\t\t// Both type and id are required\n\t\t\t\tconst type = filter?.type;\n\t\t\t\tconst id = filter?.id;\n\n\t\t\t\tif (!type || !id) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\"type and id filters are required. Use getEmDashEntry() instead of getLiveEntry() directly.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Query the per-collection table\n\t\t\t\tconst tableName = getTableName(type);\n\t\t\t\tconst locale = filter?.locale;\n\n\t\t\t\t// Use raw SQL for dynamic table name, match by slug or id\n\t\t\t\t// When locale is specified, prefer locale-scoped slug match,\n\t\t\t\t// but IDs are globally unique so always check id without locale scope.\n\t\t\t\t//\n\t\t\t\t// Byline + taxonomy hydration (foldedHydrationSelects) and per-entry\n\t\t\t\t// SEO (foldedSeoSelect) are each surfaced as a single aggregated JSON\n\t\t\t\t// column rather than flat columns. This keeps the result-set width\n\t\t\t\t// bounded at any collection schema width: a flat `LEFT JOIN _emdash_seo`\n\t\t\t\t// adds 5 alias columns to every row and pushes wide flat-schema\n\t\t\t\t// collections (common after WordPress / ACF imports) past D1's\n\t\t\t\t// per-result-set column limit, surfacing as a silent null entry. One\n\t\t\t\t// JSON column is one column, so the join stays safe at any width and\n\t\t\t\t// we keep the single round trip.\n\t\t\t\tconst {\n\t\t\t\t\tterms: termsSelect,\n\t\t\t\t\tbylines: bylinesSelect,\n\t\t\t\t\tbylinesExist: bylinesExistSelect,\n\t\t\t\t} = foldedHydrationSelects(db, type, \"c\");\n\t\t\t\tconst seoSelect = foldedSeoSelect(db, type, \"c\");\n\t\t\t\tconst booleanFieldsSelect = foldedBooleanFieldsSelect(db, type);\n\t\t\t\t// Keep collection-wide metadata in one result column for wide D1 collections.\n\t\t\t\tconst jsonObject = isPostgres(db) ? sql`json_build_object` : sql`json_object`;\n\t\t\t\tconst metadataSelect = sql`(\n\t\t\t\t\tSELECT ${jsonObject}(\n\t\t\t\t\t\t'bylinesExist', _emdash_bylines_exist,\n\t\t\t\t\t\t'booleanFields', _emdash_boolean_fields\n\t\t\t\t\t)\n\t\t\t\t\tFROM (SELECT ${bylinesExistSelect}, ${booleanFieldsSelect}) AS metadata\n\t\t\t\t) AS _emdash_entry_metadata`;\n\t\t\t\tconst result = locale\n\t\t\t\t\t? await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT c.*, ${seoSelect}, ${termsSelect}, ${bylinesSelect}, ${metadataSelect}\n\t\t\t\t\t\t\tFROM ${sql.ref(tableName)} AS c\n\t\t\t\t\t\t\tWHERE c.deleted_at IS NULL\n\t\t\t\t\t\t\tAND ((c.slug = ${id} AND c.locale = ${locale}) OR c.id = ${id})\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t`.execute(db)\n\t\t\t\t\t: await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT c.*, ${seoSelect}, ${termsSelect}, ${bylinesSelect}, ${metadataSelect}\n\t\t\t\t\t\t\tFROM ${sql.ref(tableName)} AS c\n\t\t\t\t\t\t\tWHERE c.deleted_at IS NULL\n\t\t\t\t\t\t\tAND (c.slug = ${id} OR c.id = ${id})\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t`.execute(db);\n\n\t\t\t\tconst row = result.rows[0];\n\t\t\t\tif (!row) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tconst rawMetadata = row._emdash_entry_metadata;\n\t\t\t\tconst metadata: unknown =\n\t\t\t\t\ttypeof rawMetadata === \"string\" ? JSON.parse(rawMetadata) : rawMetadata;\n\t\t\t\tdelete row._emdash_entry_metadata;\n\t\t\t\tif (isPlainObject(metadata)) {\n\t\t\t\t\trow._emdash_bylines_exist = metadata.bylinesExist;\n\t\t\t\t\trow[BOOLEAN_FIELDS_FOLDED_COLUMN] = metadata.booleanFields;\n\t\t\t\t}\n\n\t\t\t\t// Expand the folded SEO JSON column onto SEO_COLUMN_ALIASES so\n\t\t\t\t// extractSeo() reads it transparently. Missing/null SEO is a\n\t\t\t\t// no-op: extractSeo() returns null when the aliases are absent.\n\t\t\t\texpandFoldedSeo(row);\n\n\t\t\t\tconst entryId = entryIdForRow(row);\n\n\t\t\t\t// Preview mode: override content fields with revision data,\n\t\t\t\t// keeping system metadata from the content table row.\n\t\t\t\tconst revisionId = filter?.revisionId;\n\t\t\t\tif (revisionId) {\n\t\t\t\t\tconst revRow = await sql<{ data: string }>`\n\t\t\t\t\t\tSELECT data FROM revisions\n\t\t\t\t\t\tWHERE id = ${revisionId}\n\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t`.execute(db);\n\n\t\t\t\t\tconst revData = revRow.rows[0];\n\t\t\t\t\tif (revData) {\n\t\t\t\t\t\tconst revEntry = revisionEntry(\n\t\t\t\t\t\t\trow,\n\t\t\t\t\t\t\tJSON.parse(revData.data),\n\t\t\t\t\t\t\tparseFoldedBooleanFields(row),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// SEO is not revisioned — it comes from the content row's\n\t\t\t\t\t\t// joined _emdash_seo columns, not the revision snapshot.\n\t\t\t\t\t\tconst revSeo = extractSeo(row);\n\t\t\t\t\t\tif (revSeo) {\n\t\t\t\t\t\t\trevEntry.data.seo = revSeo;\n\t\t\t\t\t\t\t// SEO comes from the content row, so the panel data is\n\t\t\t\t\t\t\t// valid for the entry regardless of the revision shown.\n\t\t\t\t\t\t\tprimeSeoPanel(type, rowStr(row, \"id\"), revSeo);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstashFolded(revEntry.data, row);\n\t\t\t\t\t\treturn revEntry;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst entryData = mapRowToData(row, parseFoldedBooleanFields(row));\n\t\t\t\tconst entrySeo = extractSeo(row);\n\t\t\t\tif (entrySeo) {\n\t\t\t\t\tentryData.seo = entrySeo;\n\t\t\t\t\t// Prime the request cache so <EmDashHead> can apply the panel\n\t\t\t\t\t// values without its own _emdash_seo query. Keyed by the\n\t\t\t\t\t// content-row id — the same value templates pass as\n\t\t\t\t\t// page.content.id.\n\t\t\t\t\tprimeSeoPanel(type, rowStr(row, \"id\"), entrySeo);\n\t\t\t\t}\n\t\t\t\tstashFolded(entryData, row);\n\t\t\t\treturn {\n\t\t\t\t\tid: entryId,\n\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\tdata: entryData,\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\t// Handle missing table gracefully - return undefined (not found).\n\t\t\t\t// This happens before migrations have run.\n\t\t\t\tif (isMissingTableError(error)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\treturn {\n\t\t\t\t\terror: new Error(`Failed to load entry: ${message}`),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifest-builder-B8zjuH3f.mjs","names":[],"sources":["../src/i18n/normalize.ts","../src/migrations/manifest.ts","../src/migrations/integration-metadata.ts","../src/migrations/manifest-builder.ts"],"sourcesContent":["import type { I18nConfig } from \"./config.js\";\n\nexport interface AstroLocaleObject {\n\tpath: string;\n\tcodes: readonly string[];\n}\n\nexport interface AstroI18nInput {\n\tdefaultLocale: string;\n\tlocales: readonly (string | AstroLocaleObject)[];\n\tfallback?: Readonly<Record<string, string | undefined>>;\n\trouting?: string | { prefixDefaultLocale?: boolean };\n}\n\nexport function normalizeAstroI18n(config: AstroI18nInput | null | undefined): I18nConfig | null {\n\tif (!config) return null;\n\n\treturn {\n\t\tdefaultLocale: config.defaultLocale,\n\t\tlocales: config.locales.map((locale) => (typeof locale === \"string\" ? locale : locale.path)),\n\t\tfallback: config.fallback\n\t\t\t? Object.fromEntries(\n\t\t\t\t\tObject.entries(config.fallback).filter(\n\t\t\t\t\t\t(entry): entry is [string, string] => entry[1] !== undefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t: undefined,\n\t\tprefixDefaultLocale:\n\t\t\ttypeof config.routing === \"object\" ? (config.routing.prefixDefaultLocale ?? false) : false,\n\t};\n}\n","import { z } from \"zod\";\n\nimport type { CoreMigrationIdentity } from \"./identity.js\";\nimport { fingerprintMigrationSet } from \"./identity.js\";\n\nconst FINGERPRINT_PATTERN = /^[0-9a-f]{64}$/;\nconst MIGRATION_NAME_PATTERN = /^\\d{3}_[a-z0-9_]+$/;\nconst EXECUTOR_ENTRYPOINT_PATTERN =\n\t/^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*(?:\\/[A-Za-z0-9][A-Za-z0-9._-]*)*$/;\nconst ENVIRONMENT_VARIABLE_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst ENVIRONMENT_REFERENCE_KEY_PATTERN = /(?:env|envName|envVar)$/i;\nconst URL_SCHEME_PATTERN = /^[A-Za-z][A-Za-z0-9+.-]*:/;\nconst SECRET_QUERY_KEY_PATTERN = /(?:auth|credential|key|password|secret|signature|token)/i;\nconst SECRET_CONFIG_KEY_PATTERN =\n\t/(?:accessToken|apiKey|authToken|certificate|connectionString|password|privateKey|secret)/i;\nconst SECRET_CONFIG_EXACT_KEY_PATTERN = /^(?:ca|cert|key)$/i;\nconst CONNECTION_URL_PROTOCOLS = new Set([\"mysql:\", \"postgres:\", \"postgresql:\"]);\n\ntype JsonPrimitive = boolean | number | string | null;\ntype JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };\n\nconst i18nConfigSchema = z\n\t.object({\n\t\tdefaultLocale: z.string().min(1),\n\t\tlocales: z.array(z.string().min(1)).min(1),\n\t\tfallback: z.record(z.string(), z.string()).optional(),\n\t\tprefixDefaultLocale: z.boolean().optional(),\n\t})\n\t.strict();\n\nexport const migrationManifestV1Schema = z\n\t.object({\n\t\tschemaVersion: z.literal(1),\n\t\temdashVersion: z.string().min(1),\n\t\tmigrationSet: z\n\t\t\t.object({\n\t\t\t\tnames: z\n\t\t\t\t\t.array(z.string().regex(MIGRATION_NAME_PATTERN))\n\t\t\t\t\t.min(1)\n\t\t\t\t\t.refine((names) => new Set(names).size === names.length),\n\t\t\t\tfingerprint: z.string().regex(FINGERPRINT_PATTERN),\n\t\t\t})\n\t\t\t.strict(),\n\t\ti18n: i18nConfigSchema.nullable(),\n\t\tdatabase: z\n\t\t\t.object({\n\t\t\t\ttype: z.enum([\"sqlite\", \"postgres\"]),\n\t\t\t\texecutorEntrypoint: z.string().regex(EXECUTOR_ENTRYPOINT_PATTERN),\n\t\t\t\texecutorConfig: z.unknown(),\n\t\t\t})\n\t\t\t.strict(),\n\t})\n\t.strict();\n\nexport type MigrationManifestV1 = z.infer<typeof migrationManifestV1Schema>;\n\nexport class MigrationManifestValidationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(`Invalid migration manifest: ${message}`);\n\t\tthis.name = \"MigrationManifestValidationError\";\n\t}\n}\n\nfunction isEnvironmentReferenceKey(key: string): boolean {\n\treturn ENVIRONMENT_REFERENCE_KEY_PATTERN.test(key);\n}\n\nfunction assertSafeUrl(value: string, path: string): void {\n\tif (!URL_SCHEME_PATTERN.test(value)) return;\n\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new MigrationManifestValidationError(`${path} contains an invalid URL`);\n\t}\n\n\tif (CONNECTION_URL_PROTOCOLS.has(url.protocol)) {\n\t\tthrow new MigrationManifestValidationError(`${path} contains a database connection URL`);\n\t}\n\tif (url.username || url.password) {\n\t\tthrow new MigrationManifestValidationError(`${path} contains URL credentials`);\n\t}\n\tfor (const key of url.searchParams.keys()) {\n\t\tif (SECRET_QUERY_KEY_PATTERN.test(key)) {\n\t\t\tthrow new MigrationManifestValidationError(`${path} contains a credential query parameter`);\n\t\t}\n\t}\n}\n\nfunction cloneSecretFreeJson(value: unknown, path: string, ancestors: Set<object>): JsonValue {\n\tif (value === null || typeof value === \"boolean\") return value;\n\tif (typeof value === \"string\") {\n\t\tassertSafeUrl(value, path);\n\t\treturn value;\n\t}\n\tif (typeof value === \"number\") {\n\t\tif (Number.isFinite(value)) return value;\n\t\tthrow new MigrationManifestValidationError(`${path} contains a non-finite number`);\n\t}\n\tif (typeof value !== \"object\") {\n\t\tthrow new MigrationManifestValidationError(`${path} is not JSON-serializable`);\n\t}\n\tif (ancestors.has(value)) {\n\t\tthrow new MigrationManifestValidationError(`${path} contains a cycle`);\n\t}\n\n\tancestors.add(value);\n\ttry {\n\t\tif (Array.isArray(value)) {\n\t\t\treturn value.map((item, index) => cloneSecretFreeJson(item, `${path}[${index}]`, ancestors));\n\t\t}\n\n\t\tconst prototype = Object.getPrototypeOf(value);\n\t\tif (prototype !== Object.prototype && prototype !== null) {\n\t\t\tthrow new MigrationManifestValidationError(`${path} contains a non-plain object`);\n\t\t}\n\n\t\tconst cloned: Record<string, JsonValue> = {};\n\t\tfor (const [key, item] of Object.entries(value)) {\n\t\t\tconst itemPath = `${path}.${key}`;\n\t\t\tconst environmentReference = isEnvironmentReferenceKey(key);\n\t\t\tif (\n\t\t\t\t!environmentReference &&\n\t\t\t\t(SECRET_CONFIG_KEY_PATTERN.test(key) || SECRET_CONFIG_EXACT_KEY_PATTERN.test(key))\n\t\t\t) {\n\t\t\t\tthrow new MigrationManifestValidationError(`${itemPath} is a credential-bearing field`);\n\t\t\t}\n\t\t\tif (environmentReference) {\n\t\t\t\tif (typeof item !== \"string\" || !ENVIRONMENT_VARIABLE_PATTERN.test(item)) {\n\t\t\t\t\tthrow new MigrationManifestValidationError(\n\t\t\t\t\t\t`${itemPath} must contain an environment-variable name`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcloned[key] = cloneSecretFreeJson(item, itemPath, ancestors);\n\t\t}\n\t\treturn cloned;\n\t} finally {\n\t\tancestors.delete(value);\n\t}\n}\n\nexport function validateSecretFreeExecutorConfig(\n\tvalue: unknown,\n\tpath = \"database.executorConfig\",\n): unknown {\n\treturn cloneSecretFreeJson(value, path, new Set());\n}\n\nfunction identitiesMatch(\n\tmanifest: MigrationManifestV1,\n\texpectedIdentity: CoreMigrationIdentity,\n): boolean {\n\treturn (\n\t\tmanifest.emdashVersion === expectedIdentity.emdashVersion &&\n\t\tmanifest.migrationSet.fingerprint === expectedIdentity.fingerprint &&\n\t\tmanifest.migrationSet.names.length === expectedIdentity.names.length &&\n\t\tmanifest.migrationSet.names.every((name, index) => name === expectedIdentity.names[index])\n\t);\n}\n\nexport async function validateMigrationManifest(\n\tvalue: unknown,\n\texpectedIdentity?: CoreMigrationIdentity,\n): Promise<MigrationManifestV1> {\n\tconst parsed = migrationManifestV1Schema.safeParse(value);\n\tif (!parsed.success) {\n\t\tthrow new MigrationManifestValidationError(\"schema validation failed\");\n\t}\n\n\tconst executorConfig = validateSecretFreeExecutorConfig(parsed.data.database.executorConfig);\n\tconst manifest: MigrationManifestV1 = {\n\t\t...parsed.data,\n\t\tdatabase: { ...parsed.data.database, executorConfig },\n\t};\n\tconst fingerprint = await fingerprintMigrationSet(\n\t\tmanifest.emdashVersion,\n\t\tmanifest.migrationSet.names,\n\t);\n\tif (fingerprint !== manifest.migrationSet.fingerprint) {\n\t\tthrow new MigrationManifestValidationError(\n\t\t\t\"migrationSet fingerprint does not match its version and ordered names\",\n\t\t);\n\t}\n\tif (expectedIdentity && !identitiesMatch(manifest, expectedIdentity)) {\n\t\tthrow new MigrationManifestValidationError(\n\t\t\t\"manifest does not match the loaded EmDash migration identity\",\n\t\t);\n\t}\n\n\treturn manifest;\n}\n\nexport function serializeMigrationManifest(manifest: MigrationManifestV1): string {\n\treturn `${JSON.stringify(manifest, null, \"\\t\")}\\n`;\n}\n","import type { DatabaseDescriptor } from \"../db/adapters.js\";\nimport { validateSecretFreeExecutorConfig } from \"./manifest.js\";\n\nexport const MIGRATION_CONFIG_SYMBOL = Symbol.for(\"emdash:migration-config\");\n\nexport interface MigrationIntegrationMetadata {\n\tdatabase?: Pick<DatabaseDescriptor, \"type\" | \"migrations\">;\n}\n\nfunction isRecord(value: unknown): value is Record<PropertyKey, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction isMigrationIntegrationMetadata(value: unknown): value is MigrationIntegrationMetadata {\n\tif (!isRecord(value)) return false;\n\tconst database = value.database;\n\tif (database === undefined) return true;\n\tif (!isRecord(database) || (database.type !== \"sqlite\" && database.type !== \"postgres\")) {\n\t\treturn false;\n\t}\n\n\tconst migrations = database.migrations;\n\treturn (\n\t\tmigrations === undefined ||\n\t\t(isRecord(migrations) &&\n\t\t\ttypeof migrations.entrypoint === \"string\" &&\n\t\t\tObject.hasOwn(migrations, \"manifestConfig\"))\n\t);\n}\n\nexport function createMigrationIntegrationMetadata(\n\tdatabase?: DatabaseDescriptor,\n): MigrationIntegrationMetadata {\n\tif (!database) return {};\n\n\treturn {\n\t\tdatabase: {\n\t\t\ttype: database.type,\n\t\t\tmigrations: database.migrations\n\t\t\t\t? {\n\t\t\t\t\t\tentrypoint: database.migrations.entrypoint,\n\t\t\t\t\t\tmanifestConfig: validateSecretFreeExecutorConfig(\n\t\t\t\t\t\t\tdatabase.migrations.manifestConfig,\n\t\t\t\t\t\t\t\"database.migrations.manifestConfig\",\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t},\n\t};\n}\n\nexport function getMigrationIntegrationMetadata(\n\tintegration: unknown,\n): MigrationIntegrationMetadata | undefined {\n\tif (\n\t\t(typeof integration !== \"object\" || integration === null) &&\n\t\ttypeof integration !== \"function\"\n\t) {\n\t\treturn undefined;\n\t}\n\tif (!Object.hasOwn(integration, MIGRATION_CONFIG_SYMBOL)) {\n\t\treturn undefined;\n\t}\n\n\tconst metadata: unknown = Reflect.get(integration, MIGRATION_CONFIG_SYMBOL);\n\treturn isMigrationIntegrationMetadata(metadata) ? metadata : undefined;\n}\n","import type { DatabaseDescriptor } from \"../db/adapters.js\";\nimport type { I18nConfig } from \"../i18n/config.js\";\nimport type { CoreMigrationIdentity } from \"./identity.js\";\nimport { fingerprintMigrationSet } from \"./identity.js\";\nimport type { MigrationManifestV1 } from \"./manifest.js\";\nimport { MigrationManifestValidationError, validateMigrationManifest } from \"./manifest.js\";\n\nexport type ManifestDatabaseDescriptor = Pick<DatabaseDescriptor, \"type\" | \"migrations\">;\n\nexport interface BuildMigrationManifestOptions {\n\tidentity: CoreMigrationIdentity;\n\ti18n: I18nConfig | null;\n\tdatabase: ManifestDatabaseDescriptor;\n}\n\nexport class UnsupportedMigrationAdapterError extends Error {\n\tconstructor() {\n\t\tsuper(\"The configured database adapter does not provide a deployment migration executor\");\n\t\tthis.name = \"UnsupportedMigrationAdapterError\";\n\t}\n}\n\nexport async function buildMigrationManifest({\n\tidentity,\n\ti18n,\n\tdatabase,\n}: BuildMigrationManifestOptions): Promise<MigrationManifestV1> {\n\tconst identityFingerprint = await fingerprintMigrationSet(identity.emdashVersion, identity.names);\n\tif (identityFingerprint !== identity.fingerprint) {\n\t\tthrow new MigrationManifestValidationError(\n\t\t\t\"loaded identity fingerprint does not match its version and ordered names\",\n\t\t);\n\t}\n\tif (!database.migrations) {\n\t\tthrow new UnsupportedMigrationAdapterError();\n\t}\n\n\treturn validateMigrationManifest(\n\t\t{\n\t\t\tschemaVersion: 1,\n\t\t\temdashVersion: identity.emdashVersion,\n\t\t\tmigrationSet: {\n\t\t\t\tnames: [...identity.names],\n\t\t\t\tfingerprint: identity.fingerprint,\n\t\t\t},\n\t\t\ti18n,\n\t\t\tdatabase: {\n\t\t\t\ttype: database.type,\n\t\t\t\texecutorEntrypoint: database.migrations.entrypoint,\n\t\t\t\texecutorConfig: database.migrations.manifestConfig,\n\t\t\t},\n\t\t},\n\t\tidentity,\n\t);\n}\n"],"mappings":"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"}